# This function multiplies together a series of matrices, performing
# the multiplications in an order so as to minimize the total number
# of operations.
# At most 10 arguments are allowed. They will be converted to matrices
# if necessary (and possible), but in a context-free manner. A scalar
# becomes a 1x1 matrix, and a vector becomes a matrix with 1 row. This
# is in contrast to Algae's multiplication operator, which makes different
# conversions according to the context.
# As an example, consider an NxN matrix A and an N vector b. If you
# give Algae the product A'*A*b, it first multiplies A'*A which involves
# an order of N^3 operations. But if you do it as A'*(A*b), there are
# only an order of N^2 operations. The difference can be huge! With
# this function, you'd do it as mult(A';A;b'). (Note that we have to
# explicitly convert b to a matrix with the right shape.)
mult = function (x0; x1; x2; x3; x4; x5; x6; x7; x8; x9)
{
local (i; j; k; N; s; t; r; y; z);
t = {};
t.(0) = x0;
t.(1) = x1;
t.(2) = x2;
t.(3) = x3;
t.(4) = x4;
t.(5) = x5;
t.(6) = x6;
t.(7) = x7;
t.(8) = x8;
t.(9) = x9;
for (i in 0:9)
{
if (t.(i) == NULL) { break; }
t.(i) = matrix (t.(i));
}
N = i;
if (N > 2)
{
r = fill (N+1; 0.0);
for (i in 1:N) { r[i] = t.(i-1).nr; }
r[N+1] = t.(N-1).nc;
y = triu (fill (N,N; 1e99); 1);
z = fill (N,N; 0);
for (j in 1:N-1)
{
for (i in 1:N-j)
{
for (k in i+1:i+j)
{
s = y[i;k-1] + y[k;i+j] + r[i]*r[k]*r[i+j+1];
if (s < y[i;i+j])
{
y[i;i+j] = s;
z[i;i+j] = k;
}
}
}
}
return self.ex (1; N; t; z);
elseif (N == 2)
return t.(0) * t.(1);
elseif (N == 1)
return t.(0);
else
return NULL;
}
};
mult.ex = function (i; j; t; z)
{
if (i == j)
{
return t.(i-1);
else
return (self (i; z[i;j]-1; t; z) *
self (z[i;j]; j; t; z));
}
};
syntax highlighted by Code2HTML, v. 0.9.1