Matlab Vectorization : How to avoid this "for" loop? - matlab

I have following matrices :
X=1 2 3
Y=4 5 6
A=1 2 3
4 5 6
7 8 9
I Want to do
for each (i,j) in A
v = A(i,j)*X - Y
B(i,j) = v * v'
i.e. each element of A is multiplied by vector X, then resultant vector subtracts Y from itself and finally we take inner product of that vector to bring a single number.
Can it be done without for loop ?

One thing often forgotten in Matlab: The operator ' takes the conjugate transposed (.' is the ordinary transposed). In other words, A' == conj(trans(A)), whereas A.' == trans(A), which makes a difference if A is a complex matrix.
Ok, let's apply some mathematics to your equations. We have
v = A(i,j)*X - Y
B(i,j) = v * v'
= (A(i,j)*X - Y) * (A(i,j)*X - Y)'
= A(i,j)*X * conj(A(i,j))*X' - Y * conj(A(i,j))*X'
- A(i,j)*X * Y' + Y * Y'
= A(i,j)*conj(A(i,j)) * X*X' - conj(A(i,j)) * Y*X' - A(i,j) * X*Y' + Y*Y'
So a first result would be
B = A.*conj(A) * (X*X') - conj(A) * (Y*X') - A * (X*Y') + Y*Y'
In the case of real matrices/vectors, one has the identities
X*Y' == Y*X'
A == conj(A)
which means, you can reduce the expression to
B = A.*A * (X*X') - 2*A * (X*Y') + Y*Y'
= A.^2 * (X*X') - 2*A * (X*Y') + Y*Y'

An alternative method:
X = [1 2 3]
Y = [4 5 6]
A = [1 2 3; 4 5 6; 7 8 9]
V = bsxfun(#minus, A(:)*X, [4 5 6])
b = sum((V.^2)')
B = reshape(b , 3, 3)
I get the result:
B = 27 5 11
45 107 197
315 461 635

Related

Quadratic Program formulation: Matlab

Given this objective function:
Minimize:
f = (Ax + By)' * G * (Ax + By)
subject to some equalities and inequalities.
where x and y are real-valued vectors (decision variables) with p and q elements, respectively. A of size m * p, B of size m * q, G is a symmetric matrix of size m * m.
My question is how to write f in the form v' * G * v, such that it can be easily be used in quadprog. In other words, how to mix A, B and G?
This looks incompletely specified!
It seems, for whatever reason, you want to model in terms of two variable components. Now you did not specify how they interact with each other.
As most optimizers work on a single variable-vector, you need to concatenate yours.
As you did not show G, i'm assuming you got one G for x and one for y, let's call it H.
(Remark: not a matlab user; don't take example-syntax for granted!)
z = [x y]
P = blkdiag(G,H)
assuming x and y independent in regards to quadratic-term
e.g. no x0*y1 like terms
Solve: for z` P z
Example:
x = [x0 x1 x2]
y = [y0 y1]
G = [6 2 1; 2 5 2; 1 2 4]
H = [8 2; 2 10]
# G
6 2 1
2 5 2
1 2 4
# H
8 2
2 8
z = [x0 x1 x2 y0 y1]
P = [6 2 1 0 0; 2 5 2 0 0; 1 2 4 0 0; 0 0 0 8 2; 0 0 0 2 8]
# P
6 2 1 0 0
2 5 2 0 0
1 2 4 0 0
0 0 0 8 2
0 0 0 2 8

Fastest way to compute sum of a submatrix

What's the fastest way of computing the sum of a submatrix? Currently I'm going about this in the following way:
x = [1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4]
>> y = x(1:2, 1:2);
>> y
y =
1 2
1 2
>> sum(y(:))
ans =
6
>>
How can I compute the sum of all submatrices of x?
Edit
At each point (x,y) in the matrix, I want to compute the sum for a window of size 2M+1. For example, if I have a 4x4 matrix I want to compute the sums for 3x3 windows at each point where this is possible (e.g. it wouldn't be possible for the edges because the window would spill off the matrix)
for i = M:ncols-M
for j=M:nrows-M
end
end
Example
For a 4x4 matrix with a window size of 3, I would want these sums:
sum centered at (2,2)
+ + + x
+ + + x
+ + + x
x x x x
sum centered at (3,2)
x + + +
x + + +
x + + +
x x x x
sum centered at (2,3)
x x x x
+ + + x
+ + + x
+ + + x
sum centered at (3,3)
x x x x
x + + +
x + + +
x + + +
You're looking at computing a summed area table. Simply put, each element at row i and column j - (i,j) - in the output is the sum of the submatrix bounded from the top-left corner to the point of interest (i,j) which serves as the bottom right corner.
It's very simple with cumsum:
y = cumsum(cumsum(x, 1), 2);
Example:
>> x = repmat(1:4, 4, 1); %// your example
>> x
x =
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
... and the output:
>> y = cumsum(cumsum(x, 1), 2)
y =
1 3 6 10
2 6 12 20
3 9 18 30
4 12 24 40
As such, for your example, the submatrix sum from the top left corner to (i,j) = (2,2) is equal to 6.
If by "submatrix" you mean a sliding 2D-window of fixed size, that's essentially a 2D-convolution:
x = [1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4];
m = 2; n = 2; %// submatrix size
result = conv2(x, ones(m, n), 'valid');
In this example,
result =
6 10 14
6 10 14
6 10 14
This answer was created before clarifications by the OP. It assumes the submatrices do not overlap!
If you have the Image Processing Toolbox you can use blockproc:
A = blockproc(x,[2 2],#(k) sum(k.data(:)))
If you don't have it you can use accumarray:
n = 2; %// number of elements per block in row direction
N = size(x,1)/n; %// number of blocks in row direction
m = 2; %// number of elements per block in column direction
M = size(x,2)/m; %// number of blocks in column direction
idx = repelem( reshape(1:(N*M),N,M),n,m)
B = reshape( accumarray(x(:),idx(:)), N, M )
Some heavy reshaping will work too:
C = reshape(sum(reshape(permute(sum(reshape(x,n,m,[])),[2,3,1]).',n,[])),n,[]).'
A = B = C =
6 14
6 14
x = repmat(1:4, 4, 1); %// your example
[A,B] = size(x);
kk=1;
for ii = 1:2:A
for jj = 1:2:B
subsummed(kk) = sum(sum(x(ii:ii+1,jj:jj+1)));
kk = kk+1;
end
end
My looped version, in case you mean a "submatrix" in case of the four 2x2 matrices that make up your full one.

Simplify the looping under two sets of conditions

I want to establish a pair of indices =[row col] where
row = 4 * (n-1) + i and col = 4 * (m-1) + i
Explanation for i, m and n:
For n = 1 and m = 2, 3, 4, loop i = 1 : 4.
For n = 2 and m = 1, loop i = 1 : 4.
For n = 3 and m = 5, loop i = 1 : 4.
The outcome should be:
row = [1 1 1 2 2 2 3 3 3 4 4 4 5 6 7 8 9 10 11 12]
col = [5 9 13 6 10 14 7 11 15 8 12 16 1 2 3 4 17 18 19 20]
That is, I want to establish pairs of indices under different sets of n-m conditions.
My trial:
row = []; col = [];
n = 1;
for i = 1 : 4
for m = [2 3 4]
row = [row 4 * (n - 1) + i];
col = [col 4 * (m - 1) + i];
end
end
n = 2; m = 1;
for i = 1 : 4
row = [row 4 * (n - 1) + i];
col = [col 4 * (m - 1) + i];
end
n= 3; m = 5;
for i = 1 : 4
row = [row 4 * (n - 1) + i];
col = [col 4 * (m - 1) + i];
end
This works but indeed I have many n-m conditions and the looping for i = 1 : 4 appeared repeatedly which seems that can be simplified.
May I know if there are any elegant solutions to finish my objective?
I appreciate for your help.
You can use a bsxfun based solution for all those three cases -
ii = 1:4
row = reshape(bsxfun(#(A,B) 4 * (B-1) + A,ii,n'),1,[]) %//'
col = reshape(bsxfun(#(A,B) 4 * (B-1) + A,ii,m'),1,[]) %//'
The inputs would be as listed next.
Case #1:
m = [2, 3, 4]
n = ones(1,numel(m))
Case #2:
n = 2
m = 1
Case #3:
n = 3
m = 5
I would create a Matrix with all parameters, then apply the math once:
M=[...n m i
ones(3,1) (2:4).' (1:3).';...
2*ones(4,1) ones(4,1) (1:4).';...
3*ones(4,1) 5*ones(4,1) (1:4).';...
];
row = (4 * (M(:,1) - 1) + M(:,3)).';
col = (4 * (M(:,2) - 1) + M(:,3)).';
%alternative:
%index=(4 * (M(:,[1:2]) - 1) + M(:,[3,3])).'

Solving a linear system of equation with two variables in MATLAB

It might seem a simple question. I need it, though. Let's assume we have two equations:
2 * y + x + 1 = 0
and
y - 2 * x = 0
I would like to find their bisection which can be calculated from this equation:
|x + 2 * y + 1| |-2 *x + y |
------------------- = -----------------
(sqrt(2^2 + 1^2)) (sqrt(1^2 + 2^2))
To make the long story short, we only need to solve this below system of equation:
2 * y + x + 1 = -2 *x + y
and
2 * y + x + 1 = 2 *x - y
However, using solve function of MATLAB:
syms x y
eqn1 = 2 * y + x + 1 == -2 *x + y ;
eqn2 = 2 * y + x + 1 == 2 *x - y ;
[x, y] = solve (eqn1 , eqn2, x, y) ;
Will give me:
x = -1/5 and y = -2/5
But, I am looking for the result equations, which is:
y = -3 * x - 1 and 3 * y = 2 * x - 1
So, does anyone know how I can get the above line equation instead of the result point? Thanks,
The following should solve both equations with y on the left-hand-side:
y1 = solve(eqn1,y)
y2 = solve(eqn2,y)
Result:
y1 =
- 3*x - 1
y2 =
x/3 - 1/3
As an aside, it would be much faster to solve this system by thinking of it it as a matrix inversion problem Ax=b rather than using MATLAB's symbolic tools:
A = [1 2; -2 1];
b = [-1; 0];
x = A\b
Result:
x =
-0.2000
-0.4000

Creating Matrix with a loop in Matlab

I want to create a matrix of the following form
Y = [1 x x.^2 x.^3 x.^4 x.^5 ... x.^100]
Let x be a column vector.
or even some more variants such as
Y = [1 x1 x2 x3 (x1).^2 (x2).^2 (x3).^2 (x1.x2) (x2.x3) (x3.x1)]
Let x1,x2 and x3 be column vectors
Let us consider the first one. I tried using something like
Y = [1 : x : x.^100]
But this also didn't work because it means take Y = [1 x 2.*x 3.*x ... x.^100] ?
(ie all values between 1 to x.^100 with difference x)
So, this also cannot be used to generate such a matrix.
Please consider x = [1; 2; 3; 4];
and suggest a way to generate this matrix
Y = [1 1 1 1 1;
1 2 4 8 16;
1 3 9 27 81;
1 4 16 64 256];
without manually having to write
Y = [ones(size(x,1)) x x.^2 x.^3 x.^4]
Use this bsxfun technique -
N = 5; %// Number of columns needed in output
x = [1; 2; 3; 4]; %// or [1:4]'
Y = bsxfun(#power,x,[0:N-1])
Output -
Y =
1 1 1 1 1
1 2 4 8 16
1 3 9 27 81
1 4 16 64 256
If you have x = [1 2; 3 4; 5 6] and you want Y = [1 1 1 2 4; 1 3 9 4 16; 1 5 25 6 36] i.e. Y = [ 1 x1 x1.^2 x2 x2.^2 ] for column vectors x1, x2 ..., you can use this one-liner -
[ones(size(x,1),1) reshape(bsxfun(#power,permute(x,[1 3 2]),1:2),size(x,1),[])]
Using an adapted Version of the code found in Matlabs vander()-Function (which is also to be found in the polyfit-function) one can get a significant speedup compared to Divakars nice and short solution if you use something like this:
N = 5;
x = [1:4]';
V(:,n+1) = ones(length(x),1);
for j = n:-1:1
V(:,j) = x.*V(:,j+1);
end
V = V(:,end:-1:1);
It is about twice as fast for the example given and it gets about 20 times as fast if i set N=50 and x = [1:40]'. Although I state that is not easy to compare the times, just as an option if speed is an issue, you might have a look at this solution.
in octave, broadcasting allows to write
N=5;
x = [1; 2; 3; 4];
y = x.^(0:N-1)
output -
y =
1 1 1 1 1
1 2 4 8 16
1 3 9 27 81
1 4 16 64 256