I need to plot figures with subplots inside a parfor-loop, similar to this question (which deals more with the quality of the plots).
My code looks something like this:
parfor idx=1:numel(A)
N = A(idx);
fig = figure();
ax = subplot(3,1,1);
plot(ax, ...);
...
saveas(fig,"..."),'fig');
saveas(fig,"...",'png');
end
This gives a weird error:
Data must be numeric, datetime, duration or an array convertible to double.
I am sure that the problem does not lie in non-numeric data as the same code without parallelization works.
At this point I expected an error because threads will concurrently create and access figures and axes objects, and I do not think it is ensured that the handles always correspond to the right object (threads are "cross-plotting" so to say).
If I pre-initialize the objects and then acces them like this,
ax = cell(1,numel(A)); % or ax = zeros(1,numel(A));
ax(idx) = subplot(3,1,1);
I get even weirder errors somewhere in the fit-calls I use:
Error using curvefit.ensureLogical>iConvertSubscriptIndexToLogical (line 26)
Excluded indices must be nonnegative integers that reference the fit's input data points
Error in curvefit.ensureLogical (line 18)
exclude = iConvertSubscriptIndexToLogical(exclude, nPoints);
Error in cfit/plot (line 46)
outliers = curvefit.ensureLogical( outliers, numel( ydata ) );
I have the feeling it has to work with some sort of variable slicing described in the documentation, I just can't quite figure out how.
I was able to narrow the issues down to a fitroutine I was using.
TLDR: Do not use fitobjects (cfit or sfit) for plots in a parfor-loop!
Solutions:
Use wrappers like nlinfit() or lsqcurvefit() instead of fit(). They give you the fit parameters directly so you can call your fitfunction with them when plotting.
If you have to use fit() (for some reason it is the only one which was able to fit my data more or less consistently), extract the fit parameters and then call your fitfunction using cell expansion.
fitfunc = #(a,b,c,d,e,x) ( ... );
[fitobject,gof,fitinfo] = fit(x,y,fitfunc,fitoptions(..));
vFitparam = coeffvalues(fitobject);
vFitparam_cell = num2cell(vFitparam);
plot(ax,x,fitfunc(vFitparam_cell{:},x), ... );
As far as I know fit() requires the function handle to have subsequent parameters (not a vector), so by using a cell you can avoid bloated code like this:
plot(ax,x,fitfunc(vFitparam(1),vFitparam(2),vFitparam(3),vFitparam(4),vFitparam(5),x), ... );
Related
I am developing a small utility that calculates partial differential equation in MATLAB.
I am receiveing an error of invalid syntax:
Parse error at '[' : usage might be invalid MATLAB syntax in the function call, but I don't understand why:
Below the code I am using for the main_routine.m:
% pde operations ..
% Explicit (nonstiff) integration
if(mf == 1)
[t,u] = ode45(#pde_1, tout, u0, options);
end
%
% Implicit (sparse stiff) integration
if(mf == 2)
S = jpattern_num;
options = odeset(options, 'JPattern', S)
[t,u] = ode15s(#pde_1, tout, u0, options);
end
Function call to jpattern_num.m where the error is:
function S = jpattern_num
global n
% Set independent, dependent variables for the calculation
% of the sparsity pattern
tbase = 0;
for i=1:n
ybase(i) = 0.5;
end
ybase = ybase';
%
% Compute the corresponding derivative vector
ytbase = pde_1(tbase,ybase);
fac[]; % <-- Error Here but don't know wy
thresh = 1e-16;
vectorized = 'on';
[Jac,fac] = numjac(#pde_1, tbase, ybase, ytbase, thresh, fac, vectorized);
%
% Replace nonzero elements by "1" (so as to create a "0-1" map of the
% Jacobian matrix)
S = spones(sparse(Jac));
%
% Plot the map ….
What I tried so far:
1) I thought that it was just an array declaration problem but the error persists. I looked at the official documentation to double check possible discrepancies but I could not find the error.
2) This source was very useful as the user had a similar project.
I applied the same modification:
from
fac[];
I applied
fac();
But that didn't solve the problem unfortunately.
3) I dug more into the possible cause of the problem and came across this source, which always from official documentation. I applied what was advised but still the problem persists.
Please, if anyone had a similar problem, advise on how to sole this issue and guide to the right direction.
The line as it is now, is not creating an array. If you want to create an empty array, try
fac = [];
But the question is now, why passing an empty array to numjac? If the array will be created in the latter function, there is no need to pass it as an argument. In fact, if an array passed as an argument is modified in the function, Matlab creates a new array.
Why does the error message of this code return: "Subscript indices must either be real positive integers or logicals.", when I am using ceil for every subscript?
A=1:1:100;
B=1:1:100;
C=1;
D=1:1:100;
E=2;
F=1:1:100;
G=1:1:100;
H=0.1:0.1:10;
fun_1=#(t)integral(#(ti)G(ceil(ti)).*H(ceil(t-ti)),0.1,t-1);
fun_2=#(t)integral(#(ti)G(ceil(ti)).*B(ceil(ti)).*(C.*D(t).^E)./F(t).*...
exp(-integral(#(x)(C.*D(ceil(x)).^E)./F(ceil(x)),ti,5)-K.*(t-ti)),0.1,t-
1,'ArrayValued',true);
I=500;
J=1000;
K=2;
fun_3=#(t)I*integral(#(ti)min(fun_2(ceil(ti)),J).*exp(-(K+I).*(t-ti)),0.1,t-
1);
t=1:1:5;
figure(1)
fplot(fun_1,t);
figure(2)
fplot(fun_2,t);
figure(3)
fplot(fun_3,t);
fplot see documentation Called as fplot(f,xinterval) evaluates your function handle f over the interval xinterval. IT will evaluate f at automatically determined steps along that given interval.
From the docs:
xinterval — Interval for x [–5 5] (default) | two-element vector of
form [xmin xmax]
You seem to be trying to specify exactly where you want your functions evaluated
t=1:1:5;
...
fplot(fun_1,t);
But it doesn't work that way. What is happening is that fplot is evaluating the function from 1 to 2 (the first 2 elements of t). So for example it might feed values of t = 1, 1.05, 1.1,... ,2 into your fun_# functions.
You can tell this because you first function which does work actually plots over the x-range of 1 to 2.
The reason you are getting a subscript indices error is because in fun_2 you have this ...(C.*D(t).^E)./F(t).*... Since fplot is feeding in values for t which are spaced between 1 and 2 (ex. 1.1) that is not a valid index.
If you really just want the values of your functions at t = 1:1:5 The you probably do not want to use fplot and just want evaluate the functions at those times and plot it.
y = feval(fun_1,t);
plot(t,y)
EDIT: The above code doesn't work
You will need to do something like the code below. This is because the 2nd & 3rd trems to the intergral function need to be scalar (1x1). If you feed them an array for t then they crash. So evaluate at each t not all at once.
figure(1)
y_1 = arrayfun(fun_1,t);
plot(t,y_1);
figure(2)
y_2 = arrayfun(fun_2,t);
plot(t,y_2);
figure(3)
y_3 = arrayfun(fun_3,t);
plot(t,y_3);
Note: the Third function still errors ... and I'm not 100% sure why. I didn't really look at it.
I have to construct the following function in MATLAB and am having trouble.
Consider the function s(t) defined for t in [0,4) by
{ sin(pi*t/2) , for t in [0,1)
s(t) = { -(t-2)^3 , for t in [1,3)*
{ sin(pi*t/2) , for t in [3,4)
(i) Generate a column vector s consisting of 512 uniform
samples of this function over the interval [0,4). (This
is best done by concatenating three vectors.)
I know it has to be something of the form.
N = 512;
s = sin(5*t/N).' ;
But I need s to be the piecewise function, can someone provide assistance with this?
If I understand correctly, you're trying to create 3 vectors which calculate the specific function outputs for all t, then take slices of each and concatenate them depending on the actual value of t. This is inefficient as you're initialising 3 times as many vectors as you actually want (memory), and also making 3 times as many calculations (CPU), most of which will just be thrown away. To top it off, it'll be a bit tricky to use concatenate if your t is ever not as you expect (i.e. monotonically increasing). It might be an unlikely situation, but better to be general.
Here are two alternatives, the first is imho the nice Matlab way, the second is the more conventional way (you might be more used to that if you're coming from C++ or something, I was for a long time).
function example()
t = linspace(0,4,513); % generate your time-trajectory
t = t(1:end-1); % exclude final value which is 4
tic
traj1 = myFunc(t);
toc
tic
traj2 = classicStyle(t);
toc
end
function trajectory = myFunc(t)
trajectory = zeros(size(t)); % since you know the size of your output, generate it at the beginning. More efficient than dynamically growing this.
% you could put an assert for t>0 and t<3, otherwise you could end up with 0s wherever t is outside your expected range
% find the indices for each piecewise segment you care about
idx1 = find(t<1);
idx2 = find(t>=1 & t<3);
idx3 = find(t>=3 & t<4);
% now calculate each entry apprioriately
trajectory(idx1) = sin(pi.*t(idx1)./2);
trajectory(idx2) = -(t(idx2)-2).^3;
trajectory(idx3) = sin(pi.*t(idx3)./2);
end
function trajectory = classicStyle(t)
trajectory = zeros(size(t));
% conventional way: loop over each t, and differentiate with if-else
% works, but a lot more code and ugly
for i=1:numel(t)
if t(i)<1
trajectory(i) = sin(pi*t(i)/2);
elseif t(i)>=1 & t(i)<3
trajectory(i) = -(t(i)-2)^3;
elseif t(i)>=3 & t(i)<4
trajectory(i) = sin(pi*t(i)/2);
else
error('t is beyond bounds!')
end
end
end
Note that when I tried it, the 'conventional way' is sometimes faster for the sampling size you're working on, although the first way (myFunc) is definitely faster as you scale up really a lot. In anycase I recommend the first approach, as it is much easier to read.
I'm trying to write code that will optimize a multivariate function using sklearn's optimize function, but it keeps returning an IndexError, and I'm not sure where to go from here.
The code is this:
revcoeff = coefficients[::-1]
xdot = np.zeros(0)
normfeat1 = normfeat1.reshape(-1,1)
xdot = np.append(normfeat1, normfeat2.reshape(-1,1), axis=1)
a = revcoeff[1:3]
b = xdot[0, :]
seed = np.zeros(5) #does seed need to be the coefficients? not sure
fun = lambda x: np.multiply((1/666), np.power(np.sum(np.dot(a, xdot[x, :])-medianv[x]),2)) #costfunction
optsol = optimize.minimize(fun, seed)
where there are two features I'm using in my nearest neighbors algorithm. Coefficients for the fitted regression model are given into the array "coefficients".
What I'm having trouble understanding is 1) why my code is throwing a "IndexError: arrays used as indicies must be of integer or boolean type"....and also partially I'm confused by the optimize.minimize function itself. It takes in two input values, the function and x0 (an ndarray with initial guesses). What should x0 be, the coefficients values? Or do I pick random values, and how many are necessary?
np.zeros() does not return integers by default. Try, for example, np.zeros(5, dtype=int) instead. It won't solve all of the problems with your code, though. You'll see some other error message.
Also, notice, that 1/666 returns 0 instead of 0.00150150. You probably want 1/666.0.
It would be helpful if you could clean up your code as half of it is of no use.
My question is specific to the "learn_params()" function of the BayesNetToolbox in MatLab. In the user manual, "learn_params()" is stated to be suitable for use only if the input data is fully observed. I have tried it with a partially observed dataset where I represented unobserved values as NaN's.
It seems like "learn_params()" can deal with NaNs and the node state combinations that do not occur in the dataset. When I apply dirichlet priors to smoothen the 0 values, I get 'sensible' MLE distributions for all nodes. I have copied the script where I do this.
Can someone clarify whether what I am doing makes sense or if I am missing
something, i.e. the reason why "learn_params()" cannot be used with partially
observed data.
The MatLab Script where I test this is here:
% Incomplete dataset (where NaN's are unobserved)
Age = [1,2,2,NaN,3,3,2,1,NaN,2,1,1,3,NaN,2,2,1,NaN,3,1];
TNMStage = [2,4,2,3,NaN,1,NaN,3,1,4,3,NaN,2,4,3,4,1,NaN,2,4];
Treatment = [2,3,3,NaN,2,NaN,4,4,3,3,NaN,2,NaN,NaN,4,2,NaN,3,NaN,4];
Survival = [1,2,1,2,2,1,1,1,1,2,2,1,2,2,1,2,1,2,2,1];
matrixdata = [Age;TNMStage;Treatment;Survival];
node_sizes =[3,4,4,2];
% Enter the variablesmap
keys = {'Age', 'TNM','Treatment', 'Survival'};
v= 1:1:length(keys);
VariablesMap = containers.Map(keys,v);
% create the dag and the bnet
N = length(node_sizes); % Instead of entering it manually
dag2 = zeros(N,N);
dag2(VariablesMap('Treatment'),VariablesMap('Survival')) = 1;
bnet21 = mk_bnet(dag2, node_sizes);
draw_graph(bnet21.dag);
dirichletweight=1;
% define the CPD priors you want to use
bnet23.CPD{VariablesMap('Age')} = tabular_CPD(bnet23, VariablesMap('Age'), 'prior_type', 'dirichlet','dirichlet_type', 'unif', 'dirichlet_weight', dirichletweight);
bnet23.CPD{VariablesMap('TNM')} = tabular_CPD(bnet23, VariablesMap('TNM'), 'prior_type', 'dirichlet','dirichlet_type', 'unif', 'dirichlet_weight', dirichletweight);
bnet23.CPD{VariablesMap('Treatment')} = tabular_CPD(bnet23, VariablesMap('Treatment'), 'prior_type', 'dirichlet','dirichlet_type', 'unif','dirichlet_weight', dirichletweight);
bnet23.CPD{VariablesMap('Survival')} = tabular_CPD(bnet23, VariablesMap('Survival'), 'prior_type', 'dirichlet','dirichlet_type', 'unif','dirichlet_weight', dirichletweight);
% Find MLEs from incomplete data with Dirichlet prior CPDs
bnet24 = learn_params(bnet23, matrixdata);
% Look at the new CPT values after parameter estimation has been carried out
CPT24 = cell(1,N);
for i=1:N
s=struct(bnet24.CPD{i}); % violate object privacy
CPT24{i}=s.CPT;
end
According to my understanding of the BNT documentation, you need to make a couple of changes:
Missing values should be represented as empty cells instead of NaN values.
The learn_params_em function is the only one that supports missing values.
My previous response was incorrect, as I mis-recalled which of the BNT learning functions had support for missing values.