Version 7 of Advanced Math in Jacl

Updated 2009-10-15 14:57:45 by dkf

I ( BAJ ) use a lot of numerical methods in my work and use the Apache Commons Math library (written in Java) in my code. This term I'm teaching a course in Computer Applications in Chemistry at and we're using MATLAB for part of it. That inspired me to think about adding a scriptable interface in Jacl to the Apache Commons Math Library. I whipped up a quick prototype to see if it's feasible. As the following demo shows it's actually reasonably useful already. The prototype requires, at least at present, changes in a few core Jacl Java classes.

No lassign command so source a Tcl version here and then import various commands from ::amath namespace so we can use short names.

% source lassign.tcl
% namespace eval ::amath { namespace export svd solve norm tr }

% namespace import ::amath::svd
% namespace import ::amath::solve
% namespace import ::amath::norm
% namespace import ::amath::tr

Create a vector. At first it is a string, but as soon as we use it in math it is converted to a TclMathArray object containing an Apache Commons Math RealVector object. We can do normal Tcl style (with expr) math (here multiply by a scalar, and then add to a second vector.

% set a {1 2 3}
1 2 3
% set b [expr {$a*4}]
4.0 8.0 12.0
% set c [expr {$a+$b}]
5.0 10.0 15.0

Matrices are entered using a list notation. Here we make a 2x2 matrix and then transpose it.

% set m {{1 2} {3 4}}
{1 2} {3 4}
% set m [tr $m]
{1.0 3.0} {2.0 4.0}

Let's use our favorite Linear Algebra algorithm, the Singular Value Decomposition. The svd command creates a list of three matrices which we store into u, s and v. Multiply them back together and check the norm of the difference with the original matrix.

% lassign [svd $m] u s v
% set vt [::amath::tr $v]
{-0.40455358483375703 -0.9145142956773044} {0.9145142956773044 -0.40455358483375714}
% set usvt [expr {$u*$s*$vt}]
{0.9999999999999996 2.9999999999999982} {1.9999999999999996 3.999999999999999}
% set diffM [expr {$m-$usvt}]
{4.440892098500626E-16 1.7763568394002505E-15} {4.440892098500626E-16 8.881784197001252E-16}
% set diffNorm [norm $diffM]

Most Jacl expression functions work. Here we take the log (of each element in matrix).

% set mlog [expr {log($m)}]
{0.0 1.0986122886681096} {0.6931471805599453 1.3862943611198906}

We can do element-by-element matrix operations with .*

% set mElemSq [expr {$m.*$m}]
{1.0 9.0} {4.0 16.0}

There's also a matrix (and vector) command to get access to elements (and rows and columns). This may be useful for loading matrices from files and attempting to avoid creating an internal string rep.

% puts $m
{1.0 3.0} {2.0 4.0}
% matrix set $m 0 0 5
{5.0 3.0} {2.0 4.0}