Parfor: Not enough input arguments - matlab

I have found a weird behavior of the parfor functionality in matlab. Have a look at the following code:
function [x,y,z] = parForTest(test3)
x = zeros(100,1);
y = zeros(100,1);
z = zeros(100,1);
test1 = ones(1,100);
test2 = zeros(1,100);
useSameTest2 = false;
if nargin == 1
test3Given = true;
else
test3Given = false;
end
parfor s = 1:numel(test1)
if useSameTest2
tmpTest = test2(1);
if test3Given, tmpTest3 = test3(1); end
else
tmpTest = test2(s);
if test3Given, tmpTest3 = test3(s); end
end
if test3Given
[xt, yt, zt] = oneCombi(test1(s), tmpTest, tmpTest3);
else
[xt, yt, zt] = oneCombi(test1(s), tmpTest);
end
%% store results
x(s) = xt;
y(s) = yt;
z(s) = zt;
end
end
function [xt, yt, zt] = oneCombi(t1, tmpTest, tmpTest3)
if nargin == 3
xt = 1;
yt = 1;
zt = 1;
else
xt = 0;
yt = 0;
zt = 0;
end
end
If you call this function by typing "[x,y,z] = parForTest();" you will get an error saying that there are not enough input arguments. If you run the whole thing with "for" instead of "parfor" it will work. It will also work, when you call "[x,y,z] = parForTest(ones(100,1));" Can somebody please explain me this behavior? It seems to be connected to the fact that I have an optional argument. If I add the line "test3 = [];" after "test3Given = false;" it will also work.
Matlab2014a with parallel computing toolbox.

You are using the optional input functionality incorrectly. I have noticed that matlab sometimes allows a call of the type F() even if the function is declared as function result = F(x, y). This call will be allowed if during the execution the variables x and y are not used. I know it is weird.
Now, your problem is related to the fact that you are using the parallel computing toolbox. When using parfor, Matlab is more stringent with the variables used inside the parfor-loop, that is why it works happily with the for-loop but not with the parfor. Matlab needs to ensure that all the workers receive the correct information, properly sliced, and properly defined (regardless of the execution path).
To solve your issue you need to define your input argument as varargin and then act on the different inputs with nargin. You need to modify your function as follows (see how the variable test3 is always defined, no matter if you call it as parForTest() or parForTest(whatever)):
function [x,y,z] = parForTest(varargin)
x = zeros(100,1);
y = zeros(100,1);
z = zeros(100,1);
test1 = ones(1,100);
test2 = zeros(1,100);
useSameTest2 = false;
if nargin == 1
test3Given = true;
test3 = varargin{1};
else
test3Given = false;
test3 = [];
end
parfor s = 1:numel(test1)
if useSameTest2
tmpTest = test2(1);
if test3Given, tmpTest3 = test3(1); end
else
tmpTest = test2(s);
if test3Given, tmpTest3 = test3(s); end
end
if test3Given
[xt, yt, zt] = oneCombi(test1(s), tmpTest, tmpTest3);
else
[xt, yt, zt] = oneCombi(test1(s), tmpTest);
end
% store results
x(s) = xt;
y(s) = yt;
z(s) = zt;
end

Related

Why does this not correctly evaluate e^x using the Taylor series?

I am attempting to write a function called expSeries which uses another function factFunc to evaluate e^x. I have already written the function factFunc, as shown below:
function fact = factFunc(n)
f = 1;
for a = 1:b
f = f*a;
end
fact = f;
end
I am now attempting to write the function expSeries which evaulates e^x using the Taylor series. This is what I have so far:
function expo = exponentialFunc(x)
terms = input('Enter the number of terms');
b = 0;
for i = 1:terms
b = x/factFunc(terms);
end
expo = b;
end
And in the main program, I have
n = exponentialFunc(4);
disp(n);
Where in this instance I am trying to find e^4. However, the output is not what expected. Does anyone have any idea where I am going wrong?
Fix to factFunc:
function fact = factFunc(n)
f = 1;
for a = 1:n
f = f*a;
end
fact = f;
end
Fix to exponentialFunc
function expo = exponentialFunc(x)
terms = input('Enter the number of terms');
b = 0;
for i = 0:terms-1
b = b + x^i/factFunc(i);
end
expo = b;
end
Example
>> exponentialFunc(4)
Enter the number of terms10
ans =
54.1541
Note exp(4) = 54.59815...

Calculating values in a for loop

I have a for loop that is storing values. For some reason, it is calculating values for all the number up to and including those in the for loop, instead of just the ones in the array.
t = 3600:50:172800;x = 0.1;y = 0; ro = 0.1;
T = zeros(1,length(t));
for Cm = 1E6:1E6:4E6
for i = 1:length(t)
T = T_ILS(x,y,ro,Cm,t);
Tall(Cm,:) = [T];
end
end
The error I get is "Requested 2000000x3385 array exceeds maximum array size preferences". I would like the for loop to calculate just the Cm values and not every number in between.
You are not computing every value in between, but your indices are messed up. Cm takes values in the millions, but you use it to index Tall(Cm,:). You probably want
t = 3600:50:172800;x = 0.1;y = 0; ro = 0.1;
T = zeros(1,length(t));
Cm = 1E6:1E6:4E6;
for j = 1:length(Cm)
for i = 1:length(t)
T(i) = T_ILS(x,y,ro,Cm(j),t(i));
end
Tall(j,:) = [T];
end
Notice that the main function call assigns to T(i) and uses t(i) in the function arguments to justify the existence of the for loop.
In the inner loop, T is the output of the function T_ILS, using the same arguments each time.
for i = 1:length(t)
T = T_ILS(x,y,ro,Cm,t);
Tall(Cm,:) = [T];
end
I don't know what this function computes, but you probably wanted to do this instead
for i = 1:length(t)
T = T_ILS(x,y,ro,Cm,t(i));
Tall(Cm,:) = [T];
end
to account for each value of the vector t, or even better:
for t = 3600:50:172800
T = T_ILS(x,y,ro,Cm,t);
Tall(Cm,:) = [T];
end
EDIT: Also, to make this answer complete, I'd like to merge #MadPhysicist's answer with mine. The result would be
Cm = 1E6:1E6:4E6; x = 0.1;y = 0; ro = 0.1;
T = zeros(1,length(t));
for i = 1:length(Cm)
for t = 3600:50:172800;
T = T_ILS(x,y,ro,Cm(i),t);
Tall(i,:) = [T];
end
end

Subscripted assignment dimension mismatch in matlab

I executed this code using Feature Matrix 517*11 and Label Matrix 517*1. But once the dimensions of matrices change the code cant be run. How can I fix this?
The error is:
Subscripted assignment dimension mismatch.
in this line :
edges(k,j) = quantlevels(a);
Here is my code:
function [features,weights] = MI(features,labels,Q)
if nargin <3
Q = 12;
end
edges = zeros(size(features,2),Q+1);
for k = 1:size(features,2)
minval = min(features(:,k));
maxval = max(features(:,k));
if minval==maxval
continue;
end
quantlevels = minval:(maxval-minval)/500:maxval;
N = histc(features(:,k),quantlevels);
totsamples = size(features,1);
N_cum = cumsum(N);
edges(k,1) = -Inf;
stepsize = totsamples/Q;
for j = 1:Q-1
a = find(N_cum > j.*stepsize,1);
edges(k,j) = quantlevels(a);
end
edges(k,j+2) = Inf;
end
S = zeros(size(features));
for k = 1:size(S,2)
S(:,k) = quantize(features(:,k),edges(k,:))+1;
end
I = zeros(size(features,2),1);
for k = 1:size(features,2)
I(k) = computeMI(S(:,k),labels,0);
end
[weights,features] = sort(I,'descend');
%% EOF
function [I,M,SP] = computeMI(seq1,seq2,lag)
if nargin <3
lag = 0;
end
if(length(seq1) ~= length(seq2))
error('Input sequences are of different length');
end
lambda1 = max(seq1);
symbol_count1 = zeros(lambda1,1);
for k = 1:lambda1
symbol_count1(k) = sum(seq1 == k);
end
symbol_prob1 = symbol_count1./sum(symbol_count1)+0.000001;
lambda2 = max(seq2);
symbol_count2 = zeros(lambda2,1);
for k = 1:lambda2
symbol_count2(k) = sum(seq2 == k);
end
symbol_prob2 = symbol_count2./sum(symbol_count2)+0.000001;
M = zeros(lambda1,lambda2);
if(lag > 0)
for k = 1:length(seq1)-lag
loc1 = seq1(k);
loc2 = seq2(k+lag);
M(loc1,loc2) = M(loc1,loc2)+1;
end
else
for k = abs(lag)+1:length(seq1)
loc1 = seq1(k);
loc2 = seq2(k+lag);
M(loc1,loc2) = M(loc1,loc2)+1;
end
end
SP = symbol_prob1*symbol_prob2';
M = M./sum(M(:))+0.000001;
I = sum(sum(M.*log2(M./SP)));
function y = quantize(x, q)
x = x(:);
nx = length(x);
nq = length(q);
y = sum(repmat(x,1,nq)>repmat(q,nx,1),2);
I've run the function several times without getting any error.
I've used as input for "seq1" and "seq2" arrays such as 1:10 and 11:20
Possible error might rise in the loops
for k = 1:lambda1
symbol_count1(k) = sum(seq1 == k);
end
if "seq1" and "seq2" are defined as matrices since sum will return an array while
symbol_count1(k)
is expected to be single value.
Another possible error might rise if seq1 and seq2 are not of type integer since they are used as indexes in
M(loc1,loc2) = M(loc1,loc2)+1;
Hope this helps.

How to skip an error inside a loop and let the loop continue

The following is my full code: (Most of it isn't useful for what I'm asking, but I just put in the entire code for context, the part of the code that is causing me trouble is towards the end)
clc
clear
P = xlsread('b3.xlsx', 'P');
d = xlsread('b3.xlsx', 'd');
CM = xlsread('b3.xlsx', 'Cov');
Original_PD = P; %Store original PD
LM_rows = size(P,1)+1; %Expected LM rows
LM_columns = size(P,2); %Expected LM columns
LM_FINAL = zeros(LM_rows,LM_columns); %Dimensions of LM_FINAL
% Start of the outside loop
for k = 1:size(P,2)
P = Original_PD(:,k);
interval = cell(size(P,1)+2,1);
for i = 1:size(P,1)
interval{i,1} = NaN(size(P,1),2);
interval{i,1}(:,1) = -Inf;
interval{i,1}(:,2) = d;
interval{i,1}(i,1) = d(i,1);
interval{i,1}(i,2) = Inf;
end
interval{i+1,1} = [-Inf*ones(size(P,1),1) d];
interval{i+2,1} = [d Inf*ones(size(P,1),1)];
c = NaN(size(interval,1),1);
for i = 1:size(c,1)
c(i,1) = mvncdf(interval{i,1}(:,1),interval{i,1}(:,2),0,CM);
end
c0 = c(size(P,1)+1,1);
f = c(size(P,1)+2,1);
c = c(1:size(P,1),:);
b0 = exp(1);
b = exp(1)*P;
syms x;
eqn = f*x;
for i = 1:size(P,1)
eqn = eqn*(c0/c(i,1)*x + (b(i,1)-b0)/c(i,1));
end
eqn = c0*x^(size(P,1)+1) + eqn - b0*x^size(P,1);
x0 = solve(eqn);
for i = 1:size(x0)
id(i,1) = isreal(x0(i,1));
end
x0 = x0(id,:);
x0 = x0(x0 > 0,:);
clear x;
for i = 1:size(P,1)
x(i,:) = (b(i,1) - b0)./(c(i,1)*x0) + c0/c(i,1);
end
x = [x0'; x];
x = double(x);
x = x(:,sum(x <= 0,1) == 0)
lamda = -log(x);
LM_FINAL(:,k) = lamda;
end
% end of the outside loop
The important part of the above loop is towards the end:
x = x(:,sum(x <= 0,1) == 0)
This condition is sometimes not satisfied and hence the variable x is empty, which means LM_FINAL(:,k) = lamda is also empty. When this happens, I get the error:
x =
Empty matrix: 43-by-0
Improper assignment with rectangular empty matrix.
Error in Solution (line 75)
LM_FINAL(:,k) = lamda;
How can I skip this error so that the column for LM_FINAL remains as empty, but the loop continues (so that the rest of LM_FINAL's columns are filled) rather than terminating?
You can use try and catch phrase to explicitly handle errors inside loop (or elsewhere in your code).

Matlab. Create a loop to change variable size with each iteration

I am currently trying to run a script that calls a particular function, but want to call the function inside a loop that halfs one of the input variables for roughly 4 iterations.
in the code below the function has been replaced for another for loop and the inputs stated above.
the for loop is running an Euler method on the function, and works fine, its just trying to run it with the repeated smaller step size im having trouble with.
any help is welcomed.
f = '3*exp(-x)-0.4*y';
xa = 0;
xb = 3;
ya = 5;
n = 2;
h=(xb-xa)/n;
x = xa:h:xb;
% h = zeros(1,4);
y = zeros(1,length(x));
F = inline(f);
y(1) = ya;
for j = 1:4
hOld = h;
hNew = hOld*0.5;
hOld = subs(y(1),'h',hNew);
for i = 1:(length(x)-1)
k1 = F(x(i),y(i));
y(i+1,j+1) = y(i) + h*k1;
end
end
disp(h)
after your comment, something like this
for j = 1:4
h=h/2;
x = xa:h:xb;
y = zeros(1,length(x));
y(1) = ya;
for i = 1:(length(x)-1)
k1 = F(x(i),y(i));
y(i+1,j+1) = y(i) + h*k1;
end
end