Let's say I have a vector v with elements 1...n, and I know that v(1) = v_0, and then
v(i+1) = 1/(a*v(i) + b).
This is straightforward to implement using either a single for loop, or recursion. Recursion is a terrible idea in Matlab, and the single foor loop is still not optimal if possible. Can I vectorize such a operation?
And to make this post more useful, is there a general way to vectorize
v(i+1) = f(v(i)),
where f(x) is an arbitrary function? What about something like
v(i+1) = a(i)*v(i) + b(i)
where a, and b are now vectors.
A for loop is not as bad in MATLAB as it used to be, due to just-in-time compilation. When in doubt, just write the loop and continue with your work. Unless your vectors are gigantic, the loop won't bother you in the slightest. If (and only if) the loop is a bottleneck, go back and try silly MATLAB tricks to optimize.
In a specific answer to your question, no, I do not believe there's a generic way to express v(i+1) = f(v(i)). You could easily write one using a function handle, but the performance would be something less than just open-coding the expression.
Related
I want to decompose a part like this, into an array of x rows and y columns, and then do the operations. Mainly use the loop statement (for). Do you guys have a similar example? thank you all very much.
just be like:
equation
for i in 1:n-1 loop
for j in 1:m-1 loop
//equations
T[i+1,j] = T[i,j]+something+...;
T[i,j+1] = ...;
end for;
end for;
The best example I could find is the following: Modelica.Electrical.Analog.Basic.M_Transformer, although the loop is "only" in the initial equation section.
What is more common, is to use loops in connect statements, like in Modelica.Electrical.Batteries.BaseClasses.BaseStackWithSensors. But that will likely not be a good fit for your task.
Some general advise:
A good read to start with the topic is: https://mbe.modelica.university/behavior/arrays/looping/
For complex for/if-statements it is often simpler to formulate them in an algorithm section. Those can be placed in a function and "ease" some of the pretty strict requirements of the equation section, like allowing a multiple assignments for a single variable. It will be more like a coding in a procedural programming language.
If you prefer to write the statements in the equation section (which can make sense performance-wise) you need to make sure, that every unknown needs exactly one equation to compute it.
My task now is want to construct a cell C which contain matrices which first dimensions are contained in a vector
n = [12 23 54].
While their second dimensions are fixed with
r = 3.
So, I want the cell C = {rand(12,3), rand(23,3), rand(54,3)}.
I know for-loop can serve my purpose as:
C=cell(3,1) % pre-allocation
for i = 1 : length(n)
C{i} = rand(n(i),r);
end
May I know if I can do it smarter without using a for loop in Matlab? Thank you
There's really no harm in using a for loop in this particular scenario (and in most cases where the only alternative is cellfun or arrayfun) as it is easier for MATLAB's JIT compiler to handle, but if you're really averse to a for loop you can use arrayfun combined within non-uniform output to give you the result you want.
C = arrayfun(#(x)rand(x, r), n, 'UniformOutput', false);
This may actually be slower than the for loop for the reasons mentioned above. But hey, it's one line so that's all that matters!
for and while loops have their place, even in Matlab. You've probably been told to avoid them because vectorized operations are so much faster when you're iterating over the rows, columns or other dimensions of a packed numeric array. But with higher-level constructs, like cell arrays, there's often no advantage (and a readability penalty) to trying to do things all in neat quasi-vectorized statements. Your existing solution is probably the best approach.
A shorter alternative, just for fun:
C = mat2cell(rand(sum(n),r), n,r)';
But a plain loop is almost certainly fastest in this case, because mat2cell uses a loop, as well as copious checks on its inputs.
Last week I asked the following:
https://stackoverflow.com/questions/32658199/vectorizing-gibbs-sampler-in-matlab
Perhaps it was not that clear what I want to do, so this might be more clear.
I would like to vectorize a "for" loop in matlab, where some variables inside of the loop are bidirectionally related. So, here is an example:
A=2;
B=3;
for i=1:10000
A=3*B;
B=exp(A*(-1/2))
end
Thank you once again for your time.
A quick Excel calculation indicates that this quickly converges to 0.483908 (after much less than 10000 loops - so one way of speeding it up would be to check for convergence). If A and B are always 2 and 3 respectively, you could just replace the loop with this value.
Alternatively, using some series analysis you might be able to come up with an analytical expression for B when i is large - although with the nested exponents deriving this is a bit beyond my own abilities!
Edit
A bit of googling reveals this. Wikipedia states that for a tetration of x to infinity (i.e. x^x^x^x^x...), the solution y satisfies y = x^y. In your case, for example, 0.483908 = e^(-3/2)^0.483908, so 0.483908 is a solution. Not sure how you would exploit this though.
Wikipedia also gives a convergence condition, which might be of use to you: x lies between e^-e and e^1/e.
Final Edit (?)
Turns out you need Lambert's W function to solve for equations of the form of y = x^y. There seems to be no native function for this, but there seems to be something in the FileExchange - see here and here.
I am trying to use parallel computing with GPU in Matlab, and I would like to apply a function to a large array (to avoid the use of a for loop, which is quite slow). I have read Matlab's documentation, and I can use arrayfun, but only if I want to do elementwise operations. Maybe I am confused, but I would appreciate if someone can help me to use it. As an example of what I want to do, imagine that I would like to perform the following operation,
$X_t = B Z_t + Q\varepsilon_t$
where $X_t$ is 2x1, $B$ is 2x5, and $Z_t$ is 5x1, with $Q$ 2x2. I define a function,
function X = propose(Z,B,Q)
X=Z*B+Q*rand(2,1);
end
Now, suppose that I have an array $Z_p$ which is 5x1000. To each of the 1000 columns I would like to apply the previous function, for given matrices $B$ and $Q$, to get an array $X_p$ which is 2x1000.
Given the documentation for arrayfun I can not do this,
X=arrayfun(#propose,Zp,B,Q)
So, is there any possibility to do it?
Thanks!
PS: Yes, I know that in this simple example I can just do the multiplication without a for loop, but the application I have in mind is more complicated and I cannot do it. I just put this example as an illustration.
I've got an ODE system working perfectly. But now, I want in each iteration, sort in ascending order the solution vector. I've tried many ways but I could not do it. Does anyone know how to do?
Here is a simplified code:
function dtemp = tanque1(t,temp)
for i=1:N
if i==1
dtemp(i)=(((-k(i)*At*(temp(i)-temp(i+1)))/(y))-(U*As(i)*(temp(i)-Tamb)))/(ro(i)*vol_nodo*cp(i));
end
if i>1 && i<N
dtemp(i)=(((k(i)*At*(temp(i-1)-temp(i)))/(y))-((k(i)*At*(temp(i)-temp(i+1)))/(y))-(U*As(i)*(temp(i)-Tamb)))/(ro(i)*vol_nodo*cp(i));
end
if i==N
dtemp(i)=(((k(i)*At*(temp(i-1)-temp(i)))/(y))-(U*As(i)*(temp(i)-Tamb)))/(ro(i)*vol_nodo*cp(i));
end
end
end
Test Script:
inicial=343.15*ones(200,1);
[t temp]=ode45(#tanque1,0:360:18000,inicial);
It looks like you have three different sets of differential equations depending on the index i of the solution vector. I don't think you mean "sort," but rather a more efficient way to implement what you've already done - basically vectorization. Provided I haven't accidentally made any typos (you should check), the following should do what you need:
function dtemp = tanque1(t,temp)
dtemp(1) = (-k(1)*At*(temp(1)-temp(2))/y-U*As(1)*(temp(1)-Tamb))/(ro(1)*vol_nodo*cp(1));
dtemp(2:N-1) = (k(2:N-1).*(diff(temp(1:N-1))-diff(temp(2:N)))*At/y-U*As(2:N-1).*(temp(2:N-1)-Tamb))./(vol_nodo*ro(2:N-1).*cp(2:N-1));
dtemp(N) = (k(N)*At*(temp(N-1)-temp(N))/y-U*As(N)*(temp(N)-Tamb))/(ro(N)*vol_nodo*cp(N));
You'll still need to define N and the other parameters and ensure that temp is returned as a column vector. You could also try replacing N with the end keyword, which might be faster. The two uses of diff make the code shorter, but, depending on the value of N, they may also speed up the calculation. They could be replaced with temp(1:N-2)-temp(2:N-1) and temp(2:N-1)-temp(3:N). It may be possible to collapse these down to a single vectorized equation, but I'll leave that as an exercise for you to attempt if you like.
Note that I also removed a great many unnecessary parentheses for clarity. As you learn Matlab you'll to get used to the order of operations and figure out when parentheses are needed.