I want to compute a fractal image in two nested loops over the pixel indices (ix,iy). The sample code just assigns a random number to RGB values instead of the real calculations.
x = 0:.2:4;
y = 0:.2:3;
nX = length(x);
nY = length(y);
RenderRed = zeros(nX,nY); RenderGreen = zeros(nX,nY); RenderBlue = zeros(nX,nY);
parfor ix = 1:nX
% for iy = 1:length(y) % error
for iy = 1:nY
% "compute" pixel (ix,iy)
RenderRed(ix, iy) = rand; RenderGreen(ix, iy) = rand; RenderBlue(ix, iy) = rand;
end
end
Pctr = [];
Pctr(:,:,1)=RenderRed; Pctr(:,:,2)=RenderGreen; Pctr(:,:,3)=RenderBlue;
handle = image(Pctr);
shg
The code works as shown but if the end value of the iy loop is changed from nY to length(y) - see the commented line - an error is issued:
Error: The variable RenderRed in a parfor cannot be classified.
See Parallel for Loops in MATLAB, "Overview".
Why? In my understanding of sliced variables no version should work: one has to use an auxiliary variable collecting the results of the inner loop, and assign that to a slice of the matrix.
But length(y) instead of nY should have no effect at all on the classification of variables because y is never assigned in the loops.
mlint finds no error, in neither version. Same behaviour with MATLAB versions 2016b, 2017b.
According to the Matlab documentation, this actually can work! When you want to use nested for loops inside parfor loops:
For proper variable classification, you must define the range of a for-loop nested in a parfor-loop by constant numbers or variables.
Related
The following is my code. I try to model PFR in Matlab using ode23s. It works well with one component irreversible reaction. But when extending more dependent variables, 'Matrix dimensions must agree' problem shows. Have no idea how to fix it. Is possible to use other software to solve similar problems?
Thank you.
function PFR_MA_length
clear all; clc; close all;
function dCdt = df(t,C)
dCdt = zeros(N,2);
dCddt = [0; -vo*diff(C(:,1))./diff(V)-(-kM*C(2:end,1).*C(2:end,2)-kS*C(2:end,1))];
dCmdt = [0; -vo*diff(C(:,2))./diff(V)-(-kM*C(2:end,1).*C(2:end,2))];
dCdt(:,1) = dCddt;
dCdt(:,2) = dCmdt;
end
kM = 1;
kS = 0.5; % assumptions of the rate constants
C0 = [2, 2]; % assumptions of the entering concentration
vo = 2; % volumetric flow rate
volume = 20; % total volume of reactor, spacetime = 10
N = 100; % number of points to discretize the reactor volume on
init = zeros(N,2); % Concentration in reactor at t = 0
init(1,:) = C0; % concentration at entrance
V = linspace(0,volume,N)'; % discretized volume elements, in column form
tspan = [0 20];
[t,C] = ode23s(#(t,C) df(t,C),tspan,init);
end
'''
You can put a break point on the line that computes dCddt and observe that the size of the matrices C and V are different.
>> size(C)
ans =
200 1
>> size(V)
ans =
100 1
The element-wise divide operation, ./, between these two variables would then result in the error that you mentioned.
Per ode23s's help, the output of the call to dCdt = df(t,C) needs to be a vector. However, you are returning a matrix of size 100x2. In the next call to the same function, ode32s converts it to a vector when computing the value of C, hence the size 200x1.
In the GNU octave interpretation of Matlab behavior, one has to explicitly make sure that the solver only sees flat one-dimensional state vectors. These have to be translated forward and back in the application of the model.
Explicitly reading the object A as flat array A(:) forgets the matrix dimension information, these can be added back with the reshape(A,m,n) command.
function dCdt = df(t,C)
C = reshape(C,N,2);
...
dCdt = dCdt(:);
end
...
[t,C] = ode45(#(t,C) df(t,C), tspan, init(:));
I'm new to this concept of parallel pooling on MATLAB (I'm using the version 2019 a) and coding. This code that I'm going to share with you was available on the net, with some few modifications that I've made it for my requirements.
Problem Statement: I'm having a non-linear system (Rossler equation) & I have to plot its Bifurcation diagram, I tried to do it normally using for loop but its computation time was too much and my computer got hanged several times, so I got an advice to parallel pool my code in order to come out of this problem. I tried to learn how to parallel pool using MATLAB on the net but still I'm not able to resolve my Issues as there are still some problems since there are 2 parfor loops in my code I'm having problems with Indexing and in assignment of the global parameter (Please note: This code is written for normal execution without using parallel pooling).
I'm attaching my code below here, please excuse if I've mentioned a lot many lines of codes.
clc;
a = 0.2; b = 0.2; global c;
crange = 1:0.05:90; % Range for parameter c
k = 0; tspan = 0:0.1:500; % Time interval for solving Rossler system
xmax = []; % A matrix for storing the sorted value of x1
for c = crange
f = #(t,x) [-x(2)-x(3); x(1)+a*x(2); b+x(3)*(x(1)-c)];
x0 = [1 1 0]; % initial condition for Rossler system
k = k + 1;
[t,x] = ode45(f,tspan,x0); % call ode() to solve Rossler system
count = find(t>100); % find all the t values which is >10
x = x(count,:);
j = 1;
n = length(x(:,1)); % find the length of vector x1(x in our problem)
for i=2 : n-1
% check for the min value in 1st column of sol matrix
if (x(i-1,1)+eps) < x(i,1) && x(i,1) > (x(i+1,1)+eps)
xmax(k,j)=x(i,1); % Sorting the values of x1 in increasing order
j=j+1;
end
end
% generating bifurcation map by plotting j-1 element of kth row each time
if j>1
plot(c,xmax(k,1:j-1),'k.','MarkerSize',1);
end
hold on;
index(k)=j-1;
end
xlabel('Bifuracation parameter c');
ylabel('x max');
title('Bifurcation diagram for c');
This can be made compatible with parfor by taking a few relatively simple steps. Firstly, parfor workers cannot produce on-screen graphics, so we need to change things to emit a result. In your case, this is not totally trivial since your primary result xmax is being assigned-to in a not-completely-uniform manner - you're assigning different numbers of elements on different loop iterations. Not only that, it appears not to be possible to predict up-front how many columns xmax needs.
Secondly, you need to make some minor changes to the loop iteration to be compatible with parfor, which requires consecutive integer loop iterates.
So, the major change is to have the loop write individual rows of results to a cell array I've called xmax_cell. Outside the parfor loop, it's trivial to convert this back to matrix form.
Putting all this together, we end up with this, which works correctly in R2019b as far as I can tell:
clc;
a = 0.2; b = 0.2;
crange = 1:0.05:90; % Range for parameter c
tspan = 0:0.1:500; % Time interval for solving Rossler system
% PARFOR loop outputs: a cell array of result rows ...
xmax_cell = cell(numel(crange), 1);
% ... and a track of the largest result row
maxNumCols = 0;
parfor k = 1:numel(crange)
c = crange(k);
f = #(t,x) [-x(2)-x(3); x(1)+a*x(2); b+x(3)*(x(1)-c)];
x0 = [1 1 0]; % initial condition for Rossler system
[t,x] = ode45(f,tspan,x0); % call ode() to solve Rossler system
count = find(t>100); % find all the t values which is >10
x = x(count,:);
j = 1;
n = length(x(:,1)); % find the length of vector x1(x in our problem)
this_xmax = [];
for i=2 : n-1
% check for the min value in 1st column of sol matrix
if (x(i-1,1)+eps) < x(i,1) && x(i,1) > (x(i+1,1)+eps)
this_xmax(j) = x(i,1);
j=j+1;
end
end
% Keep track of what's the maximum number of columns
maxNumCols = max(maxNumCols, numel(this_xmax));
% Store this row into the output cell array.
xmax_cell{k} = this_xmax;
end
% Fix up xmax - push each row into the resulting matrix.
xmax = NaN(numel(crange), maxNumCols);
for idx = 1:numel(crange)
this_max = xmax_cell{idx};
xmax(idx, 1:numel(this_max)) = this_max;
end
% Plot
plot(crange, xmax', 'k.', 'MarkerSize', 1)
xlabel('Bifuracation parameter c');
ylabel('x max');
title('Bifurcation diagram for c');
I need to model negative, positive and simple regulation of a gene for my systems biology class using MATLAB. The problem is that the functions for negative and simple regulation work but the positive regulation function is only outputting zeros.
My script is as follows:
% Simulation of simple regulation, negative autoregulation and positive
% autoregulation
% Define constants
global a b K n
a = 1;
b = 1;
K = 0.5;
n = 2; % Hill coefficient
% Simulation time
tspan = [0,10];
% Initial condition
X0 = 0;
% Run simulations
[t1,X1] = ode45(#autoregulation_f0,tspan,X0); % Simple regulation
[t2,X2] = ode45(#autoregulation_f1,tspan,X0); % Negative autoregulation
[t3,X3] = ode23(#autoregulation_f2,tspan,X0); % Positive autoregulation
% Plot results
figure;
plot(t1,X1,t2,X2,t3,X3);
legend('simple','negative','Location','southeast');
And my functions are:
function dxdt = autoregulation_f0(t,X)
global a b
dxdt = b - a*X;
end
function dxdt = autoregulation_f1(t,X)
global a b K n
dxdt = b/(1+(X^n)/(K^n)) - a*X;
end
function dxdt = autoregulation_f2(t,X)
global a b K n
dxdt = b*X.^n./(K.^n+X.^n) + a*X;
end
The third function "autoregulation_f2(t,X)" is the one that outputs zeros and therefore when plotting the graph I just get a straight line.
Does anyone know what could be causing this?
Thanks in advance!
It looks to be the correct result for the given function. Your provided dxdt has an X in every term. The initial X0=0 will result in dxdt=0, giving you no change in X. As a result you just end up with a flat line.
I want to Calculating the value of a function for different inputs in matlab and insert output in a matrix for example: x(1,1)=1 y(1,1)=1 x(1,2)=2 y(1,2)=4 and etc.
this is my m file in matlab:
clc,clear all,close all
x0=0;
xn=10;
n=10;
h=(xn-x0)/n;
k=1;
for k=1:n
x=[1:10];
x=x0+h;
y=x^2
x0=x;
end
My problem is that every time the for loop runs The output value is stored in the y and I can't use the output value for example: x=2 in somewhere else.
A few thoughts:
x=[1:10] does not do anything as you overwrite it in the next line
If you remove x = [1:10] you can achieve what you want to achieve by using indexing, i.e. x(k) = x0 + h and y(k) = x(k)^2 and x0 = x(k)
There is a simpler way though using vectorization though!
x = 1:10
y = x.^2
I am trying to use meshgrid in Matlab together with Chebfun to get rid of double for loops. I first define a quasi-matrix of N functions,
%Define functions of type Chebfun
N = 10; %number of functions
x = chebfun('x', [0 8]); %Domain
psi = [];
for i = 1:N
psi = [psi sin(i.*pi.*x./8)];
end
A sample calculation would be to compute the double sum $\sum_{i,j=1}^10 psi(:,i).*psi(:,j)$. I can achieve this using two for loops in Matlab,
h = 0;
for i = 1:N
for j = 1:N
h = h + psi(:,i).*psi(:,j);
end
end
I then tried to use meshgrid to vectorize in the following way:
[i j] = meshgrid(1:N,1:N);
h = psi(:,i).*psi(:,j);
I get the error "Column index must be a vector of integers". How can I overcome this issue so that I can get rid of my double for loops and make my code a bit more efficient?
BTW, Chebfun is not part of native MATLAB and you have to download it in order to run your code: http://www.chebfun.org/. However, that shouldn't affect how I answer your question.
Basically, psi is a N column matrix and it is your desire to add up products of all combinations of pairs of columns in psi. You have the right idea with meshgrid, but what you should do instead is unroll the 2D matrix of coordinates for both i and j so that they're single vectors. You'd then use this and create two N^2 column matrices that is in such a way where each column corresponds to that exact column numbers specified from i and j sampled from psi. You'd then do an element-wise multiplication between these two matrices and sum across all of the columns for each row. BTW, I'm going to use ii and jj as variables from the output of meshgrid instead of i and j. Those variables are reserved for the complex number in MATLAB and I don't want to overshadow those unintentionally.
Something like this:
%// Your code
N = 10; %number of functions
x = chebfun('x', [0 8]); %Domain
psi = [];
for i = 1:N
psi = [psi sin(i.*pi.*x./8)];
end
%// New code
[ii,jj] = meshgrid(1:N, 1:N);
%// Create two matrices and sum
matrixA = psi(:, ii(:));
matrixB = psi(:, jj(:));
h = sum(matrixA.*matrixB, 2);
If you want to do away with the temporary variables, you can do it in one statement after calling meshgrid:
h = sum(psi(:, ii(:)).*psi(:, jj(:)), 2);
I don't have Chebfun installed, but we can verify that this calculates what we need with a simple example:
rng(123);
N = 10;
psi = randi(20, N, N);
Running this code with the above more efficient solution gives us:
>> h
h =
8100
17161
10816
12100
14641
9216
10000
8649
9025
11664
Also, running the above double for loop code also gives us:
>> h
h =
8100
17161
10816
12100
14641
9216
10000
8649
9025
11664
If you want to be absolutely sure, we can have both codes run with the outputs as separate variables, then check if they're equal:
%// Setup
rng(123);
N = 10;
psi = randi(20, N, N);
%// Old code
h = 0;
for i = 1:N
for j = 1:N
h = h + psi(:,i).*psi(:,j);
end
end
%// New code
[ii,jj] = meshgrid(1:N, 1:N);
hnew = sum(psi(:, ii(:)).*psi(:, jj(:)), 2);
%// Check for equality
eql = isequal(h, hnew);
eql checks if both variables are equal, and we do get them as such:
>> eql
eql =
1