Compute matrix product in base sas ( not using IML) - matrix

In order to Compute the product of 2 matrices I am using this method:
First I put my matrices in the long format (col,row,value)
I use proc sql to compute the product of 2 matrices.
I use proc transpose to put the result of precedent step in the wide format.
My question is there is simpler method? Or at least how can I simplify my code?
here my code:
/* macro to put a matrix in the long format*/
%macro reshape(in_A = , ou_A= );
data &ou_A.;
set &in_A.;
array arr_A{*} _numeric_;
row = _n_;
do col = 1 to dim(arr_A);
value = arr_A{col};
output;
end;
keep row col value;
run;
%mend;
%macro prod_mat( in_A = , in_B= ,ou_AB =);
/* put the matrix in the long format */
%reshape(in_A=&in_A.,ou_A=lA);
%reshape(in_A=&in_B.,ou_A=lB);
/* compute product */
PROC SQL ;
CREATE TABLE PAB AS
SELECT lA.row, lB.col, SUM(lA.value * lB.value) as value
FROM lA JOIN lB ON lA.col = lB.row
GROUP BY lA.row, lB.col;
QUIT;
/* reshape the output to the wide format */
proc transpose data=PAB out=&ou_AB.(DROP=_name_) prefix=x;
by row ;
id col;
var value;
run;
%mend;
data A ;
input x1 x2 x3;
datalines ;
1 2 3
3 4 4
5 6 9
;
data B ;
input x1 x2;
datalines ;
1 2
3 4
4 5
;
%prod_mat(in_A =A,in_B=B,ou_AB=AB)

Well, here's my variant. It's not that the code itself is shorter then yours, but for big matrices it'll work faster because it avoids using SQL-join with cartesian product of all elements.
The main idea - full join (cartesian product) of rows of A and transposed B and then multiplying corresponding columns. E.g. in case of 3x3 and 3x2 matrices, we'll need to:
1) multiply and sum up in each row of the merged dataset column1*column4+column2*column5+column3*column6;
2) repeat it for the second row;
3) output the both values in one row.
%macro prod_mat_merge(in_A =,in_B=,ou_AB=);
/*determine number of rows and columns in the 2nd matrix*/
%let B_id=%sysfunc(open(&in_B));
%let B_rows=%sysfunc(attrn(&B_id,nobs));
%let B_cols=%sysfunc(attrn(&B_id,nvars));
%let rc=%sysfunc(close(&B_id));
/*transpose the 2nd matrix*/
proc transpose data=&in_B out=t&in_B(drop=_:);run;
/*making Cartesian product of the 1st and transposed 2nd matrices*/
data &ou_AB;
do until(eofA);
set &in_A end=eofA;
do i=1 to n;
set t&in_B nobs=n point=i;
output;
end;
end;
run;
/*multiplication*/
data &ou_AB;
/*new columns for products, equal to number of columns in the 2nd matrix*/
array p[&B_cols];
do j=1 to &B_cols;
p[j]=0;
set &ou_AB;
array col _ALL_;
/*multiply corresponding pairs of columns*/
do i=&B_cols+2 to &B_cols+1+&B_rows;
p[j]+col[i]*col[i+&B_rows];
end;
end;
output;
keep p:;
run;
%mend prod_mat_merge;
I've tested the both methods multiplying two random matrices 100x100 each. The method with reshaping and SQL-join takes ~1.5 sec, while the method with merging takes ~0.2 sec.

Related

Algorithm to get cell row and column in table

I am building a function which will allow the user to choose a cell in a dynamically created table, by passing in an integer.
I.e., if I have a 3x3 grid, and the user passes in the number 4, the program should know that he wants the 1st cell in the second row. (the cells will be counted by rows)
As I mentioned, the table is created dynamically and can be any size.
I can do this with a bunch of if statements, but I was wondering if there is maybe an algorithm to figure this out easily.
(P.S. I am using a very basic programming language, so please, no fancy pythonic math functions... :) )
All you need to do is divide by columns and find the remainder. Something like this:
input = 4
row = floor(input / columns)
column = input % columns
Assuming the output should be 1 based index
input = n, k // n * n grid, k number
row = floor( (k - 1) / n ) + 1;
col = k % n;
if(col == 0) {
col += n;
}
// print row, col

Convert table to matrix in Lua

I want to perform matrix related operations such as multiplication, transpose and inversion of a matrix. I could find out matrix support in Lua here
I have a table which I want to convert to matrix. The table has following structure-
for i=1,myTableSize[1],1 do
str=''
for j=1,myTableSize[2],1 do
if #str~=0 then
str=str..', '
end
str=str..string.format("%.1e",myTable[(j-1)*myTableSize[1]+i])
end
print(str)
end
I am looking for something like myMatrix=matrix(myTable) or myMatrix=matrix.init(myTable), which is compatible with Lua Matrix.
-
Thanks
Try (not tested)
local function tableToMatrix(table, rows cols)
local myMatrix = matrix:new(rows, cols) -- function returns matrix of size rows x cols
for i=1, rows do
for j=1, cols do
matrix.setelement(myMatrix, i, j, table[(i - 1) * cols + j] )
end
end
return matrix
end

Reshape vector to matrix with column-wise zero padding in matlab

for an input matrix
in = [1 1;
1 2;
1 3;
1 4;
2 5;
2 6;
2 7;
3 8;
3 9;
3 10;
3 11];
i want to get the output matrix
out = [1 5 8;
2 6 9;
3 7 10;
4 0 11];
meaning i want to reshape the second input column into an output matrix, where all values corresponding to one value in the first input column are written into one column of the output matrix.
As there can be different numbers of entries for each value in the first input column (here 4 values for "1" and "3", but only 3 for "2"), the normal reshape function is not applicable. I need to pad all columns to the maximum number of rows.
Do you have an idea how to do this matlab-ish?
The second input column can only contain positive numbers, so the padding values can be 0, -x, NaN, ...
The best i could come up with is this (loop-based):
maxNumElem = 0;
for i=in(1,1):in(end,1)
maxNumElem = max(maxNumElem,numel(find(in(:,1)==i)));
end
out = zeros(maxNumElem,in(end,1)-in(1,1));
for i=in(1,1):in(end,1)
tmp = in(in(:,1)==i,2);
out(1:length(tmp),i) = tmp;
end
Either of the following approaches assumes that column 1 of in is sorted, as in the example. If that's not the case, apply this initially to sort in according to that criterion:
in = sortrows(in,1);
Approach 1 (using accumarray)
Compute the required number of rows, using mode;
Use accumarray to gather the values corresponding to each column, filled with zeros at the end. The result is a cell;
Concatenate horizontally the contents of all cells.
Code:
[~, n] = mode(in(:,1)); %//step 1
out = accumarray(in(:,1), in(:,2), [], #(x){[x; zeros(n-numel(x),1)]}); %//step 2
out = [out{:}]; %//step 3
Alternatively, step 1 could be done with histc
n = max(histc(in(:,1), unique(in(:,1)))); %//step 1
or with accumarray:
n = max(accumarray(in(:,1), in(:,2), [], #(x) numel(x))); %//step 1
Approach 2 (using sparse)
Generate a row-index vector using this answer by #Dan, and then build your matrix with sparse:
a = arrayfun(#(x)(1:x), diff(find([1,diff(in(:,1).'),1])), 'uni', 0); %//'
out = full(sparse([a{:}], in(:,1), in(:,2)));
Introduction to proposed solution and Code
Proposed here is a bsxfun based masking approach that uses the binary operators available as builtins for use with bsxfun and as such I would consider this very appropriate for problems like this. Of course, you must also be aware that bsxfun is a memory hungry tool. So, it could pose a threat if you are dealing with maybe billions of elements depending also on the memory available for MATLAB's usage.
Getting into the details of the proposed approach, we get the counts of each ID from column-1 of the input with histc. Then, the magic happens with bsxfun + #le to create a mask of positions in the output array (initialized by zeros) that are to be filled by the column-2 elements from input. That's all you need to tackle the problem with this approach.
Solution Code
counts = histc(in(:,1),1:max(in(:,1)))'; %//' counts of each ID from column1
max_counts = max(counts); %// Maximum counts for each ID
mask = bsxfun(#le,[1:max_counts]',counts); %//'# mask of locations where
%// column2 elements are to be placed
out = zeros(max_counts,numel(counts)); %// Initialize the output array
out(mask) = in(:,2); %// place the column2 elements in the output array
Benchmarking (for performance)
The benchmarking presented here compares the proposed solution in this post against the various methods presented in Luis's solution. This skips the original loopy approach presented in the problem as it appeared to be very slow for the input generated in the benchmarking code.
Benchmarking Code
num_ids = 5000;
counts_each_id = randi([10 100],num_ids,1);
num_runs = 20; %// number of iterations each approach is run for
%// Generate random input array
in = [];
for k = 1:num_ids
in = [in ; [repmat(k,counts_each_id(k),1) rand(counts_each_id(k),1)]];
end
%// Warm up tic/toc.
for k = 1:50000
tic(); elapsed = toc();
end
disp('------------- With HISTC + BSXFUN Masking approach')
tic
for iter = 1:num_runs
counts = histc(in(:,1),1:max(in(:,1)))';
max_counts = max(counts);
out = zeros(max_counts,numel(counts));
out(bsxfun(#le,[1:max_counts]',counts)) = in(:,2);
end
toc
clear counts max_counts out
disp('------------- With MODE + ACCUMARRAY approach')
tic
for iter = 1:num_runs
[~, n] = mode(in(:,1)); %//step 1
out = accumarray(in(:,1), in(:,2), [], #(x){[x; zeros(n-numel(x),1)]}); %//step 2
out = [out{:}];
end
toc
clear n out
disp('------------- With HISTC + ACCUMARRAY approach')
tic
for iter = 1:num_runs
n = max(histc(in(:,1), unique(in(:,1))));
out = accumarray(in(:,1), in(:,2), [], #(x){[x; zeros(n-numel(x),1)]}); %//step 2
out = [out{:}];
end
toc
clear n out
disp('------------- With ARRAYFUN + Sparse approach')
tic
for iter = 1:num_runs
a = arrayfun(#(x)(1:x), diff(find([1,diff(in(:,1).'),1])), 'uni', 0); %//'
out = full(sparse([a{:}], in(:,1), in(:,2)));
end
toc
clear a out
Results
------------- With HISTC + BSXFUN Masking approach
Elapsed time is 0.598359 seconds.
------------- With MODE + ACCUMARRAY approach
Elapsed time is 2.452778 seconds.
------------- With HISTC + ACCUMARRAY approach
Elapsed time is 2.579482 seconds.
------------- With ARRAYFUN + Sparse approach
Elapsed time is 1.455362 seconds.
slightly better, but still uses a loop :(
out=zeros(4,3);%set to zero matrix
for i = 1:max(in(:,1)); %find max in column 1, and loop for that number
ind = find(in(:,1)==i); %
out(1: size(in(ind,2),1),i)= in(ind,2);
end
don't know if you can avoid the loop...

Matrix input based on random value output (Matlab)

I am looking to use the output of a random value to choose the column which will be input into a new matrix, called Matrix1.
I have something like the following:
a = [1 2 3 4; 5 3 6 2; 9 8 1 4];
n = length(a(1,:))-1;
RandomValue = round(rand()*n+1);
Matrix1 = [];
L=3;
for i=n:-1:1
RandomValue
if RandomValue < L
Matrix1 = [a(:,i) Matrix1];
a(:, i) = [];
Matrix1
end
end
E.g. If the random value is 2, I would like to place [2;3;8] into the Matrix1 (based on the value of the first row). How could I modify the code, so instead of i it is that Randomvalue number?
I don't follow you exactly, but I can't see why some variant of
Matrix1 = [a(:,round(rand()*n+1)) Matrix1]
isn't appropriate. Better than rounding a rand would be to use the randi function which returns a pseudo-random integer, maybe
Matrix1 = [a(:,randi(n)) Matrix1]
But if, as #angainor has suggested, you are trying to permute the columns of your input matrix, then look to the permute function.

transforming a matrix into a vector along its diagonals

im not not a programmer, i just need to solve something numerically in matlab.
i need a function to make the following transformation for any square matrix:
from
row 1: 1 2 3
row 2: 4 5 6
row 3: 7 8 9
to
1 4 2 7 5 3 8 6 9
ie write the matrix in a vector along its diagonals from left to top right.
any ideas please?
i really need a little more help though:
say the matrix that we have transformed into the vector, has entries denoted by M(i,j), where i are rows and j columns. now i need to be able to find out from a position in the vector, the original position in the matrix, i.e say if its 3rd entry in the vector, i need a function that would give me i=1 j=2. any ideas please? im really stuck on this:( thanks
This is quite similar to a previous question on traversing the matrix in a zigzag order. With slight modification we get:
A = rand(3); %# input matrix
ind = reshape(1:numel(A), size(A)); %# indices of elements
ind = spdiags(fliplr(ind)); %# get the anti-diagonals
ind = ind(end:-1:1); %# reverse order
ind = ind(ind~=0); %# keep non-zero indices
B = A(ind); %# get elements in desired order
using the SPDIAGS function. The advantage of this is that it works for any arbitrary matrix size (not just square matrices). Example:
A =
0.75127 0.69908 0.54722 0.25751
0.2551 0.8909 0.13862 0.84072
0.50596 0.95929 0.14929 0.25428
B =
Columns 1 through 6
0.75127 0.2551 0.69908 0.50596 0.8909 0.54722
Columns 7 through 12
0.95929 0.13862 0.25751 0.14929 0.84072 0.25428
Here's one way to do this.
%# n is the number of rows (or cols) of the square array
n = 3;
array = [1 2 3;4 5 6;7 8 9]; %# this is the array we'll reorder
%# create list of indices that allow us
%# to read the array in the proper order
hh = hankel(1:n,n:(2*n-1)); %# creates a matrix with numbered antidiagonals
[dummy,sortIdx] = sort(hh(:)); %# sortIdx contains the new order
%# reorder the array
array(sortIdx)
ans =
1 4 2 7 5 3 8 6 9
You can convert your matrix to a vector using the function HANKEL to generate indices into the matrix. Here's a shortened version of Jonas' answer, using M as your sample matrix given above:
N = size(M,1);
A = hankel(1:N,N:(2*N-1));
[junk,sortIndex] = sort(A(:));
Now, you can use sortIndex to change your matrix M to a vector vec like so:
vec = M(sortIndex);
And if you want to get the row and column indices (rIndex and cIndex) into your original matrix that correspond to the values in vec, you can use the function IND2SUB:
[rIndex,cIndex] = ind2sub(N,sortIndex);
A=[1,2,3;4,5,6;7,8,9];
d = size(A,1);
X=[];
for n = 1:2*size(A,1) - 1
j = min(n,d); i = (n+1)-(j);
X = cat(2,X,diag(flipud(A(i:j,i:j)))');
end
X
X =
1 4 2 7 5 3 8 6 9
You can generate the diagonals in this way:
for i = -2:2
diag(flipud(a), i)
end
I don't know whether this is the optimal way to concatenate the diagonals:
d = []
for i = -2:2
d = vertcat(d, diag(flipud(a), i))
end
(I tested it in octave, not in matlab)

Resources