Print the value of a multidimensional array with the output as compatible matlab code - matlab

For matrices with dimensions equal or less then 2 the command is:
For instance:
>> mat2str(ones(2,2))
ans =
[1 1;1 1]
However, as the help states, this does not work for higher dimensions:
>> mat2str(rand(2,2,2))
Error using mat2str (line 49)
Input matrix must be 2-D.
How to output matrices with higher dimensions than 2 with that is code compatible, without resorting to custom made for loops?

This isn't directly possible because there is no built-in character to represent concatenation in the third dimension (an analog to the comma and semicolon in 2D). One potential workaround for this would be to perform mat2str on all "slices" in the third dimension and wrap them in a call to cat which, when executed, would concatenate all of the 2D matrices in the third dimension to recreate your input matrix.
M = reshape(1:8, [2 2 2]);
arrays = arrayfun(#(k)mat2str(M(:,:,k)), 1:size(M, 3), 'uni', 0);
result = ['cat(3', sprintf(', %s', arrays{:}), ')'];
result =
'cat(3, [1 3;2 4], [5 7;6 8])'
isequal(eval(result), M)
1
UPDATE
After thinking about this some more, a more elegant solution is to flatten the input matrix, run mat2str on that, and then in the string used to recreate the data, we utilize reshape combined with the original dimensions to provide a command which will recreate the data. This will work for any dimension of data.
result = sprintf('reshape(%s, %s);', mat2str(M(:)), mat2str(size(M)));
So for the following 4D input
M = randi([0 9], 1, 2, 3, 4);
result = sprintf('reshape(%s, %s);', mat2str(M(:)), mat2str(size(M)));
'reshape([6;9;4;6;5;2;6;1;7;2;1;7;2;1;6;2;2;8;3;1;1;3;8;5], [1 2 3 4]);'
Now if we reconstruct the data using this generated string, we can ensure that we get the correct data back.
Mnew = eval(result);
size(Mnew)
1 2 3 4
isequal(Mnew, M)
1
By specifying both the class and precision inputs to mat2str, we can even better approximate the input data including floating point numbers.
M = rand(1,2,3,4,5);
result = sprintf('reshape(%s, %s);', mat2str(M(:),64,'class'), mat2str(size(M)));
isequal(eval(result), M)
1

Related

Extracting a matrix from a cell vector in MATLAB

A sparse matrix is a large matrix with almost all elements of the same
value (typically zero). The normal representation of a sparse matrix
takes up lots of memory when the useful information can be captured
with much less. A possible way to represent a sparse matrix is with a
cell vector whose first element is a 2-element vector representing the
size of the sparse matrix. The second element is a scalar specifying
the default value of the sparse matrix. Each successive element of the
cell vector is a 3-element vector representing one element of the
sparse matrix that has a value other than the default. The three
elements are the row index, the column index and the actual value.
Write a function called "sparse2matrix" that takes a single input of a
cell vector as defined above and returns the output argument called
"matrix", the matrix in its traditional form. Consider the following
run:
cellvec = {[2 3], 0, [1 2 3], [2 2 -3]};
matrix = sparse2matrix(cellvec)
matrix =
0 3 0
0 -3 0
Good morning/afternoon/night, everyone
I was wondering if you could help me with this.
I am trying to complete this, but I am not sure how to deal with this. I understand that I am interested in the first part of the cell vector, but I am not sure about how to tell Matlab I need that. This is my code:
function matrix = sparse2matrix(x)
A = [2 3];
B = 0;
C = [1, 2, 3];
x = {A, 0, C};
matrix = cell2mat(x);
end
The result of this code is different from the result I showed above.
I am not getting the right answer and honestly I do not know what to do, so I would appreciate if you guide me a little bit.
Not the most elegant way of doing it but it gets the job done. Uses the cell2mat() function and indexing to grab the necessary values for each step. A for-loop is then used to obtain the 3-element vectors that is used to change the array values from the default values in the respective indices.
cellvec = {[2 3], 0, [1 2 3], [2 2 -3]};
[matrix] = sparse2matrix(cellvec)
function [matrix] = sparse2matrix(x)
Matrix_Size = cell2mat(x(1,1));
Matrix_Height = Matrix_Size(1);
Matrix_Width = Matrix_Size(2);
Default_Value = cell2mat(x(1,2));
matrix = Default_Value*ones(Matrix_Height,Matrix_Width);
Triplets = x(3:end);
Number_Of_Triplets = length(Triplets);
for Triplet_Index = 1: Number_Of_Triplets
Current_Triplet = cell2mat(Triplets(1,Triplet_Index));
Row = Current_Triplet(1,1);
Column = Current_Triplet(1,2);
Value = Current_Triplet(1,3);
matrix(Row,Column) = Value;
end
end
Explanation:
The first line in the local function sparse2matrix() indicates to retrieve row 1, column 1 of the cell array x and then convert it to a matrix. The conversion is done using the cell2mat() function.
Matrix_Size = cell2mat(x(1,1));
Results in:
Matrix_Size = [2 3]
The following line indicates to grab index 1 of the previous array Matrix_Size. This will be used to determine the height of the output array matrix. This is done in a similar fashion to evaluate the Matrix_Width using index 2.
Matrix_Height = Matrix_Size(1);
Results in:
Matrix_Height = 2
Ran using MATLAB R2019b

Octave access elements of matrix by lines

I made a matrix like this :
A = randi([-10, 10], 3, 3);
Which can have this result :
-1 1 -2
2 2 8
5 3 10
How can I transform it in a way that A(1) = -1, A(2) = 1 and A(3) = -2
(Accessing first line with terms 1,2,3)
Currently, A(1) = -1, A(2) = 2 and A(3) = 5 (columns)
Note : Not only the first line, but I want to access all elements sorted by lines
Thank you !
In Octave and MATLAB, data is stored in column-major order which means for your matrix, indices and elements are like this:
You need to take the transpose of the original matrix to access them the way you stated. In Octave, you can directly access them using A.'(1) , A.'(2), A.'(3) etc. In MATLAB, you cannot access them like Octave. So save them in a new matrix or replace the contents of the previous matrix. i.e. A = A.' and then you can use A(1), A(2), A(3) etc to access the desired elements.
A.' or transpose(A) for the given A actually gives:
So now as per the column major order, first, second and third elements are -1, 1 and -2 respectively and so on.

Append vector to 3d matrix in Matlab

I wish to append a row-vector (and later, also a column vector) to an existing x by y by z matrix. So basically "Add a new row (at the "bottom") for each z in the original 3d matrix. Consider the following short Matlab program
appendVector = [1 2 3 4 5]; % Small matrix for brevity. Actual matrices used are much larger.
origMatrix = ones(5,5,3);
appendMatrix = [origMatrix( ... ); appendVector];
My question is: How do I adress (using Matlab-style matrix adressing, not a "manual" C-like loop) origMatrix( ... ) in order to append the vector above? Feel free to also include a suggestion on how to do the same operation for a column-vector (I am thinking that the correct way to do the latter is to simply use the '-operator in Matlab).
A "row" in a 3D matrix is actually a multi-dimensional array.
size(origMatrix(1,:,:))
% 5 3
So to append a row, you would need to append a 5 x 3 array.
toAppend = rand(5, 3);
appendMatrix = cat(1, origMatrix, toAppend);
You could append just a 5 element vector and specify an index for the third dimension. In this case, the value for the "row" for all other indices in the third dimension would be filled with zeros.
appendVector = [1 2 3 4 5];
origMatrix = ones(5,5,3);
appendMatrix = origMatrix;
appendMatrix(end+1, :, 1) = appendVector;
If instead, you want to append the same vector along the third dimension, you could use repmat to turn your vector into a 1 x 5 x 3 array and then append that.
appendVector = repmat([1 2 3 4 5], 1, 1, size(origMatrix, 3));
appendMatrix = cat(1, origMatrix, appendVector);

bsxfun: Dimensions of matrices being concatenated are not consistent

Any one knows where the error is? Many thanks!
beta=randn(50,1);
bsxfun(#(x1,x2) max([x1 x2 x1+x2]), beta, beta')
error message:
Error using horzcat
Dimensions of matrices being concatenated are not consistent.
Error in #(x1,x2)max([x1,x2,x1+x2])
I'm not 100% sure what you want to achieve, but the error is in the transposition of beta as third argument of bsxfun; it works like this:
beta=randn(50,1);
bsxfun(#(x1,x2) max([x1 x2 x1+x2]), beta, beta)
The second and third argument of bsxfun needs to be of the same size to apply element-wise binary operations to it.
Edit: From the manual (http://www.mathworks.de/de/help/matlab/ref/bsxfun.html):
fun can also be a handle to any binary element-wise function not
listed above. A binary element-wise function of the form C = fun(A,B)
accepts arrays A and B of arbitrary, but equal size and returns output
of the same size. Each element in the output array C is the result of
an operation on the corresponding elements of A and B only.
EDIT2: Is this, what you want?
A = rand(1,50);
[x, y] = ndgrid(1:length(A), 1:length(A));
idc = [x(:) y(:)];
allMin = min([A(idc(:,1)) A(idc(:,2)) A(idc(:,1))+A(idc(:,2))]);
First, with the second and third code-line I generate all possible combinations of indices (all pairs i/j), e.g.: If A has 3 entries, idc would look like:
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
and then I'm building up a vector containing the value A(i), A(j) and A(i)+A(j) for each row of entries (i, j) and getting the min of it.
Here's what I got (using two max in bsxfun)
beta = randn(50,1);
res = bsxfun(#(x,y) max( x, max(y, x+y) ), beta, beta');
Verifying using repmat
tmp = max( cat(3, repmat(beta,[1 50]), repmat(beta',[50 1]), ...
repmat(beta,[1 50])+ repmat(beta',[50 1]) ), [], 3);
isequal( tmp, res )

Octave and Matlab "wat" matrix/vector inconsistencies

I've noticed various cases in Matlab and octave where functions accept both matrices and vectors, but doesn't do the same thing with vectors as it does with matrices.
This can be frustrating because when you input a matrix with a variable number of rows/columns, it could be interpreted as a vector and do something you don't expect when the height/width is 1 making for difficult debugging and weird conditional edge cases.
I'll list a few I've found, but I'm curious what others people have run into
(Note: I'm only looking for cases where code accepts matrices as valid input. Anything that raises an exception when a non-vector matrix is given as an argument doesn't count)
1) "diag" can be used to mean diagonal of a matrix or turn a vector into a diagonal matrix
Since the former is generally only used for square matrices this isn't so egregious in matlab, but in Octave it can be particularly painful when Octave interperets a vector beginning with a nonzero element and everything else zeros as a "diagonal matrix" ie
t=eye(3);
size(diag(t(:,3))) == [3,3]
size(diag(t(:,2))) == [3,3]
size(diag(t(:,1))) == [1,1]
2) Indexing into a row-vector with logicals returns a row-vector
Indexing into anything else with logicals returns a column vector
a = 1:3;
b = true(1,3);
size(a(b)) == [1, 3]
a = [a; a];
b = [b; b];
size(a(b)) == [6, 1]
3) Indexing into a vector v with an index vector i returns a vector of the same (row/col) type as v. But if either v or i is a matrix, the return value has the same size as i.
a = 1:3;
b = a';
size(a(b)) == [1, 3]
b = [b,b];
size(a(b)) == [3, 2]
4) max, min, sum etc. operate on the columns of a matrix M individiually unless M is 1xn in which case they operate on M as a single row-vector
a = 1:3
size(max(a)) == [1, 1]
a = [a;a]
size(max(a)) == [1, 3]
max is particularly bad since it can't even take a dimension as an argument (unlike sum)
What other such cases should I watch out for when writing octave/matlab code?
Each language has its own concepts. An important point of this language is to very often think of matrices as an array of vectors, each column an entry. Things will start to make sense then. If you don't want that behavior, use matrix(:) as the argument to those functions which will pass a single vector, rather than a matrix. For example:
octave> a = magic (5);
octave> max (a)
ans =
23 24 25 21 22
octave> max (a(:))
ans = 25
1) This is not true with at least Octave 3.6.4. I'm not 100% sure but may be related related to this bug which has already been fixed.
2) If you index with boolean values, it will considered to be a mask and treated as such. If you index with non-boolean values, then it's treated as the indexes for the values. This makes perfect sense to me.
3) This is not true. The returned has always the same size of the index, independent if it's a matrix or vector. The only exception is that if the index is a vector, the output will be a single row. The idea is that indexing with a single vector/matrix returns something of the same size:
octave> a = 4:7
a =
4 5 6 7
octave> a([1 1])
ans =
4 4
octave> a([1 3])
ans =
4 6
octave> a([1 3; 3 1])
ans =
4 6
6 4
4) max does take dimension as argument at least in Octave. From the 3.6.4 help text of max:
For a vector argument, return the maximum value. For a matrix
argument, return the maximum value from each column, as a row vector,
or over the dimension DIM if defined, in which case Y should be set to
the empty matrix (it's ignored otherwise).
The rest applies like I said on the intro. If you supply a matrix, it will think of each column as a dataset.
1) As pointed out by the other user, this is not true with at Octave >= 3.6.4.
In case 2) the rule is for vectors, return always the same shape of vector, for anything else return a column vector, consider:
>> a = reshape (1:3, 1,1,3)
a(:,:,1) =
1.0000e+000
a(:,:,2) =
2.0000e+000
a(:,:,3) =
3.0000e+000
>> b = true(1,3)
b =
1×3 logical array
1 1 1
>> a(b)
ans(:,:,1) =
1.0000e+000
ans(:,:,2) =
2.0000e+000
ans(:,:,3) =
3.0000e+000
>> a = [a;a]
a(:,:,1) =
1.0000e+000
1.0000e+000
a(:,:,2) =
2.0000e+000
2.0000e+000
a(:,:,3) =
3.0000e+000
3.0000e+000
>> b = [b;b]
b =
2×3 logical array
1 1 1
1 1 1
>> a(b)
ans =
1.0000e+000
1.0000e+000
2.0000e+000
2.0000e+000
3.0000e+000
3.0000e+000
You can see that this makes sense since vectors have a clear 'direction' but other shaped matrices do not when you remove elements. EDIT: actually I just checked and Octave doesn't seem work this way exactly, but probably should.
3) This is consistent with 2). Essentially if you supply a list of indices the direction of the indexed vector is preserved. If you supply indices with a shape like a matrix, the new information is the index matrix shape is used. This is more flexible, since you can always do a(b(:)) to preserve the shape of a if you so wish. You may say it is not consistent, but remember indexing with logicals may reduce the number of elements to be returned, so they cannot be reshaped in this way.
4) As pointed out in a comment, you can specify dimension for max/min to operate on: min(rand(3),[],1) or max(rand(3),[],2), but in this case there are 'legacy' issues with these functions which data back to when they were first created and now are very difficult to change without upsetting people.