Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
KEIRA
Frequent Visitor

Matrix Multiplication

Hello everyone,
I really need your help.
I have two matrices and I want to multiply the matrices with each other.
I found a way to do it, as you can see in the picture:
EX-1.PNG

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


but the matrix written in the test file only works on physical tables.
The matrices on my real data are virtual tables (My Data File):
EX-2.PNG
and I need your help to find a way to multiply these matrices with each other.
Can anyone help me? 😞
Both files are attached here:
Test File
My Data

1 ACCEPTED SOLUTION

I think I've got it and it's simpler than I initially anticipated.

Matrix Product = 
VAR _C1 = SELECTEDVALUE ( H1_CurrencyList[C1] )
VAR _C2 = SELECTEDVALUE ( H2_CurrencyList[C2] )
VAR _Matrix_ =
    ADDCOLUMNS (
        ALL ( H1_CurrencyList[C1] ),
        "Row_1",
            VAR _C = H1_CurrencyList[C1]
            RETURN
                CALCULATE (
                    [Covariance],
                    H1_CurrencyList[C1] = _C1,
                    H2_CurrencyList[C2] = _C
                ),
        "Col_2",
            VAR _C = H1_CurrencyList[C1]
            RETURN
                CALCULATE (
                    [Cross Weights],
                    H1_CurrencyList[C1] = _C,
                    H2_CurrencyList[C2] = _C2
                )
    )
RETURN
    SUMX ( _Matrix_, [Row_1] * [Col_2] )

Having a square matrix that's a cross product of a list of currencies with itself gives a nice solution that only requires one evaluation each of [Covariance] and [Cross Weights] per currency per cell in the result matrix (each of the N^2 result cells requires 2N measure calls for N currencies).

 

This is simpler than my comment on the gallery post I mentioned previously since I don't need to load the entire matrices, just the relevant row & column from each one. The main difficulty there is just setting up the indexing and filtering for the parts needed. The key logic in both is the same sum product.

View solution in original post

20 REPLIES 20
AlexisOlson
Super User
Super User

It looks like you found my StackOverflow post.

 

I'm interested in helping (writing this as a measure instead of a calculated table sound like a fun challenge) but the files you've linked to appear to have been deleted.

AlexisOlson_0-1661461638205.png

@AlexisOlson here are my current WIP versions

I think I've got it and it's simpler than I initially anticipated.

Matrix Product = 
VAR _C1 = SELECTEDVALUE ( H1_CurrencyList[C1] )
VAR _C2 = SELECTEDVALUE ( H2_CurrencyList[C2] )
VAR _Matrix_ =
    ADDCOLUMNS (
        ALL ( H1_CurrencyList[C1] ),
        "Row_1",
            VAR _C = H1_CurrencyList[C1]
            RETURN
                CALCULATE (
                    [Covariance],
                    H1_CurrencyList[C1] = _C1,
                    H2_CurrencyList[C2] = _C
                ),
        "Col_2",
            VAR _C = H1_CurrencyList[C1]
            RETURN
                CALCULATE (
                    [Cross Weights],
                    H1_CurrencyList[C1] = _C,
                    H2_CurrencyList[C2] = _C2
                )
    )
RETURN
    SUMX ( _Matrix_, [Row_1] * [Col_2] )

Having a square matrix that's a cross product of a list of currencies with itself gives a nice solution that only requires one evaluation each of [Covariance] and [Cross Weights] per currency per cell in the result matrix (each of the N^2 result cells requires 2N measure calls for N currencies).

 

This is simpler than my comment on the gallery post I mentioned previously since I don't need to load the entire matrices, just the relevant row & column from each one. The main difficulty there is just setting up the indexing and filtering for the parts needed. The key logic in both is the same sum product.

Yes, I saw your StackOverflow solution and I love your answer.
Wow amazing, A very good way to solve the case.
Congratulations!
Everyone where I asked this question told me that it is almost "impossible" to do this (I mean, I'd have to write long code and stuff...). I found a way to solve this problem and left this post - waiting for someone  who likes to do "impossible" - glad to see you here too.
Thank you very much for your solution and help.

I found a solution that's even shorter by taking advantage of the evaluation context.

 

It's easiest if I have an independent currency dimension Dim_Currency[CUR]:

Matrix Product = 
SUMX (
    VALUES ( Dim_Currency[CUR] ),
    CALCULATE ( [Covariance],    TREATAS ( { Dim_Currency[CUR] }, H2_CurrencyList[C2] ) ) *
    CALCULATE ( [Cross Weights], TREATAS ( { Dim_Currency[CUR] }, H1_CurrencyList[C1] ) )
)

 

Without the independent column (i.e. if I used ALL ( H1_CurrencyList[C1]) for the first argument), the data lineage of the column being iterated over overwrites the evaluation context during the context transition induced by CALCULATION (which is why I had to specify _C1 and _C2 in filter arguments for my previous solution).

 

After reviewing the SQLBI data lineage article, I realized I can skip the need for a new independent table by breaking the data lineage with an empty string concatenation. Thus the previous DAX can be replaced with this:

Matrix Product = 
SUMX (
    SELECTCOLUMNS ( ALL ( H1_CurrencyList[C1] ), "CUR", H1_CurrencyList[C1] & "" ),
    CALCULATE ( [Covariance],    TREATAS ( { [CUR] }, H2_CurrencyList[C2] ) ) *
    CALCULATE ( [Cross Weights], TREATAS ( { [CUR] }, H1_CurrencyList[C1] ) )
)

Not sure if this resulting in the correct output.  Neither ALL nor VALUES is guaranteeing a sort order, and you may risk multiplying the wrong elements. (also keep in mind that matrix multiplication is not commutative)  Here is an variation of a measure that is horribly inefficient due to the cross join (i couldn't get the naturalinnerjoin to work) but it does produce the correct output.

 

 

Matrix Product Measure = 
        SUMX (
            FILTER (
                CROSSJOIN ( GROUPBY ( MatrixA, [ca], [va] ), GROUPBY ( Matrixb, [rb], [vb] ) ),
                [ca] = [rb]
            ),
            [va] * [vb]
        )

 

 The visual above it uses your version and it comes out a bit too high.

@lbendlin You didn't quite implement it correctly.

 

This is what you had:

Matrix Product = 
SUMX (
    SELECTCOLUMNS ( ALL ( MatrixA[ra] ), "Col", MatrixA[ra] & "" ),
    CALCULATE ( sum(MatrixA[va]), TREATAS ( { [Col] }, MatrixB[cb] ) ) *
    CALCULATE ( sum(MatrixB[vb]), TREATAS ( { [Col] }, MatrixA[ra] ) )
)

 

This is a corrected version:

Matrix Product = 
SUMX (
    SELECTCOLUMNS ( ALL ( MatrixA[ra] ), "Col", MatrixA[ra] & "" ),
    CALCULATE ( SUM ( MatrixA[va] ), TREATAS ( { [Col] }, MatrixA[ca] ) ) *
    CALCULATE ( SUM ( MatrixB[vb] ), TREATAS ( { [Col] }, MatrixB[rb] ) )
)

 

yes, that fixed it.  Now the question is which of the many implementations is the most efficient. 🙂

 

lbendlin_0-1661786322533.png

lbendlin_1-1661786353074.png

For example changing your ALL to ALLSELECTED  seems to improve performance too.

Ok, with your lineage breaker trick I got the NaturalInnerJoin to work

 

Mv2 = SUMX (
   NATURALINNERJOIN(SELECTCOLUMNS(MatrixA,"c",[ca]+0,"va",[va]), SELECTCOLUMNS ( MatrixB, "c",[rb]+0, "vb",[vb] ) ),
   [va] * [vb]
)

Here is another solution:
Covar x CW_measure.png

Matrix multiplication is only deterministic if the  number of columns in the first matrix matches the number of rows in the second matrix. By using a left join you are bending the rules.

@lbendlin Thanks. I'll take a look.

 

You may also be interested in the comment I just left on @Greg_Deckler's gallery post here:
https://community.powerbi.com/t5/Quick-Measures-Gallery/MMULT/m-p/630231

KEIRA
Frequent Visitor

Yes, the result of matrix multiplication must be scalar (it cannot be a table as in the test file). When I drop this measure into columns C1 and C2 - I should get a matrix.

"scalar"  in the Power BI sense means "single value, not a list, not a record, not a table"

I think we have a terminoloy issue here.  What you seem to be trying to do is to apply weighting to one of your tables.  "Multiplying matrices"  has  a very different meaning.

 

Matrix Multiplication | How to Multiply Matrices | Formula & Examples (byjus.com)

Hello, thanks for the comments.
I know what it means to multiply matrices - there is an example in the test file.
I want to multiply the given two matrices by each other (picture two) and I want to get the matrix again.

Can you please show the expected result for three currencies.

 

Your [Covariance] and [Cross Weights] measures are complex, and they need to be called 529 times for each loop of the matrix multiplication.  You  may run into memory issues on this one.

Capture.PNG

I don't get that result in Excel

 

lbendlin_0-1661285927904.png

Maybe some rounding issues.

 

Anyway, what will need to happen is that each currency gets assigned a numeric index (starting from 1). Then you can write a measure that can compute the result of the matrix multiplication for each cell of the crossjoins - all 529 of them. That measure formula will be massive, and I am not sure yet it can be done dynamically. Will have to think about it some more.

lbendlin
Super User
Super User

What is your next step? What are you planning to do after the matrix multiplication?

 

Measures can use table variables during the computation process but the final result of a measure must be a scalar value.

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.