When usng rows with LAPACKE_sgetrs, why must ldb=1 (instead of 3, instead of n)? - lapack

We want to solve x for Ax=b,
A=
0 2 3
1 1 -1
0 -1 1
b=
13
0
1
x=
1
2
3
The program below first writes A=P*L*U. It works with columns. It is something like:
float a[3*3]={
0,1,0,
2,1,-1,
3,-1,1
};
float b[8]={
13,
0,
1
lapack_int n=3,lda=3,ldb=3,nrhs=1,info,piv[3];
info= LAPACKE_sgetrf(LAPACK_COL_MAJOR,n,n,a,lda,piv);
info= LAPACKE_sgetrs(LAPACK_COL_MAJOR,'N',n,nrhs,a,lda,piv,b,ldb);
This works. Now I would like to program with rows:
float a[3*3]={
0,2,3,
1,1,-1,
0,-1,1
};
float b[8]={
13,
0,
1
lapack_int n=3,lda=3,ldb=1,nrhs=1,info,piv[3];
info= LAPACKE_sgetrf(LAPACK_ROW_MAJOR,n,n,a,lda,piv);
info= LAPACKE_sgetrs(LAPACK_ROW_MAJOR,'N',n,nrhs,a,lda,piv,b,ldb);
My question is: why must ldb=1 (instead of 3)?

This behavior is due to the wrapper LAPACKE.
If LAPACK_COL_MAJOR is used, the wrapper almost directly calls sgetrs() of LAPACK, as shown in the source of LAPACKE. Hence, the leading dimension ldb of the array b must be equal or higher than the number of rows of the matrix a, that is n=3. Therefore, the requirement is LDB >= max(1,N) as in sgetrs().
One the other hand, if LAPACK_ROW_MAJOR is used, b is transposed. Consequently, the leading dimension of the array ldb is now related to the number of right hand sides nrhs=1. The requirement is now LDB >= max(1,NRHS) as tested on line 59 : if( ldb < nrhs ). Then the array b and the matrix are transposed by calling LAPACKE_sge_trans. Finally, sgetrs() is called using lbd=n and the result is transposed back.

Related

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!

confused about the output of hist

I am confused by the
[m,n]=hist(y,x)
such as
M = [1, 2, 3;
4, 5, 6;
1, 2, 3];
[m,n] = hist(M,1:3)
Which results in
m = 2 0 0
0 2 0
1 1 3
Can someone please explain how m is calculated?
hist actually takes vectors as input arguments, you wrote a matrix, so it just handles your input as if it was several vector-inputs. The output are the number of elements for each container (in your case 1:3, the second argument).
[m,n] = hist([1,2,3;4,5,6;1,2,3],1:3)
treats each column as one input. You put in 3 inputs (# of columns) and you get 3 outputs.
[2 0 1]'
means, for the input [1;4;1] and the bin 1:3 two elements are in bin 1 and one element is in bin 3.
Look at the last column of m, here all three values are in the third bin, which makes sense, since the corresponding vector is [3;6;3], and out of those numbers all have to go into the bin/container 3.

Condition execute for different columns in each row

A = [0,0,1,0,1,0,1,0,0,0;
0,0,0,0,1,0,1,0,0,0;
0,0,1,0,1,0,1,0,0,0];
B = [2,5;
1,6;
3,10];
Expected Output Cell Array:
C = [1,1,1,1; %// 2-3-4, 3-4-5, 4-5, 5
0,0,1,1,1,0; %// 1-2-3, 2-3-4, 3-4-5, 4-5-6, 5-6, 6
1,1,1,1,1,0,0,0]; %// 3-4-5, 4-5-6, 5-6-7, 7-8-9, 8-9-10, 9-10, 10
Matrix B includes which columns should be used to execute the condition on Matrix A. For example, first row of B is 2 and 5; so elements between 2nd 5th column of matrix A should be used to execute the condition. Second row of B is 1 and 6; so elements between 1st 6th column should be used to execute the condition. And so on...
The condition: if sum of successive 3 elements is bigger than or equal to 1 then write 1 to matrix C; otherwise write 0. For example, A includes 0,1,0 as three successive elements (sum is 0+1+0=1), so write 1 to matrix C. Another example, first three elements of A in second row are 0,0,0 (sum is 0), so write 0 to matrix C. And so on...
"Sometimes it can be considered only 1 or 2 successive elements."
For example, condition execution of first row of A ends with 5th column, so only value 5th column should be considered; which is 1. So 1 is written to matrix C.
Explaining the first row of C:
1, since (sum of 2,3,4 elements of A(1,:)) >= 1
1, since (sum of 3,4,5 elements of A(1,:)) >= 1
since max limit is 5, only 2 successive elements are taken here
1, since (sum of 4,5 elements alone of A(1,:)) >= 1
since max limit is 5, only 1 successive element is taken here
1, since (sum of 5th element alone of A(1,:)) >= 1
Without for loop, only with matrix operations, how can I do this complex task? or any trick?
Using mat2cell, cellfun, im2col and any
subMatLen = 3;
%// Converting both A & B matrix to Cell Arrays to perform operations Row-wise
AC = mat2cell(A,ones(1,size(A,1)),size(A,2));
BC = mat2cell(B,ones(1,size(B,1)),size(B,2));
%// Getting only the columns of each rows within the limits specified by Matrix B
%// Also appended with zeros for my own convenience as it wont affect the 'summing' process
out = cellfun(#(x,y) [x(y(1):y(2)),zeros(1,subMatLen-1)],AC, BC, 'uni', 0);
%// Finally taking each 1x3 sliding sub-matrix and returning 1 if `any` of it is non-zero
%// which is equivalent to summing and checking whether they are >= 1
out = cellfun(#(x) any(im2col(x, [1,subMatLen], 'sliding')), out, 'uni', 0);
Your Sample Input:
A = [0,0,1,0,1,0,1,0,0,0;
0,0,0,0,1,0,1,0,0,0;
0,0,1,0,1,0,1,0,0,0];
B = [2,5;
1,6;
3,10];
Output:
>> celldisp(out)
out{1} =
1 1 1 1
out{2} =
0 0 1 1 1 0
out{3} =
1 1 1 1 1 0 0 0
If you want them as a single row or column matrix, you could add this to the bottom of the code:
out = cat(2,out{:})
or
out = (cat(2,out{:})).'

Eliminating zeros in a matrix - Matlab

Hi I have the following matrix:
A= 1 2 3;
0 4 0;
1 0 9
I want matrix A to be:
A= 1 2 3;
1 4 9
PS - semicolon represents the end of each column and new column starts.
How can I do that in Matlab 2014a? Any help?
Thanks
The problem you run into with your problem statement is the fact that you don't know the shape of the "squeezed" matrix ahead of time - and in particular, you cannot know whether the number of nonzero elements is a multiple of either the rows or columns of the original matrix.
As was pointed out, there is a simple function, nonzeros, that returns the nonzero elements of the input, ordered by columns. In your case,
A = [1 2 3;
0 4 0;
1 0 9];
B = nonzeros(A)
produces
1
1
2
4
3
9
What you wanted was
1 2 3
1 4 9
which happens to be what you get when you "squeeze out" the zeros by column. This would be obtained (when the number of zeros in each column is the same) with
reshape(B, 2, 3);
I think it would be better to assume that the number of elements may not be the same in each column - then you need to create a sparse array. That is actually very easy:
S = sparse(A);
The resulting object S is a sparse array - that is, it contains only the non-zero elements. It is very efficient (both for storage and computation) when lots of elements are zero: once more than 1/3 of the elements are nonzero it quickly becomes slower / bigger. But it has the advantage of maintaining the shape of your matrix regardless of the distribution of zeros.
A more robust solution would have to check the number of nonzero elements in each column and decide what the shape of the final matrix will be:
cc = sum(A~=0);
will count the number of nonzero elements in each column of the matrix.
nmin = min(cc);
nmax = max(cc);
finds the smallest and largest number of nonzero elements in any column
[i j s] = find(A); % the i, j coordinates and value of nonzero elements of A
nc = size(A, 2); % number of columns
B = zeros(nmax, nc);
for k = 1:nc
B(1:cc(k), k) = s(j == k);
end
Now B has all the nonzero elements: for columns with fewer nonzero elements, there will be zero padding at the end. Finally you can decide if / how much you want to trim your matrix B - if you want to have no zeros at all, you will need to trim some values from the longer columns. For example:
B = B(1:nmin, :);
Simple solution:
A = [1 2 3;0 4 0;1 0 9]
A =
1 2 3
0 4 0
1 0 9
A(A==0) = [];
A =
1 1 2 4 3 9
reshape(A,2,3)
ans =
1 2 3
1 4 9
It's very simple though and might be slow. Do you need to perform this operation on very large/many matrices?
From your question it's not clear what you want (how to arrange the non-zero values, specially if the number of zeros in each column is not the same). Maybe this:
A = reshape(nonzeros(A),[],size(A,2));
Matlab's logical indexing is extremely powerful. The best way to do this is create a logical array:
>> lZeros = A==0
then use this logical array to index into A and delete these zeros
>> A(lZeros) = []
Finally, reshape the array to your desired size using the built in reshape command
>> A = reshape(A, 2, 3)

Appending "in a way" multiple matrices

Say I have matrices A and B. I want to create a third matrix C where
A = [1,0,0,1]
B = [1,0,1,0]
C = [11, 00, 01, 10]
Is there such a function in Matlab? If not how would I go about creating a function that does this?
Edit: C is not literal numbers. They are concatenated values of A,B element-wise.
Edit2: The actual problem I am dealing with is I have 10 large matrices of the size [x,y] where x,y > 1000. The elements in these matrices all have 0s and 1s. No other number. What I need to accomplish is have the element [x1,y1] in matrix 1 to be appended to the element in [x1,y1] of matrix 2. and then that value to be appended to [x1,y1] of matrix 3.
Another example:
A = [1,1,1,1;
0,0,0,0]
B = [0,0,0,0;
1,1,1,1]
C = [1,0,1,0;
0,1,0,1]
And I need a matrix D where
D = [101, 100, 101, 101; 010, 011, 010, 011]
I recommend that you avoid manipulating binary numbers as strings where possible. It seems tempting, and there are cases where matlab provides a more elegant solution if you treat a binary number as a string, but you cannot perform binary arithmetic on strings. You can always work with integers as if they were binary (they are stored as bits in your machine after all), and then just display them as binary numbers using dec2bin when necessary.
A = [1,0,0,1]
B = [1,0,1,0]
C = bitshift(A,1)+B;
display(dec2bin(C));
In the other case you show in your question you could use:
A = [1,1,1,1; 0,0,0,0];
B = [0,0,0,0; 1,1,1,1];
C = [1,0,1,0; 0,1,0,1];
D = bitshift(A,2) + bitshift(B,1) + C;
You can also convert an arbitrary length row vector of zeros and ones into its decimal equivalent by defining this simple function:
mat2dec = #(x) x*2.^(size(x,2)-1:-1:0)';
This will also work for matrices too. For example
>> M = [0 0 1; 0 1 1; 0 1 0; 1 1 0; 1 1 1; 1 1 0; 1 0 0];
>> dec2bin(mat2dec(M))
ans =
001
011
010
110
111
110
100
In my experience, treating binary numbers as strings obfuscates your code and is not very flexible. For example, try adding two binary "strings" together. You have to use bin2dec every time, so why not just leave the numbers as numbers until you want to display them? You have already run into some of the issues caused by strings of different lengths too. You will be amazed how one simple change can break everything when treating numbers as strings. The worst part is that an algorithm may work great for one set of data and not for another. If all I test with is two-bit binary numbers and a three-bit number somehow sneaks its way in, I may not see an error, but my results will be inexplicably incorrect. I realize that this is a very subjective issue, and I think that I definitely stand in the minority on StackOverflow, so take it for what it's worth.
It depends how you want the output formatted. You could apply bitshift to the numerical values and convert to binary:
>> b = dec2bin(bitshift(A,1)+B)
b =
11
00
01
10
For a general matrix Digits:
>> Digits
Digits =
1 0 0 0
0 1 0 0
1 0 1 1
1 1 0 0
1 0 0 0
1 0 1 1
1 1 0 0
1 0 1 0
0 1 1 1
0 1 1 1
>> Ddec = D*(2.^(size(D,2)-1:-1:0))'; % dot product
>> dec2bin(Ddec)
ans =
1000
0100
1011
1100
1000
1011
1100
1010
0111
0111
Another way to write that is dec2bin(sum(D .* repmat(2.^(size(D,2)-1:-1:0),size(D,1),1),2)).
For your larger problem, with 10 large matrixes (say M1, M2, ..., M10), you can build the starting Digits matrix by:
Digits = [M1(:) M2(:) M3(:) M4(:) M5(:) M6(:) M7(:) M8(:) M9(:) M10(:)];
If that is reverse the order of the digits, just do Digits = fliplr(Digits);.
If you would rather not reshape anything you can compute the matrix decimal values from the matrices of digits as follows:
M = cat(3,A,B,C);
Ddec = sum(bsxfun(#times,M,permute(2.^(size(M,3)-1:-1:0),[1 3 2])),3)
I see some quite extensive answers so perhaps this is thinking too simple, but how about just this assuming you have vectors of ones and zeros representing your binary numbers:
A = [1,0,0,1];
B = [1,0,1,0];
C = 10*A + B
This should give you the numbers you want, you may want to add leading zeros. Of course this method can easily be expanded to append multiple matrices, you just need to make sure there is a factor (base) 10 between them before adding.