Using a for loop to generate elements of a vector - arrays

I am trying to compute with the equation
and I would like to store each value into a row vector. Here is my attempt:
multiA = [1];
multiB = [];
NA = 6;
NB = 4;
q = [0,1,2,3,4,5,6];
for i=2:7
multiA = [multiA(i-1), (factorial(q(i) + NA - 1))/(factorial(q(i))*factorial(NA-1))];
%multiA = [multiA, multiA(i)];
end
multiA
But this does not work. I get the error message
Attempted to access multiA(3); index out
of bounds because numel(multiA)=2.
multiA = [multiA(i-1), (factorial(q(i)
+ NA -
1))/(factorial(q(i))*factorial(NA-1))];
Is my code even remotely close to what I want to achieve? What can I do to fix it?

You don't need any loop, just use the vector directly.
NA = 6;
q = [0,1,2,3,4,5,6];
multiA = factorial(q + NA - 1)./(factorial(q).*factorial(NA-1))
gives
multiA =
1 6 21 56 126 252 462
For multiple N a loop isn't necessary neither:
N = [6,8,10];
q = [0,1,2,3,4,5,6];
[N,q] = meshgrid(N,q)
multiA = factorial(q + N - 1)./(factorial(q).*factorial(N-1))
Also consider the following remarks regarding the overflow for n > 21 in:
f = factorial(n)
Limitations
The result is only accurate for double-precision values of n that are less than or equal to 21. A larger value of n produces a result that
has the correct order of magnitude and is accurate for the first 15
digits. This is because double-precision numbers are only accurate up
to 15 digits.
For single-precision input, the result is only accurate for values of n that are less than or equal to 13. A larger value of n produces a
result that has the correct order of magnitude and is accurate for the
first 8 digits. This is because single-precision numbers are only
accurate up to 8 digits.

Factorials of moderately large numbers can cause overflow. Two possible approaches to prevent that:
Avoid computing terms that will cancel. This approach is specially suited to the case when q is of the form 1,2,... as in your example. It also has the advantage that, for each value of q, the result for the previous value is reutilized, thus minimizing the number of operations:
>> q = 1:6;
>> multiA = cumprod((q+NA-1)./q)
multiA =
6 21 56 126 252 462
Note that 0 is not allowed in q. But the result for 0 is just 1, so the final result would be just [1 multiA].
For q arbitrary (not necessarily of the form 1,2,...), you can use the gammaln function, which gives the logarithms of the factorials:
>> q = [0 1 2 6 3];
>> multiA = exp(gammaln(q+NA)-gammaln(q+1)-gammaln(NA));
>>multiA =
1.0000 6.0000 21.0000 462.0000 56.0000

You want to append a new element to the end of 'multiA':
for i=2:7
multiA = [multiA, (factorial(q(i) + NA - 1))/(factorial(q(i))*factorial(NA-1))];
end
A function handle makes it much simpler:
%define:
omega=#(q,N)(factorial(q + N - 1))./(factorial(q).*factorial(N-1))
%use:
omega(0:6,4) %q=0..6, N=4

It might be better to use nchoosek as opposed to factorial. The latter can overflow quite easily, I'd imagine.
multiA=nan(1,7);
for i=1:7
multiA(i)=nchoosek(q(i)+N-1, q(i));
end

Related

Check subset sum for special array equation

I was trying to solve the following problem.
We are given N and A[0]
N <= 5000
A[0] <= 10^6 and even
if i is odd then
A[i] >= 3 * A[i-1]
if i is even
A[i]= 2 * A[i-1] + 3 * A[i-2]
element at odd index must be odd and at even it must be even.
We need to minimize the sum of the array.
and We are given a Q numbers
Q <= 1000
X<= 10^18
We need to determine is it possible to get subset-sum = X from our array.
What I have tried,
Creating a minimum sum array is easy. Just follow the equations and constraints.
The approach that I know for subset-sum is dynamic programming which has time complexity sum*sizeof(Array) but since sum can be as large as 10^18 that approach won't work.
Is there any equation relation that I am missing?
We can make it with a bit of math:
sorry for latex I am not sure it is possible on stack?
let X_n be the sequence (same as being defined by your A)
I assume X_0 is positive.
Thus sequence is strictly increasing and minimization occurs when X_{2n+1} = 3X_{2n}
We can compute the general term of X_{2n} and X_{2n+1}
v_0 =
X0
X1
v_1 =
X1
X2
the relation between v_0 and v_1 is
M_a =
0 1
3 2
the relation between v_1 and v_2 is
M_b =
0 1
0 3
hence the relation between v_2 and v_0 is
M = M_bM_a =
3 2
9 6
we deduce
v_{2n} =
X_{2n}
X_{2n+1}
v_{2n} = M^n v_0
Follow the classical diagonalization... and we (unless mistaken) get
X_{2n} = 9^n/3 X_0 + 2*9^{n-1}X_1
X_{2n+1} = 9^n X_0 + 2*9^{n-1}/3X_1
recall that X_1 = 3X_0 thus
X_{2n} = 9^n X_0
X_{2n+1} = 3.9^n X_0
Now if we represent the sum we want to check in base 9 we get
9^{n+1} 9^n
___ ________ ___ ___
X^{2n+2} X^2n
In the X^{2n} places we can only put a 1 or a 0 (that means we take the 2n-th elem from the A)
we may also put a 3 in the place of the X^{2n} place which means we selected the 2n+1th elem from the array
so we just have to decompose number in base 9, and check whether all its digits or either 0,1 or 3 (and also if its leading digit is not out of bound of our array....)

loop to remove repeated elements of a vector and add corresponding elements of another vector

I am using MATLAB to write a code that multiplies polynomials. Most parts of my code work however there is one part where I have two row vectors a and b. I want to remove repeated elements of a and then add the corresponding elements of b. This is what I have written
c=length(a);
d=length(b);
remove=[];
for i=1:c
for j=i+1:c
if (a(i)==a(j))
remove=[remove,i];
b(j)=b(i)+b(j);
end
end
end
a(remove)=[];
b(remove)=[];
The problem with this is if there is an element in a that appears more than twice, it doesn't work properly.
For example if a=[5,6,8,9,6,7,9,10,8,9,11,12] and b=[1,7,1,-1,3,21,3,-3,-4,-28,-4,4]
then once this code is run a becomes [5,6,7,10,8,9,11,12] which is correct but b becomes [1,10,21,-3,-3,-27,-4,4] which is correct except the -27 should be a -26.
I know why this happens because the 9 in a(1,4) gets compared with the 9 in a(1,7) so b(1,7) becomes b(1,7)+b(1,4) and then a(1,4) gets compared with the 9 in a(1,10). and then later the a(1,7) compares with a(1,10) and so the new b(1,7) adds to the b(1,10) however the b(1,4) adds to the b(1,10) too. I somehow need to stop this once one repeated element has been found because here b(1,4) has been added twice when it should only be added once.
I am not supposed to use any built in functions, is there a way of resolving this easily?
I would prefer using built in functions, but assuming you have to stick to your own approach, you can try this:
a=[5,6,8,9,6,7,9,10,8,9,11,12];
b=[1,7,1,-1,3,21,3,-3,-4,-28,-4,4];
n = numel(a);
remove = zeros(1,n);
temp = a;
for ii = 1:n
for jj = ii+1:n
if temp(ii) == temp(jj)
temp(ii) = NaN;
remove(ii) = ii;
b(jj) = b(jj) + b(ii);
end
end
end
a(remove(remove>0)) = []
b(remove(remove>0)) = []
a =
5 6 7 10 8 9 11 12
b =
1 10 21 -3 -3 -26 -4 4
It's not much different from your approach, except for changing the iith value of a if it is found later. To avoid overwriting the values in a with NaN, I'm using a temporary variable for this.
Also, as you can see, I'm avoiding remove = [remove i], because this will create a growing vector, which is very slow.
It can be solved in a vectorized manner with the following indexing nightmare (perhaps someone will come up with a simpler approach):
a = [5,6,8,9,6,7,9,10,8,9,11,12];
b = [1,7,1,-1,3,21,3,-3,-4,-28,-4,4];
[sa, ind1] = sort(a);
[~, ii, jj] = unique(sa);
[ind2, ind3] = sort(ind1(ii));
a = a(ind2);
b = accumarray(jj(:),b(ind1)).';
b = b(ind3);
Anyway, to multiply polynomials you could use conv:
>> p1 = [1 3 0 2]; %// x^3 + 3x^2 + 1
>> p2 = [2 -1 4]; %// 2x^2 - x + 4
>> conv(p1,p2)
ans =
2 5 1 16 -2 8 %// 2x^5 + 5x^4 + x^3 + 16x^2 - 2x + 8

How to generate a multiplicative space vector in Matlab?

I am trying to generate "automatically" a vector 0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30 (in multiplicative space).
I know linspace and logspace functions, but I couldn't find any similar function for multiplicative space.
Is there any? Otherwise, how to generate a vector like the one I need?
An easy way with bsxfun, also considering multiplication to smaller spaces:
x = [0.01,0.03,0.05] % initial vector, works for various lengths
n = 12; % times it should get multiplied in rising direction
m = 3; % times it should get multiplied in falling direction
Z = bsxfun( #times, x(:), 10.^(-m:n) )
Z = Z(:)
% if preferred, bulky one-liner:
% Z = reshape( bsxfun( #times, x(:), 10.^(-m:n) ) , 1 , [])
I assumed a multiplication with the multiplication vector, e.g.:
10.^(0:n) = 1 10 100 1000 10000 100000 ....
But custom vectors Y are also possible:
Z = bsxfun( #times, x(:), Y(:)' ) Z = Z(:)
A function that might help you achieving this in a very easy and compact way is the Kronecker tensor product kron.
You can use it to rewrite thewaywewalk's answer as:
v = [0.01;0.03;0.05]; % initial vector
emin = -3; % minimal exponent
emax = 12; % maximal exponent
Z = kron(10.^(emin:emax)',v(:))
which should give you the exact same result.
not very efficient but this will generate what you want. inputvec is your initial vector [0.01 0.03] in this case, multiplier is 10. length of the required string n is 8. n should be a multiple of nn (length of the input vector)
function newvec=multispace(n,inputvec,multiplier)
nn=length(inputvec);
newvec=zeros(1,n);
newvec(1:nn)=inputvec;
for i=1:n/nn-1
newvec(i*nn+1:(i+1)*nn)=(newvec((i-1)*nn+1:(i)*nn)).*multiplier;
end
end

Building array from conditions on another array

I am new to matlab. I want to do the following:
Generate an array of a thousand replications of a random draws between three alternatives A,B and C, where at every draw, each alternative has the same probability to be picked.
So eventually I need something like P = [ A A B C B B B C A C A C C ... ] where each element in the array was chosen randomly among the three possible outcomes.
I came up with a solution which gives me exactly what I want, namely
% Generating random pick among doors 1,2,3, where 1 stands for A, 2 for B,
% 3 for B.
I = rand(1);
if I < 1/3
PP = 1;
elseif 1/3 <= I & I < 2/3
PP = 2;
else
PP = 3;
end
% Generating a thousand random picks among dors A,B,C
I = rand(999);
for i=1:999
if I(i) < 1/3
P = 1;
elseif 1/3 <= I(i) & I(i) < 2/3
P = 2;
else
P = 3;
end
PP = [PP P]
end
As I said, it works, but when I run the procedure, it takes a while for what appears to me as a simple task. At the same time, I long such a task is "supposed" to take in matlab. So I have three question:
Is this really a slow procedure to generate the desired outcome?
If it is, why is this procedure particularly slow?
What would be a more effective way to produce the desired outcome?
This can be done much easier with randi
>> PP = randi(3,1,10)
PP =
2 1 3 3 2 2 2 3 2 1
If you actually want to choose between 3 alternatives, you use the output of randi directly to index into another matrix.
>> options = [13,22,77]
options =
13 22 77
>> options(randi(3,1,10))
ans =
22 13 77 13 77 13 22 22 77 13
As to the reason why your solution is slow, you do something similar to this:
x = [];
for i=1:10
x = [x i^2]; %size of x grows on every iteration
end
This is not very good, since on every iteration, Matlab needs to allocate space for a larger vector x. In old versions of Matlab, this lead to quadratic behavior (if you double the size of the problem, it takes 4 times longer). In newer versions, Matlab is smart enough to avoid this problem. It is however still considered nice to preallocate space for your array if you know beforehand how big it will be:
x = zeros(1,10); % space for x is preallocated. can also use nan() or ones()
for i = 1:length(x)
x(i) = i^2;
end
But in many cases, it is even faster to use vectorized code that does not use any for-loops like so:
x = (1:10).^2;
All 3 solutions give the same result:
x = 1 4 9 16 25 36 49 64 81 100
cnt=10;
option={'a','b','c'}
x=option([randi(numel(option),cnt,1)])

What's the fastest way to remove or change large number of entries in arrays in MATLAB?

I want to change a number of values in a 4D array M_ ijkl to NaN using MATLAB.
I use find to get the indices i and j that meet a certain condition for k = 2 and l = 4 (in my case it's the y component of a position at time t_4). I now want to set all the entries for these i and j combinations and for all k and l to NaN.
I used this method to do it (example by nkjt):
% initialise
M = zeros(10,10,2,4);
% set two points in (:,:,2,4) to be above threshold.
M(2,4,2,4)=5;
M(6,8,2,4)=5;
% find and set to NaN
[i,j] = find(M(:,:,2,4) > 4);
M(i,j,:,:)= NaN;
% count NaNs
sum(isnan(M(:))) % returns 32
This method is is very slow as this example illustrates:
M = rand(360,360,2,4);
threshold = 0.5;
% slow and wrong result
[i,j] = find(M(:,:,2,4) > threshold);
tic;
M(i,j,:,:) = NaN;
toc;
Elapsed time is 54.698449 seconds.
Note that the tic and toc don't time the find so that is not the problem.
With Rody's and njkt's help I also realized that my method doesn't actually do what I want. I only want to change entries with the combinations i and j i found with find (for all k and l), i.e. [2,4,:,:] and [6,8,:,:], but not [2,8,:,:] and [6,4,:,:]. In the first example sum(isnan(M(:))) should return 16.
Have you checked your results? Because I think they are wrong. For example, if you have
A = [...
1 2 3
4 5 6
7 8 9];
and you want to set element A(1,1) and A(2,3) to NaN. What you are doing is
A([1 2], [1 3]) = NaN
but that gives
A =
NaN 2 NaN
NaN 5 NaN
7 8 9
The easiest and fastest way around this is to not use find, but logical indexing:
M = rand(360,360,2,4);
maximum = 0.05;
tic;
M(M(:,:,2,4) > maximum) = NaN;
toc
Which gives on my PC:
Elapsed time is 0.003547 seconds.
Much faster for me by reshaping M:
M = rand(360,360,2,4);
M = reshape(M,[360*360,2,4]);
maximum = 0.05;
n = find(M(:,2,4) > maximum);
tic;
M(n,:,:) = NaN;
M = reshape(M,[360, 360, 2, 4]);
toc;
ETA:
M(i,j,:,:)= NaN; sets all combinations of i, j to NaN for all k,l (as explained in Rody's answer).
So for example:
% initialise
M = zeros(10,10,2,4);
% set two points in (:,:,2,4) to be above threshold.
M(2,4,2,4)=5;
M(6,8,2,4)=5;
% find and set to NaN
[i,j] = find(M(:,:,2,4) > 4);
M(i,j,:,:)= NaN;
% count NaNs
sum(isnan(M(:))) % returns 32
e.g. '(2,4,l,k) = NaN' but also '(4,2,l,k) = NaN'.
If this is what you want, reduce the size of i,j with unique after find.
In terms of logical indexing, basically, it's often better to do something like A(A>2)=NaN; instead of n = find(A>2); A(n)=NaN;. In the reshaped case you could do M(M(:,2,4)>maximum,:,:) = NaN;. I didn't tic/toc it so I don't know if it would be faster in this case.

Resources