Пример #1
0
        /// <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);
            }
        }