MATLAB Generate matrix with logical values according to vector - matlab

I have a vertical Nx1 matrix A full of integers.
A:
+---+
| 4 |
| 3 |
| 1 |
| . |
+---+
My goal is to create a NxM matrix B where each cell's value is 1 if it's row is less than or equal to the corresponding number in A and the rest are 0.
B:
+-------------+
| 1 1 1 1 0 . |
| 1 1 1 0 0 . |
| 1 0 0 0 0 . |
| . . . . . . |
+-------------+
This could be achieved by iterating row by row, but I'm trying to find a quicker method. I feel this could be done through logical indexing but cannot think of how to exactly off the top of my head.

You can type:
B = A>=1:size(A,1)
% or, in versions earlier than 2016b:
B = bsxfun(#ge,A,1:size(A,1))
This will compare each value in A to all the numbers between 1 to the length of A, and returns 1 if it's greater or equals (#ge...) to it, and 0 if not. The result is a matrix, where each row k is the comparison for the value A(k) with all values between 1 to the length of A.

Found a solution for my problem.
index = repmat(1:max(A),length(A),1);
B = ones(length(A),max(A));
B(index>repmat(A,1,max(A))) = 0;
index is a NxM matrix where the value of a cell is equal to its column number. Whenever that value is greater than the value in A, the corresponding cell in B is set to 0.

Related

How do I compare elements of one array to a column of a matrix, then shorten the matrix correspondingly?

I have a matrix 'Z' sized 100000x2 and imported as an Excel file using readmatrix. I have a created array 'Time' (Time = [-200:0.1:300]'). I would like to compare all values in column 1 of 'Z' to 'Time' and eliminate all values of column 1 of 'Z' that do not equal a value of 'Time', thus shortening my 'Z' matrix to match my desired time values. Column 2 are pressure traces, so this would give me my desired time values and the corresponding pressure trace.
This sort of thing can be done without loops:
x = [1,2,3,4,1,1,2,3,4];
x = [x', (x+1)'] % this is your 'Z' data from the excel file (toy example here)
x =
1 2
2 3
3 4
4 5
1 2
1 2
2 3
3 4
4 5
y = [1,2]; % this is your row of times you want eliminated
z = x(:,1)==y % create a matrix logical arrays indicating the matches in the first column
z =
9×2 logical array
1 0
0 1
0 0
0 0
1 0
1 0
0 1
0 0
0 0
z = z(:,1)+z(:,2); % there is probably another summing technique that is better for your case
b = [x(z~=1,1), x(z~=1,2)] % use matrix operations to extract the desired rows
b =
3 4
4 5
3 4
4 5
All the entries of x where the first column did not equal 1 or 2 are now gone.
x = ismember(Z(:,1),Time); % logical indexes of the rows you want to keep
Z(~x,:) = []; % get rid of the other rows
Or instead of shortening Z you could create a new array to use downstream in your code:
x = ismember(Z(:,1),Time); % logical indexes of the rows you want to keep
Znew = Z(x,:); % the subset you want
You have to loop over all rows, use a nested if statement to check the item, and delete the row if it doesn't match.
Syntax for loops:
for n = 1:100000:
//(operation)//
end
Syntax for if statements:
if x == y
//(operation)//
Syntax for deleting a row: Z(rownum,:) = [];

Shuffle a list in Minizinc

array[1..6] of var 0..1: Path;
include "alldifferent.mzn";
constraint
forall(j in 1..6)(
alldifferent(i in 1..6)(Path[i])
)
Iam trying to shuffle a list into minizinc but i want different results every time like with a for all . how can i do it?
print this:
Path = array1d(1..6, [5, 4, 3, 2, 1, 0]);
There are - at least - two approaches for generating a random matrix depending on if you want to generate all possible variables (the first model below using decision values), or if you just want a "random" random matrix (the second model using built-in random generator). (A third approach would be that you write your own random generator, but this is left as an exercise :-)).
Here is a simple MiniZinc model that generates all the possible 6x6 matrices of {0,1} as decision variables.
int: n = 6;
array[1..n,1..n] of var 0..1: x;
solve :: int_search(array1d(x), first_fail, indomain_random) satisfy;
constraint
true
;
output
[
if j = 1 then "\n" else " " endif ++
show(x[i,j])
| i,j in 1..n
];
Note: The indomain_random heuristic generates the solutions in a more "random-like" order.
There is another way of doing this, using the bernoulli(0.5) function, which generates randomly 0 or 1 during the creation of the model, i.e. it's not decision variables:
int: n = 6;
array[1..n,1..n] of int: x = array2d(1..n,1..n,[ bernoulli(0.5) | i,j in 1..n]);
solve satisfy;
constraint
true
;
output
[
if j = 1 then "\n" else " " endif ++
show(x[i,j])
| i,j in 1..n
];
Which happens to generate the following matrix:
1 1 1 0 0 0
1 0 1 1 0 0
0 0 0 0 1 1
0 1 0 0 1 0
1 1 1 1 0 1
0 1 1 1 1 1
The drawback of this is that you then have to manually seed the random generator for generating different matrices. This is (according to https://www.minizinc.org/doc-2.5.1/en/command_line.html?highlight=random#cmdoption-r ) done with the --random-seed i flag (or -r i) but this don't work right now on my MiniZinc version.
MiniZinc has quite a few random generators, see more here: https://www.minizinc.org/doc-2.5.1/en/lib-stdlib.html?highlight=random#random-number-generator-builtins .

Output a matrix size n x m, 1 when the sum of the indices is even, 0 otherwise

I'm attempting the following as a hobby, not as homework. In Computer Programming with MATLAB: J. Michael Fitpatrick and Akos Ledeczi, there is a practice problem that asks this:
Write a function called alternate that takes two positive integers, n and m, as input arguments (the function does not have to check the format of the input) and returns one matrix as an output argument. Each element of the n-by-m output matrix for which the sum of its indices is even is 1.
All other elements are zero.
A previous problem was similar, and I wrote a very simple function that does what it asks:
function A = alternate(n,m)
A(1:n,1:m)=0;
A(2:2:n,2:2:m)=1;
A(1:2:n,1:2:m)=1;
end
Now my question is, is that good enough? It outputs exactly what it asks for, but it's not checking for the sum. So far we haven't discussed nested if statements or anything of that sort, we just started going over very basic functions. I feel like giving it more functionality would allow it to be recycled better for future use.
Great to see you're learning, step 1 in learning any programming language should be to ensure you always add relevant comments! This helps you, and anyone reading your code. So the first improvement would be this:
function A = alternate(n,m)
% Function to return an n*m matrix, which is 1 when the sum of the indices is even
A(1:n,1:m)=0; % Create the n*m array of zeros
A(2:2:n,2:2:m)=1; % All elements with even row and col indices: even+even=even
A(1:2:n,1:2:m)=1; % All elements with odd row and col indicies: odd+odd=even
end
You can, however, make this more concise (discounting comments), and perhaps more clearly relate to the brief:
function A = alternate(n,m)
% Function to return an n*m matrix, which is 1 when the sum of the indices is even
% Sum of row and col indices. Uses implicit expansion (R2016b+) to form
% a matrix from a row and column array
idx = (1:n).' + (1:m);
% We want 1 when x is even, 0 when odd. mod(x,2) is the opposite, so 1-mod(x,2) works:
A = 1 - mod( idx, 2 );
end
Both functions do the same thing, and it's personal preference (and performance related for large problems) which you should use.
I'd argue that, even without comments, the alternative I've written more clearly does what it says on the tin. You don't have to know the brief to understand you're looking for the even index sums, since I've done the sum and tested if even. Your code requires interpretation.
It can also be written as a one-liner, whereas the indexing approach can't be (as you've done it).
A = 1 - mod( (1:n).' + (1:m), 2 ); % 1 when row + column index is even
Your function works fine and output the desired result, let me propose you an alternative:
function A = alternate(n,m)
A = zeros( n , m ) ; % pre-allocate result (all elements at 0)
[x,y] = meshgrid(1:m,1:n) ; % define a grid of indices
A(mod(x+y,2)==0) = 1 ; % modify elements of "A" whose indices verify the condition
end
Which returns:
>> alternate(4,5)
ans =
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
initialisation:
The first line is the equivalent to your first line, but it is the cannonical MATLAB way of creating a new matrix.
It uses the function zeros(n,m).
Note that MATLAB has similar functions to create and preallocate matrices for different types, for examples:
ones(n,m) Create
a matrix of double, size [n,m] with all elements set to 1
nan(n,m) Create a
matrix of double, size [n,m] with all elements set to NaN
false(n,m) Create a
matrix of boolean size [n,m] with all elements set to false
There are several other matrix construction predefined function, some more specialised (like eye), so before trying hard to generate your initial matrix, you can look in the documentation if a specialised function exist for your case.
indices
The second line generate 2 matrices x and y which will be the indices of A. It uses the function meshgrid. For example in the case shown above, x and y look like:
| x = | y = |
| 1 2 3 4 5 | 1 1 1 1 1 |
| 1 2 3 4 5 | 2 2 2 2 2 |
| 1 2 3 4 5 | 3 3 3 3 3 |
| 1 2 3 4 5 | 4 4 4 4 4 |
odd/even indices
To calculate the sum of the indices, it is now trivial in MATLAB, as easy as:
>> x+y
ans =
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
Now we just need to know which ones are even. For this we'll use the modulo operator (mod) on this summed matrix:
>> mod(x+y,2)==0
ans =
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
This result logical matrix is the same size as A and contain 1 where the sum of the indices is even, and 0 otherwise. We can use this logical matrix to modify only the elements of A which satisfied the condition:
>> A(mod(x+y,2)==0) = 1
A =
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
Note that in this case the logical matrix found in the previous step would have been ok since the value to assign to the special indices is 1, which is the same as the numeric representation of true for MATLAB. In case you wanted to assign a different value, but the same indices condition, simply replace the last assignment:
A(mod(x+y,2)==0) = your_target_value ;
I don't like spoiling the learning. So let me just give you some hints.
Matlab is very efficient if you do operations on vectors, not on individual elements. So, why not creating two matrices (e.g. N, M) that holds all the indices? Have a look at the meshgrid() function.
Than you might be able find all positions with an even sum of indices in one line.
Second hint is that the outputs of a logic operation, e.g. B = A==4, yields a logic matrix. You can convert this to a matrix of zeros by using B = double(B).
Have fun!

How can I delete table row values in pairs? For example, if either column is less than 0.01, how do I delete the row?

I have two sets of data from different instruments that have common X-variables (XThompsons) but various Y-variables (YCounts) due to various experimental conditions. The data resemble the example below:
[Table1]
XThompsons | YCounts (1) | YCounts (2) | YCounts (3) | .... | ....
------------------------------------------------------------------
[Table2]
XThompsons | YCounts (1) | YCounts (2) | YCounts (3) | .... | ....
------------------------------------------------------------------
When I have two sets of data that are like this, I have written a script to take a single Y-column information from Table1 and do some math to all Y-columns in Table2. However, when comparing two table columns if either column has a value of a specific threshold (0.10) I want to delete that value. In the example below I want to delete row 4 and row 6 because either column has a value containing 0.10 or less
XThompsons | Table1.YCounts(1) | Table2.YCounts(2)
--------------------------------------------------
1 1.00 0.50
2 0.22 0.12
3 0.29 0.14
4 0.29 0.09 (delete row)
5 0.11 0.49
6 0.02 0.83 (delete row)
How can I carry this out in Matlab? My current code is below; I convert each table row to an array first. How can I make it so that if Y < 0.10 delete the row?
datax = readtable('table1.xls'); % Instrument 1
datay = readtable('table2.xls'); % Instrument 2
SIDATA = [];
for idx=2:width(datay);
% Read the indexed column of datax (instrument 1) then normalize to 1
x = table2array(datax(:,idx));
x = x ./ max(x);
% Read indexed column of datay (instrument 2) and carry out loop
for idy=2:width(datay);
% Normalize y data to 1
y = table2array(datay(:,idy));
y = y ./ max(y);
% Calculate similarity index (SI) at using the datax index for all collision energies for datay
xynum = sum(sqrt(x) .* sqrt(y));
xyden = sqrt(sum(x) .* sum(y));
SIDATA(idy,idx) = (xynum/xyden);
end
end
Help would be appreciated.
Thanks!
Generally when looping through and pruning values you want to increment from the end of the matrix back to one; this way, if you delete any rows, you don't skip. (If you delete row 2, then advance to row 3, you skip the data formerly in row 3).
To me, the easiest way to do this is that if all your data is in one matrix A, with columns Y1 Y2,
APruned = A((A(:,1) > 0.1) & (A(:,2) > 0.1),:)
This takes the A matrix, finds the rows where Y1 > 0.1, finds the rows where Y2 > 0.1, finds the overlap, and then outputs only the rows in A where both of these are true.
You should read about logical indecies for more on this topic
EDIT: It looks like you could also clean up your earlier code using element-wise operations;
A = [datax./max(datax) datay./max(datay)];

Generating all combinations containing at least one element of a given set in Matlab

I use combnk to generate a list of combinations. How can I generate a subset of combinations, which always includes particular values. For example, for combnk(1:10, 2) I only need combinations which contain 3 and/or 5. Is there a quick way to do this?
Well, in your specific example, choosing two integers from the set {1, ..., 10} such that one of the chosen integers is 3 or 5 yields 9+9-1 = 17 known combinations, so you can just enumerate them.
In general, to find all of the n-choose-k combinations from integers {1, ..., n} that contain integer m, that is the same as finding the (n-1)-choose-(k-1) combinations from integers {1, ..., m-1, m+1, ..., n}.
In matlab, that would be
combnk([1:m-1 m+1:n], k-1)
(This code is still valid even if m is 1 or n.)
For a brute force solution, you can generate all your combinations with COMBNK then use the functions ANY and ISMEMBER to find only those combinations that contain one or more of a subset of numbers. Here's how you can do it using your above example:
v = 1:10; %# Set of elements
vSub = [3 5]; %# Required elements (i.e. at least one must appear in the
%# combinations that are generated)
c = combnk(v,2); %# Find pairwise combinations of the numbers 1 through 10
rowIndex = any(ismember(c,vSub),2); %# Get row indices where 3 and/or 5 appear
c = c(rowIndex,:); %# Keep only combinations with 3 and/or 5
EDIT:
For a more elegant solution, it looks like Steve and I had a similar idea. However, I've generalized the solution so that it works for both an arbitrary number of required elements and for repeated elements in v. The function SUBCOMBNK will find all the combinations of k values taken from a set v that include at least one of the values in the set vSub:
function c = subcombnk(v,vSub,k)
%#SUBCOMBNK All combinations of the N elements in V taken K at a time and
%# with one or more of the elements in VSUB as members.
%# Error-checking (minimal):
if ~all(ismember(vSub,v))
error('The values in vSub must also be in v.');
end
%# Initializations:
index = ismember(v,vSub); %# Index of elements in v that are in vSub
vSub = v(index); %# Get elements in v that are in vSub
v = v(~index); %# Get elements in v that are not in vSub
nSubset = numel(vSub); %# Number of elements in vSub
nElements = numel(v); %# Number of elements in v
c = []; %# Initialize combinations to empty
%# Find combinations:
for kSub = max(1,k-nElements):min(k,nSubset)
M1 = combnk(vSub,kSub);
if kSub == k
c = [c; M1];
else
M2 = combnk(v,k-kSub);
c = [c; kron(M1,ones(size(M2,1),1)) repmat(M2,size(M1,1),1)];
end
end
end
You can test this function against the brute force solution above to see that it returns the same output:
cSub = subcombnk(v,vSub,2);
setxor(c,sort(cSub,2),'rows') %# Returns an empty matrix if c and cSub
%# contain exactly the same rows
I further tested this function against the brute force solution using v = 1:15; and vSub = [3 5]; for values of N ranging from 2 to 15. The combinations created were identical, but SUBCOMBNK was significantly faster as shown by the average run times (in msec) displayed below:
N | brute force | SUBCOMBNK
---+-------------+----------
2 | 1.49 | 0.98
3 | 4.91 | 1.17
4 | 17.67 | 4.67
5 | 22.35 | 8.67
6 | 30.71 | 11.71
7 | 36.80 | 14.46
8 | 35.41 | 16.69
9 | 31.85 | 16.71
10 | 25.03 | 12.56
11 | 19.62 | 9.46
12 | 16.14 | 7.30
13 | 14.32 | 4.32
14 | 0.14 | 0.59* #This could probably be sped up by checking for
15 | 0.11 | 0.33* #simplified cases (i.e. all elements in v used)
Just to improve Steve's answer : in your case (you want all combinations with 3 and/or 5) it will be
all k-1/n-2 combinations with 3 added
all k-1/n-2 combinations with 5 added
all k-2/n-2 combinations with 3 and 5 added
Easily generalized for any other case of this type.