Good morning,
I have a doubt about a loop. I think it's real simple but I don't get how to do it. I'm going to try to simplify the question.
x= [... ; 106; 112; 111]
param= [1.2 ; 1.5; 1.7]
What I need to do is the following. Create three new values, by doing this:
1st loop:
> y(k) = a1*x(k-1) - a2*x(k-2) - a3*x(k-3)
> y(k) = (1.2*111)+(1.5*112)+( 1.7*106) =
> y(K) = 481, 4 result of the new value
2nd loop:
x= [... ; 106; 112; 111; 481,4] % this is the new added value to the vector:
y(k) = a1*x(k-1) - a2*x(k-2) - a3*x(k-3)
y(k) = (1.2*481,4)+(1.5 *111)+( 1.7*112) =
y(K) = result of the 2 new value
The routine consists in using always the param values 'by order' and multiply the x vector using penultimate value, then the antepenultimate and the following. I don't know how to manage it because it has to create three new times.
Any advice would be appreciated! :) Thanks in advance
You can use only y (or x) no need for both, as you just add all y in the end of x. Here is a simple solution for adding another N values:
N = 103;
y = zeros(N,1);
y(1:3) = [106 112 111]; % this is the end of your x
param = [1.2 ; 1.5; 1.7];
for k = 4:N
y(k) = (param(1).*y(k-1))+(param(2).*y(k-2))+(param(3).*y(k-3));
end
Related
To compute the mean of every bins along a dimension of a nd array in matlab, for example, average every 10 elements along dim 4 of a 4d array
x = reshape(1:30*30*20*300,30,30,20,300);
n = 10;
m = size(x,4)/10;
y = nan(30,30,20,m);
for ii = 1 : m
y(:,:,:,ii) = mean(x(:,:,:,(1:n)+(ii-1)*n),4);
end
It looks a bit silly. I think there must be better ways to average the bins?
Besides, is it possible to make the script applicable to general cases, namely, arbitray ndims of array and along an arbitray dim to average?
For the second part of your question you can use this:
x = reshape(1:30*30*20*300,30,30,20,300);
dim = 4;
n = 10;
m = size(x,dim)/10;
y = nan(30,30,20,m);
idx1 = repmat({':'},1,ndims(x));
idx2 = repmat({':'},1,ndims(x));
for ii = 1 : m
idx1{dim} = ii;
idx2{dim} = (1:n)+(ii-1)*n;
y(idx1{:}) = mean(x(idx2{:}),dim);
end
For the first part of the question here is an alternative using cumsum and diff, but it may not be better then the loop solution:
function y = slicedmean(x,slice_size,dim)
s = cumsum(x,dim);
idx1 = repmat({':'},1,ndims(x));
idx2 = repmat({':'},1,ndims(x));
idx1{dim} = slice_size;
idx2{dim} = slice_size:slice_size:size(x,dim);
y = cat(dim,s(idx1{:}),diff(s(idx2{:}),[],dim))/slice_size;
end
Here is a generic solution, using the accumarray function. I haven't tested how fast it is. There might be some room for improvement though.
Basically, accumarray groups the value in x following a matrix of customized index for your question
x = reshape(1:30*30*20*300,30,30,20,300);
s = size(x);
% parameters for averaging
dimAv = 4;
n = 10;
% get linear index
ix = (1:numel(x))';
% transform them to a matrix of index per dimension
% this is a customized version of ind2sub
pcum = [1 cumprod(s(1:end-1))];
sub = zeros(numel(ix),numel(s));
for i = numel(s):-1:1,
ixtmp = rem(ix-1, pcum(i)) + 1;
sub(:,i) = (ix - ixtmp)/pcum(i) + 1;
ix = ixtmp;
end
% correct index for the given dimension
sub(:,dimAv) = floor((sub(:,dimAv)-1)/n)+1;
% run the accumarray to compute the average
sout = s;
sout(dimAv) = ceil(sout(dimAv)/n);
y = accumarray(sub,x(:), sout, #mean);
If you need a faster and memory efficient operation, you'll have to write your own mex function. It shouldn't be so difficult, I think !
As you probably guessed from the title, I'm attempting to do tridiagonal GaussJordan elimination. I'm trying to do it without the default solver. My answers aren't coming out correct and I need some assistance as to where the error is in my code.
I'm getting different values for A/b and x, using the code I have.
n = 4;
#Range for diagonals
ranged = [15 20];
rangesd = [1 5];
#Vectors for tridiagonal matrix
supd = randi(rangesd,[1,n-1]);
d = randi(ranged,[1,n]);
subd = randi(rangesd,[1,n-1]);
#Creates system Ax+b
A = diag(supd,1) + diag(d,0) + diag(subd,-1)
b = randi(10,[1,n])
#Uses default solver
y = A/b
function x = naive_gauss(A,b);
#Forward elimination
for k=1:n-1
for i=k+1:n
xmult = A(i,k)/A(k,k);
for j=k+1:n
A(i,j) = A(i,j)-xmult*A(k,j);
end
b(i) = b(i)-xmult*b(k);
end
end
#Backwards elimination
x(n) = b(n)/A(n,n);
for i=n-1:-1:1
sum = b(i);
for j=i+1:n
sum = sum-A(i,j)*x(j);
end
x(i) = sum/A(i,i)
end
end
x
Your algorithm is correct. The value of y that you compare against is wrong.
you have y=A/b, but the correct syntax to get the solution of the system should be y=A\b.
I can't seem to find a fix to my infinite loop. I have coded a Jacobi solver to solve a system of linear equations.
Here is my code:
function [x, i] = Jacobi(A, b, x0, TOL)
[m n] = size(A);
i = 0;
x = [0;0;0];
while (true)
i =1;
for r=1:m
sum = 0;
for c=1:n
if r~=c
sum = sum + A(r,c)*x(c);
else
x(r) = (-sum + b(r))/A(r,c);
end
x(r) = (-sum + b(r))/A(r,c);
xxx end xxx
end
if abs(norm(x) - norm(x0)) < TOL;
break
end
x0 = x;
i = i + 1;
end
When I terminate the code it ends at the line with xxx
The reason why your code isn't working is due to the logic of your if statements inside your for loops. Specifically, you need to accumulate all values for a particular row that don't belong to the diagonal of that row first. Once that's done, you then perform the division. You also need to make sure that you're dividing by the diagonal coefficient of A for that row you're concentrating on, which corresponds to the component of x you're trying to solve for. You also need to remove the i=1 statement at the beginning of your loop. You're resetting i each time.
In other words:
function [x, i] = Jacobi(A, b, x0, TOL)
[m n] = size(A);
i = 0;
x = [0;0;0];
while (true)
for r=1:m
sum = 0;
for c=1:n
if r==c %// NEW
continue;
end
sum = sum + A(r,c)*x(c); %// NEW
end
x(r) = (-sum + b(r))/A(r,r); %// CHANGE
end
if abs(norm(x) - norm(x0)) < TOL;
break
end
x0 = x;
i = i + 1;
end
Example use:
A = [6 1 1; 1 5 3; 0 2 4]
b = [1 2 3].';
[x,i] = Jacobi(A, b, [0;0;0], 1e-10)
x =
0.048780487792648
-0.085365853612062
0.792682926806031
i =
20
This means it took 20 iterations to achieve a solution with tolerance 1e-10. Compare this with MATLAB's built-in inverse:
x2 = A \ b
x2 =
0.048780487804878
-0.085365853658537
0.792682926829268
As you can see, I specified a tolerance of 1e-10, which means we are guaranteed to have 10 decimal places of accuracy. We can certainly see 10 decimal places of accuracy between what Jacobi gives us with what MATLAB gives us built-in.
There is a two-dimensional random walk that one can find here which works perfectly in Octave. However, when I tried to write a one-dimensional random walk program, I got an error. Here is the program:
t=[];
x=[];
for i=1:100000
J=rand;
if J<0.5
x(i+1)=x(i)+1;
t(i+1)=t(i)+1;
else
x(i+1)=x(i)-1;
t(i+1)=t(i)+1;
end
end
plot(t,x)
Here is the error:
error: A(I): index out of bounds; value 1 out of bound 0
Thank you.
No need for a loop:
N = 100000;
t = 1:N;
x = cumsum(2*(rand(1,N)<.5)-1);
plot(t,x)
For the 2D case you could use the same approach:
N = 100000;
%// t = 1:N; it won't be used in the plot, so not needed
x = cumsum(2*(rand(1,N)<.5)-1);
y = cumsum(2*(rand(1,N)<.5)-1);
plot(x,y)
axis square
You get an error because you ask MATLAB to use x(1) in the first iteration when you actually defined x to be of length 0. So you need to either initialize x and t with the proper size:
x=zeros(1,100001);
t=zeros(1,100001);
or change your loop to add the new values at the end of the vectors:
x(i+1)=[x(i) x(i)+1];
Since t and x are empty, therefore, you cannot index them through x(i+1) and x(i).
I believe you should intialize x and t with all zeros.
In the first iteration, i = 1, you have x(2) = x(1) +or- 1 while x has dimension of zero. You should define the starting point for x and t, which is usually the origin, you can also change the code a little bit,
x = 0;
N = 100000;
t = 0 : N;
for i = 1 : N
x(i+1) = x(i) + 2 * round(rand) - 1;
end
plot(t,x)
Not sure what I am doing wrong here;
I am trying to make a for loop with conditional statements for the following functions. I want to make it though so h is not a vector. I am doing this for 1 through 5 with increment 0.1.
Y = f(h) = h^2 if h <= 2 or h >= 3
Y = f(h) = 45 otherwise
my code is
for h = 0:0.1:5
if h <= 2;
Y = h^2;
elseif h >= 3;
Y = h^2;
else;
h = 45;
end
end
This could be done easier, but with a for loop i think you could use:
h=0:0.1:5;
y=zeros(1,length(h));
for i=1:length(h)
if or(h(i) <= 2, h(i) >= 3)
y(i) = h(i)^2;
else
y(i) = 45;
end
end
Why do you want to avoid making h an array? MATLAB specializes in operations on arrays. In fact, vectorized operations in MATLAB are generally faster than for loops, which I found counter-intuitive having started coding in C++.
An example of a vectorized verison of your code could be:
h = 0:0.1:5;
inds = find(h > 2 & h < 3); % grab indices where Y = 45
Y = h.^2; % set all of Y = h^2
Y(inds) = 45; % set only those entries for h between 2 and 3 to 45
The period in the .^2 operator broadcasts that operator to every element in the h array. This means that you end up squaring each number in h individually. In general, vectorized operation like this are more efficient in MATLAB, so it is probably best to get in the habit of vectorizing your code.
Finally, you could reduce the above code a bit by not storing your indices:
h = 0:0.1:5;
Y = h.^2; % set all of Y = h^2
Y(find(h > 2 & h < 3)) = 45; % set only those entries for h between 2 and 3 to 45
This blog series seems to be a good primer on vectorizing your MATLAB code.