Store values within recursion to use later MATLAB - matlab

I'm trying to write a recursive multigrid algorithm in MATLAB.
I need to store the values of v and TC at each of the levels I'm going through to use when I'm no longer in the recursion by just calling them, in a similar way v{L} would have worked for example if I did a for loop.
Any help is much appreciated. Thank you.
function x = vcycle1d(n, x, b, T, w, levels)
x = damped_jacobiM(w, x, T, b, 10^-7, 3);
res = b - T*x;
k = log2(n+1);
N = 2^(k-1)-1;
RE = zeros(N,n);
for i = 1:N
RE(i,2*i-1:2*i+1) = [1 2 1];
end
RE = RE/4;
II = 2*RE';
TC = RE * T * II;
v = zeros(N, 1);
for i = 1:N
v(i) = (res(2*i-1) + 2*res(2*i) + res(2*i+1))/4;
end
if levels ~= 1
err= vcycle1d(N, zeros(length(v), 1), v, TC, w, levels-1);
else
err = TC\v;
end

There are two ways to do this.
Option 1: Use a persistent variable. This allows you to store details in a variable that retains values between calls.
The pros of this are that you can use it to "remember" all sorts of things from previous calls.
The cons of this are that you'll need to manage that memory in some sensible way.
Option 2: Use additional, optional, inputs.
function x = vcycle1d(n, x, b, T, w, levels, varargin)
if nargin == 7
priordetails = varargin{1};
end
currentdetails = ... ;
....
err= vcycle1d(N, zeros(length(v), 1), v, TC, w, levels-1, currentdetails);

Related

How do I call a function handle with an vector rather than a list of arguments?

I was wondering how to call a function handle with an vector of inputs - rather than the list of aguments.
So if I have a function handle which is defined: (I guess it will be clear that I am working on fitting functions here)
fitFunctionHandle = #(a1, wG1, x1,a2, wG2, x2, c, x)(FitGaussianFn(x, [a1, 0, wG1, x1]) +FitGaussianFn(x, [a2, 0, wG2, x2]) + c
And I have an vector of inputs to hand to it
a1Init = 1
wG1Init = 2
x1Init = 3
a2Init = 4
wG2Init = 5
x2Init = 6
a2Init = 7
x = 8
%startPoint = [a1Init, wG1, x1,a2, wG2, x2, c]
inputArray = [a1Init, wG1, x1,a2, wG2, x2, c, x]
How do I call it with the vector startPoint as the input. If I try (for example)
>> fitFunctionHandle(inputArray)
I get an error:
Not enough input arguments.
That makes sense since it is expecting 8 inputs rather than a 8 element vector - but I'm wondering whether there is a way of calling it like that. I think for example in python you can convert an array to a list or something.
I'm aware that I could simplify things in this example case where I have a list of known inputs so I could just do:
fitFunctionHandle(a1Init, wG1, x1,a2, wG2, x2, c, x)
or
fitFunctionHandle(inputArray(1),inputArray(2),inputArray(3,inputArray(4), inputArray(5), inputArray(6),inputArray(7),inputArray(8))
BUT! I guess I'm trying to allow for expansion where I don't know how many arguments there would be.
For bonus points (again since I'm working on fitting functions) - It would be cool to know how to call it when x is a vector as well. I suspect that I would be doing something like
arrayfunc(fitFunctionHandle([startPoint,x]), xVector)
Thanks in advance for your help.
If I understand correctly, you are looking for a way to pass a variable number of input arguments to an anonymous function.
Take a look at this example:
anonymousFunction = #(varargin)(image(varargin{:}));
x = [5 8];
y = [3 6];
C = [0 2 4 6; 8 10 12 14; 16 18 20 22];
input = {C};
anonymousFunction(input{:});
input = {x,y,C};
anonymousFunction(input{:});
You can see in the example that a variable number of inputs is used for calling the anonymous function. Of course, this depends on the actual function that is using the arguments (in this case, image)
Regarding the varargin, the general idea was already presented in UnbearableLightness' answer. I just wanted to address your specific case.
It seems, you want to have some dynamic linear combinations of your FitGaussianFn calls with varying parameters, resulting in some complex function handle. For variable amount of terms, I would recommend to write a separate function to generate the final function handle. I made up a small toy example.
That's my fitFunctionHandle.m function:
function h = fitFunctionHandle(varargin)
n = numel(varargin);
if (n < 2)
error('Not enough input arguments.');
end
% Last input argument is considered t
t = varargin{end};
h = #(x) 0;
for iArg = 1:n-1
a = varargin{iArg}(1);
b = varargin{iArg}(2);
h = #(x) h(x) + (a*sin(b*x+t));
end
end
Each input argument consists of two parameters, that form a sin term. An additional shift parameter t is always passed at last.
And, here's some test script:
% Set up parameters
a1 = 1; b1 = 1;
a2 = 2; b2 = 2;
a3 = 3; b3 = 3;
t = pi/16;
% Evaluation point
x = pi/4;
% Compare results with explicit function calls
h = fitFunctionHandle([a1, b1], t);
res = h(x)
cmp = sin(x+t)
h = fitFunctionHandle([a1, b1], [a2, b2], t);
res = h(x)
cmp = sin(x+t) + 2*sin(2*x+t)
h = fitFunctionHandle([a1, b1], [a2, b2], [a3, b3], t);
res = h(x)
cmp = sin(x+t) + 2*sin(2*x+t) + 3*sin(3*x+t)
You see, it doesn't matter, how many parameter vectors are passed.
The output reveals, that the passed function handles are correct:
res = 0.83147
cmp = 0.83147
res = 2.7930
cmp = 2.7930
res = 4.4598
cmp = 4.4598
Regarding your last question, let's see this test:
% Set up array of t parameters, and get set of function handles
t = [pi/16, pi/8, pi/4];
hh = arrayfun(#(x) fitFunctionHandle([a1, b1], x), t, 'UniformOutput', false);
% Compare results with explicit function calls
for iH = 1:numel(hh)
h = hh{iH};
res = h(x)
cmp = sin(x + t(iH))
end
Here, the t, which is used for all sin terms in fitFunctionHanle, is a vector. The arrayfun call will return a cell array of function handles. Again, the output shows comparable results:
res = 0.83147
cmp = 0.83147
res = 0.92388
cmp = 0.92388
res = 1
cmp = 1
Hope that helps!

MATLAB: efficient generating of block matrices using a block vector

Suppose
x = [x1;x2; ...; xn]
where each xi is a column vector with length l(i). We can set L = sum(l), the total length of x. I would like to generate 2 matrices based on x:
Let's call them A and B. For example, when x only as 2 blocks x1 and x2 then:
A = [x1*x1' zeros(l(1),l(2)); zeros(l(2),l(1)), x2*x2'];
B = [x1 zeros(l(1),1);
zeros(l(2),1), x2];
In the notation of the problem, A is always L by L and B is L by n. I can generate A and B given x using loops but it is tedious. Is there a clever (loop-free) way to generate A and B. I am using MATLAB 2018b but you can assume earlier version of MATLAB if necessary.
I think it is both short and fast:
B = x .* (repelem((1:numel(l)).',l)==(1:numel(l)));
A = B * B.';
If you have large data It is better to use sparse matrix:
B = sparse(1:numel(x), repelem(1:numel(l), l), x);
A = B * B.';
The following should work. In this case I do an inefficient conversion to cell arrays so there may be a more efficient implementation possible.
cuml = [0; cumsum(l(:))];
get_x = #(idx) x((1:l(idx))+cuml(idx));
x_cell = arrayfun(get_x, 1:numel(l), 'UniformOutput', false);
B = blkdiag(x_cell{:});
A = B*B';
Edit
After running some benchmarks I found a direct loop based implementation to be about twice as fast as the cell based approach above.
A = zeros(sum(l));
B = zeros(sum(l), numel(l));
prev = 0;
for idx = 1:numel(l)
xidx = (1:l(idx))+prev;
A(xidx, xidx) = x(xidx,1) * x(xidx,1)';
B(xidx, idx) = x(idx,1);
prev = prev + l(idx);
end
Here's an alternative approach:
s = repelem(1:numel(l), l).';
t = accumarray(s, x, [], #(x){x*x'});
A = blkdiag(t{:});
t = accumarray(s, x, [], #(x){x});
B = blkdiag(t{:});

How to create a matrix from a row vector and a column vector without using a loop in MATLAB?

I have two vectors, say A of size nx1, and B of size 1xm. I want to create a result matrix C (nxm) from a non-linear formula so that
C(i,j) = A(i)/(A(i)+B(j)).
I know I can do this with a loop such as:
for i=1:n,
C(i,1:m)=A(i)./(A(i)+B(1:m));
end
but is it possible in some way to do this without using a loop?
EDIT: Thanks for your answers! As a small addition, before I saw them a friend suggested the following solution:
C = A*ones(1,m)./(ones(n,1)*B+A*ones(1,m))
If you are on MATLAB R2016a or earlier you'll want to use bsxfun to accomplish this
result = bsxfun(#rdivide, A, bsxfun(#plus, A, B));
If you are on R2016b or newer, then there is implicit expansion which allows you to remove bsxfun and just apply the element-operators directly
result = A ./ (A + B);
Benchmark
Here is a real benchmark using timeit to compare the execution speed of using bsxfun, repmat, implicit broadcasting and a for loop. As you can see from the results, the bsxfun and implicit broadcasting methods yield the fastest execution time.
function comparision()
sz = round(linspace(10, 5000, 30));
times1 = nan(size(sz));
times2 = nan(size(sz));
times3 = nan(size(sz));
times4 = nan(size(sz));
for k = 1:numel(sz)
A = rand(sz(k), 1);
B = rand(1, sz(k));
times1(k) = timeit(#()option1(A,B));
A = rand(sz(k), 1);
B = rand(1, sz(k));
times2(k) = timeit(#()option2(A,B));
A = rand(sz(k), 1);
B = rand(1, sz(k));
times3(k) = timeit(#()option3(A,B));
A = rand(sz(k), 1);
B = rand(1, sz(k));
times4(k) = timeit(#()option4(A,B));
end
figure
p(1) = plot(sz, times1 * 1000, 'DisplayName', 'bsxfun');
hold on
p(2) = plot(sz, times2 * 1000, 'DisplayName', 'repmat');
p(3) = plot(sz, times3 * 1000, 'DisplayName', 'implicit');
p(4) = plot(sz, times4 * 1000, 'DisplayName', 'for loop');
ylabel('Execution time (ms)')
xlabel('Elements in A')
legend(p)
end
function C = option1(A,B)
C = bsxfun(#rdivide, A, bsxfun(#plus, A, B));
end
function C = option2(A,B)
m = numel(B);
n = numel(A);
C = repmat(A,1,m) ./ (repmat(A,1,m) + repmat(B,n,1));
end
function C = option3(A, B)
C = A ./ (A + B);
end
function C = option4(A, B)
m = numel(B);
n = numel(A);
C = zeros(n, m);
for i=1:n,
C(i,1:m)=A(i)./(A(i)+B(1:m));
end
end
See this answer for more information comparing implicit expansion and bsxfun.
Implicit expansion is the way to go if you have 2016b or newer, as mentioned by Suever. Another approach without that is to do element-wise operations after making A and B the same size as C, using repmat...
A1 = repmat(A,1,m);
B1 = repmat(B,n,1);
C = A1 ./ (A1 + B1);
Or in 1 line...
C = repmat(A,1,m) ./ (repmat(A,1,m) + repmat(B,n,1));
As a benchmark, I ran your loop method, the above repmat method, and Suever's bsxfun method for m = 1000, n = 100, averaging over 1,000 runs each:
Using for loop 0.00290520 sec
Using repmat 0.00014693 sec
Using bsxfun 0.00016402 sec
So for large matrices, repmat and bsxfun are comparable with repmat edging it. For small matrices though, just looping can be quicker than both, especially with a small n as that's your loop variable!
It's worth testing the given methods for your specific use case, as the timing results seem fairly variable depending on the inputs.

How to plot a function of multiple variables in Matlab?

I'm trying to figure out a way to make a plot of a function in Matlab that accepts k parameters and returns a 3D point. Currently I've got this working for two variables m and n. How can I expand this process to any number of parameters?
K = zeros(360*360, number);
for m = 0:5:359
for n = 1:5:360
K(m*360 + n, 1) = cosd(m)+cosd(m+n);
K(m*360 + n, 2) = sind(m)+sind(m+n);
K(m*360 + n, 3) = cosd(m)+sind(m+n);
end
end
K(all(K==0,2),:)=[];
plot3(K(:,1),K(:,2),K(:,3),'.');
end
The code you see above is for a similar problem but not exactly the same.
Most of the time you can do this in a vectorized manner by using ndgrid.
[M, N] = ndgrid(0:5:359, 1:5:360);
X = cosd(M)+cosd(M+N);
Y = sind(M)+sind(M+N);
Z = cosd(M)+sind(M+N);
allZero = (X==0)&(Y==0)&(Z==0); % This ...
X(allZero) = []; % does not ...
Y(allZero) = []; % do ...
Z(allZero) = []; % anything.
plot3(X,Y,Z,'b.');
A little explanation:
The call [M, N] = ndgrid(0:5:359, 1:5:360); generates all combinations, where M is an element of 0:5:359 and N is an element of 1:5:360. This will be in the form of two matrices M and N. If you want you can reshape these matrices to vectors by using M = M(:); N = N(:);, but this isn't needed here.
If you were to have yet another variable, you would use: [M, N, P] = ndgrid(0:5:359, 1:5:360, 10:5:1000).
By the way: The code part where you delete the entry [0,0,0] doesn't do anything here, because this value doesn't appear. I see you only needed it, because you were allocating a lot more memory than you actually needed. Here are two versions of your original code, that are not as good as the ndgrid version, but preferable to your original one:
m = 0:5:359;
n = 1:5:360;
K = zeros(length(m)*length(n), 3);
for i = 1:length(m)
for j = 1:length(n)
nextRow = (i-1)*length(n) + j;
K(nextRow, 1) = cosd(m(i)) + cosd(m(i)+n(j));
K(nextRow, 2) = sind(m(i)) + sind(m(i)+n(j));
K(nextRow, 3) = cosd(m(i)) + sind(m(i)+n(j));
end
end
Or simpler, but a bit slower:
K = [];
for m = 0:5:359
for n = 1:5:360
K(end+1,1:3) = 0;
K(end, 1) = cosd(m)+cosd(m+n);
K(end, 2) = sind(m)+sind(m+n);
K(end, 3) = cosd(m)+sind(m+n);
end
end

How to write a generalized code

I write a code for linear feedback shift register.My code is in below:
X=5712;
D1(1)=0;
D2(1)=0;
D3(1)=0;
D4(1)=0;
D5(1)=0;
D6(1)=1;
for i=1:X-1
D6(i+1)=D1(i);
D5(i+1)=xor(D1(i),D6(i));
D4(i+1)=D5(i);
D3(i+1)=D4(i);
D2(i+1)=D3(i);
D1(i+1)=D2(i);
end
In my code i can only use 6 shift register.I know for degree,n=2,3,4,6,7,15,22, the polynomial is x^n+x+1.As the polynomial is same for those degrees so i want to write a common code for all.
Matlab experts Please need your help.
Your problem is that you are making separate vectors for each register. Rather make a single matrix (i.e. D replaces all of your D1, D2, ..., Dn) so that you can loop:
X = 20;
n = 6;
D = zeros(X, n);
D(1,n) = 1;
for ii = 1:X-1
D(ii+1, 1:n-2) = D(ii, 2:n-1);
D(ii+1, n-1) = xor(D(ii,1), D(ii,n));
D(ii+1, n) = D(ii, 1);
end
E = D(:, end:-1:1)