So, I got a strange problem.
Below is my code, it is a simple Euler method for integrating a Linear system of ODE's.
function [V, h, n, b, z] = hodgkin_huxley_CA1(t, Iapp, t_app)
%function based on the CA1 pyramidal neuron model:
h = zeros(length(t));
n = zeros(length(t));
b = zeros(length(t));
z = zeros(length(t));
V = zeros(length(t));
% Initial conditions
h(1) = 0.9771;
n(1) = 0.0259;
b(1) = 0.1787;
z(1) = 8.0222e-04;
V(1) = -71.2856;
% Euler method
delta_t = t(2) - t(1);
for i=1:(length(t)-1)
h(i+1) = h(i) + delta_t*feval(#h_prime,V(i),h(i));
n(i+1) = n(i) + delta_t*feval(#n_prime,V(i),n(i));
b(i+1) = b(i) + delta_t*feval(#b_prime,V(i),b(i));
z(i+1) = z(i) + delta_t*feval(#z_prime,V(i),z(i));
minf = m_inf(V(i));
pinf = p_inf(V(i));
ainf = a_inf(V(i));
if (t(i) >= t_app(1) && t(i) <= t_app(2))
I = Iapp;
else I = 0;
end;
V(i+1) = V(i) + delta_t*feval(#V_prime,V(i),h(i),n(i),b(i),z(i),minf,pinf,ainf,I);
end;
So, this function returns me 5 arrays, V,h,n,b and z. The problem is that if I use V(1), V(2), V(3), ..., I get the expected result. But when I tell matlab to print the whole array, I receive all values as 0.
So, if I plot this array, I will get 2 curves: one that is the right one, and one that is zero.
Note that this also happens to all the other variables h,n,b and z.
Anyone knows what may be happening?
Your outputs are meant to be vectors, however you are initializing them as square matrices.
You can simply replace:
h = zeros(length(t));
n = zeros(length(t));
b = zeros(length(t));
z = zeros(length(t));
V = zeros(length(t));
With
h = zeros(length(t),1);
n = zeros(length(t),1);
b = zeros(length(t),1);
z = zeros(length(t),1);
V = zeros(length(t),1);
The zeros function, with 1 input, creates a 2D square matrix of that dimension. With two or more inputs, it interprets the inputs as specification for all dimensions. For example:
>> x = zeros(3)
x =
0 0 0
0 0 0
0 0 0
>> x = zeros(3,1)
x =
0
0
0
Related
I'm currently forming a matrix from a vector in MATLAB following the scheme described below:
Given is a vector x containing ones and zeros in an arbitrary order, e.g.
x = [0 1 1 0 1];
From this, I would like to form a matrix Y that is described as follows:
Y has m rows, where m is the number of ones in x (here: 3).
Each row of Y is filled with a one at the k-th entry, where k is the position of a one in vector x (here: k = 2,3,5)
For the example x from above, this would result in:
Y = [0 1 0 0 0;
0 0 1 0 0;
0 0 0 0 1]
This is identical to an identity matrix, that has its (x=0)th rows eliminated.
I'm currently achieving this via the following code:
x = [0,1,1,0,1]; %example from above
m = sum(x==1);
Y = zeros(m,numel(x));
p = 1;
for n = 1:numel(x)
if x(n) == 1
Y(p,n) = 1;
p = p+1;
end
end
It works but I'm kind of unhappy with it as it seems rather inefficient and inelegant. Any ideas for a smoother implementation, maybe using some matrix multiplications or so are welcome.
Here are a few one-line alternatives:
Using sparse:
Y = full(sparse(1:nnz(x), find(x), 1));
Similar but with accumarray:
Y = accumarray([(1:nnz(x)).' find(x(:))], 1);
Using eye and indexing. This assumes Y is previously undefined:
Y(:,logical(x)) = eye(nnz(x));
Use find to obtain the indices of ones in x which are also the column subscripts of ones in Y. Find the number of rows of Y by adding all the elements of the vector x. Use these to initialise Y as a zero matrix. Now find the linear indices to place 1s using sub2ind. Use these indices to change the elements of Y to 1.
cols = find(x);
noofones = sum(x);
Y = zeros(noofones, size(x,2));
Y(sub2ind(size(Y), 1:noofones, cols)) = 1;
Here's an alternative using matrix multiplications:
x = [0,1,1,0,1];
I = eye(numel(x));
% construct identity matrix with zero rows
Y = I .* x; % uses implicit expansion from 2016b or later
Y = Y(logical(x), :); % take only non-zero rows of Y
Result:
Y =
0 1 0 0 0
0 0 1 0 0
0 0 0 0 1
Thanks to #SardarUsama's comment for simplifying the code a bit.
Thanks everybody for the nice alternatives! I tried out all your solutions and averaged execution times over 1e4 executions for random (1000-entry) x-vectors. Here are the results:
(7.3e-4 sec) full(sparse(1:nnz(x), find(x), 1));
(7.5e-4 sec) cols = find(x);
noofones = sum(x);
Y = zeros(noofones, size(x,2));
Y(sub2ind(size(Y), 1:noofones, cols)) = 1;
(7.7e-4 sec) Y = accumarray([(1:nnz(x)).' find(x(:))], 1);
(1.7e-3 sec) I = speye(numel(x));
Y = I .* x;
Y = full(Y(logical(x), :));
(3.1e-3 sec) Y(:,logical(x)) = eye(nnz(x));
From your comment "This is identical to an identity matrix, that has its (x=0)th rows eliminated.", well, you can also explicitly generate it as such:
Y = eye(length(x));
Y(x==0, :) = [];
Very slow option for long x, but it works slightly faster than full(sparse(... for x with 10 elements on my computer.
I need to pre-allocate arrays in my code below.
I don't quite understand how to pre-allocate arrays in multi-loop iteration.
a=0:1:2;
b=0:1:2;
c=0:1:2;
xx1=[];yy1=[];zz1=[];xx2=[];yy2=[];zz2=[];
for k=1:length(c)-1;
z1=c(k); z2=c(k+1);
for w=1:length(b)-1;
y1=b(w); y2=b(w+1);
for q=1:length(a)-1;
x1=a(q); x2=a(q+1);
xx1=[xx1;x1]; xx2=[xx2;x2];
yy1=[yy1;y1]; yy2=[yy2;y2];
zz1=[zz1;z1]; zz2=[zz2;z2];
end
end
end
The expected results are:
[xx1 xx2 yy1 yy2 zz1 zz2]
ans =
0 1 0 1 0 1
1 2 0 1 0 1
0 1 1 2 0 1
1 2 1 2 0 1
0 1 0 1 1 2
1 2 0 1 1 2
0 1 1 2 1 2
1 2 1 2 1 2
Increase a counter in the innermost loop to keep track of which entry of xx1 etc you should fill.
a = 0:1:2;
b = 0:1:2;
c = 0:1:2;
xx1 = NaN((length(a)-1)*(length(b)-1)*(length(c)-1),1); %// preallocate
xx2 = NaN((length(a)-1)*(length(b)-1)*(length(c)-1),1);
yy1 = NaN((length(a)-1)*(length(b)-1)*(length(c)-1),1);
yy2 = NaN((length(a)-1)*(length(b)-1)*(length(c)-1),1);
zz1 = NaN((length(a)-1)*(length(b)-1)*(length(c)-1),1);
zz2 = NaN((length(a)-1)*(length(b)-1)*(length(c)-1),1);
n = 0; %// initiallize counter
for k=1:length(c)-1;
z1=c(k); z2=c(k+1);
for w=1:length(b)-1;
y1=b(w); y2=b(w+1);
for q=1:length(a)-1;
n = n + 1; %// increase counter;
x1 = a(q);
x2 = a(q+1);
xx1(n) = x1; %// fill values
xx2(n) = x2;
yy1(n) = y1;
yy2(n) = y2;
zz1(n) = z1;
zz2(n) = z2;
end
end
end
Anyway, it can be done without loops, adapting the procedure given in this answer. This has two advantages:
It may be faster if a, b, c are large.
The same code works for any number of vectors, not just 3. Simply define vectors1 and vectors2 accordingly in the code below.
Code without loops:
a = 0:1:2;
b = 0:1:2;
c = 0:1:2;
vectors1 = { a(1:end-1), b(1:end-1), c(1:end-1) };
vectors2 = { a(2:end), b(2:end), c(2:end) };
n = numel(vectors1);
combs1 = cell(1,n);
[combs1{:}] = ndgrid(vectors1{end:-1:1});
combs1 = reshape(cat(n+1, combs1{:}),[],n);
combs2 = cell(1,n);
[combs2{:}] = ndgrid(vectors2{end:-1:1});
combs2 = reshape(cat(n+1, combs2{:}),[],n);
result(:,2:2:2*n) = combs2;
result(:,1:2:2*n) = combs1;
I have 3 arrays in matlab that are 1xN, X Y Z respectively. I need to read these arrays into a 3xN matrix respectively so I get
x1 y1 z1
x2 y2 z2
.. .. ..
xn yn zn
I have currently got the data in a Nx 3 matrix, the wrong way round. The code I have is
X = [];
Y = [];
Z = [];
for ctr = 1:length(A)
X = [X A(ctr,1)];
Y = [Y A(ctr,2)];
Z = [Z A(ctr,3)];
end
M = [X;Y;Z];
Where A is the input data from a 624*600 double cell and M is my desired matrix.
Thanks
I guess you want that:
X = [];
Y = [];
Z = [];
for ctr = 1:length(A)
X(end+1, 1) = A(ctr,1);
Y(end+1, 1) = A(ctr,2);
Z(end+1, 1) = A(ctr,3);
end
M = [X Y Z];
Faster with 1 line code:
M = [A(:, 1) A(:, 2) A(:, 3)];
I just found that you can transpose with Mt = transpose(M); which has the overall intended result but feels like 3 rights to make a left.
I'm developing a program with MatLab that calculates powers of numbers, adds them together, and then sees if any of the first set of numbers (numbers to powers) equals any of the added numbers to powers. I'm trying to check this for each value in the first array, however, I am getting an output like this:
m =
1
128
2187
16384
78125
279936
823543
2097152
4782969
10000000
for each m value, which is just the result of a simple for loop of the array. So when I go to check if m is in the array, it checks is [1, 128,2187,16384,78125...] in the array, and the answer is no. How can I get it to evaluate each individual entry, like this:
Array n is [1,128,2187,16384]
for m = n
m = 1
Is m in array? No
m = 128
Is m in array? No
m = 2187
Is m in array? Yes
m = 16384
Is m in array? No
end
My code is below:
C = [];
D = [];
E = [];
F = [];
numbers1 = [];
numbers2 = [];
numbers = 10;
powers = 10;
for i = 1:numbers
for j = 3:powers
C = [C;i^j];
end
C = transpose(C);
D = [D;C];
C = [];
end
[~,b] = unique(D(:,1)); % indices to unique values in first column of D
D(b,:); % values at these rows
for i = D
for a = D
E = [E;i+a];
end
E = transpose(E);
F = [F;E];
E = [];
end
[~,b] = unique(F(:,1)); % indices to unique values in first column of F
F(b,:); % values at these rows
for m = D % this is the for loop mentioned above
m
end
Example vectors:
>> m = [1 3 5 9];
n = [5 2 1 4 8];
To check if each element of vector m is in n, use ismember:
>>ismember(m,n)
ans =
1 0 1 0
To get the values, not the indices: use logical indexing on m:
>> m(ismember(m,n))
ans =
1 5
or directly use intersect:
>> intersect(m,n)
ans =
1 5
I have the following problem. Suppose I have to arrays X and Y whose entries consist of integers in the range 0 through 9 like
X = [1 2 3]
Y = [7 0 9]
I want to think of these arrays as being the digits of base-10 numbers, so X represents the number 123 and Y represents the number 709. I want to write a program which outputs the digits of the sum of these integers. So in the example given, it should output the array
Z = [8 3 2]
since 123 + 709 = 832. For the sake of this question it suffices to assume that X and Y have the same length, i.e., that the numbers they represent have the same number of digits. While I am doing this, I also want to keep track of carries which were performed during the addition. So in the example, I'd also want to output
C = [0 0 1]
which represents that I had to carry a 1 when I added the digits 9 + 3 = 12, but that the additions of the digits in other positions went through without carries. So my main question is
Does anyone know of a simple way to achieve this goal using MATLAB?
So far, what I've come up with is the following code which is given the two numbers as X and Y
clear all; clc;
C = zeros(1, length(X));
for j=length(X):-1:1
if X(j) + Y(j) > 9
C(j) = 1;
end
Z(j) = mod(X(j) + Y(j), 10);
if j < length(X)
if Z(j) + C(j+1) < 9
Z(j) = Z(j) + C(j+1);
else
Z(j) = mod(Z(j) + C(j+1), 10);
C(j) = 1;
end
end
end
if C(1) == 1
Z = [1 Z];
end
Z
C
The problem is that the code only works sometimes. For example, it has no problem working through the example I gave above, that 123 + 709 = 832 with a "carry array" of [0 0 1]. But the input X = 52514 and Y = 41525 does not yield the correct results. So my follow up question is
Does anyone see the bug in the code above/how can I fix it?
You need to change the line
if Z(j) + C(j+1) < 9
to
if Z(j) + C(j+1) <= 9
Then it should work.
You can take advantage of dec2base, str2num and num2str functions:
function StackOverflow
x = [1 2 3];
y = [4 5 6];
numX = DigitsToNum(x);
numY = DigitsToNum(y);
digits = NumToDigits(numX+numY);
disp(digits);
end
function digits = NumToDigits(x)
digits = double( dec2base(x,10) - '0');
end
function num = DigitsToNum(x)
st = strrep(num2str(x),' ','');
num = str2num(st); %#ok<ST2NM>
end
Another way to implement the two functions above:
function digits = NumToDigits(x)
digits = [];
while x > 0
digits(end+1) = mod(x,10); %#ok<AGROW>
x = floor(x/10);
end
end
function num = DigitsToNum(x)
baseMult = power(10,0: (numel(x)-1));
num = sum( baseMult.*x );
end