assigning multiple structures to an array of structures in matlab - arrays

I have a function newPartical that randomizes a structure:
function partical = newPartical(b)
partical.a = rand;
partical.b = b;
end
I want to make an array of structures, and I want each structure in the array to be randomized. can I do this without a for loop?

You may use iterative functions like arrayfun and cellfun. These take a function itself as input (via a function handle) and a range of values for each input of the passed function. The output is an array or cell array, where each entry is a single result of the function.
particleHandle = #particle;
c = arrayfun ( particleHandle , 1:100 );
In this case, c is a 1x100 struct array with fields: a b
Sample results I obtained include:
c(1).a = 0.5496
c(1).b = 1
c(2).a = 0.9575
c(2).b = 2
c(3).a = 0.9649
c(3).b = 3
Depending on what you are doing, this may or may not provide significant improvements in speed. For instance, running these two operations:
timeStartArrayFun = tic;
c = arrayfun ( particleHandle , 1:1000 );
timeStopArrayFun = toc ( timeStart );
timeStartFor = tic;
for ( ii = 1 : 1000 )
d ( ii ) = particle ( ii );
end
timeStopFor = toc ( timeStartFor );
The results are timeStartArrayFun == 0.0201 and timeStartFor == 0.2090. You obtain an ~10X speed increase...not bad at all.

Related

Index Subset of Array in For Loop in MATLAB

I have a question regarding indexing and loops in MATLAB. I have a vector of length n (named data in the code below). I want to examine this vector 4 elements at a time inside of a for loop. How can I do this? My attempt included below does not work because it will exceed the array dimensions at the end of the loop.
for k = 1:length(data)
index = k:k+3;
cur_data = data(index);
pre_q_data1 = cur_data(1);
pre_q_data2 = cur_data(2);
% Interweaving the data
q = [pre_q_data1; pre_q_data2];
qdata = q(:)';
pre_i_data1 = cur_data(3);
pre_i_data2 = cur_data(4);
i = [pre_i_data1; pre_i_data2];
idata = i(:)';
end
You shouldn't have k go all the way to length(data) if you're planning on indexing up to k+3.
I've also taken the liberty of greatly simplifying your code, but feel free to ignore that!
for k = 1:length(data)-3
% maximum k = length(data)-3, so maximum index = length(data)-3+3=length(data)
index = k:k+3;
cur_data = data(k:k+3);
% Interweaving the data
q = cur_data(1:2); % transpose at end of line here if need be
i = cur_data(3:4); % could just use data(k+2:k+3) and not use cur_data
end

MATLAB : how to solve coupled differential equations dependend on data stored in arrays

I want to solve a system of two ordinary differential equations in MATLAB.
The parameters of the ODEs depend on measured data stored in two arrays, F and T.
When I run the program, I always get the error shown below. I am sure it has something to do with the arrays, because when I use single numbers for F and T (e.g. F = 60; T = 30;) the program works fine.
Subscript indices must either be real positive integers or logicals.
Error in dynamics (line 46)
ddyn(1) = k1*F(t) + v_b(t) - k_1*dyn(1) - v_a(t);
Error in ode23 (line 256)
f(:,2) = feval(odeFcn,t+h*A(1),y+f*hB(:,1),odeArgs{:});
Error in main (line 33)
[t,sol] = ode23(#dynamics , (1:1:3000),[0 0]);
Here is the code I use for the main function and the ODE system:
Main function:
[t,sol] = ode45(#dynamics , (1:1:3000),[0 0]);
ODE system:
function [ddyn] = dynamics(t,dyn)
% constant numbers
k1 = 10^-2; k_1 = 8* 10^-3; k2 = 10^-2; k_2 = 4*10^-3;
V_max_a = 1.6; V_max_b = 3.5;
K_M_a = 1.5*10^-3; K_M_b = 2*10^-3;
K_a_F = 9.4*10^5; K_a_T = 3.9*10; K_b_F = 1.3*10^4; K_b_T = 1.2*10^-10;
r_a_F = 4.3*10^7; r_a_T = 4.2*10^9; r_b_F = 6.9*10^-7; r_b_T = 6.2*10^-9;
%arrays with data e.g.
F = 1:3000;
T = 1:3000;
% program works if I use numbers, e.g.:
%F = 60; T = 30;
ddyn = zeros(2,1);
R_a_F = (K_a_F + r_a_F* F)/(K_a_F + r_a_F);
R_a_T = (K_a_T + r_a_T* T)/(K_a_T + r_a_T);
R_b_F = (K_b_F + r_b_F* F)/(K_b_F + r_b_F);
R_b_T = (K_b_T + r_b_T* T)/(K_b_T + r_b_T);
v_a = (V_max_a*dyn(1))/(K_M_a + dyn(1))*R_a_F .*R_a_T;
v_b = (V_max_b*dyn(2))/(K_M_b + dyn(2))*R_b_F .*R_b_T;
ddyn(1) = k1*F(t) + v_b(t) - k_1*dyn(1) - v_a(t);
ddyn(2) = k2*T(t) + v_a(t) - k_2*dyn(2) - v_b(t);
All of the functions in the Matlab ODE suite, including ode45, assume t to be continuous and use a dynamic time-step to achieve a certain level of accuracy.1 As such, you cannot assume t to be an integer and should never be used as an index as you are doing with F(t). To quote from the documentation:
If tspan contains more than two elements [t0,t1,t2,...,tf], then the solver returns the solution evaluated at the given points. This does not affect the internal steps that the solver uses to traverse from tspan(1) to tspan(end). Thus, the solver does not necessarily step precisely to each point specified in tspan.
Therefore, assuming F and T are continuous functions in time, I'd recommend making a function that performs interpolation in time, more than likely via interp1, and pass that function to your ODE function through parametrization. For example:
tspan = 1:3000;
Ffun = #(t) interp1(tspan,F,t); % Default is linear
[t,sol] = ode45(#(t,dyn) dynamics(t,dyn,Ffun) , tspan , [0 0]);
That's just an example but should, hopefully, be serviceable.
1 In particular, ode45 uses the Dormand-Prince (4,5) Runkge-Kutta pair for its time integration; in short, the function compares a fourth order and fifth order solution to decide if the result from the current time-step is good enough or if it should be reduced.

Find specific union of two arrays with different length in MATLAB

I have a coding problem in Matlab, where I try to find a solution without too many for-loops slowing down the process.
I have an array that looks like:
A = [1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4,4,5]
Another that looks like:
B = [0,1,0,1,1]
In B there's always as many elements as their are unique elements in A and the value corresponds to the unique element in A, in other words:
length(unique(A)) = length(B)
I want to compute a result that tells me the index where B == 0 (C) and B == 1 (D) in A.
C = [1,2,3,9,10,11,12]
D = [4,5,6,7,8,13,14,15,16,17,18]
Here is my approach: first "calculate" Au as unique vector of A. In the next step use B for logical indexing of Au: Au( logical(B) ) - this gets the values to be found in A. Then check which values are member of this group and then get their indices. There may be a simpler approach though.
A = [1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4,4,5]
Au = unique( A );
B = [0,1,0,1,1];
C = find( ismember( A, Au( logical(B) ) ) )
D = find( ismember( A, Au( ~logical(B) ) ) )

Sort array elements by the frequency of its elements

Is it possible in matlab/octave to use the sort function to sort an array based on the relative frequency of their elements?
For example the array
m= [4,4,4,10,10,10,4,4,5]
should result in this array:
[5,10,10,10,4,4,4,4,4]
5 is the less frequent element and is on the top while 4 is the most frequent and it's on bottom.
Should one use the indices provided by histcount?
The following code first calculates how often each element occurs and then uses runLengthDecode to expand the unique elements.
m = [4,4,4,10,10,10,4,4,5];
u_m = unique(m);
elem_count = histc(m,u_m);
[elem_count, idx] = sort(elem_count);
m_sorted = runLengthDecode(elem_count, u_m(idx));
The definition of runLengthDecode is copied from this answer:
For MATLAB R2015a+:
function V = runLengthDecode(runLengths, values)
if nargin<2
values = 1:numel(runLengths);
end
V = repelem(values, runLengths);
end
For versions before R2015a:
function V = runLengthDecode(runLengths, values)
%// Actual computation using column vectors
V = cumsum(accumarray(cumsum([1; runLengths(:)]), 1));
V = V(1:end-1);
%// In case of second argument
if nargin>1
V = reshape(values(V),[],1);
end
%// If original was a row vector, transpose
if size(runLengths,2)>1
V = V.'; %'
end
end
One way would be to use accumarray to find the count of each number (I suspect you can use histcounts(m,max(m))) but then you have to clear all the 0s).
m = [4,4,4,10,10,10,4,4,5];
[~,~,subs]=unique(m);
freq = accumarray(subs,subs,[],#numel);
[~,i2] = sort(freq(subs),'descend');
m(i2)
By combinging my approach with that of m.s. you can get a simpler solution:
m = [4,4,4,10,10,10,4,4,5];
[U,~,i1]=unique(m);
freq= histc(m,U);
[~,i2] = sort(freq(i1),'descend');
m(i2)
You could count the number of repetitions with bsxfun, sort that, and apply that sorting to m:
[~, ind] = sort(sum(bsxfun(#eq,m,m.')));
result = m(ind);

Calling method for every class instance in array (Matlab)

I'm new to Matlab and I was told, that it is faster to use dot operator instead of for loop when performing the same operation on array.
Example:
A = 1:200
A = A .* 10;
Instead of:
A = 1:200
for i = 1:200
A(i) = A(i) * 10;
end
I have created an multi-dimensional array of Objects (the objects are instances of class I created). Is it possible to call the same method with the same arguments on all instances without using the for loop?
I have tried this 3 approaches, but they don't work (A is three-dimensional array):
A(:,:,:).methodName(argument1, argument2);
A.methodName(argument1, argument2);
A..methodName(argument1, argument2);
You should be able to call your method using the 'functional form'
methodName(A, argument1, argument2)
However, 'methodName' will need to handle the fact that you've passed an array of object. Here's a simple example
classdef Eg
properties
X
end
methods
function obj = Eg( arg )
if nargin == 0
% Default-constructor required
arg = [];
end
obj.X = arg;
end
function x = maxX( objs )
% collect all 'X' values:
xVals = [objs.X];
% return the max
x = max( xVals(:) );
end
end
methods ( Static )
function testCase()
% Just a simple test case to show how this is intended to work.
for ii = 10:-1:1
myObjArray(ii) = Eg(ii);
end
disp( maxX( myObjArray ) );
end
end
end
If possible, it's better (in MATLAB) to have fewer objects storing larger arrays, rather than lots of small objects.

Resources