/// <summary> /// multiplies an <see cref="BlockDiagonalMatrix"/> by an <see cref="MsrMatrix"/> /// </summary> public static MsrMatrix Multiply(BlockDiagonalMatrix left, MsrMatrix right) { using (new FuncTrace()) { if (left.NoOfCols != right.NoOfRows) { throw new ArgumentException("matrix size mismatch"); } int _N = left.NoOfRowsPerBlock; // left blocks: no. of rows int _M = left.NoOfColsPerBlock; // left blocks: no. of columns = right blocks: no. of rows int _L = _M; // right blocks: no. of columns. Hope that fits, otherwise inefficient MsrMatrix result = new MsrMatrix(left.RowPartitioning, right.ColPartition); MultidimensionalArray lBlock = MultidimensionalArray.Create(_N, _M); //MsrMatrix.MSREntry[][] BlockRow = new MsrMatrix.MSREntry[_M][]; //List<int> OccupiedBlocks = new List<int>(); var OccupiedBlocks = new SortedDictionary <int, MultidimensionalArray>(); List <MultidimensionalArray> MatrixPool = new List <MultidimensionalArray>(); // avoid realloc int poolCnt = 0; MultidimensionalArray resBlock = MultidimensionalArray.Create(_N, _L); // loop over all blocks ... int NoBlks = left.m_RowPart.LocalLength / left.NoOfRowsPerBlock; for (int iBlk = 0; iBlk < NoBlks; iBlk++) { // reset: OccupiedBlocks.Clear(); poolCnt = 0; foreach (var M in MatrixPool) { M.Clear(); } // upper left corner of block int i0 = iBlk * _N + (int)left.RowPartitioning.i0; int j0 = (i0 / _N) * _M; // load block for (int n = 0; n < _N; n++) { for (int m = 0; m < _M; m++) { lBlock[n, m] = left.Blox[iBlk, n, m]; } } // read Msr rows int Last_rBlkCol = int.MinValue; MultidimensionalArray Block = null; for (int m = 0; m < _N; m++) { var BlockRow = right.GetRowShallow(j0 + m); foreach (var e in BlockRow) { if (e.m_ColIndex >= 0) { int rBlkCol = e.m_ColIndex / _L; if (rBlkCol != Last_rBlkCol) { if (!OccupiedBlocks.TryGetValue(rBlkCol, out Block)) { if (MatrixPool.Count <= poolCnt) { MatrixPool.Add(MultidimensionalArray.Create(_M, _L)); } Block = MatrixPool[poolCnt]; OccupiedBlocks.Add(rBlkCol, Block); poolCnt++; } Last_rBlkCol = rBlkCol; } int jj = e.m_ColIndex % _L; Block[m, jj] = e.Value; } } } Block = null; // execute multiplys foreach (KeyValuePair <int, MultidimensionalArray> rBlock in OccupiedBlocks) { resBlock.GEMM(1.0, lBlock, rBlock.Value, 0.0); // upper left edge of resBlock int _i0 = i0; int _j0 = rBlock.Key * _L; // write block for (int i = 0; i < _M; i++) { for (int j = 0; j < _L; j++) { result[i + _i0, j + _j0] = resBlock[i, j]; } } } } // return return(result); } }