Strassen's Subcubic Matrix Multiplication Algorithm with recursion - algorithm

I am having an difficult time conceptualizing how to implement Strassen's version of this algorithm.
For background, I have the following pseudocode for the iterative version:
def Matrix(a,b):
result = []
for i in range(0,len(a)):
new_array = []
result.extend(new_array)
for j in range(0,len(b[0])):
ssum = 0
for k in range(0,len(a[0])):
ssum += a[i][k] * b[k][j]
result[i][j] = ssum
return result
I also have the following pseudocode for the initial divide and conquer version:
def recMatrix(x,y):
if(len(x) == 1):
return x[0] * y[0]
z = []
z[0] = recMatrix(x[0], y[0]) + recMatrix(x[1], y[2])
z[1] = recMatrix(x[0], y[1]) + recMatrix(x[1], y[3])
z[2] = recMatrix(x[2], y[0]) + recMatrix(x[3], y[2])
z[3] = recMatrix(x[2], y[1]) + recMatrix(x[3], y[3])
return z
So my question is, is my understanding of the divide and conquer method even correct, and if so, how can I modify to allow for Strassen's method? (This is not homework.)
(Specifically where I am having a hard time conceptualizing it is in the math on the entity itself prior (or after) the recursion. I.e. where P1 = A(F-H). If the recursion is actively multiplying the base elements, how is the strassen recursion taking care of the arithmetic (add and subtract) on the matrices? I have the following pseudocode to show where my brain is at:
def recMatrix(x,y):
if(len(x) == 1):
return x[0] * y[0]
z = []
p1 = recMatrix2(x[0], (y[1] - y[3]));
p2 = recMatrix2(y[3], (x[0] + x[1]));
p3 = recMatrix2(y[0], (x[2] + x[3]));
p4 = recMatrix2(x[3], (y[2] - y[0]));
p5 = recMatrix2((x[0] + x[3]), (y[0] + y[3]));
p6 = recMatrix2((x[1] - x[3]), (y[2] + y[3]));
p7 = recMatrix2((x[0] - x[3]), (y[0] + y[3]));
z[0] = p5 + p4 - p2 + p6;
z[1] = p1 + p2;
z[2] = p3 + p4;
z[3] = p1 + p5 - p3 - p7;
return z

The problem with the last piece of code is that it doesn't take the right submatrix. For example in p1 you want to take the upper left submatrix of x but you are using x[0] which is just the first row of x. You need some code that splits a matrix in 4 smaller ones. Or you can use a math library like numpy:
In [14]: from numpy import *
In [15]: x=range(16)
In [16]: x=reshape(x,(4,4))
In [17]: x
Out[17]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
In [18]: x[0:2,0:2]
Out[18]:
array([[0, 1],
[4, 5]])
In [19]: x[2:4,2:4]
Out[19]:
array([[10, 11],
[14, 15]])

Found an implementation that does what I'm looking for... namely, it specifically shows how/when to recurse: https://github.com/MartinThoma/matrix-multiplication/blob/master/Python/strassen-algorithm.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from optparse import OptionParser
from math import ceil, log
def read(filename):
lines = open(filename, 'r').read().splitlines()
A = []
B = []
matrix = A
for line in lines:
if line != "":
matrix.append(map(int, line.split("\t")))
else:
matrix = B
return A, B
def printMatrix(matrix):
for line in matrix:
print "\t".join(map(str,line))
def add(A, B):
n = len(A)
C = [[0 for j in xrange(0, n)] for i in xrange(0, n)]
for i in xrange(0, n):
for j in xrange(0, n):
C[i][j] = A[i][j] + B[i][j]
return C
def subtract(A, B):
n = len(A)
C = [[0 for j in xrange(0, n)] for i in xrange(0, n)]
for i in xrange(0, n):
for j in xrange(0, n):
C[i][j] = A[i][j] - B[i][j]
return C
def strassenR(A, B):
""" Implementation of the strassen algorithm, similar to
http://en.wikipedia.org/w/index.php?title=Strassen_algorithm&oldid=498910018#Source_code_of_the_Strassen_algorithm_in_C_language
"""
n = len(A)
# Trivial Case: 1x1 Matrices
if n == 1:
return [[A[0][0]*B[0][0]]]
else:
# initializing the new sub-matrices
newSize = n/2
a11 = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
a12 = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
a21 = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
a22 = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
b11 = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
b12 = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
b21 = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
b22 = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
aResult = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
bResult = [[0 for j in xrange(0, newSize)] for i in xrange(0, newSize)]
# dividing the matrices in 4 sub-matrices:
for i in xrange(0, newSize):
for j in xrange(0, newSize):
a11[i][j] = A[i][j]; # top left
a12[i][j] = A[i][j + newSize]; # top right
a21[i][j] = A[i + newSize][j]; # bottom left
a22[i][j] = A[i + newSize][j + newSize]; # bottom right
b11[i][j] = B[i][j]; # top left
b12[i][j] = B[i][j + newSize]; # top right
b21[i][j] = B[i + newSize][j]; # bottom left
b22[i][j] = B[i + newSize][j + newSize]; # bottom right
# Calculating p1 to p7:
aResult = add(a11, a22)
bResult = add(b11, b22)
p1 = strassen(aResult, bResult) # p1 = (a11+a22) * (b11+b22)
aResult = add(a21, a22) # a21 + a22
p2 = strassen(aResult, b11) # p2 = (a21+a22) * (b11)
bResult = subtract(b12, b22) # b12 - b22
p3 = strassen(a11, bResult) # p3 = (a11) * (b12 - b22)
bResult = subtract(b21, b11) # b21 - b11
p4 =strassen(a22, bResult) # p4 = (a22) * (b21 - b11)
aResult = add(a11, a12) # a11 + a12
p5 = strassen(aResult, b22) # p5 = (a11+a12) * (b22)
aResult = subtract(a21, a11) # a21 - a11
bResult = add(b11, b12) # b11 + b12
p6 = strassen(aResult, bResult) # p6 = (a21-a11) * (b11+b12)
aResult = subtract(a12, a22) # a12 - a22
bResult = add(b21, b22) # b21 + b22
p7 = strassen(aResult, bResult) # p7 = (a12-a22) * (b21+b22)
# calculating c21, c21, c11 e c22:
c12 = add(p3, p5) # c12 = p3 + p5
c21 = add(p2, p4) # c21 = p2 + p4
aResult = add(p1, p4) # p1 + p4
bResult = add(aResult, p7) # p1 + p4 + p7
c11 = subtract(bResult, p5) # c11 = p1 + p4 - p5 + p7
aResult = add(p1, p3) # p1 + p3
bResult = add(aResult, p6) # p1 + p3 + p6
c22 = subtract(bResult, p2) # c22 = p1 + p3 - p2 + p6
# Grouping the results obtained in a single matrix:
C = [[0 for j in xrange(0, n)] for i in xrange(0, n)]
for i in xrange(0, newSize):
for j in xrange(0, newSize):
C[i][j] = c11[i][j]
C[i][j + newSize] = c12[i][j]
C[i + newSize][j] = c21[i][j]
C[i + newSize][j + newSize] = c22[i][j]
return C
def strassen(A, B):
assert type(A) == list and type(B) == list
assert len(A) == len(A[0]) == len(B) == len(B[0])
nextPowerOfTwo = lambda n: 2**int(ceil(log(n,2)))
n = len(A)
m = nextPowerOfTwo(n)
APrep = [[0 for i in xrange(m)] for j in xrange(m)]
BPrep = [[0 for i in xrange(m)] for j in xrange(m)]
for i in xrange(n):
for j in xrange(n):
APrep[i][j] = A[i][j]
BPrep[i][j] = B[i][j]
CPrep = strassenR(APrep, BPrep)
C = [[0 for i in xrange(n)] for j in xrange(n)]
for i in xrange(n):
for j in xrange(n):
C[i][j] = CPrep[i][j]
return C
if __name__ == "__main__":
parser = OptionParser()
parser.add_option("-i", dest="filename", default="2000.in",
help="input file with two matrices", metavar="FILE")
(options, args) = parser.parse_args()
A, B = read(options.filename)
C = strassen(A, B)
printMatrix(C)

Related

Mathematica more input is needed

I'm not much familiar with this programming language and I just need to run one function to compute some coeficients.
f[x] = x^2 - 2 x + 2
g[x] = x^3 - 2 x^2 - 2 x - 2
f1 = Root[f[x], 1];
f2 = Root[f[x], 2];
g1 = Root[g[x], 1];
g2 = Root[g[x], 2];
g3 = Root[g[x], 3];
foo[rootList, alpha, beta] :=
(
res = {};
For[i = 1, i <= Length[rootList], i++, alphaI = rootList[[i]];
For[j = 1, j <= Length[rootList], j++, betaJ = rootList[[j]];
If[betaJ != beta,
(
kor = Simplify [(alphaI - alpha) / (beta - betaJ)];
res = Append[res, N[kor, 5]];
),
]
]
]
Return[res];
)
roots = [f1, f2, g1, g2, g3];
cs = foo[roots, f1, g1]
this piece of code gives me this error:
Syntax::tsntxi: "For[i=1,i<=Length[rootList],i++,alphaI=rootList[[i]];" is incomplete; more input is needed.
And don't see what is wrong. I'm using mathematica 10.4
Fixing the syntax errors.
f[x_] := x^2 - 2 x + 2
g[x_] := x^3 - 2 x^2 - 2 x - 2
f1 = Root[f[x], 1];
f2 = Root[f[x], 2];
g1 = Root[g[x], 1];
g2 = Root[g[x], 2];
g3 = Root[g[x], 3];
foo[rootList_, alpha_, beta_] :=
(
res = {};
For[i = 1, i <= Length[rootList], i++, alphaI = rootList[[i]];
For[j = 1, j <= Length[rootList], j++, betaJ = rootList[[j]];
If[betaJ != beta,
(
kor = Simplify[(alphaI - alpha)/(beta - betaJ)];
res = Append[res, N[kor, 5]];
)
]
]
];
res
)
roots = {f1, f2, g1, g2, g3};
cs = foo[roots, f1, g1]

Why doesn't my octave code run, No errors are shown

I'm new to octave and I wrote this code. But even the fprintf statement on the first line isn't getting printed. Someone please help
I typed
C = strassen(zeros(1024, 1024), zeros(1024, 1024)
But nothing is being printed and the word
octave 2:> does not show up on the next line after giving the command
function [C] = strassen(A, B)
fprintf('strassen called\n');
row = size(A, 1);%Incase zeros must be padded to make dimensions even
column = size(B, 2);
common = size(A, 2);
if row*common*column <= 1000000,%Base case when less than 10^6 multiplications needed
C = zeros( row, column );
for x = 1 : row,
for y = 1 : column,
for z = 1 : common,
C(x, y) += A(x, z)*B(z, y);
end;
end;
end;
else
%Padding zeros if needed
if rem(row, 2) == 1,
A = [A; zeros(1, common)];
end;
if rem(column, 2) == 1,
B = [B zeros(common, 1)];
end;
if rem(common, 2) == 1,
A = [A zeros(size(A, 1), 1)];
B = [B; zeros(1, size(B, 2))];
end;
m = size(A, 1);
n = size(A, 2);
o = size(B, 2);
A11 = A(1:m/2, 1:n/2 );
A12 = A(1:m/2, n/2+1: n);
A21 = A(m/2+1 :m, 1:n/2);
A22 = A(m/2+1 :m ,n/2+1: n);
B11 = A(1:n/2, 1:o/2 );
B12 = A(1:n/2, o/2+1: o);
B21 = A(n/2+1 :n, 1:o/2);
B22 = A(n/2+1 :n, o/2+1: o);
M1 = strassen(A11 + A22, B11 + B22);
M2 = strassen(A21 + A22, B11);
M3 = strassen(A11, B12 - B22);
M4 = strassen(A22, B21 - B11);
M5 = strassen(A11 + A12, B22);
M6 = strassen(A21 - A11, B11 + B12);
M7 = strassen(A12 - A22, B21 + B22);
%C11 = M1 + M4 - M5 + M7;
%C12 = M3 + M5;
%C21 = M2 + M4;
%C22 = M1 + M3 - M2 + M6;
%C = [C11 C12; C21 C22];
%C = C(1:row, 1:column);
C = [(M1 + M4 - M5 + M7) (M3 + M5);(M2 + M4) (M1 + M3 - M2 + M6)](1:row, 1:column);
end;
end;
As Dan said there is a ")" missing in your call. But this may be a copy&paste error. If you use
C = strassen(zeros(1024, 1024), zeros(1024, 1024));
You don't see "strassen called" because the calculation takes long. I haven't waited until it finished and aborted after 30s. If you want to see the recursive calls you can flush stdout:
...
fprintf('strassen called\n');
fflush (stdout);
...
or disable the pager with more off. In this case you'll see
>> C = strassen(zeros(1024, 1024), zeros(1024, 1024));
strassen called
strassen called
strassen called
strassen called
strassen called
what I think is what you would expect.

Optimize sum of series with genetic algorithm

As I am new to optimization toolbox in MATLAB I am struggling with the right code on how to optimize my objective function. At the beginning I have the following data:
a = [3 3 1 1];
c = [2 5 5 10];
My objective function along with the equality and inequality constraints are:
F=∑(k=1..4){[0.2.*a(k)]+[0.16.*x_1(k)]+[b(k).*x_2 (k)]}
The objective function F is a sum of series from k = 1..4
Equality Constraints:
a(k)+x_1 (k)+x_2 (k)=c(k) AND d(k)=x_1 (k)+d(k-1)
Inequality Constraints
x_1 (k)≤d(k)≤10
The variables that optimize the above function are x1(k) and x2(k). Is there a method how can I do that?
Image of the equations:
Since your constraints are linear, you can use linear programming:
clear all;
n_k = 4; % number of k
n_v = 3; % number of variables
a = [3 3 1 1];
b = [0.19 0.19 0.19 0.19];
c = [2 5 5 10];
d0 = 0;
% Objective x1 x2 d
f = zeros(1, n_k * n_v);
f(1:n_v:end) = 0.16; % x1 coefficient
f(2:n_v:end) = b; % x2 coefficient (b(k))
% Equality 1
eq1 = [1 1 0]; % x1 + x2 + 0 * d = c(k) - a(k)
Aeq = zeros(2 * n_k, n_v * n_k);
for i = 1:1:n_k
Aeq(i, :) = cat(2, eq1, zeros(1, n_k * n_v - length(eq1)));
eq1 = cat(2, zeros(1, n_v), eq1);
end
eq2 = [1 1 0 -1]; % d(k-1) + x1(k) + 0 * x2(k) - d(k) = 0
Aeq(n_k + 1, :) = [1 0 -1 0 0 0 0 0 0 0 0 0];
Aeq(n_k + 2, :) = [0 0 1 1 0 -1 0 0 0 0 0 0];
Aeq(n_k + 3, :) = [0 0 0 0 0 1 1 0 -1 0 0 0];
Aeq(n_k + 4, :) = [0 0 0 0 0 0 0 0 1 1 0 -1];
beq = zeros(1, 8);
beq(1:n_k) = c - a;
beq(5) = -d0;
% Inequality
le1 = [1 0 -1];
A = zeros(n_k, n_v * n_k);
for i = 1:1:n_k
A(i, :) = cat(2, le1, zeros(1, n_k * n_v - length(le1)));
le1 = cat(2, zeros(1, n_v), le1);
end
b = zeros(1, 4);
ub = inf(1, n_k * n_v);
ub(3:n_v:end) = 10;
lb = -inf(1, n_k * n_v);
And to solve:
X = linprog(f, A, b, Aeq, beq, lb, ub);
Output:
>> reshape(X, 3, 4)
ans =
5.8261 1.1680 -4.1562 7.1621
-6.8261 0.8320 8.1562 1.8379
5.8261 6.9941 2.8379 10.0000
You can check:
>> [X(1:3:end), X(2:3:end), transpose(a),
X(1:3:end) + X(2:3:end) + transpose(a), transpose(c)]
ans =
5.8261 -6.8261 3.0000 2.0000 2.0000
1.1680 0.8320 3.0000 5.0000 5.0000
-4.1562 8.1562 1.0000 5.0000 5.0000
7.1621 1.8379 1.0000 10.0000 10.0000
>> [X(3:3:end), X(1:3:end), X(3:3:end) - X(1:3:end), [0; X(3:3:11)]]
ans =
5.8261 5.8261 -0.0000 0
6.9941 1.1680 5.8261 5.8261
2.8379 -4.1562 6.9941 6.9941
10.0000 7.1621 2.8379 2.8379
>> [X(1:3:end), X(3:3:end)]
ans =
5.8261 5.8261
1.1680 6.9941
-4.1562 2.8379
7.1621 10.0000
Old answer (before comment)
% Objective a c d x1 x2
f = [.2 0 0 .16 .19];
f = repmat(f, 1, 4);
% Equality 1
eq1 = [1 -1 0 1 1]; % a c d x1 x1
eq2 = [1 0 0 0 0 -1 1 0]; % d(k-1) x1(k-1) x2(k-1) a(k) c(k) d(k) x1(k) x2(k)
Aeq = [cat(2, eq1, zeros(1, 15));
cat(2, zeros(1, 5), eq1, zeros(1, 10));
cat(2, zeros(1, 10), eq1, zeros(1, 5));
cat(2, zeros(1, 15), eq1);
cat(2, zeros(1, 2), eq2, zeros(1, 10));
cat(2, zeros(1, 7), eq2, zeros(1, 5));
cat(2, zeros(1, 12), eq2)];
beq = zeros(1, 7);
% Inequality
le1 = [0 0 -1 1 0];
A = [cat(2, le1, zeros(1, 15));
cat(2, zeros(1, 5), le1, zeros(1, 10));
cat(2, zeros(1, 10), le1, zeros(1, 5));
cat(2, zeros(1, 15), le1)];
b = zeros(1, 4);
ub = [inf inf 10 inf inf];
ub = repmat(ub, 1, 4);
lb = ones(1, 5) * (-inf);
lb = repmat(lb, 1, 4);
ub(3) = d0;
lb(3) = d0;
And to solve:
linprog(f, A, b, Aeq, beq, lb, ub)
Note that there are probably some information missing in your original post since it looks like this problem is unbounded.

Solve mixed equation in one variable

I have this equation and want to solve it for v. I tried Mathematica but it is not able to do it. Is there any software, language capable of solving it?
Equation:
Solve[1 + 0.0914642/v^5 - 1.87873/v^4 + 96.1878/v^2 - (
17.3914 E^(-(0.0296/v^2)) (1.398 + 0.0296/v^2))/v^2 - 0.947895/v -
1.37421 v == 0, v]
The text file/m-file is here.
Using Mathematica 9 :-
Clear[v]
expr = 1 + 0.0914642/v^5 - 1.87873/v^4 + 96.1878/v^2 - (
17.3914 E^(-(0.0296/v^2)) (1.398 + 0.0296/v^2))/v^2 - 0.947895/v -
1.37421 v;
sol = Solve[expr == 0, v, Reals]
{{v -> -0.172455}, {v -> 0.0594091}, {v -> 0.105179}, {v -> 3.93132}}
Checking solutions :-
roots = v /. sol;
(v = #; expr) & /# roots
{2.27374*10^-13, 2.32703*10^-12, -9.66338*10^-13, -1.77636*10^-15}
(v = #; Chop[expr]) & /# roots
{0, 0, 0, 0}
Try this in Matlab. You need to have the Symbolic Math Toolbox installed:
>> syms v %// declare symbolic variable, used in defining y
>> y = 1 + 0.0914642/v^5 - 1.87873/v^4 + 96.1878/v^2 - (17.3914*exp(-(0.0296/v^2)) * (1.398 + 0.0296/v^2))/v^2 - 0.947895/v - 1.37421*v;
>> solve(y,v) %// seeks zeros of y as a function of v
ans =
3.931322452560060553464772086259
>> subs(y,3.931322452560060553464772086259) %// check
ans =
-4.4409e-016 %// almost 0 (precision of floating point numbers): it is correct
Without the symbolic math toolbox, you can still do it numerically with fzero:
a1 = 8.99288497*10^(-2);
a2 = -4.94783127*10^(-1);
a3 = 4.77922245*10^(-2);
a4 = 1.03808883*10^(-2);
a5 = -2.82516861*10^(-2);
a6 = 9.49887563*10^(-2);
a7 = 5.20600880*10^(-4);
a8 = -2.93540971*10^(-4);
a9 = -1.77265112*10^(-3);
a10 = -2.51101973*10^(-5);
a11 = 8.93353441*10^(-5);
a12 = 7.88998563*10^(-5);
a13 = -1.66727022*10^(-2);
a14 = 1.39800000 * exp(0);
a15 = 2.96000000*10^(-2);
t = 30;
p = 10;
tr = t/(273.15 + 31.1);
pr = p/(73.8);
s1 = #(v) (a1 + (a2/tr^2) + (a3/tr^3))./v;
s2 = #(v) (a4 + (a5/tr^2) + (a6/tr^3))./v.^2;
s3 = #(v) (a7 + (a8/tr^2) + (a9/tr^3))./v.^4;
s4 = #(v) (a10 + (a11/tr^2) + (a12/tr^3))./v.^5;
s5 = #(v) (a13./(tr^3.*v.^2)).*(a14 + (a15./v.^2)).*exp(-a15./v.^2);
y = #(v) -(pr*v./tr) + 1 + s1(v) + s2(v) + s3(v) + s4(v) + s5(v);
root = fzero(y, [1 5]);
% Visualization
fplot(y, [1 5]); hold all; refline(0,0); line([root,root], [-10,30])

Create matrix and fill it in wolfram

i want to translate my C++ code to wolfram, to improve my calcs.
C++ code
for(int i = 0; i < N - 1; ++i){
matrix[i][i] += L / 3 * uCoef - duCoef / 2 - (double)du2Coef/L;
matrix[i][i+1] += L / 6 * uCoef + duCoef / 2 + (double)du2Coef/L;
matrix[i+1][i] += L / 6 * uCoef - duCoef / 2 + (double)du2Coef/L;
matrix[i+1][i+1] += L / 3 * uCoef + duCoef / 2- (double)du2Coef/L;
}
all this coef are const, N - size of my matrix.
In[1]:= n = 4; uCoef = 2; duCoef = 3; du2Coef = 7; L = 11.;
matrix = Table[0, {n}, {n}];
For[i = 1, i < n, ++i,
matrix[[i, i]] += L/3*uCoef - duCoef/2 - du2Coef/L;
matrix[[i, i+1]] += L/6*uCoef - duCoef/2 - du2Coef/L;
matrix[[i+1, i]] += L/6*uCoef + duCoef/2 + du2Coef/L;
matrix[[i+1, i+1]] += L/3*uCoef - duCoef/2 + du2Coef/L];
matrix
Out[4]= {
{5.19697, 1.5303, 0, 0},
{5.80303, 11.6667, 1.5303, 0},
{0, 5.80303, 11.6667, 1.5303},
{0, 0, 5.80303, 6.4697}}
Each character that has been changed from your original is hinting there is a fundamental difference between C++ and Mathematica
You should use SparseArray for such banded arrays in mathematica:
n = 5; uCoef = 2; duCoef = 3; du2Coef = 7; L = 11.;
matrix = SparseArray[
{{1, 1} -> L/3*uCoef - duCoef/2 - du2Coef/L,
{i_ /; 1 < i < n, i_} -> -duCoef + 2 L uCoef/3 ,
{n, n} -> ( L/3 uCoef - duCoef/2 + du2Coef/L ),
Band[{1, 2}] -> L/6 uCoef - duCoef/2 - du2Coef/L,
Band[{2, 1}] -> L/6 uCoef + duCoef/2 + du2Coef/L}, {n, n}];
MatrixForm#matrix
Even if you insist on the For loop, initialize the matrix as :
matrix = SparseArray[{{_, _} -> 0}, {n, n}];

Resources