Fluorite | Level 6

## IML how to calculate new matrix based on values of two matrices

I am looking to generate a matrix that's based on two others (letters are column names and numbers are row numbers to visualize😞

X = {u1 h1 a1, u2 h2 a2, u3 h3 a3};

Y = {b1 f1 r1, b2 f2 r2};

what I am trying to come up with is this:

Z = {(b1-u1)+(f1-h1)+(r1-a1) (b2-u1)+(f2-h1)+(r2-a1)

, (b1-u2)+(f1-h2)+(r1-a2) (b2-u2)+(f2-h2)+(r2-a2)

, (b1-u3)+(f1-h3)+(r1-a3) (b2-u3)+(f2-h3)+(r2-a3)

, (b1-u4)+(f1-h4)+(r1-a4) (b2-u4)+(f2-h4)+(r2-a4)}

what's the most efficient way to go about this? I can only think of do-loops for each expression within parenthesis to create submatrices and then add them together? has any one done something similar. please point me in the right direction. many thanks in advance!

1 ACCEPTED SOLUTION

Accepted Solutions
SAS Super FREQ

## Re: IML how to calculate new matrix based on values of two matrices

I assume you made a mistake and the z[1,2] element should be -5 and the Z[3,1] element should be -9.

It looks like you want to form the matrices

M1 = Y[1, ] - X;

M2 = Y[2,] - X;

and then sum the rows of these matrices to form the columns of Z.

For this example, you can use this one-liner, which uses the '+' subscript reduction operator to get the row sums:

``````proc iml;
X = {2 7 4,
3 2 1,
5 9 3};
Y = {1 3 4,
2 5 1};

Z = ((Y[1,] - X)[ ,+]) ||
((Y[2,] - X)[ ,+]);
print Z;``````

If you have an arbitrary number of rows in Y, you can loop over the rows of Y like this:

``````free Z;
do i = 1 to nrow(Y);
Z = Z || (Y[i,] - X)[ ,+];
end;
print Z;``````

It might also be possible to get this result by using matrix operators instead of a loop. Maybe by using a strategic application of the Kronecker product? If so, @IanWakeling might have a suggestion.

10 REPLIES 10
SAS Super FREQ

## Re: IML how to calculate new matrix based on values of two matrices

> I am looking to generate a matrix that's based on two others (letters are column names and
> numbers are row numbers to visualize

X = {u1 h1 a1, u2 h2 a2, u3 h3 a3};

Y = {b1 f1 r1, b2, f2, r2};

I don't understand. Can you provide numbers for the "two other" matrices and what you expect for X and Y? I don't even know what "two other" matrices you are talking about. It looks like the matrices are u, h, a, b, f, and r.

X = u || h || a;

Y = b || f || r;

Fluorite | Level 6

## Re: IML how to calculate new matrix based on values of two matrices

my apologies - I made a mistake with extra commas in the second matrix. I corrected the original post. here is what I am after in numbers

X = {2 7 4, 3 2 1, 5 9 3}

Y = {1 3 4, 2 5 1}

I am trying to have Z calculate like so:

Z = {(1-2)+(3-7)+(4-4) (2-2)+(5-7)+(4-1)

,(1-3)+(3-2)+(4-1) (2-3)+(5-2)+(1-1)

,(1-5)+(3-9)+(4-3) (2-5)+(5-9)+(1-3)}

so result looks like this:

Z = {-5 1, 2 2, 9 -9}

SAS Super FREQ

## Re: IML how to calculate new matrix based on values of two matrices

I assume you made a mistake and the z[1,2] element should be -5 and the Z[3,1] element should be -9.

It looks like you want to form the matrices

M1 = Y[1, ] - X;

M2 = Y[2,] - X;

and then sum the rows of these matrices to form the columns of Z.

For this example, you can use this one-liner, which uses the '+' subscript reduction operator to get the row sums:

``````proc iml;
X = {2 7 4,
3 2 1,
5 9 3};
Y = {1 3 4,
2 5 1};

Z = ((Y[1,] - X)[ ,+]) ||
((Y[2,] - X)[ ,+]);
print Z;``````

If you have an arbitrary number of rows in Y, you can loop over the rows of Y like this:

``````free Z;
do i = 1 to nrow(Y);
Z = Z || (Y[i,] - X)[ ,+];
end;
print Z;``````

It might also be possible to get this result by using matrix operators instead of a loop. Maybe by using a strategic application of the Kronecker product? If so, @IanWakeling might have a suggestion.

Fluorite | Level 6

## Re: IML how to calculate new matrix based on values of two matrices

Thank you! This is almost there!

I just can't figure out why calculation is always on the first element of X and Y

here is Z after calculating it both ways (loop or no loop, same result)

Z
-5        -5
2         2
-9        -9

Z
-5        -5
2         2
-9        -9
SAS Super FREQ

## Re: IML how to calculate new matrix based on values of two matrices

Because both rows of Y sum to 8. You can further simplify the computation to become

``````rowSumX = X[ ,+];    /* sum of rows of X */
Z = Y[1 ,+] - rowSumX  ||
Y[1 ,+] - rowSumX;
print Z;
``````
Fluorite | Level 6

## Re: IML how to calculate new matrix based on values of two matrices

this is great! Thank you so much!

Barite | Level 11

## Re: IML how to calculate new matrix based on values of two matrices

You could apply the Kroneker product (the @ operator) and avoid the loop as follows:

``````diff = Y @ j(nrow(X), 1) - j(nrow(Y), 1) @ X;
Z = shapecol( diff[ ,+], nrow(X));
print Z;``````

It is not as easy to see what is going on, so you may prefer Rick's solution if others need to use your code.

Fluorite | Level 6

## Re: IML how to calculate new matrix based on values of two matrices

Thank you! I need to study up this approach - not easy to see.

I am just curious - how to make this work on multiplication?

a = {1 2 3}

b={1 2 3, 4 5 6, 7 8 9}

to get to:

c={1 4 9, 4 10 18, 7 16 27}

Fluorite | Level 6

## Re: IML how to calculate new matrix based on values of two matrices

never mind - this is just element wise multiplication. I am thinking too much I suppose. 🙂

Barite | Level 11

## Re: IML how to calculate new matrix based on values of two matrices

Indeed it is elementwise multiplication, but if you want the row sums of c, which was part of the original problem, then the whole process simplifies to normal matrix multiplication:

``````a = {1 2 3};
b = {1 2 3, 4 5 6, 7 8 9};
d = b * a`;``````
From The DO Loop