Skip to main content

programming - Creating Mathematica packages



I'm building a package to help me write packages and their documentation. In this post I explained how to make a package and its documentation. In the answer I provided I describe how to build a very simple package. However, I have been looking around the extra packages that come with Mathematica and in some packages I see many .m files. I see this as a good way of dividing the application. Can someone describe the structure of a package?


To do this lets try to make a package out of the next simple functions. Suppose that we have the following in a notebook:


AddTwo::usage = "AddTwo[a, b] returns a+b";
AddThree::usage = "AddThree[a, b, c] returns a+b+c";
DotTwo::usage = "DotTwo[a, b] returns a*b";
DotThree::usage = "DotThree[a, b, c] returns a*b*c";
AddTwo[a_, b_] := a + b;
AddThree[a_, b_, c_] := a + b + c;
DotTwo[a_, b_] := a*b;
DotThree[a_, b_, c_] := a*b*c;


I would like to put these functions in a package. They all seem to be very simple arithmetic operations so let us make a package named SimpleArithmetic. This package is perfect to be divided into sections. One for additions and one for products, so we can make "subpackages" Addition and Product. If we follow some of the examples in the Mathematica installation we can create a folder called SimpleArithmetic in say $UserBaseDirectory. Inside SimpleArithmetic we can create two other files Addition.m and Product.m. The code for the additions would be placed in Addition.m and the code for multiplications would be placed in Product.m.


The question now is, how would these files look like? There is also a folder called Kernel which contains Init.m.


Could someone please just explain the best practices to create packages? I've read over the documentation and the whole "context" and "packages" keywords have already confused me. The code in the files I have described would be very appreciated.



Answer



Package creation is a large topic indeed. I will still attempt to give a minimal clarification of the encapsulation mechanism behind packages, since in my experience it pays off to understand it.


What constitutes a package


Basically, a piece of Mathematica code (usually containing a number of variable and function definitions), which is placed inside


Begin[someContext]


code

End[]

can be called a package. Usually, however, at least some more structure is present. In particular, to separate interface from implementation, the typical package looks like


BeginPackage[someContext]

public-functions-usage-messages

Begin["`Private`"]


code

End[]

EndPackage[]

Contexts and symbol names


The context here is a namespace. The convention is that context name is a string ending with "`". At any given moment, the value for the current working namespace is stored in the system variable $Context, and can also be queried by calling Context[]. Begin["test`"] will simply add the current context to the context stack, and then change it to "test`", while End[] will exit the current context by making the previous one current.


Every symbol must belong to some context. The system commands belong to the "System`" context, and the default working context for interactive FrontEnd sessions is "Global`". When mma code is parsed, the symbols are given their "true" (long) names, which contain both a symbol name and a context where the symbol is. For example, Map is really System`Map, and if I define a function f[x_]:=x^2 in the FE session, it will be Global`f. For any symbol, one can call Context[symbol] to determine the context where that symbol belongs. To "export" a symbol defined in a package, it is sufficient to simply use it in any way in the "public" part of the package, that is, before "`Private`" or other sub-contexts are entered. Usage messages is just one way to do it, one in principle could just write sym; and the sym would be created in the main package context just the same (although this practice is discouraged).



Every symbol can be referenced by its long name. Using the short name for a symbol is acceptable if the context where it belongs belongs to the list of contexts currently on the search path, stored in a variable $ContextPath. If there is more than one context on the $ContextPath, containing the symbol with the same short name, a symbol search ambiguity arises, which is called shadowing. This problem should be avoided, either by not loading packages with conflicting public (exported) symbols at the same time, or by referring to a symbol by its long name. I discussed this mechanics in slightly more detail in this post.


Contexts can be nested. In particular, the "`Private`" above is a sub-context of the main context someContext. When the package is loaded with Get or Needs,only its main context is added to the $ContextPath. Symbols created in sub-contexts are therefore inaccessible by their short names, which naturally creates the encapsulation mechanism. They can be accessed by their full long names however, which is occasionally handy for debugging.


Storing and loading packages


Packages are stored in files with ".m" extension. It is recommended that the name of the package coincides with the name of the package context. For the system to find a package, it must be placed into some of the locations specified in the system variable $Path. As a quick alternative (useful at the development stage), $Path can be appended with the location of a directory that contains a package.


When the Needs or Get command are called, the package is read into a current context. What is meant by this is that the package is read, parsed and executed, so that the definitions it contains are added to the global rule base. Then, its context name is added to the current $ContextPath. This makes the public symbols in a package accessible within the current working context by their short names. If a package A is loaded by another package B, then generally the public symbols of A will not be accessible in the context C which loads B - if needed, the A package must generally be explicitly loaded into C.


If the package has been loaded once during the work session, its functions can be accessed by their long names even if it is not currently on the $ContextPath. Typically, one would just call Needs again - if the package has been loaded already, Needs does not call Get but merely adds its context name to the $ContextPath. The internal variable $Packages contains a list of currently read in packages.


The case at hand


Here is how a package might look like:


BeginPackage["SimpleArithmetic`"]


AddTwo::usage = "AddTwo[a, b] returns a+b";
AddThree::usage = "AddThree[a, b, c] returns a+b+c";
TimesTwo::usage = "TimesTwo[a, b] returns a*b";
TimesThree::usage = "TimesThree[a, b, c] returns a*b*c";

Begin["`Private`"]

plus[args___] := Plus[args];
times[args___] := Times[args]


AddTwo[a_, b_] := plus[a, b];
AddThree[a_, b_, c_] := plus[a, b, c];
TimesTwo[a_, b_] := times[a, b];
TimesThree[a_, b_, c_] := times[a, b, c];

End[]
EndPackage[]

The functions AddTwo, AddThree, TimesTwo,TimesThree are public because these symbols were used in the public part of the package. Their long names would be then SimpleArithmetic`AddTwo, SimpleArithmetic`AddThree, SimpleArithmetic`TimesTwo, SimpleArithmetic`TimesThree. The functions plus and times are private to the package, since they are in the sub-context `Private`, which is not added to the ContextPath when the main package is loaded. Note that this is the only reason they are private. Should I call AppendTo[$ContextPath,SimpleArithmetic`Private`], and they'd become as "public" as the main functions (practice that should of course be discouraged by which should clarify the encapsulation mechanism).


With regards to splitting a package into several packages, this is a normal practice, but usually an individual mma package contains much more functionality than say a typical Java class, more like Java package. So, in the case at hand, I'd not split it until you get a much more functionality in it.



Of course, I only discussed here a very small subset of things related to packages. I will hopefully update this tutorial soon. An excellent reference for writing packages is a book of Roman Maeder "Programming in Mathematica". It is pretty old, but still one of the most (if not the most) useful accounts on the matter.


Comments

Popular posts from this blog

mathematical optimization - Minimizing using indices, error: Part::pkspec1: The expression cannot be used as a part specification

I want to use Minimize where the variables to minimize are indices pointing into an array. Here a MWE that hopefully shows what my problem is. vars = u@# & /@ Range[3]; cons = Flatten@ { Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; Minimize[{Total@((vec1[[#]] - vec2[[u[#]]])^2 & /@ Range[1, 3]), cons}, vars, Integers] The error I get: Part::pkspec1: The expression u[1] cannot be used as a part specification. >> Answer Ok, it seems that one can get around Mathematica trying to evaluate vec2[[u[1]]] too early by using the function Indexed[vec2,u[1]] . The working MWE would then look like the following: vars = u@# & /@ Range[3]; cons = Flatten@{ Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; NMinimize[ {Total@((vec1[[#]] - Indexed[vec2, u[#]])^2 & /@ R...

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

What is and isn't a valid variable specification for Manipulate?

I have an expression whose terms have arguments (representing subscripts), like this: myExpr = A[0] + V[1,T] I would like to put it inside a Manipulate to see its value as I move around the parameters. (The goal is eventually to plot it wrt one of the variables inside.) However, Mathematica complains when I set V[1,T] as a manipulated variable: Manipulate[Evaluate[myExpr], {A[0], 0, 1}, {V[1, T], 0, 1}] (*Manipulate::vsform: Manipulate argument {V[1,T],0,1} does not have the correct form for a variable specification. >> *) As a workaround, if I get rid of the symbol T inside the argument, it works fine: Manipulate[ Evaluate[myExpr /. T -> 15], {A[0], 0, 1}, {V[1, 15], 0, 1}] Why this behavior? Can anyone point me to the documentation that says what counts as a valid variable? And is there a way to get Manpiulate to accept an expression with a symbolic argument as a variable? Investigations I've done so far: I tried using variableQ from this answer , but it says V[1...