# blaze / Matrix-Matrix Multiplication

## Componentwise Multiplication / Schur Product

Multiplying two matrices with the same dimensions (i.e. the same number of rows and columns) via the modulo operator results in a componentwise multiplication (Schur product) of the two matrices:

```using blaze::DynamicMatrix;
using blaze::CompressedMatrix;

DynamicMatrix<double>   M1( 28UL, 35UL );
CompressedMatrix<float> M2( 28UL, 35UL );

// ... Initialization of the matrices

DynamicMatrix<double> M3 = M1 % M2;
```

Both dense and sparse matrices can be used for a Schur product. The storage order of the two matrices poses no restrictions on the operation, all variations are possible. It is also possible to multiply two matrices with different element type, as long as the element types themselves can be multiplied.

## Matrix Product

The matrix/matrix product can be formulated exactly as in mathematical textbooks:

```using blaze::DynamicMatrix;
using blaze::CompressedMatrix;

DynamicMatrix<double>   M1( 45UL, 85UL );
CompressedMatrix<float> M2( 85UL, 37UL );

// ... Initialization of the matrices

DynamicMatrix<double> M3 = M1 * M2;
```

The storage order of the two matrices poses no restrictions on the operation, all variations are possible. It is also possible to multiply two matrices with different element type, as long as the element types themselves can be multiplied and added. Note however that the highest performance for a multiplication between two matrices can be expected for two matrices with the same scalar element type.

In case the resulting matrix is known to be symmetric, Hermitian, lower triangular, upper triangular, or diagonal, the computation can be optimized by explicitly declaring the multiplication as symmetric, Hermitian, lower triangular, upper triangular, or diagonal by means of the Declaration Operations:

```using blaze::DynamicMatrix;

DynamicMatrix<double> M1, M2, M3;

// ... Initialization of the square matrices

M3 = declsym ( M1 * M2 );  // Declare the result of the matrix multiplication as symmetric
M3 = declherm( M1 * M2 );  // Declare the result of the matrix multiplication as Hermitian
M3 = decllow ( M1 * M2 );  // Declare the result of the matrix multiplication as lower triangular
M3 = declupp ( M1 * M2 );  // Declare the result of the matrix multiplication as upper triangular
M3 = decldiag( M1 * M2 );  // Declare the result of the matrix multiplication as diagonal
```

Using a declaration operation on the a multiplication expression can speed up the computation by a factor of 2. Note however that the caller of the according declaration operation takes full responsibility for the correctness of the declaration. Falsely declaring a multiplication as symmetric, Hermitian, lower triangular, upper triangular, or diagonal leads to undefined behavior!

## Kronecker Product

The Kronecker product of two matrices can be computed via the `kron()` function:

```using blaze::DynamicMatrix;
using blaze::CompressedMatrix;

DynamicMatrix<double>   M1( 28UL, 35UL );
CompressedMatrix<float> M2( 17UL, 11UL );

// ... Initialization of the matrices

CompressedMatrix<double> M3 = kron( M1, M2 );
```

Both dense and sparse matrices can be used for a Kronecker product. The storage order of the two matrices poses no restrictions on the operation, all variations are possible. It is also possible to multiply two matrices with different element type, as long as the element types themselves can be multiplied.

Previous: Matrix/Vector Multiplication ---- Next: Shared Memory Parallelization

Updated