Nested loop to fill matrix - loops

Noob here... I want to use a nested for-loop to set up a matrix of the following kind:
1 2 3 4
0 3 5 7
0 0 8 12
(just an example, the numbers do not grow incrementally)
i.e. each number is the sum of the element above and the element above to the left. Which means that on row i, all elements until column i are zero.
The actual numbers will depend on a starting value n., and the matrix will have the shape n*n.
I have the starting values for the first row, and need to find a way to go through each row and fill up every element.
def function(x,n):
M=zeros([n,n]) #create the matrix
a=(1+x)/2 #formula to set starting value
g=sqrt(x)
for i in range(n): #fill up first row
M[0,i]=a #change value in cell
a=(a+g)/2 #set a new value for 'a' and 'g'
g=sqrt(a*g)
for j in range(n): #Do the same for each row
M[j:n,???]=M[j-1,???]+M[j,???]
But here I'm stuck.. I can't find a way to have the formula run through the elements on each line.

I do not understand the logic that you use to fill the first, row, but this should work to fill the remainder.
from math import sqrt
from numpy import zeros
def function(x,n):
M = zeros([n,n]) #create the matrix
a = (1 + x) / 2 #formula to set starting value
g = sqrt(x)
for i in range(n): #fill up first row
M[0,i] = a #change value in cell
a = (a + g) / 2 #set a new value for 'a' and 'g'
g = sqrt(a * g)
for row in range(1,n): # iterate over rows, skip the first
for col in range(row,n): #iterate over columns, skip the first few
M[row, col] = M[row - 1, col - 1] + M[row - 1, col]
return M

Related

Maximum cost of Matrix

You are given an N*M 2D matrix, Each cell contains a number and no two cells have the same number. We have to select one element from each of the N rows, let selected elements be c1,c2,...cN.
The cost of Matrix is defined as - the sum of (ci-sj)(1<=i,j<=N) where sj represents the greatest element in jth row that is <=ci, If no such sj exists then sj=0.
We have to find the maximum possible cost of the matrix.
For Example:-
If N=M=3 and matrix = [[4,3,2], [6,1,5], [8,9,7]]
Now the values for c1 can be 4,3 or 2, values for c2 can be 6,1 or 5 and values for c3 can be 8,9 or 7
If we select c1=4, c2=6 and c3=9
Cost of c1 = (4-4)+(4-1)+(4-0)=7, here s1 = 4(greatest element <=c1=4 in 1st row), s2 = 1, s3 = 0(as no element is <=c3=9 in 3rd row)
similarly, Cost of c2 = (6-4)+(6-6)+(6-0)=8
cost of c3 = (9-4)+(9-6)+(9-9) = 8
Total Cost = 7+8+8 = 23
This is the maximum score that we can get from any values of c1,c2,c3.
Another Example:-
If Matrix = [[2,22,28,30],[21,5,14,4],[20,6,15,23]] then maximum cost would be 60.
I tried choosing the maximum element from each row as ci, but this does not work. Can anyone tell how we can approach and solve this problem?
Edit:
I have tried long for coding and understanding this but am unable to do so successfully, here is what I am able to code until now, this passes some cases but fails some.
def solve(matrix):
N = len(matrix)
M = len(matrix[1])
i = 0
totalcost = 0
for row in matrix:
itotalcost = 0
for ci in row:
icost = 0
totalicost = 0
for k in range(0, N):
if k != i:
idx = 0
sj = 0
isj = 0
for idx in range(0, M):
isj = matrix[k][idx]
if isj <= ci and isj > sj:
sj = isj
icost = ci - sj
totalicost += icost
#print("ci=", ci, "sj", sj, "icost=", icost)
if itotalcost < totalicost:
itotalcost = totalicost
i += 1
#print("itotalcost=", itotalcost)
totalcost += itotalcost
return totalcost
You can solve this in O(N log N) time, where N is the total number of elements.
First, we can define the value of a nonnegative integer x independently of what row it is in. Letting max_at_most(row, x) denote a function returning the largest element in row that is at most x, or 0 if none exists.
Then:
value(x) = sum over all rows R of: { x - max_at_most(R, x) }
Now, max_at_most is a monotonic function of x for a fixed row, and it only changes at most length(row) times for each row, which we can use to calculate it quickly.
Find all unique elements in your matrix, and track the row indices where each element occurs. Sort the unique elements. Now, if we iterate over the elements in order, we can track the largest elements seen in each row (and also the sum of max_at_most(row, x) over all rows) in O(1) time.
def max_matrix_value(matrix: List[List[int]]) -> int:
"""Maximize the sum over all rows i, j, of (c_i - f(j, c_i)})
where c_i must be an element of row i and f(j, c_i) is the largest
element of row j less than or equal to c_i, or 0 if none exists."""
num_rows = len(matrix)
elem_to_indices = defaultdict(list)
for index, row in enumerate(matrix):
for elem in row:
elem_to_indices[elem].append(index)
current_max_element = [0] * num_rows
current_max_sum = 0
max_value_by_row = [0] * num_rows
for element in sorted(elem_to_indices):
# Update maximum element seen in each row
for index in elem_to_indices[element]:
difference = element - current_max_element[index]
current_max_sum += difference
current_max_element[index] = element
max_value_for_element = element * num_rows - current_max_sum
# Update maximum value achieved by row, if we have a new record
for index in elem_to_indices[element]:
max_value_by_row[index] = max(max_value_by_row[index],
max_value_for_element)
return sum(max_value_by_row)

Create all possible n-tuples from n vectors in Matlab, ordered in a specific way

Consider n row vectors in Matlab, each of size 1xU. For example,
U=20;
n=3;
sU=[U U U];
vectors = arrayfun(#(x) {1:x}, sU);
where vector{1} is the first row vector, vector{2} is the second row vector,..., vector{n} is the last row vector.
We create the matrix Tcoord of size U^n x n reporting all the possible n-tuples from the n row vectors. For each row i of Tcoord, Tcoord(i,1) is an element of the first row vector, Tcoord(i,2) is an element of the second row vector, ... , Tcoord(i,n) is an element of the last row vector.
Tcoord_temp = cell(1,n);
[Tcoord_temp{:}] = ndgrid(vectors{:});
Tcoord_temp = cat(n+1, Tcoord_temp{:});
Tcoord = reshape(Tcoord_temp,[],n);
Suppose now that I augment each of the n row vectors of 3 elements. For example,
vectors_augmented{1}=[vectors{1} 8 9 10];
vectors_augmented{2}=[vectors{2} 11 12 13];
vectors_augmented{3}=[vectors{3} 14 15 16];
I then create a matrix similar to Tcoord but now using vectors_augmented.
Tcoord_temp = cell(1,n);
[Tcoord_temp{:}] = ndgrid(vectors_augmented{:});
Tcoord_temp = cat(n+1, Tcoord_temp{:});
Tcoord_augmented = reshape(Tcoord_temp,[],n); %(U+3)^nxn
I would like your help to re-order the rows of the matrix Tcoord_augmented in a matrix Tcoord_augmented_reshape such that
Tcoord_augmented_reshape(1:U^n,:) is equal to Tcoord.
The remaining rows of Tcoord_augmented_reshape contains the other left rows of Tcoord_augmented.
The simplest approach is to build an auxiliary zero-one matrix the same size as Tcoord_augmented and sort rows based on that:
aug_size = [3 3 3]; % augment size of each vector. Not necessarily equal
vectors_aux = arrayfun(#(a) {[false(1,U) true(1, a)]}, aug_size);
T_aux = cell(1,n);
[T_aux{:}] = ndgrid(vectors_aux{:});
T_aux = cat(n+1, T_aux{:});
T_aux = reshape(T_aux,[],n);
[~, ind] = sortrows(T_aux, n:-1:1); % indices of stably sorting the rows.
% Most significant column is rightmost, as per your code
Tcoord_augmented_reorder = Tcoord_augmented(ind, :);

i have a matrix of 18*9, I want to calculate the mean values of 6 rows each and get a resultant matrix of 3*9

I want to calculate the mean value of 6 rows each of a matrix 600*9 dimension. The new matrix should be of size 100*9. Can someone help me ?
I saw this code for calculating mean of 2 rows each and it is working fine foe 2 rows :-
x = rand(1028, 18);
result1 = zeros(1028/2, 18);
for ii = 1:1028/2;
result1(ii,:) = mean(x((2*ii-1):(2*ii),:));
end;
The output matrix will have the mean of first 6 rows ( of the input matrix) as the first row and next 6 rows as the 2nd row and so on
Let the data be defined as
x = rand(600, 9); % example data
N = 6; % group size
The desired result can be obtained very easily without loops:
Reshape the data matrix as a 3-D array, where the size along the first dimension is the desired group size;
Compute the mean along the first dimension;
Remove the first dimension, which is now a singleton.
result = reshape(mean(reshape(x, N, [], size(x,2)), 1), [], size(x,2));
Note how this single line contains the three steps described above:
reshape(x, N, [], size(x,2)) % step 1
mean( , 1) % step 2
result = reshape( , [], size(x,2)); % step 3
Using mean and a for loop:
data = rand(600,9);
num_groups = 6;
group_size = size(data,1)/num_groups;
mean_by_group = NaN(num_groups, size(data,2));
for k = 1:num_groups
mean_by_group(k,:) = mean(data((k-1)*group_size+(1:group_size),:),1)
end

Select entries from matrices according to indices in another matrix in MATLAB

I have matrices:
a= 0.8147 0.1270 0.6324
0.9058 0.9134 0.0975
b= 0.2785 0.9649 0.9572
0.5469 0.1576 0.4854
0.9575 0.9706 0.8003
c = 0.1419 0.7922
0.4218 0.9595
0.9157 0.6557
and also I have another matrix
I= 1 3 1 1
2 1 3 2
I want to get d matrix such that
d= a(1,3) b(3,1) c(1,1)
a(2,1) b(1,3) c(3,2)
where indices come as two consecutive entries of I matrix.
This is one example I get. However, I get different size matrices for a,b,c,.. and I.
Added: I is m x (n+3) which includes indices, and other (n+2) matrices which have corresponding entries are X,A1,A2,...,An,Y. When n is given, A1,A2,...,An matrices are generated.
Can someone please help me to write Matlab code for this task?
You can do it with varargin. Assuming that your matrices are constructed such that you can form your desired output in the way you want (Updated according to Carmine's answer):
function out = IDcombiner(I, varargin)
out = zeros(size(I, 1), nargin-1);
idx = #(m, I, ii) (sub2ind(size(m), I(:, ii), I(:, ii+1)));
for ii = 1:1:nargin-1
out(:, ii) = varargin{ii}(idx(varargin{ii}, I, ii));
end
Now using this function you can make your selection on a flexible number of inputs:
out = IDcombiner(I, a, b, c)
out =
0.6324 0.9575 0.1419
0.9058 0.9572 0.6557
There is also a one-liner solution, which I do not recommend, since it dramatically decreases the readability of the code and doesn't help you gain much:
IDcombiner = #(I,varargin) ...
cell2mat(arrayfun(#(x) varargin{x}(sub2ind(size(varargin{x}), ...
I(:,x), I(:,x+1))), 1:nargin-1, 'UniformOutput', false));
Normally a matrix is not interpreted as a list of indices, but you can have this if you use sub2ind. To use it you need the size of the matrix you are addressing. Let's make an example starting with a:
a(sub2ind(size(a), I(:,1), I(:,2)))
The code does not change if you first assign the newly generated matrices to a variable name.
will use the column I(:,1) as rows and I(:,2) as columns.
To make the code more readable you can define an anonymous function that does this, let's call it idx:
idx = #(m,I,i)(sub2ind(size(m), I(:,i), I(:,i+1)))
So finally the code will be
d = [a(idx(a,I,1)), b(idx(b,I,2)), c(idx(c,I,3))]
The code does not change if you first assign the newly generated matrices to a variable name.
Other details
Let's make an example with 2 central matrices:
a = rand(3,1) % 3 rows, 1 column
b = rand(3,3) % 3 rows, 3 columns
c = rand(3,3) % another squared matrix
d = rand(3,1) % 3 rows, 1 column
The definition of the anonymous function is the same, you just change the definition of the output vector:
output = [a(idx(a,I,1)), b(idx(b,I,2)), c(idx(c,I,3)), d(idx(d,I,3))]
Keep in mind that following that pattern you always need a I matrix with (n_matrices + 1) columns.
Generalization
Let's generalize this code for a number n of central matrices of size rxr and for "side matrices" of size rxc. I will use some values of those parameters for this example, but you can use what you want.
Let me generate an example to use:
r = 3;
c = 4;
n = 3;
a = rand(r,c); % 2D array
b = rand(r,r,n); % 3D array, along z = 1:n you have 2D matrices of size rxr
c = rand(r,c);
I = [1 3 1 2 1 3; 2 1 3 1 1 1];
The code I wrote can easily be extended using cat to append matrices (note the 2 in the function tells MATLAB to append on the direction of the columns) and a for cycle:
idx = #(m,I,i)(sub2ind(size(m), I(:,i), I(:,i+1)))
d = a(idx(a,I,1));
for i = 1:n
temp = b(:,:,i);
d = cat(2,d,temp(idx(tmp,I,i+1)));
end
d = cat(2,d,c(idx(c,I,n+1)));
If you really don't want to address anything "by hand", you can use cell arrays to put all the matrices together and then cyclically apply the anonymous function to each matrix in the cell array.

reshape 2d array to 3d array in matlab /octave

How can I reshape a 2d array to a 3d array with the last column being used as pages?
All data found in array2d should be in pages
example:
array2d=[7,.5,12; ...
1,1,1; ...
1,1,1; ...
4,2,4; ...
2,2,2; ...
2,2,2; ...
3,3,3; ...
3,3,3; ...
3,3,3];
The first page in the array would be
7,.5,12;
1,1,1;
1,1,1;
The second page in the array would be
4,2,4;
2,2,2;
2,2,2;
The third page in the array would be
3,3,3;
3,3,3;
3,3,3;
This is a 9x3 array how can I get it to be a 9x3x? (not sure what this number should be so I placed a question mark as a place holder) multidimensional array?
What I'm trying to get is to have
All the ones would be on one dimension/page all the two's would be another dimension/page etc... –
I tried reshape(array2d,[9,3,1]) and it's still a 9x3
Use permute with reshape -
N = 3; %// Cut after every N rows to form a "new page"
array3d = permute(reshape(array2d,N,size(array2d,1)/N,[]),[1 3 2]) %// output
Assuming that each slice of your matrix is the same in dimensions, we can do this very easily. Let's call the number of rows and columns that each slice would have to be M and N respectively. In your example, this would be M = 3 and N = 3. As such, assuming array2d is of the above form, we can do the following:
M = 3;
N = 3; %// This is also simply the total number of columns we have,
%// so you can do size(array2d, 2);
outMatrix = []; %// Make this empty. We will populate as we go.
%// Figure out how many slices we need
numRows = size(array2d,1) / M;
for k = 1 : numRows
%// Extract the k'th slice
%// Reshape so that it has the proper dimensions
%// of one slice
sliceK = reshape(array2d(array2d == k), M, N);
%// Concatenate in the third dimension
outMatrix = cat(3,outMatrix,sliceK);
end
With your example, we thus get:
>> outMatrix
outMatrix(:,:,1) =
1 1 1
1 1 1
1 1 1
outMatrix(:,:,2) =
2 2 2
2 2 2
2 2 2
outMatrix(:,:,3) =
3 3 3
3 3 3
3 3 3
This method should generalize for any number of rows and columns for each slice, provided that each slice shares the same dimensions.
Your array is already of size 1 in the 3rd dimension (in other words, it is already 9x3x1, to prove this try entering array2d(1,1,1)). If you want to concatenate 2d matrices along the 3rd dimension you can use cat.
For example:
a = [1,2;3,4];
b = [5,6;7,8];
c = cat(3,a,b);
c will be a 2x2x2 matrix.
This piece of code is specific for this example, I hope you will be able to understand how to go for other data samples.
out2 = [];
col = size(array2d,2);
for i = 1:3
temp2 = reshape(array2d(array2d == i),[],col);
out2 = cat(3,out2,temp2);
end

Resources