Dynamic combinations of values - arrays

Here is what i want to do:
I have 4 inputs x1, x2, x3, x4
They each have a range of possible values, f.e
x1={1,2}
x2=x3=x4={1,2,3}
These values x1, x2, x3, x4 may be known, but they can also be unknow (input=0). I want to generate a matrix with all possible combinations.
So for example:
the input (0,0,2,3) means, that x1 and x2 are unknown and x3 and x4 are known. Since x1 has 2 possibilities and x2 has 3 possibilities I need 2*3=6 combinations, where x3 and x4 are fixed:
1 1 2 3
1 2 2 3
1 3 2 3
2 1 2 3
2 2 2 3
2 3 2 3
How do i archieve that? Normally i would do a couple nested for loops, but that doenst work, since i dont know which variables are known and which one are not. On the other hand perm() doenst really help either.

You can pre-generate all of the possible combinations of values for [x1 x2 x3 x4] and store it in the variable, for example comb.
From there on:
inputs = [x1 x2 x3 x4]; % Put your inputs in a vector
fixed = ~(inputs == 0); % Logical vector for where inputs is not zero
select = ismember(combs(:,fixed),inputs(fixed),'rows') % find where the values correspond
yourMatrix = combs(select,:); % Get your results

Try this (this should be generalisable):
% This is your input
ranges = {[1, 2], [1, 2, 3], [1, 2, 3], [1, 2, 3]};
input_v = [0, 0, 2, 3];
% initialise a cell to hold vectors to be combined
combine_us = cell(size(ranges));
for ii = 1:length(input_v)
% this tests for 0. If your arrays can contain 0, use NaN instead
if input_v(ii) == 0
combine_us{ii} = ranges{ii};
else
combine_us{ii} = input_v(ii);
end
end
% calculate the numbers of combinations added with every input
n_combinations = [1 cumprod(cellfun(#numel, combine_us))];
% initialize output matrix
out_v = zeros(n_combinations(end), length(input_v));
% set the output values, cycling so that each combination will be obtained
for ii = 1:length(input_v)
for jj = 1:n_combinations(end)
out_v(jj, ii) = combine_us{ii}(mod(ceil(jj / n_combinations(ii)) - 1, length(combine_us{ii} )) + 1);
end
end

I'm assuming your inputs are numeric vectors, rather than cell arrays of numbers. If they are really cell arrays of numbers, you can convert to numeric vectors with x1 = [x1{:}]; etc.
You can proceed as follows:
Build a cell array such that each cell contains either a whole input vector or a specific value thereof, according to s. This is easily done with a for loop, or with arrayfun.
Apply one of these answers to generate all combinations.
Code:
%// Inputs
x1 = [1,2];
x2 = [1,2,3];
x3 = [1,2,3];
x4 = [1,2,3];
s = [0 0 2 3];
%// Step 1
x = {x1 x2 x3 x4};
ind = s~=0;
x(ind) = arrayfun(#(y,t) {y{1}(t)}, x(ind), s(ind));
%// Step 2
n = numel(x);
combs = cell(1,n);
[combs{end:-1:1}] = ndgrid(x{end:-1:1});
combs = cat(n+1, combs{:});
combs = reshape(combs,[],n);

Related

Return all possible permutations and combinations of numbers from n arrays whose sum is less than m and greater than r

I have two arrays:
array1: [0 1 2 3]
array2: [0 1 2 3 4 5 6 7]
array3: [0 1 2 3 4 5]
I want to find combination from each array like 1 element from each array such that the sum >= m eg.3 and sum <=r eg. 6
Example:
array1 array2 array3 elements
1 1 1 (sum is 3)
1 5 0 (sum is 6)
1 6 1 (wrong result sum is greater than 6)
Thanks in advance.
I don't understand how to solve this problem . A pseudocode will be very helpful.
As I have mentioned in my comment; compared to the brute force, in JS by a dynamical programming approach you may get the results much faster, like in total around 10ms for your test case, as follows;
function getCombos(arr,n,m){
function getBinaryMap(d){
return Array(a.length).fill()
.reduce((p,c,i) => p.concat(d >> i & 1),[]);
}
var a = arr.reduce((p,c) => p.concat(c.filter(e => e !== 0 && e <= m)),[]);
t = [0],
r = [];
a.forEach(e => t = t.concat(t.map((f,i) => (f + e >= n && f + e <= m && r.push(getBinaryMap(t.length + i)), f + e))));
return r.map(e => e.reduce((p,c,i) => c ? p.concat(a[i]) : p,[]));;
}
var arrays = [[0, 1, 2, 3],[0, 1, 2, 3, 4, 5, 6, 7],[0, 1, 2, 3, 4, 5]];
result = getCombos(arrays,3,6);
console.log(JSON.stringify(result));
Let there be N=3 sorted arrays A(size = p), B(size = q) and C(size=r).
Choose a number say X and try finding a sum of N=3 numbers x1 + x2 + x3
such that X = x1 + x2 + x3. Finding x1, x2 and x3 can be done using dynamic programming.
Now,
Consider the sequence ABC and use binary search to find x1 in array A, x2 in array B and x3 in array C.
Consider the sequence ACB and use binary search to find x1 in array A, x2 in array C and x3 in array B.
Consider the sequence BAC and use binary search to find x1 in array B, x2 in array A and x3 in array C.
You will find that there are N! number of such sequences.
You will be required to repeat the above process for all X such that [m]<=[X]<=[r].
Total Complexity would be (r - m + 1) * (N!) * ((log p) + (log q) + (log r)).
Total Complexity does not include the dynamic programming part.

How can I use different dimension of matrix in a loop?

This is my input:
x1=[1 2 3 4]
x2=[1 2 3 4 1]
x3=[ 1 2 3 4 5 6 ]
I want to develop a for loop code to calculate this equation D = x1(i+1)-x1(i), for example:
for i:1:k % k is referring to matrix of x1, x2 and x3
for i=1:n % n is referring to number of element in matrix x1, x2 and x3
D= x1(i+1)-x1(i) % for k=2 i want to change x1 to matrix x2
end
end
Can anyone help me how to write the correct code for my problem? I have tried many times, but it failed.

Finding the best way to define a function of dot product for a 3D grid

I am trying to build the following function in a three dimensional domain.
where is a constant vector, is the position vector, is a constant, and is time.
is a vector of size [1 3], is the array of size [NX*NY*NZ 3] that represents the points in the three-dimensional domain, is constant, and is array of size [1 NT].
The following is the setup of the problem.
dx = 0.1;
dy = 0.5;
dz = 0.1;
[x, y, z] = meshgrid( (1:100)*dx, (1:100)*dy, (1:100)*dz );
X = [x(:) y(:) z(:)];
k = [1 2 3];
c = 0.5;
t = 0:0.1:1;
In fact, the following loop works but it is very slow (~200 seconds).
f = zeros(numel(X)/3, numel(t));
for n = 1:numel(t)
for i = 1:numel(X)/3
f(i, n) = tan(dot(k, X(i,:)+c*t(n)));
end
end
I thought about using arrayfun and repeating the vector k using repmat and dot it with X in the second dimension but I don't know what I should do for the multiplication of c and t.
What would be an efficient way of defining the function for all the points and all the times? The output of this function, for example, looks like an array of size [NX*NY*NZ NT].
bsxfun approach to speedup f calculation -
t1 = bsxfun(#plus,X,permute(c*t,[1 3 2]));
t2 = permute(k(ones(numel(t),1),:),[3 2 1]);
t3 = bsxfun(#times,t1,t2);
f = tan(squeeze(sum(t3,2)));
Or a slight variant -
t1 = bsxfun(#plus,X,permute(c*t,[1 3 2]));
t3 = bsxfun(#times,t1,k);
f = tan(squeeze(sum(t3,2)));
f = tan(sum(bsxfun(#times, permute(k, [1 3 2]), bsxfun(#plus, permute(X, [1 3 2]), c*t)), 3));
Or replace the outer bsxfun by matrix multiplication. This seems to be slightly faster:
f = tan(reshape(reshape(bsxfun(#plus, permute(X, [1 3 2]), c*t), [], 3) * k(:), [size(X,1) numel(t)]));

How to plot specific points in matlab?

I've X axis with values [2,6,10] and for Y axis [0.5,0.4,0.2,0.2,....0.5], all values between 0 and 1.
There are certain points which correspond to 2, let's say 1/3rd and the remaining 1/3rd for 6 and remaining 1/3rd for 10. The points corresponding to 2 can have any values between 0 and 1, same applies for point 6 and point 10.
How can I plot this?
I guess you have some way to match up each Y-value to its corresponding X-value. By generating a vector of the same length as Y with these X-values they can then be plotted against each other.
The two vectors will then have the following form:
X = [2,6,2,10,6,6,10,2,....6]
Y = [0.5,0.4,0.2,0.2,0.9,0.3....0.5]
Here is a sample code
% X-data
X = [2,6,10];
% Generate random Y-data
n1 = 10;
n2 = 20;
n3 = 30;
n = n1 + n2 + n3;
Y = rand(1,n);
% Match X indices corresponding to Y
% Xall = [2,2,2,...,2,6,6,6,...,6,10,10,10,...,10]
X1 = zeros(1,n1);
X1(:) = X(1);
X2 = zeros(1,n2);
X2(:) = X(2);
X3 = zeros(1,n3);
X3(:) = X(3);
Xall = [X1 X2 X3];
plot(Xall,Y,'o')
xlim([min(X)-2,max(X)+2])
which will generate a figure of the following form
plot(a(1:3:end))
This will plot every third point.
a=[0.5,0.4,0.2,0.2,....0.5]
b=[1:3:length(a)]
plot(a(b))

Array rotation in MATLAB

In MATLAB, is there a way to rotate the elements of a array to another dimension, like:
y=[-1,0,1] --> y=[-1; 0; 1] (like transpose)
y=[-1,0,1] --> y(:,:,1)=-1, y(:,:,2)=0, y(:,:,3)=1
y=[-1,0,1] --> y(:,:,1,1)=-1, y(:,:,1,2)=0, y(:,:,1,3)=1
I would like to avoid for loops.
You can do these sorts of matrix operations using transposition, the function RESHAPE, or the function PERMUTE. For example:
y = [-1 0 1]; %# Your 1-by-3 sample array
y2 = y.'; %'# Transposing y gives you a 3-by-1 array
y2 = reshape(y,[3 1]); %# This also gives you a 3-by-1 array
y2 = permute(y,[2 1]); %# This also gives you a 3-by-1 array
y3 = reshape(y,[1 1 3]); %# This gives you a 1-by-1-by-3 array
y3 = permute(y,[3 1 2]); %# This also gives you a 1-by-1-by-3 array
y4 = reshape(y,[1 1 1 3]); %# This gives you a 1-by-1-by-1-by-3 array
y4 = permute(y,[4 1 2 3]); %# This also gives you a 1-by-1-by-1-by-3 array
While reshape and permute are more powerful tools, you can solve the given example quite easy with:
y = [-1 0 1];
y2(:,1)=y;
y3(1,1,:)=y;
y4(1,1,1,:)=y;

Resources