/// <summary> /// creates a non-shallow copy /// </summary> public object Clone() { var ret = new BlockDiagonalMatrix(); ret.Blox = this.Blox.CloneAs(); ret.m_RowPart = this.RowPartitioning; // immutable object, so shallow cloning is ok. ret.m_ColumnPart = this.ColPartition; return(ret); }
public BlockDiagonalMatrix InvertSymmetrical(bool ignoreEmptyBlocks = false) { if (this.NoOfRows != this.NoOfCols) { throw new NotSupportedException("Can't invert non-square matrix."); } if (this.NoOfRowsPerBlock != this.NoOfColsPerBlock) { throw new NotSupportedException("Can't invert matrix with non-square blocks."); } // Matrix for the result BlockDiagonalMatrix res = new BlockDiagonalMatrix(RowPartitioning, ColPartition, NoOfRowsPerBlock, NoOfColsPerBlock); // FullMatrix to calculate inverse var tmp = MultidimensionalArray.Create(this.NoOfRowsPerBlock, NoOfColsPerBlock); for (int BlockNo = 0; BlockNo < NoOfBlocks; BlockNo++) { // Copy values from current block to FullMatrix for (int i = 0; i < this.NoOfRowsPerBlock; i++) { for (int j = 0; j < this.NoOfColsPerBlock; j++) { tmp[i, j] = this.Blox[BlockNo, i, j]; } } if (ignoreEmptyBlocks && tmp.AbsSum() < 1e-15) { // No inversion of empty blocks requested continue; } // Calculate inverse of FullMatrix tmp.InvertSymmetrical(); // Write inverse of FullMatrix to current block for (int i = 0; i < this.NoOfRowsPerBlock; i++) { for (int j = 0; j < this.NoOfColsPerBlock; j++) { res.Blox[BlockNo, i, j] = tmp[i, j]; } } } return(res); }
/// <summary> /// Calculates the inverse of this matrix and returns the result. /// </summary> /// <returns>Inverse of this matrix</returns> public BlockDiagonalMatrix Invert() { // Some checks if (this.NoOfRows != this.NoOfCols) { throw new NotSupportedException("Can't invert non-square matrix."); } if (this.NoOfRowsPerBlock != this.NoOfColsPerBlock) { throw new NotSupportedException("Can't invert matrix with non-square blocks."); } // Matrix for the result BlockDiagonalMatrix res = new BlockDiagonalMatrix(RowPartitioning, ColPartition, NoOfRowsPerBlock, NoOfColsPerBlock); // FullMatrix to calculate inverse for (int BlockNo = 0; BlockNo < NoOfBlocks; BlockNo++) { var tmp = MultidimensionalArray.Create(this.NoOfRowsPerBlock, NoOfColsPerBlock); // Copy values from current block to FullMatrix for (int i = 0; i < this.NoOfRowsPerBlock; i++) { for (int j = 0; j < this.NoOfColsPerBlock; j++) { tmp[i, j] = this.Blox[BlockNo, i, j]; } } // Calculate inverse of FullMatrix var BlockInverse = tmp.GetInverse(); // Write inverse of FullMatrix to current block for (int i = 0; i < this.NoOfRowsPerBlock; i++) { for (int j = 0; j < this.NoOfColsPerBlock; j++) { res.Blox[BlockNo, i, j] = BlockInverse[i, j]; } } } return(res); }
/// <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); } }