Variables are continuously zero while creating matrice with for loop - matlab

Here is my code;
%Blasius solution by Euler Method
%---------------
g0=zeros(101,1);
g1=zeros(101,1);
g2=zeros(101,1);
%---------------
g0(1)=0;
g1(1)=0;
% g1(101)=1;
g2(1)=2;
%---------------
G=zeros(101,3);
T=zeros(101,3);
G=[g0 g1 g2];
T=[g1 g2 (-1)*g0.*g2];
%Euler method%
for i=1:100
G(i+1) = G(i) + (T(i)*0.1);
end
What am I missing? I am trying to create the G matrix but it is always a 101*3 zero matrix. It looks like for loop doesn't work but I couldn't figure out why.

I figured out why your code is not working:
First of all you need to call row indices, not linear indices, i.e. change your loop to:
for ii=1:100
G(ii+1,:) = G(ii,:) + (T(ii,:)*0.1);
end
note that I also used ii as opposed to i, since using that as a variable is bad.
This results in T remaining constant, obviously, since you do not change it. You initialise it as a zero array and set only the second element on the first row to 2, but leave the rest as zeros. Adding a row of T to a row of G will therefore not do anything, since you are adding zeros to an existing row. This is why the second row of G becomes [0 0.2 2] and does not change anymore , since you are only adding zeros to it.
You probably forgot to add the line of code which assigns a new value to rows of T. Adhering to your suggestion in the comments:
for ii=1:100
G(ii+1,:) = G(ii,:) + (T(ii,:)*0.1);
T(ii+1,:) = G(ii,:);
end

Here is the new solution, we have spend hours but finally figure it out.
%Blasius solution by Euler Method
%---------------
g0=zeros(101,1);
g1=zeros(101,1);
g2=zeros(101,1);
g2(1)=2;
%---------------
G=zeros(101,3);
T=zeros(101,3);
G=[g0 g1 g2];
T=[g1 g2 ((-1)*g0.*g2)];
%Euler method%
for i=1:100
A=[g0(i) g1(i) g2(i)] ;
B=[g1(i)*0.1 g2(i)*0.1 (-1).*g0(i)*g2(i)*0.1];
C(i,:)=A+B;
g0(i+1)=C(i,1);
g1(i+1) =C(i,2);
g2(i+1) =C(i,3);
end

Related

Make vector of elements less than each element of another vector

I have a vector, v, of N positive integers whose values I do not know ahead of time. I would like to construct another vector, a, where the values in this new vector are determined by the values in v according to the following rules:
- The elements in a are all integers up to and including the value of each element in v
- 0 entries are included only once, but positive integers appear twice in a row
For example, if v is [1,0,2] then a should be: [0,1,1,0,0,1,1,2,2].
Is there a way to do this without just doing a for-loop with lots of if statements?
I've written the code in loop format but would like a vectorized function to handle it.
The classical version of your problem is to create a vector a with the concatenation of 1:n(i) where n(i) is the ith entry in a vector b, e.g.
b = [1,4,2];
gives a vector a
a = [1,1,2,3,4,1,2];
This problem is solved using cumsum on a vector ones(1,sum(b)) but resetting the sum at the points 1+cumsum(b(1:end-1)) corresponding to where the next sequence starts.
To solve your specific problem, we can do something similar. As you need two entries per step, we use a vector 0.5 * ones(1,sum(b*2+1)) together with floor. As you in addition only want the entry 0 to occur once, we will just have to start each sequence at 0.5 instead of at 0 (which would yield floor([0,0.5,...]) = [0,0,...]).
So in total we have something like
% construct the list of 0.5s
a = 0.5*ones(1,sum(b*2+1))
% Reset the sum where a new sequence should start
a(cumsum(b(1:end-1)*2+1)+1) =a(cumsum(b(1:end-1)*2+1)+1)*2 -(b(1:end-1)+1)
% Cumulate it and find the floor
a = floor(cumsum(a))
Note that all operations here are vectorised!
Benchmark:
You can do a benchmark using the following code
function SO()
b =randi([0,100],[1,1000]);
t1 = timeit(#() Nicky(b));
t2 = timeit(#() Recursive(b));
t3 = timeit(#() oneliner(b));
if all(Nicky(b) == Recursive(b)) && all(Recursive(b) == oneliner(b))
disp("All methods give the same result")
else
disp("Something wrong!")
end
disp("Vectorised time: "+t1+"s")
disp("Recursive time: "+t2+"s")
disp("One-Liner time: "+t3+"s")
end
function [a] = Nicky(b)
a = 0.5*ones(1,sum(b*2+1));
a(cumsum(b(1:end-1)*2+1)+1) =a(cumsum(b(1:end-1)*2+1)+1)*2 -(b(1:end-1)+1);
a = floor(cumsum(a));
end
function out=Recursive(arr)
out=myfun(arr);
function local_out=myfun(arr)
if isscalar(arr)
if arr
local_out=sort([0,1:arr,1:arr]); % this is faster
else
local_out=0;
end
else
local_out=[myfun(arr(1:end-1)),myfun(arr(end))];
end
end
end
function b = oneliner(a)
b = cell2mat(arrayfun(#(x)sort([0,1:x,1:x]),a,'UniformOutput',false));
end
Which gives me
All methods give the same result
Vectorised time: 0.00083574s
Recursive time: 0.0074404s
One-Liner time: 0.0099933s
So the vectorised one is indeed the fastest, by a factor approximately 10.
This can be done with a one-liner using eval:
a = eval(['[' sprintf('sort([0 1:%i 1:%i]) ',[v(:) v(:)]') ']']);
Here is another solution that does not use eval. Not sure what is intended by "vectorized function" but the following code is compact and can be easily made into a function:
a = [];
for i = 1:numel(v)
a = [a sort([0 1:v(i) 1:v(i)])];
end
Is there a way to do this without just doing a for loop with lots of if statements?
Sure. How about recursion? Of course, there is no guarantee that Matlab has tail call optimization.
For example, in a file named filename.m
function out=filename(arr)
out=myfun(in);
function local_out=myfun(arr)
if isscalar(arr)
if arr
local_out=sort([0,1:arr,1:arr]); % this is faster
else
local_out=0;
end
else
local_out=[myfun(arr(1:end-1)),myfun(arr(end))];
end
end
end
in cmd, type
input=[1,0,2];
filename(input);
You can take off the parent function. I added it just hoping Matlab can spot the recursion within filename.m and optimize for it.
would like a vectorized function to handle it.
Sure. Although I don't see the point of vectorizing in such a unique puzzle that is not generalizable to other applications. I also don't foresee a performance boost.
For example, assuming input is 1-by-N. In cmd, type
input=[1,0,2];
cell2mat(arrayfun(#(x)sort([0,1:x,1:x]),input,'UniformOutput',false)
Benchmark
In R2018a
>> clear all
>> in=randi([0,100],[1,100]); N=10000;
>> T=zeros(N,1);tic; for i=1:N; filename(in) ;T(i)=toc;end; mean(T),
ans =
1.5647
>> T=zeros(N,1);tic; for i=1:N; cell2mat(arrayfun(#(x)sort([0,1:x,1:x]),in,'UniformOutput',false)); T(i)=toc;end; mean(T),
ans =
3.8699
Ofc, I tested with a few more different inputs. The 'vectorized' method is always about twice as long.
Conclusion: Recursion is faster.

Implementing forward Euler method in matlab

I'm trying to implement the forward Euler method using matlab, but don't understand the error I'm getting. This is what I have written:
function y = ForwardEulerMethod(f,y0,T,N)
h=T/N;
t=zeros(N+1,1);
for i=0:N
t(i)=i.*h; %line 5
end
y=zeros(N+1,1);
y(0)=y0;
for i=1:N
y(i)=y(i-1)+h.*f(t(i-1),y(i-1));
end
end
My error is with line 5 and says, "Subscript indices must either be real positive integers or logicals." I am familiar with this rule, but don't see how I'm breaking it. I'm just trying to replace a zero at each location in t with a numerical value. What am I missing?
Agree with #vijoc above. You are indexing with 0 at multiple places. You could either change how you are indexing the values or get rid of the for loop altogether, like below:
function y = ForwardEulerMethod(f,y0,T,N)
h=T/N;
t=0:N .* h; % this takes the place of the first for-loop
y=zeros(N+1,1);
y(1)=y0;
for i=2:N+1
y(i)=y(i-1)+h.*f(t(i-1),y(i-1));
end
end
You could even replace the second loop if the function f takes vector inputs like so:
y(1) = y0;
y(2:end) = y(1:end-1) + h .* f(t(1:end-1), y(1:end-1));
You're iterating over i = 0:N and using it as t(i)=i.*h, so you're trying to access t(0) during the first iteration. Matlab indexing starts from 1, hence the error.
You also have other lines which will cause the same error, once the execution gets that far.

Matlab: make a matrix by looping through an index without using a For loop?

I have a function A(k) which returns a matrix dependent on k when I type for example A(1). I want to automatically create the matrix:
[A(3)*A(2)*A(1) A(3)*A(2) A(3)]
In Mathematica I can do for example:
Table[Apply[Dot,Table[A(k),{k,3,i,-1}]],{i,1,3}]
Assume A(k) is a function which returns a 3x3 matrix. For example typing A(1) may return:
[1,2,3;4,5,6;7,8,9]
Explanation of Mathematica code: Table[A(k),{k,3,i,-1}] is a "loop" from k=3 to k=i with each iteration decrementing k by -1. Therefore the output would be a list {A(3),A(2),...,A(i)}... obviously k starting from 3 then for i=2 the output list will be {A(3),A(2)}. The function Apply[Dot,Table[A(k),{k,3,i,-1}]] multiplied the elements of the list together. For i=2 this produces A(3)*A(2). Finally, Table[Apply[Dot,Table[A(k),{k,3,i,-1}]],{i,1,3}] applies the same logic as the first statement, looping i from 1 to 3. Because the inner table depends on i, this creates a list of elements {A(3)*A(2)*A(1),A(3)*A(2),A(3)}. A list is Mathematica's version of a matrix.
How can I achieve the same effect in MATLAB, i.e. not use a for loop to achieve the result? Thanks!
For the record, here's a looping version, mostly for subsequent timing checks. This is not the answer you want, but the answer you need;)
N = 10; %size of A
old = eye(N);
M2 = [];
for i=3:-1:1
new = old*A(i);
M2 = [new M2];
old = new;
end
Or if you want to be really efficient (which is probably not the case):
N = 10; %size of A
M2 = A(3);
old = M2;
for i=2:-1:1
new = old*A(i);
M2 = [new M2];
old = new;
end
This answer basically is the solution to the problem, but as we are discussing efficient use of matlab I want to leave my thoughts here how to use Matlab efficient. Instead of the large 2D-Matrix it is much simpler to create a 3D-Matrix where the results of each multiplication are stacked. If a 3D-Matrix is acceptable use the code as it is, otherwise comment in the last line to get a 2D-matrix.
M3=[];
n=3;
M3(:,:,n) = A(n);
for ix=n-1:-1:1
M3(:,:,ix) = M3(:,:,ix+1)*A(i);
end
%M3=reshape(M3,size(M3,1),[]);
You can use arrayfun() with indexes as parameters, eg:
%// Compute the product A(3)*A(2)*...*A(idx)
F = #(idx) prod(reshape(cell2mat(arrayfun(A,3:-1:idx, 'UniformOutput', false)),10,10,4-idx),3);
%// Use the last function with idx=1:3
M = cell2mat(arrayfun(F,1:3, 'UniformOutput', false));

Subscript indices must either be real positive integers or logicals error within Matlab decay program

I am having issues with a code of mine dealing with decay. The error "Subscript indices must either be real positive integers or logicals" continues to occur no matter how many times I attempt to fix the line of code: M=M(t)+h.*F
Here is the complete code so that it may be easier to solve the issue:
M=10000;
M=#(t) M*exp(-4.5*t);
F=-4.5*M(t);
h=.1;
t(1)=0;
tmax=20;
n=(tmax-t(1))/h;
i=1;
while h<=.5
while i<=n
t=t+h;
M=M(t)+h.*F;
data_out=[t,M];
dlmwrite('single_decay_euler_h.txt',data_out,'delimiter','\t','-append');
i=i+1;
end
h=h+.1;
end
Thanks for any help.
In the start, you're setting M = 5000;. In the following line, you're creating an anonymous function also called M:
M=#(t) M*exp(-4.5*t);
Now, your initial M = 5000 variable has been overwritten, and is substituted by the function:
M(t) = 5000 * exp(-4.5*t); %// Note that the first M is used to get 5000
Thereafter you do F = -4.5*M(t). I don't know what the value t is here, but you're giving F the value -4.5 * 5000 * exp(-4.5*t), for some value of t. You are not creating a function F.
In the first iteration of the loop, M=M(t)+h.*F; is interpreted as:
M = 5000 * exp(-4.5*0) + 0.1*F %// Where F has some value determined by previous
%// the function above and the previous value of t
%// -4.5*0 is because t = 0
M is now no longer a function, but a single scalar value. The next iteration t = 0.1. When you do: M=M(t)+h.*F; now, it interprets both the first and second M as a variable, not a function. t is therefore used as an index, instead of being an input parameter to the function M (since you have overwritten it).
When you are writing M(t), you are trying to access the 0.1'th element of the 1x1 matrix (scalar) M, which obviously isn't possible.
Additional notes:
The outer while loop has no purpose as it stands now, since i isn't reset after the inner loop. When you're finished with the first iteration of the outer loop, i is already >n, so it will never enter the inner loop again.
You shouldn't mix variable and function names (as you do with M. Use different names, always. Unless you have a very good reason not to.
data_out=[t,M]; is a growing vector inside a loop. This is considered very bad practice, ans is very slow. It's better to pre-allocate memory for the vector, for instance using data_out = zeros(k,1), and insert new values using indexes, data_out(ii) = M.
It's recommended not to use i and j as variable names in MATLAB as these also represent the imaginary unit sqrt(-1). This might cause some strange bugs if you're not paying attention to it.
You can almost certainly do what you're trying to do without loops. However, the function you have written is not functioning, and it's not explained all too well what you're trying to do, so it's hard to give advice as to how you can get what you want (but I'll give it a try). I'm skipping the dlmwrite-part, because I don't really understand what you want to output.
M = 5000;
t0 = 0;
tmax = 20;
h = 0.1; %// I prefer leading zeros in decimal numbers
t = t0: h: tmax;
data_out = M .* exp(-4.5 * t);
The problem is caused by M(t) in your code, because t is not an integer or logical (t=1,1.1,1.2,...)
You need to change your code to pass an integer as a subscript. Either multiply t by 10, or don't use the matrix M if you don't need it.

Finding eigenvalues in a loop matlab

Ok this is how it's supposed to work. In the while loop eigenvalues are calculated for the increments of U in the variable lambda. The idea is to break the while loop once a real part of a variable lambda becomes positive and return the value of U for which this happens. I was trying to use a for loop to do it for a number of k1 values so that in the end I have a vector where in one column I have my k1 values and in the next column values of U for which lambda becomes positive. Hope you get the idea. The problem is that something doesn't seem to be working here and I really can't figure out what. Thanks for help
rho=1.225;
b=0.2;
m=5;
I_cg=0.05;
k1=2000;
k2=1000;
c1=10;
k_theta=2000;
c_theta=2;
c=2*b;
s=1;
x2=0.1;
xg=0.04;
M=[m -m*xg;-m*xg (m*(xg^2)+I_cg)];
kRoof = 60;
for kIndex = 0:kRoof
kStart = 2000;
k1 = kStart * kIndex;
U=0.1;
lambda=-1;
while (real(lambda)<0)
i=1;
U(i)=U+i;
q=0.5*rho*U(i)^2;
B=[((2*pi*q*s*c)/U(i))+c1 (pi*q*s*c)/(5*U(i));-pi*q*s*(c^2)/(2*U(i)) c_theta];
C=[k1+k2 -k2*x2+(2*pi*q*s*c);-k2*x2 (k2*(x2^2)+(k_theta)-(pi*q*s*(c^2)/2))];
A=[M B;zeros(2) M];
D=[zeros(2) C;-M zeros(2)];
lambda=eig(D,-A);
i=i+1
U=U+i
if imag(lambda)==0
disp(lambda)
end
end
end