compute weights by Generalized Hebbian Algorithm in matlab - matlab

I have a task to do some calculations in matlab .. I use the Generalized Hebbian Algorithm to compute some weights , here is the functions of Hebbian Algorithm , slice 15
http://www.eit.lth.se/fileadmin/eit/courses/eitn55/Downloads/ICA_Ch6.pdf
here is my code
alfa=0.5;
e=randn(3,5000);
A=[1 0 0;-0.5 0.5 0;0.3 0.1 0.1];
x=A*e;
W=rand(3);
nn=size(x);
for n=1:nn
y=W*x(:,n);
k=tril(y*y')*W;
W(:,n+1)= alfa*(y*x(:,n)'-k);
end
In my task I know that x=A*e;
but I do not know if I am iterating in correct way or not?
is my for loop doing correct?
and are those equations below correct?
y=W*x(:,n);
k=tril(y*y')*W;
W(:,n+1)= alfa*(y*x(:,n)'-k);
W(:,n+1) should print out a 3*3 matrix (that what I understood)...
Matlab says when I run this code : Error using *
Inner matrix dimensions must agree.
thanks

If you check size of each matrix, you will find out that the order is incorrect:
size(x)
ans =
3 5000
size(W)
ans =
3 3
so you should multiply them as
for n=1:nn
y=W*x;
end
However this part does not make sense either,
k=tril(y'*y)*W;
because tril(y'*y) is a matrix size 5000x5000 and W is 3x3. So I guess you should change it to:
k=tril(y*y')*W;
Then alfa*(y*x'-k); would be a 3x3 matrix.

Related

optimizing a matlab code involving for loop

I have a Matlab code that goes like this
s=[0.5 0.6 0.7];
u=[0.3618 0.9826 0.7237 0.0346 0.5525 0.0692 0.8949 0.1384
0.3418 0.9226 0.7213 0.0346 0.7525 0.0692 0.8949 0.1384
0.3318 0.9326 0.7237 0.0336 0.5575 0.0792 0.8949 0.1385]
A= u(1:2:7); % Here u is a 1-D vector and hence A
B=u(2:2:8); % Here u is a 1-D vector and hence B
C=mod(s(1)-(A+B),1);
I want to implement this code for the other two values of s also using next 8 values of u i.e now my code becomes
A=u(9:2:15);
B=u(10:2:16);
C=mod(s(2)-(A+B),1);
Similarly for last value of s. But each time i need the next 8 values of u. How do i code this so that it takes less time.
So you start with a 24 element array in u that you wish to perform this operation on in a vectorized fashion. I assume you have many more elements but that they all fit in memory. The way to do this is to reshape u to where you want the elements to be. You can do this via:
u1 = reshape(u1,[2,4,3]);
From there you also need to modify s to match it
s1 = permute(s,[1 3 2]);
Finally, you can calculate your C matrix in vectorized form
C1 = mod(s1-sum(u1),1);
For this problem, this gives a 1x4x3 matrix where the 3rd dimension represents each set of 8. From there you can then extract the problem set you want
C = squeeze(C1(1,:,1));

Large image matrix: save to small matrices

I'm new to MATLAB and its development. I have a image which is 1134 (rows) X 1134 (columns). I want that image to save 3 (columns) X 3 (rows). In order to do that I need 378 cells. For that I used following code, but it gives me an error.
image=imread('C:\Users\ven\Desktop\test\depth.png');
I=reshape(image,1,1134*1134);
chunk_size = [3 3]; % your desired size of the chunks image is broken into
sc = sz ./ chunk_size; % number of chunks in each dimension; must be integer
% split to chunk_size(1) by chunk_size(2) chunks
X = mat2cell(I, chunk_size(1) * ones(sc(1),1), chunk_size(2) *ones(sc(2),1));
Error:
Error using mat2cell (line 97)
Input arguments, D1 through D2, must sum to each dimension of the input matrix size, [1 1285956].'
Unfortunately your code does not work as you think it would.
The ./ operator performs point wise division of two matrices. Short example:
[12, 8] ./ [4, 2] == [12/4, 8/2] == [3, 4]
In order for it to work both matrices must have exactly the same size. In your case you try to perform such an operation on a 1134x1134 matrix (the image) and a 1x2 matrix (chunk_size).
In other words you can not use it to divide matrices into smaller ones.
However, a solution to your problem is to use the mat2cell function to pick out subsets of the matrix. A explanation of how it is done can be found here (including examples): http://se.mathworks.com/matlabcentral/answers/89757-how-to-divide-256x256-matrix-into-sixteen-16x16-blocks.
Hope it helps :)
Behind the C=A./B command is loop over all elements of A(ii,jj,...) and B(ii,jj,..) and each C(ii,jj,..)=A(ii,jj,...)/B(ii,jj,...).
Therefore martices A and B must be of same dimension.
If you want to split matrix into groups you can use
sc=cell(1134/3,1);
kk=0;ll=0;
for ii=2:3:1133
kk=kk+1;
for jj=2:3:1133
ll=ll+1;
sc{kk,ll}=image(ii-1:ii+1,jj-1:jj+1);
end
end
The code allocates cell array sc for resulting submatrices and arbitrary counters kk and ll. Then it loops over ii and jj with step of 3 representing centers of each submatrices.
Edit
Or you can use mat2cell command (type help mat2cell or doc mat2cell in matlab shell)
sc=mat2cell(image,3,3);
In both cases the result is cell array and its iith and jjth elements (matrices) are accessible by sc{ii,jj}. If you want call iith anr jjth number in kkth and llth matrix, do it via sc{kk,ll}(ii,jj).
In short, you divided a 1134 x 1134 by 2 x 1 matrix. That doesn't work.
The error "Matrix dimensions must agree**" is from the dividing a matrix with another matrix that doesn't have the right dimensions.
You used the scalar divide "./" which divided a matrix by another matrix.
You want something like:
n = 1134 / 3 % you should measure the length of the image
I1=image(1:n,1:n); % first row
I2=image(1:n,n:2n);
I3=image(1:n,2n:3n);
I4=image(n:2n,1:n); % second row
I5=image(n:2n,n:2n);
I6=image(n:2n,2n:3n);
I7=image(2n:3n,1:n); % third row
I8=image(2n:3n,n:2n);
I9=image(2n:3n,2n:3n);
from here:
http://au.mathworks.com/matlabcentral/answers/46699-how-to-segment-divide-an-image-into-4-equal-halves
There would be a nice loop you could do it in, but sometimes thinking is hard.

determine the frequency of a number if a simulation

I have the following function:
I have to generate 2000 random numbers from this function and then make a histogram.
then I have to determine how many of them is greater that 2 with P(X>2).
this is my function:
%function [ output_args ] = Weibullverdeling( X )
%UNTITLED Summary of this function goes here
% Detailed explanation goes here
for i=1:2000
% x= rand*1000;
%x=ceil(x);
x=i;
Y(i) = 3*(log(x))^(6/5);
X(i)=x;
end
plot(X,Y)
and it gives me the following image:
how can I possibly make it to tell me how many values Do i Have more than 2?
Very simple:
>> Y_greater_than_2 = Y(Y>2);
>> size(Y_greater_than_2)
ans =
1 1998
So that's 1998 values out of 2000 that are greater than 2.
EDIT
If you want to find the values between two other values, say between 1 and 4, you need to do something like:
>> Y_between = Y(Y>=1 & Y<=4);
>> size(Y_between)
ans =
1 2
This is what I think:
for i=1:2000
x=rand(1);
Y(i) = 3*(log(x))^(6/5);
X(i)=x;
end
plot(X,Y)
U is a uniform random variable from which you can get the X. So you need to use rand function in MATLAB.
After which you implement:
size(Y(Y>2),2);
You can implement the code directly (here k is your root, n is number of data points, y is the highest number of distribution, x is smallest number of distribution and lambda the lambda in your equation):
X=(log(x+rand(1,n).*(y-x)).*lambda).^(1/k);
result=numel(X(X>2));
Lets split it and explain it detailed:
You want the k-th root of a number:
number.^(1/k)
you want the natural logarithmic of a number:
log(number)
you want to multiply sth.:
numberA.*numberB
you want to get lets say 1000 random numbers between x and y:
(x+rand(1,1000).*(y-x))
you want to combine all of that:
x= lower_bound;
y= upper_bound;
n= No_Of_data;
lambda=wavelength; %my guess
k= No_of_the_root;
X=(log(x+rand(1,n).*(y-x)).*lambda).^(1/k);
So you just have to insert your x,y,n,lambda and k
and then check
bigger_2 = X(X>2);
which would return only the values bigger than 2 and if you want the number of elements bigger than 2
No_bigger_2=numel(bigger_2);
I'm going to go with the assumption that what you've presented is supposed to be a random variate generation algorithm based on inversion, and that you want real-valued (not complex) solutions so you've omitted a negative sign on the logarithm. If those assumptions are correct, there's no need to simulate to get your answer.
Under the stated assumptions, your formula is the inverse of the complementary cumulative distribution function (CCDF). It's complementary because smaller values of U give larger values of X, and vice-versa. Solve the (corrected) formula for U. Using the values from your Matlab implementation:
X = 3 * (-log(U))^(6/5)
X / 3 = (-log(U))^(6/5)
-log(U) = (X / 3)^(5/6)
U = exp(-((X / 3)^(5/6)))
Since this is the CCDF, plugging in a value for X gives the probability (or proportion) of outcomes greater than X. Solving for X=2 yields 0.49, i.e., 49% of your outcomes should be greater than 2.
Make suitable adjustments if lambda is inside the radical, but the algebra leading to solution is similar. Unless I messed up my arithmetic, the proportion would then be 55.22%.
If you still are required to simulate this, knowing the analytical answer should help you confirm the correctness of your simulation.

Extremely large weighted average

I am using 64 bit matlab with 32g of RAM (just so you know).
I have a file (vector) of 1.3 million numbers (integers). I want to make another vector of the same length, where each point is a weighted average of the entire first vector, weighted by the inverse distance from that position (actually it's position ^-0.1, not ^-1, but for example purposes). I can't use matlab's 'filter' function, because it can only average things before the current point, right? To explain more clearly, here's an example of 3 elements
data = [ 2 6 9 ]
weights = [ 1 1/2 1/3; 1/2 1 1/2; 1/3 1/2 1 ]
results=data*weights= [ 8 11.5 12.666 ]
i.e.
8 = 2*1 + 6*1/2 + 9*1/3
11.5 = 2*1/2 + 6*1 + 9*1/2
12.666 = 2*1/3 + 6*1/2 + 9*1
So each point in the new vector is the weighted average of the entire first vector, weighting by 1/(distance from that position+1).
I could just remake the weight vector for each point, then calculate the results vector element by element, but this requires 1.3 million iterations of a for loop, each of which contains 1.3million multiplications. I would rather use straight matrix multiplication, multiplying a 1x1.3mil by a 1.3milx1.3mil, which works in theory, but I can't load a matrix that large.
I am then trying to make the matrix using a shell script and index it in matlab so only the relevant column of the matrix is called at a time, but that is also taking a very long time.
I don't have to do this in matlab, so any advice people have about utilizing such large numbers and getting averages would be appreciated. Since I am using a weight of ^-0.1, and not ^-1, it does not drop off that fast - the millionth point is still weighted at 0.25 compared to the original points weighting of 1, so I can't just cut it off as it gets big either.
Hope this was clear enough?
Here is the code for the answer below (so it can be formatted?):
data = load('/Users/mmanary/Documents/test/insertion.txt');
data=data.';
total=length(data);
x=1:total;
datapad=[zeros(1,total) data];
weights = ([(total+1):-1:2 1:total]).^(-.4);
weights = weights/sum(weights);
Fdata = fft(datapad);
Fweights = fft(weights);
Fresults = Fdata .* Fweights;
results = ifft(Fresults);
results = results(1:total);
plot(x,results)
The only sensible way to do this is with FFT convolution, as underpins the filter function and similar. It is very easy to do manually:
% Simulate some data
n = 10^6;
x = randi(10,1,n);
xpad = [zeros(1,n) x];
% Setup smoothing kernel
k = 1 ./ [(n+1):-1:2 1:n];
% FFT convolution
Fx = fft(xpad);
Fk = fft(k);
Fxk = Fx .* Fk;
xk = ifft(Fxk);
xk = xk(1:n);
Takes less than half a second for n=10^6!
This is probably not the best way to do it, but with lots of memory you could definitely parallelize the process.
You can construct sparse matrices consisting of entries of your original matrix which have value i^(-1) (where i = 1 .. 1.3 million), multiply them with your original vector, and sum all the results together.
So for your example the product would be essentially:
a = rand(3,1);
b1 = [1 0 0;
0 1 0;
0 0 1];
b2 = [0 1 0;
1 0 1;
0 1 0] / 2;
b3 = [0 0 1;
0 0 0;
1 0 0] / 3;
c = sparse(b1) * a + sparse(b2) * a + sparse(b3) * a;
Of course, you wouldn't construct the sparse matrices this way. If you wanted to have less iterations of the inside loop, you could have more than one of the i's in each matrix.
Look into the parfor loop in MATLAB: http://www.mathworks.com/help/toolbox/distcomp/parfor.html
I can't use matlab's 'filter' function, because it can only average
things before the current point, right?
That is not correct. You can always add samples (i.e, adding or removing zeros) from your data or from the filtered data. Since filtering with filter (you can also use conv by the way) is a linear action, it won't change the result (it's like adding and removing zeros, which does nothing, and then filtering. Then linearity allows you to swap the order to add samples -> filter -> remove sample).
Anyway, in your example, you can take the averaging kernel to be:
weights = 1 ./ [3 2 1 2 3]; % this kernel introduces a delay of 2 samples
and then simply:
result = filter(w,1,[data, zeros(1,3)]); % or conv (data, w)
% removing the delay introduced by the kernel
result = result (3:end-1);
You considered only 2 options:
Multiplying 1.3M*1.3M matrix with a vector once or multiplying 2 1.3M vectors 1.3M times.
But you can divide your weight matrix to as many sub-matrices as you wish and do a multiplication of n*1.3M matrix with the vector 1.3M/n times.
I assume that the fastest will be when there will be the smallest number of iterations and n is such that creates the largest sub-matrix that fits in your memory, without making your computer start swapping pages to your hard drive.
with your memory size you should start with n=5000.
you can also make it faster by using parfor (with n divided by the number of processors).
The brute force way will probably work for you, with one minor optimisation in the mix.
The ^-0.1 operations to create the weights will take a lot longer than the + and * operations to compute the weighted-means, but you re-use the weights across all the million weighted-mean operations. The algorithm becomes:
Create a weightings vector with all the weights any computation would need:
weights = (-n:n).^-0.1
For each element in the vector:
Index the relevent portion of the weights vector to consider the current element as the 'centre'.
Perform the weighted-mean with the weights portion and the entire vector. This can be done with a fast vector dot-multiply followed by a scalar division.
The main loop does n^2 additions and subractions. With n equal to 1.3 million that's 3.4 trillion operations. A single core of a modern 3GHz CPU can do say 6 billion additions/multiplications a second, so that comes out to around 10 minutes. Add time for indexing the weights vector and overheads, and I still estimate you could come in under half an hour.

Most efficient matrix inversion in MATLAB

When computing the inverse for some square matrix A in MATLAB, using
Ai = inv(A)
% should be the same as:
Ai = A^-1
MATLAB usually notifies me that this is not the most efficient way of inverting.
So what's more efficient? If I have an equation system, using the /,\ operators probably is.
But sometimes I need the inverse for other computations.
What's the most efficient way to invert?
I would recommend to use svd (unless you are really absolute sure that your matrix is not ill-conditioned). Then, based on singular values you make your decisions on further actions to take. This may sound like a 'overkill' approach, but in long run it will pay back.
Now if your matrix A is actually invertible, then the pseudo inverse of A coincidence with inv(A), however if you are close to 'singularity' you'll easily make appropriate decision how to proceed to actually make the pseudo inverse. Naturally these decisions will depend on your application.
Added a straightforward example:
> A= randn(3, 2); A= [A A(:, 1)+ A(:, 2)]
A =
-1.520342 -0.239380 -1.759722
0.022604 0.381374 0.403978
0.852420 1.521925 2.374346
> inv(A)
warning: inverse: matrix singular to machine precision, rcond = 0
ans =
Inf Inf Inf
Inf Inf Inf
Inf Inf Inf
> [U, S, V]= svd(A)
U =
-0.59828 -0.79038 0.13178
0.13271 -0.25993 -0.95646
0.79022 -0.55474 0.26040
S =
Diagonal Matrix
3.6555e+000 0 0
0 1.0452e+000 0
0 0 1.4645e-016
V =
0.433921 0.691650 0.577350
0.382026 -0.721611 0.577350
0.815947 -0.029962 -0.577350
> s= diag(S); k= sum(s> 1e-9) % simple thresholding based decision
k = 2
> Ainv= (U(:, 1: k)* diag(1./ s(1: k))* V(:, 1: k)')'
Ainv =
-0.594055 -0.156258 -0.273302
0.483170 0.193333 0.465592
-0.110885 0.037074 0.192290
> A* Ainv
ans =
0.982633 0.126045 -0.034317
0.126045 0.085177 0.249068
-0.034317 0.249068 0.932189
> A* pinv(A)
ans =
0.982633 0.126045 -0.034317
0.126045 0.085177 0.249068
-0.034317 0.249068 0.932189
I think LU decomposition is more efficient than than inversion (and potentially more stable if you use pivoting). It works especially well if you need to solve for more than one right hand side vector, because once you have the LU decomposition you can do the forward back substitutions for each one as you need it.
I would recommend LU decomposition over a full inverse. I agree if that's what MATLAB is saying.
UPDATE: 3x3 matrix? You can invert that by hand in closed form if you need it. Just check the determinant first to make sure that it's not singular or nearly singular.
If you only need the inverse then just do, it will be numerically more stable than inv(A):
inv_A = 1\A;
If there isn't a clever way to do all your calculations without explicitly forming the inverse then you have to use the "inv" function. You could of course solve a linear system with your matrix and the identity matrix, but there is nothing to be gained by doing that.