Xah Lee, 2008-12-05
Here's a explanation of some high powered construct of Mathematica.
Let's say for example, we want to write a function that takes a vector (of linear algebra), and return a vector in the same direction but with length 1. In linear algebar terminology, the new vector is called the “normalized” vector of the original.
For those of you who don't know linear algebra but knows coding, this means, we want a function whose input is a list of 3 elements say {x,y,z}, and output is also a list of 3 elements, say {a,b,c}, with the condition that:
a = x/Sqrt[x^2+y^2+z^2] b = y/Sqrt[x^2+y^2+z^2] c = z/Sqrt[x^2+y^2+z^2]
In Mathematica, this can be defined like this:
normalize=Function[#/Sqrt@(Plus@@(#^2))]
Here i explain how it is so succinct.
Mathematica's syntax support what's called FullForm, which is basically a fully nested notation like lisp's. In fact, the Mathematica compiler works with FullForm. The FullForm is not something internal. A programer can type his code that way if he so pleases.
In FullForm, the above expression is this:
Set[ normalize, Function[ Times[Slot[1], Power[ Sqrt[ Apply[ Plus, Power[ Slot[1], 2 ] ] ], -1 ] ] ]
Now, in “normalize=Function[#/Sqrt@(Plus@@(#^2))]”, the “Function” is your lisper's “lambda”. The “#” is the formal parameter. So, in the outset we set “normalize” to be a pure function. Now, note that the “#” is not just a number, but can be any argument, including vector of the form {x,y,z}. So, we see here that math operations are applied to list entities directly. For example, in Mathematica, {3,4,5}/2 returns {3/2,2,5/2} and {3,4,5}^2 returns {9,16,25}.
In typical lang such as python, including lisp, you would have to map the operation into each lisp elements instead.
The “Sqrt@...” is a syntax shortcut for “Sqrt[...]”, and the “Plus@@...” is a syntax shortcut for “Apply[Plus, ...]”, which is lisp's “funcall”. So, taking the above all together, the code for “normalize” given above is _syntactically equivalent_ to this:
normalize=Function[ #/Sqrt[ Apply[Plus, #^2] ]]
the above means: square the vector, add them together, take the square root, then have the original vector divide it.
The “#” is in fact a syntax shortcut for “Slot[1]”, meaning the first formal parameter. The “=” is in fact a syntax shortcut for “Set[]”. The “^” is a shortcut for “Power[]”, and the “/” in “a/b” is a shortcut for “Times[a,Power[b, -1]]”. Putting all these together, you can see how the code is syntactically equivalent to the above nested FullFolm.
Note, that the “normalize” as defined above works for vectors of any dimention, i.e. list of any length.
In lisp, python, perl, etc, you'll have 10 or so lines. In C or Java, you'll have 50 or hundreds of lines. (Exaggerated. see addendum below)
Note: Normalize function is now a builtin function in Mathematica v6, released sometimes in 2007. See: http://reference.wolfram.com/mathematica/ref/Normalize.html.
Addendum
Thanks to “comp.lang.*” newsgroups, various people have given code for different languages.
-- Haskell. By the.brown.dragon...@gmail.com let normalize vec = map (/ (sqrt $ sum (map (^2) vec))) vec in normalize [3,4]
# ruby. By w_a_x...@yahoo.com def normalize vec s = Math.sqrt(vec.map{|x|x*x}.inject{|x,y|x+y}) vec.map{|x| x/s} end p normalize([3,4])
# Python. By Roberto Bonvallet def normalize(v): return (lambda norm: [x/norm for x in v])(sum(x**2 for x in v) **0.5) print normalize([3,4])
# Perl. By Jim Gibson sub normalize { my $sum = 0; $sum += $_ ** 2 for @_; my $length = sqrt($sum); return map { $_ / $length } @_; } @vec = (3,4); @vec2 = normalize(@vec); use Data::Dumper; print Dumper(\@vec2);
;; Scheme Lisp. By Bakul Shah (define (normalize vec) (let ((d (sqrt (apply + (map (lambda (x) (* x x)) vec))))) (map (lambda (x) (/ x d)) vec))) (normalize '(3 4))
// Javascript. By Gerard Flanagan var map = function(fn, v) { var b = new Array(v.length); for (i = 0; i < v.length; i++) { b[i] = fn(v[i]); } return b }; var reduce = function(fn, v, init) { var s = init; for (i = 0; i < v.length; i++) { s = fn(s, v[i]); } return s }; var sum = function(v) { return reduce(function(x, y) { return x + y }, v, 0.0) }; var vectorLength = function(v) { var pow = Math.pow; return Math.sqrt(sum(map(function(x) { return pow(x, 2) }, v))) }; var normalize = function(vec) { var N = vectorLength(vec); return map(function(x) { return x/N }, vec) } print(normalize([3,4]));
// Java. By John W Kennedy. Class wrapper and printing code added by Xah Lee. class Test { static float[] normalize(final float[] vec) { float sum = 0.0f; for (int i = 0; i < vec.length; ++i) sum += vec[i] * vec[i]; final float divisor = (float) Math.sqrt(sum); float[] a = new float[vec.length]; for (int i = 0; i < vec.length; ++i) a[i] = vec[i]/divisor; return a; } public static void main(String[] args) { float[] inputVector = {3,4}; float[] resultVector = normalize(inputVector); for (int i = 0; i < resultVector.length; i++) { System.out.print(resultVector[i] + " "); } } }
The following javascript program is not qualified. It is syntax error in SpiderMonkey engine “JavaScript-C 1.7.0 2007-10-03”.
// Javascript. By William James function normalize( vec ) { var div=Math.sqrt(vec.map(function(x) x*x).reduce(function(a,b) a+b)) return vec.map(function(x) x/div) }
The following C code is not qualified. It needs to be a full stand alone program that takes vector of any dimention and prints the result. Due to C's low-level nature, the program perhaps needs include code to parse command line input of arbitrary vector such as a list of numbers separated by space, and print the result in output.
// C. By John W Kennedy #include <stdlib.h> #include <math.h> void normalize(int dim, float* x, float* a) { float sum = 0.0f; int i; float divisor; for (i = 0; i < dim; ++i) sum += x[i] * x[i]; divisor = sqrt(sum); for (i = 0; i < dim; ++i) a[i] = x[i]/divisor; }
Related essays: