Wednesday, May 15, 2013

Getting Help: Find a Function Using Wildcards

There are over 4000 built-in functions in Mathematica, not including those in add-on Packages. 

In[340]:= Names["System`*"]//Length

Out[340]= 4131

Therefore it makes sense to see if there is a built-in function before we write one. Likewise, the large number of functions means that we often have a vague memory of a function we've used but can't put our finger on its name when we need it again. If I have some idea of the name of a function I've used, or want to see if there is an existing function and guess at part of its name, I use a wildcard in my current Notebook with the short form of Information (?). To find a function or survey related functions, this is faster than using the Doc Center.

Here I want to know the filepath of my current Notebook, which I cannot find in any Mathematica menu item. Maybe there's a Notebook function to tell me. I scan down the results until I see NotebookFileName, which is the one I want. I also quickly click on a half-dozen or so functions to refresh my memory of them or explore new ones and read the short info displayed below the results.

Using Information this way is always fruitful for me since I efficiently learn about functions I didn't remember or didn't know. But if it fails to flush out the function I want, I go to the Doc Center and search there.

Friday, May 10, 2013

Flat (Function Attribute of associativity; removes brackets and parentheses)

Why does this function works for more than the two arguments for which it is defined?

In[100]:= log[a_ b_]:=log@a+log@b

In[101]:= log[2 x y]

Out[101]= log[2]+log[x]+log[y]

The answer is that Times has the Attribute Flat, which is Mathematica's interesting name for the mathematical property of associativity. I.e., as we learned in school, (2 + 3) + 4 = 2 + (3 + 4). We can remove the parentheses. So the Attribute is called Flat since, after the name for the function Flatten that removes List brackets, Mathematica knows that for some functions it's valid to remove all parentheses or List brackets. What is handy is to automatically remove all brackets from a user-defined function, use SetAttributes[ function, Flat].

Thus Time's Attributes show it to be more profound than we might expect. We check function Attributes like this:

In[102]:= Attributes@Plus

Out[102]= {Flat,Listable,NumericFunction,OneIdentity,Orderless,Protected}

And we can find all built-in functions with a given attribute like this, first taking all function Names from the System context where they live, using the wildcard "*", then using a pattern in Cases:

In[103]:= Names@"System`*"//Cases[#,_?(MemberQ[Attributes@#,Orderless]&)]&

Out[103]= {ArithmeticGeometricMean,BitAnd,BitOr,BitXor,CoprimeQ,DiracDelta,DiscreteDelta,Equivalent,GCD,HeavisideTheta,KroneckerDelta,LCM,Majority,Max,Min,Multinomial,Plus,Times,UnitStep,Xnor,Xor}

Last, Trace shows how the Flat Attribute affects the operation of Times in the simple example. Mathematica knows it can split up a function applied to two arguments times each other, and, typically for the evaluator, keeps applying the rule to split up all arguments of Times until there are no lists of more than two left.

In[104]:= log[2x y]//Trace

Out[104]= {log[2 x y],log[2]+log[x y],{log[x y],log[x]+log[y]},log[2]+(log[x]+log[y]),log[2]+log[x]+log[y]}

Wednesday, May 8, 2013

How to Write a Program in Mathematica: Basic Programming Principles

If you look at the code of the creators of Mathematica's programming language, Stephen Wolfram (e.g. Ch. 5., Cellular Automata, of A New Kind of Science) and Roman Maeder (see his superb books), you will see simplicity and organization. They are master programmers. So if the method of Wolfram and Maeder is to keep things simple and thoughtfully organize their programs, let us follow their example. With that in mind, here are some principles to create any program, step by step.
  1. Write and debug a series of one liners to execute your program. In other words, start by just doing what you want to do "by hand," one line at a time. Then when you're done and it works, assemble the series of one liners into a program.
  2. If the input or output of any step is at all complicated, first solve a toy version. If your entire program is complicated, first solve a toy version of it. Then try each step on the actual problem.
  3. A Functional programming principle is write functions few inputs and outputs as possible–ideally just one output. If you have only one input and one output per function, each is easy to write and debug. Sometimes you have to carry related parameters together. In the function under construction, it's still advisable to have as few parameters affect a single output as possible. 
  4. To assemble the program, first create the shell, i.e. just a Module (or With or Block) with the name of the program function and those of its arguments. Then put each one-liner in the program one at a time, on a separate line, and run the program. 
  5. A Print statement is the simplest form of debugging. So Return or Print the output of any command that you need to see. If you have a long set of arguments or if any are complex, start by just returning the arguments to see if you get what you expected. Leave a Print statement in the program if you need to monitor each output, or if not, delete it. If you think you might need it, comment it out (*Print@variable1."*).
  6. And in general, per the 2000-year old army saying, Clean As You Go (which derives from the law of increasing entropy). Precede your function with Clear@function. Delete things you don't need. Re-organize for clarity. 
  7. There is no shame in clarity. Someone else may need to read your code. And you may be that someone else. As an acquaintance of mine, Gary Drescher, once said, "The 'I' of the future is only loosely coupled to the 'I' of the present." You, 6 months from now, will not have an easy time of deciphering your own code unless you go for clarity. 
  • Use long variable names (like master programmers Hoare and Trott). 
  • Format a cell for text (Alt+7) above your program and comment freely. 
  • Use inline comments (* comment here *) judiciously alongside lines of your code. Too many comments break up the readability.
  • Use the combination of Prefix and Postfix with pure Function that I advocate (here in this blog), which simplifies your code and gives you total control over which functions to emphasize and which to subordinate. 
  1. As you put each one liner in the program, be sure to include any variable names in the local variable List in the Module. If variable names are not listed Mathematica will flag them in a color (blue in my version). You can save space and simplify things by putting assignment functions in the local variable List as long as they're not dependent on a variable that came earlier in the List. If they are dependent, the assignment has to be put in the program body. Put the local variable names in the List in the order that they appear in your program.
  1. Remember the fundamental data structure principles:
  • Write and debug a special function, called a Selector, to extract each subset of what you need from your data. Only use Selectors to touch the data; never touch it directly with the program. When the structure of your data changes, re-write the Selector.
  • Write and debug a special function, called a Constructor, to build each construct from the data. Only use Constructors to build the constructs. Leave the original data alone.
  • If need be, write and debug a special function to export or format the output of your program. Only use the special function to export or format your output.
  • Two other arch-typical data structure functions are constants, that always return the same thing either with no input or no matter what the input, and predicates, that take an input and return True or False.
  1. Whether to define a function in your program, or outside of it and then call it in the program, is a judgment call. A simple but valid answer is if you plan on using the function outside of your program, define it outside to facilitate that usage. But an equally important reason for defining a function outside of your program is to simplify it.
  2. With a medium to large program, consider just throwing out the original version if you see a better approach. At an IEEE seminar on object-oriented programming, the speaker said often you just need to start coding for a bit to get a feel for what you want to do before you can envision a better architectural solution.
Obviously I need to provide examples to illustrate all these principles and will do so.