public static BlockMsrMatrix CreateShapeOfOnes(BlockMsrMatrix A) { var rowmap = A._RowPartitioning; var colmap = A._ColPartitioning; int RowBlocks = rowmap.LocalNoOfBlocks; int ColBlocks = colmap.LocalNoOfBlocks; BlockMsrMatrix B = new BlockMsrMatrix(rowmap, colmap); Partitioning rowpart = new Partitioning(RowBlocks); for (int iBlock = rowpart.i0; iBlock < rowpart.iE; iBlock++) { for (int jBlock = rowpart.i0; jBlock < rowpart.iE; jBlock++) { int i0 = rowmap.GetBlockI0(iBlock); int j0 = colmap.GetBlockI0(jBlock); int iL = rowmap.GetBlockLen(iBlock); int jL = colmap.GetBlockLen(jBlock); var subM = MultidimensionalArray.Create(iL, jL); A.ReadBlock(i0, j0, subM); subM.ApplyAll(i => i != 0.0 ? 1 : 0); B.AccBlock(i0, j0, 1.0, subM); } } double min, max; int minc, minr, maxc, maxr; B.GetMinimumAndMaximum_MPILocal(out min, out minr, out minc, out max, out maxr, out maxc); Debug.Assert(min == 0); Debug.Assert(max == 1); return(B); }
internal static MultidimensionalArray GetBlock(BlockMsrMatrix Mtx, int jCell) { Debug.Assert(Mtx._RowPartitioning.FirstBlock + jCell == Mtx._ColPartitioning.FirstBlock + jCell); int jCellGlb = Mtx._RowPartitioning.FirstBlock + jCell; int i0Glb = Mtx._RowPartitioning.GetBlockI0(jCellGlb); int j0Glb = Mtx._ColPartitioning.GetBlockI0(jCellGlb); int Mblk = Mtx._RowPartitioning.GetBlockLen(jCellGlb); int Nblk = Mtx._ColPartitioning.GetBlockLen(jCellGlb); MultidimensionalArray ret = MultidimensionalArray.Create(Mblk, Nblk); Mtx.ReadBlock(i0Glb, j0Glb, ret); return(ret); }
private MultidimensionalArray GetBlock(BlockMsrMatrix target, bool ignoreVarCoupling, bool ignoreSpecCoupling, int iLoc, int jLoc) { var _Sblocks = MultidimensionalArray.Create(BMLoc.GetLengthOfCell(iLoc), BMLoc.GetLengthOfCell(jLoc)); for (int iVar = 0; iVar < StructuredNi0[iLoc].Length; iVar++) // loop over (row/codomain/test) variables { for (int jVar = 0; jVar < StructuredNi0[jLoc].Length; jVar++) // loop over (column/domain/trial) variables { if (ignoreVarCoupling && jVar != iVar) { continue; } for (int iSpc = 0; iSpc < StructuredNi0[iLoc][iVar].Length; iSpc++) // loop over species { for (int jSpc = 0; jSpc < StructuredNi0[jLoc][jVar].Length; jSpc++) { if (ignoreSpecCoupling && jSpc != iSpc) { continue; } for (int iMode = 0; iMode < StructuredNi0[iLoc][iVar][iSpc].Length; iMode++) { for (int jMode = 0; jMode < StructuredNi0[jLoc][jVar][jSpc].Length; jMode++) { extNi0 RowNi0 = StructuredNi0[iLoc][iVar][iSpc][iMode]; extNi0 ColNi0 = StructuredNi0[jLoc][jVar][jSpc][jMode]; int Targeti0 = RowNi0.Gi0; int Targetj0 = ColNi0.Gi0; int Subi0 = BMLoc.GetRelativeSubBlockOffset(iLoc, iVar, iSpc, iMode); int Subj0 = BMLoc.GetRelativeSubBlockOffset(jLoc, jVar, jSpc, jMode); int Subie = Subi0 + RowNi0.N - 1; int Subje = Subj0 + ColNi0.N - 1; target.ReadBlock(Targeti0, Targetj0, _Sblocks.ExtractSubArrayShallow(new int[] { Subi0, Subj0 }, new int[] { Subie, Subje })); } } } } } } return(_Sblocks); }
private static void ExtractBlock( int[] _i0s, int[] _Lns, bool Sp2Full, BlockMsrMatrix MtxSp, ref MultidimensionalArray MtxFl) // { Debug.Assert(_i0s.Length == _Lns.Length); int E = _i0s.Length; int NN = _Lns.Sum(); if (MtxFl == null || MtxFl.NoOfRows != NN) { Debug.Assert(Sp2Full == true); MtxFl = MultidimensionalArray.Create(NN, NN); } else { if (Sp2Full) { MtxFl.Clear(); } } if (!Sp2Full) { Debug.Assert(MtxSp != null); } int i0Rowloc = 0; for (int eRow = 0; eRow < E; eRow++) // loop over variables in configuration { int i0Row = _i0s[eRow]; int NRow = _Lns[eRow]; int i0Colloc = 0; for (int eCol = 0; eCol < E; eCol++) // loop over variables in configuration { int i0Col = _i0s[eCol]; int NCol = _Lns[eCol]; MultidimensionalArray MtxFl_blk; if (i0Rowloc == 0 && NRow == MtxFl.GetLength(0) && i0Colloc == 0 && NCol == MtxFl.GetLength(1)) { MtxFl_blk = MtxFl; } else { MtxFl_blk = MtxFl.ExtractSubArrayShallow(new[] { i0Rowloc, i0Colloc }, new[] { i0Rowloc + NRow - 1, i0Colloc + NCol - 1 }); } if (Sp2Full) { if (MtxSp != null) { MtxSp.ReadBlock(i0Row, i0Col, MtxFl_blk); } else { MtxFl_blk.AccEye(1.0); } } else { MtxSp.AccBlock(i0Row, i0Col, 1.0, MtxFl_blk, 0.0); } #if DEBUG for (int n_row = 0; n_row < NRow; n_row++) // row loop... { for (int n_col = 0; n_col < NCol; n_col++) // column loop... { Debug.Assert(MtxFl[n_row + i0Rowloc, n_col + i0Colloc] == ((MtxSp != null) ? (MtxSp[n_row + i0Row, n_col + i0Col]) : (n_col == n_row ? 1.0 : 0.0))); } } #endif i0Colloc += NCol; } i0Rowloc += NRow; } }
/// <summary> /// Specialized version of /// <see cref="BlockDiagonalMatrix.SpMV{VectorType1, VectorType2}(double, VectorType1, double, VectorType2)"/> /// where each block corresponds to an individual cell and where the /// multiplication shall only be performed over the cells in a given /// <paramref name="mask"/> /// </summary> /// <typeparam name="VectorType1"></typeparam> /// <typeparam name="VectorType2"></typeparam> /// <param name="M"></param> /// <param name="alpha"></param> /// <param name="a"></param> /// <param name="beta"></param> /// <param name="acc"></param> /// <param name="mask"></param> internal static void SubMatrixSpMV <VectorType1, VectorType2>(BlockMsrMatrix M, double alpha, VectorType1 a, double beta, VectorType2 acc, CellMask mask) where VectorType1 : IList <double> where VectorType2 : IList <double> { if (acc.Count != M.RowPartitioning.LocalLength) { throw new ArgumentException("mismatch between accumulator and number of rows, i.e. row partition.", "acc"); } if (a.Count != M.ColPartition.LocalLength) { throw new ArgumentException("mismatch between input vector 'a' and number of columns, i.e. column partition.", "a"); } //int M1 = M.NoOfColsPerBlock; //int N1 = M.NoOfRowsPerBlock; double[] aBuf = null;// new double[M1]; MultidimensionalArray Mbuf = null; int Glob_cell0 = mask.GridData.CellPartitioning.i0; foreach (int cell in mask.ItemEnum) { //int i0 = cell * N1; // row //int j0 = cell * M1; // col int i0Glob = M._RowPartitioning.GetBlockI0(cell + Glob_cell0); int j0Glob = M._ColPartitioning.GetBlockI0(cell + Glob_cell0); int i0 = i0Glob - M._RowPartitioning.i0; int j0 = j0Glob - M._RowPartitioning.i0; int M1 = M._RowPartitioning.GetBlockLen(cell + Glob_cell0); int N1 = M._ColPartitioning.GetBlockLen(cell + Glob_cell0); if (aBuf == null || aBuf.Length < M1) { aBuf = new double[M1]; } for (int j = 0; j < M1; j++) { aBuf[j] = a[j + j0]; } if (Mbuf == null || Mbuf.GetLength(0) != M1 || Mbuf.GetLength(1) != N1) { Mbuf = MultidimensionalArray.Create(M1, N1); } M.ReadBlock(i0Glob, j0Glob, Mbuf); for (int i = 0; i < N1; i++) { double _acc = 0; for (int j = 0; j < M1; j++) { _acc += Mbuf[i, j] * aBuf[j]; } acc[i + i0] = acc[i + i0] * beta + _acc * alpha; } } }
private static void ExtractBlock(int jCell, AggregationGridBasis basis, int[] Degrees, ChangeOfBasisConfig conf, int E, int[] _i0s, bool Sp2Full, BlockMsrMatrix MtxSp, ref MultidimensionalArray MtxFl) { int NN = conf.VarIndex.Sum(iVar => basis.GetLength(jCell, Degrees[iVar])); if (MtxFl == null || MtxFl.NoOfRows != NN) { Debug.Assert(Sp2Full == true); MtxFl = MultidimensionalArray.Create(NN, NN); } else { if (Sp2Full) { MtxFl.Clear(); } } if (!Sp2Full) { Debug.Assert(MtxSp != null); } int i0Rowloc = 0; for (int eRow = 0; eRow < E; eRow++) // loop over variables in configuration { int i0Row = _i0s[eRow]; int iVarRow = conf.VarIndex[eRow]; int NRow = basis.GetLength(jCell, Degrees[iVarRow]); int i0Colloc = 0; for (int eCol = 0; eCol < E; eCol++) // loop over variables in configuration { int i0Col = _i0s[eCol]; int iVarCol = conf.VarIndex[eCol]; int NCol = basis.GetLength(jCell, Degrees[iVarCol]); MultidimensionalArray MtxFl_blk; if (i0Rowloc == 0 && NRow == MtxFl.GetLength(0) && i0Colloc == 0 && NCol == MtxFl.GetLength(1)) { MtxFl_blk = MtxFl; } else { MtxFl_blk = MtxFl.ExtractSubArrayShallow(new[] { i0Rowloc, i0Colloc }, new[] { i0Rowloc + NRow - 1, i0Colloc + NCol - 1 }); } /* * for(int n_row = 0; n_row < NRow; n_row++) { // row loop... * for(int n_col = 0; n_col < NCol; n_col++) { // column loop... * if(Sp2Full) { * // copy from sparse to full * MtxFl[n_row + i0Rowloc, n_col + i0Colloc] = (MtxSp != null) ? ( MtxSp[n_row + i0Row, n_col + i0Col]) : (n_col == n_row ? 1.0 : 0.0); * } else { * // the other way around. * MtxSp[n_row + i0Row, n_col + i0Col] = MtxFl[n_row + i0Rowloc, n_col + i0Colloc]; * } * } * } */ if (Sp2Full) { if (MtxSp != null) { MtxSp.ReadBlock(i0Row, i0Col, MtxFl_blk); } else { MtxFl_blk.AccEye(1.0); } } else { #if DEBUG Debug.Assert(MtxSp != null); //for (int n_row = 0; n_row < NRow; n_row++) { // row loop... // for (int n_col = 0; n_col < NCol; n_col++) { // column loop... // Debug.Assert(MtxSp[n_row + i0Row, n_col + i0Col] == 0.0); // } //} #endif MtxSp.AccBlock(i0Row, i0Col, 1.0, MtxFl_blk, 0.0); } #if DEBUG for (int n_row = 0; n_row < NRow; n_row++) // row loop... { for (int n_col = 0; n_col < NCol; n_col++) // column loop... { Debug.Assert(MtxFl[n_row + i0Rowloc, n_col + i0Colloc] == ((MtxSp != null) ? (MtxSp[n_row + i0Row, n_col + i0Col]) : (n_col == n_row ? 1.0 : 0.0))); } } #endif i0Colloc += NCol; } i0Rowloc += NRow; } }
void BlockSol <V1, V2>(BlockMsrMatrix M, V1 X, V2 B) where V1 : IList <double> where V2 : IList <double> // { Debug.Assert(X.Count == M.ColPartition.LocalLength); Debug.Assert(B.Count == M.RowPartitioning.LocalLength); var Part = M.RowPartitioning; Debug.Assert(Part.EqualsPartition(this.CurrentStateMapping)); int J = m_LsTrk.GridDat.Cells.NoOfLocalUpdatedCells; Debug.Assert(J == M._RowPartitioning.LocalNoOfBlocks); Debug.Assert(J == M._ColPartitioning.LocalNoOfBlocks); var basisS = this.CurrentStateMapping.BasisS.ToArray(); int NoOfVars = basisS.Length; MultidimensionalArray Block = null; double[] x = null, b = null; #if DEBUG var unusedIndex = new System.Collections.BitArray(B.Count); #endif for (int j = 0; j < J; j++) // loop over cells... { for (int iVar = 0; iVar < NoOfVars; iVar++) { int bS = this.CurrentStateMapping.LocalUniqueCoordinateIndex(iVar, j, 0); int Nj = basisS[iVar].GetLength(j); if (Block == null || Block.NoOfRows != Nj) { Block = MultidimensionalArray.Create(Nj, Nj); x = new double[Nj]; b = new double[Nj]; } else { Block.Clear(); } // extract block M.ReadBlock(bS + M._RowPartitioning.i0, bS + M._ColPartitioning.i0, Block); // extract part of RHS for (int iRow = 0; iRow < Nj; iRow++) { bool ZeroRow = Block.GetRow(iRow).L2NormPow2() == 0; b[iRow] = B[iRow + bS]; if (ZeroRow) { if (b[iRow] != 0.0) { throw new ArithmeticException(); } else { Block[iRow, iRow] = 1.0; } } #if DEBUG unusedIndex[iRow + bS] = true; #endif } // solve Block.SolveSymmetric(x, b); // store solution for (int iRow = 0; iRow < Nj; iRow++) { X[iRow + bS] = x[iRow]; } } } #if DEBUG for (int i = 0; i < unusedIndex.Length; i++) { if (unusedIndex[i] == false && B[i] != 0.0) { throw new ArithmeticException("Non-zero entry in void region."); } } #endif }
private void AuxGetSubBlockMatrix(BlockMsrMatrix target, BlockMsrMatrix source, BlockMaskBase mask, bool ignoreCellCoupling, bool ignoreVarCoupling, bool ignoreSpecCoupling) { bool IsLocalMask = mask.GetType() == typeof(BlockMaskLoc); extNi0[][][][] RowNi0s = mask.m_StructuredNi0; extNi0[][][][] ColNi0s = this.StructuredNi0; int auxIdx = 0; for (int iLoc = 0; iLoc < RowNi0s.Length; iLoc++) { for (int jLoc = 0; jLoc < ColNi0s.Length; jLoc++) { if (ignoreCellCoupling && jLoc != iLoc) { continue; } for (int iVar = 0; iVar < RowNi0s[iLoc].Length; iVar++) { for (int jVar = 0; jVar < ColNi0s[jLoc].Length; jVar++) { if (ignoreVarCoupling && jVar != iVar) { continue; } for (int iSpc = 0; iSpc < RowNi0s[iLoc][iVar].Length; iSpc++) { for (int jSpc = 0; jSpc < ColNi0s[jLoc][jVar].Length; jSpc++) { if (ignoreSpecCoupling && jSpc != iSpc) { continue; } for (int iMode = 0; iMode < RowNi0s[iLoc][iVar][iSpc].Length; iMode++) { int Trgi0 = RowNi0s[iLoc][iVar][iSpc][iMode].Si0; for (int jMode = 0; jMode < ColNi0s[jLoc][jVar][jSpc].Length; jMode++) { extNi0 RowNi0 = RowNi0s[iLoc][iVar][iSpc][iMode]; extNi0 ColNi0 = ColNi0s[jLoc][jVar][jSpc][jMode]; int Srci0 = IsLocalMask? RowNi0.Gi0: RowNi0.Li0 + source._RowPartitioning.i0 - m_map.LocalLength; int Srcj0 = ColNi0.Gi0; var tmpBlock = MultidimensionalArray.Create(RowNi0.N, ColNi0.N); int Trgj0 = ColNi0s[jLoc][jVar][jSpc][jMode].Si0; #if Debug SubMSR.ReadBlock(SubRowIdx, SubColIdx, tmpBlock); Debug.Assert(tmpBlock.Sum() == 0); Debug.Assert(tmpBlock.InfNorm() == 0); #endif try { source.ReadBlock(Srci0, Srcj0, tmpBlock); } catch (Exception e) { Console.WriteLine("row: " + Srci0); Console.WriteLine("col: " + Srcj0); throw new Exception(e.Message); } Debug.Assert(Trgi0 < target.RowPartitioning.LocalLength); Debug.Assert(Trgj0 < target.ColPartition.LocalLength); target.AccBlock(Trgi0, Trgj0, 1.0, tmpBlock); } } } } } } auxIdx++; } auxIdx++; } }
private MultidimensionalArray[] AuxGetSubBlocks(BlockMsrMatrix source, BlockMaskBase mask, bool ignoreCellCoupling, bool ignoreVarCoupling, bool ignoreSpecCoupling) { bool IsLocMask = mask.GetType() == typeof(BlockMaskLoc); // if external cells are masked, we have to consider other offsets ... int NoOfCells = mask.m_StructuredNi0.Length; int size = ignoreCellCoupling ? NoOfCells : NoOfCells * NoOfCells; MultidimensionalArray[] Sblocks = new MultidimensionalArray[size]; int auxIdx = 0; for (int iLoc = 0; iLoc < mask.m_StructuredNi0.Length; iLoc++) { for (int jLoc = 0; jLoc < mask.m_StructuredNi0.Length; jLoc++) { if (ignoreCellCoupling && jLoc != iLoc) { continue; } int CellBlockLen = mask.GetLengthOfCell(jLoc); Sblocks[auxIdx] = MultidimensionalArray.Create(CellBlockLen, CellBlockLen); for (int iVar = 0; iVar < mask.m_StructuredNi0[iLoc].Length; iVar++) { for (int jVar = 0; jVar < mask.m_StructuredNi0[jLoc].Length; jVar++) { if (ignoreVarCoupling && jVar != iVar) { continue; } for (int iSpc = 0; iSpc < mask.m_StructuredNi0[iLoc][iVar].Length; iSpc++) { for (int jSpc = 0; jSpc < mask.m_StructuredNi0[jLoc][jVar].Length; jSpc++) { if (ignoreSpecCoupling && jSpc != iSpc) { continue; } for (int iMode = 0; iMode < mask.m_StructuredNi0[iLoc][iVar][iSpc].Length; iMode++) { for (int jMode = 0; jMode < mask.m_StructuredNi0[jLoc][jVar][jSpc].Length; jMode++) { extNi0 RowNi0 = mask.m_StructuredNi0[iLoc][iVar][iSpc][iMode]; extNi0 ColNi0 = mask.m_StructuredNi0[jLoc][jVar][jSpc][jMode]; int Targeti0 = IsLocMask ? RowNi0.Gi0 : RowNi0.Li0 + source._RowPartitioning.i0 - m_map.LocalLength; int Targetj0 = ColNi0.Gi0; int Subi0 = mask.GetRelativeSubBlockOffset(iLoc, iVar, iSpc, iMode); int Subj0 = mask.GetRelativeSubBlockOffset(jLoc, jVar, jSpc, jMode); int Subie = Subi0 + RowNi0.N - 1; int Subje = Subj0 + ColNi0.N - 1; var tmp = Sblocks[auxIdx].ExtractSubArrayShallow(new int[] { Subi0, Subj0 }, new int[] { Subie, Subje }); Debug.Assert((m_map.IsInLocalRange(Targeti0) && m_map.IsInLocalRange(Targetj0) && mask.GetType() == typeof(BlockMaskLoc)) || mask.GetType() == typeof(BlockMaskExt)); try { source.ReadBlock(Targeti0, Targetj0, tmp ); } catch (Exception e) { Console.WriteLine("row: " + Targeti0); Console.WriteLine("col: " + Targetj0); throw new Exception(e.Message); } } } } } } } auxIdx++; } } return(Sblocks); }
/// <summary> /// ~ /// </summary> public void Init(MultigridOperator op) { BlockMsrMatrix M = op.OperatorMatrix; var MgMap = op.Mapping; this.m_MultigridOp = op; if (!M.RowPartitioning.EqualsPartition(MgMap.Partitioning)) { throw new ArgumentException("Row partitioning mismatch."); } if (!M.ColPartition.EqualsPartition(MgMap.Partitioning)) { throw new ArgumentException("Column partitioning mismatch."); } Mtx = M; int L = M.RowPartitioning.LocalLength; /* * diag = new double[L]; * int i0 = Mtx.RowPartitioning.i0; * * for(int i = 0; i < L; i++) { * diag[i] = Mtx[i0 + i, i0 + i]; * } */ //if (op.Mapping.MaximalLength != op.Mapping.MinimalLength) // // 'BlockDiagonalMatrix' should be completely replaced by 'BlockMsrMatrix' // throw new NotImplementedException("todo - Block Jacobi for variable block Sizes"); Diag = new BlockMsrMatrix(M._RowPartitioning, M._ColPartitioning); invDiag = new BlockMsrMatrix(M._RowPartitioning, M._ColPartitioning); int Jloc = MgMap.LocalNoOfBlocks; int j0 = MgMap.FirstBlock; MultidimensionalArray temp = null; for (int j = 0; j < Jloc; j++) { int jBlock = j + j0; int Nblk = MgMap.GetBlockLen(jBlock); int i0 = MgMap.GetBlockI0(jBlock); if (temp == null || temp.NoOfCols != Nblk) { temp = MultidimensionalArray.Create(Nblk, Nblk); } M.ReadBlock(i0, i0, temp); Diag.AccBlock(i0, i0, 1.0, temp, 0.0); temp.Invert(); invDiag.AccBlock(i0, i0, 1.0, temp, 0.0); } #if DEBUG invDiag.CheckForNanOrInfM(); #endif }
public static void SubBlockExtractionWithCoupling( [Values(XDGusage.none, XDGusage.all)] XDGusage UseXdg, [Values(2)] int DGOrder, [Values(MatrixShape.diagonal, MatrixShape.diagonal_var, MatrixShape.diagonal_spec, MatrixShape.diagonal_var_spec)] MatrixShape MShape ) { Utils.TestInit((int)UseXdg, DGOrder, (int)MShape); Console.WriteLine("ExtractDiagonalBlocks({0},{1},{2})", UseXdg, DGOrder, MShape); //Arrange --- get multigridoperator MultigridOperator MGOp = Utils.CreateTestMGOperator(UseXdg, DGOrder, MShape); BlockMsrMatrix M = MGOp.OperatorMatrix; MultigridMapping map = MGOp.Mapping; //Arrange --- setup masking SubBlockSelector SBS = new SubBlockSelector(map); BlockMask mask = new BlockMask(SBS, null); bool[] coupling = Utils.SetCoupling(MShape); //Arrange --- some time measurement Stopwatch stw = new Stopwatch(); stw.Reset(); //Arrange --- setup auxiliary matrix //this will show us if more is extracted, than it should ... var Mprep = new BlockMsrMatrix(map); Mprep.Acc(1.0, M); //Act --- diagonal subblock extraction stw.Start(); var blocks = mask.GetDiagonalBlocks(Mprep, coupling[0], coupling[1]); stw.Stop(); //Assert --- all diagonal blocks are extracted Assert.IsTrue(blocks.Length == map.LocalNoOfBlocks); for (int i = 0; i < map.LocalNoOfBlocks; i++) { //Arrange --- get ith diagonal block of M: M_i int iBlock = i + map.AggGrid.CellPartitioning.i0; int L = map.GetBlockLen(iBlock); int i0 = map.GetBlockI0(iBlock); var Mblock = MultidimensionalArray.Create(L, L); M.ReadBlock(i0, i0, Mblock); //Act --- M_i-Mones_i Mblock.Acc(-1.0, blocks[i]); //Assert --- are extracted blocks and Assert.IsTrue(Mblock.InfNorm() == 0.0, String.Format("infNorm of block {0} neq 0!", i)); } //BlockMsrMatrix all1; //all1.SetAll(1); //Generate broken diagonal matrix, die zur Maske passt: M //M+all1=M_prep //Wende Extraction auf M_prep an, Man sollte nun M bekommen //Test: M_prep-extract(M_prep)=all1 //Test-crit: Result.SumEntries=DOF^2 oder Result.Max()==Result.Min()==1 //oder (besser) //Test: M-extract(M_prep)=zeros //Test-crit: Result.InfNorm()==0 //Der Test kann für ExtractSubMatrix mit ignore coupling wiederholt werden //eventuell: Testmatrix finden mit brauchbaren Nebendiagonalen für einen Fall //Was wird getestet: funktioniert ignorecoupling richtig? }