/// <summary> /// Construct packed versions of input matrices, and then use sparse row/column dot /// to compute elements of output matrix. This is faster. But still relatively expensive. /// </summary> void multiply_fast(SymmetricSparseMatrix M2in, ref SymmetricSparseMatrix Rin, bool bParallel) { int N = Rows; if (M2in.Rows != N) { throw new Exception("SymmetricSparseMatrix.Multiply: matrices have incompatible dimensions"); } if (Rin == null) { Rin = new SymmetricSparseMatrix(); } SymmetricSparseMatrix R = Rin; // require alias for use in lambda below PackedSparseMatrix M = new PackedSparseMatrix(this); M.Sort(); PackedSparseMatrix M2 = new PackedSparseMatrix(M2in, true); M2.Sort(); // Parallel variant is vastly faster, uses spinlock to control access to R if (bParallel) { // goddamn SpinLock is in .Net 4 //SpinLock spin = new SpinLock(); gParallel.ForEach(Interval1i.Range(N), (r1i) => { for (int c2i = r1i; c2i < N; c2i++) { double v = M.DotRowColumn(r1i, c2i, M2); if (Math.Abs(v) > MathUtil.ZeroTolerance) { //bool taken = false; //spin.Enter(ref taken); //Debug.Assert(taken); //R[r1i, c2i] = v; //spin.Exit(); lock (R) { R[r1i, c2i] = v; } } } }); } else { for (int r1i = 0; r1i < N; r1i++) { for (int c2i = r1i; c2i < N; c2i++) { double v = M.DotRowColumn(r1i, c2i, M2); if (Math.Abs(v) > MathUtil.ZeroTolerance) { R[r1i, c2i] = v; } } } } }
public SymmetricSparseMatrix Multiply(SymmetricSparseMatrix M2) { SymmetricSparseMatrix R = new SymmetricSparseMatrix(); Multiply(M2, ref R); return(R); }
public void Multiply(SymmetricSparseMatrix M2, ref SymmetricSparseMatrix R, bool bParallel = true) { // testing code //multiply_slow(M2, ref R); //SymmetricSparseMatrix R2 = new SymmetricSparseMatrix(); //multiply_fast(M2, ref R2); //Debug.Assert(R.EpsilonEqual(R2)); multiply_fast(M2, ref R, bParallel); }
public PackedSparseMatrix(SymmetricSparseMatrix m, bool bTranspose = false) { int numRows = (bTranspose) ? m.Columns : m.Rows; Columns = (bTranspose) ? m.Columns : m.Rows; Rows = new nonzero[numRows][]; int[] counts = new int[numRows]; foreach (Index2i ij in m.NonZeroIndices()) { counts[ij.a]++; if (ij.a != ij.b) { counts[ij.b]++; } } NumNonZeros = 0; for (int k = 0; k < numRows; ++k) { Rows[k] = new nonzero[counts[k]]; NumNonZeros += counts[k]; } int[] accum = new int[numRows]; foreach (KeyValuePair <Index2i, double> ijv in m.NonZeros()) { int i = ijv.Key.a, j = ijv.Key.b; if (bTranspose) { int tmp = i; i = j; j = tmp; } int k = accum[i]++; Rows[i][k].j = j; Rows[i][k].d = ijv.Value; if (i != j) { k = accum[j]++; Rows[j][k].j = i; Rows[j][k].d = ijv.Value; } } //for (int k = 0; k < numRows; ++k) // Debug.Assert(accum[k] == counts[k]); Sorted = false; IsSymmetric = true; StorageMode = StorageModes.Full; }
// returns this*this (requires less memory) public SymmetricSparseMatrix Square(bool bParallel = true) { var R = new SymmetricSparseMatrix(); var M = new PackedSparseMatrix(this); M.Sort(); // Parallel variant is vastly faster, uses spinlock to control access to R if (bParallel) { // goddamn SpinLock is in .Net 4 //SpinLock spin = new SpinLock(); gParallel.ForEach(Interval1i.Range(N), (r1i) => { for (int c2i = r1i; c2i < N; c2i++) { double v = M.DotRowColumn(r1i, c2i, M); if (Math.Abs(v) > MathUtil.ZeroTolerance) { //bool taken = false; //spin.Enter(ref taken); //Debug.Assert(taken); //R[r1i, c2i] = v; //spin.Exit(); lock (R) { R[r1i, c2i] = v; } } } }); } else { for (int r1i = 0; r1i < N; r1i++) { for (int c2i = r1i; c2i < N; c2i++) { double v = M.DotRowColumn(r1i, c2i, M); if (Math.Abs(v) > MathUtil.ZeroTolerance) { R[r1i, c2i] = v; } } } } return(R); }
public bool EpsilonEqual(SymmetricSparseMatrix B, double eps = MathUtil.Epsilon) { foreach (var val in d) { if (Math.Abs(B[val.Key.a, val.Key.b] - val.Value) > eps) { return(false); } } foreach (var val in B.d) { if (Math.Abs(this[val.Key.a, val.Key.b] - val.Value) > eps) { return(false); } } return(true); }
/// <summary> /// directly multiply the matrices. This is very slow as the matrix gets /// larger because we are iterating over all indices to find nonzeros /// </summary> void multiply_slow(SymmetricSparseMatrix M2, ref SymmetricSparseMatrix R) { // this multiply is probably not ideal.... int N = Rows; if (M2.Rows != N) { throw new Exception("SymmetricSparseMatrix.Multiply: matrices have incompatible dimensions"); } if (R == null) { R = new SymmetricSparseMatrix(); } List <mval> row = new List <mval>(128); for (int r1i = 0; r1i < N; r1i++) { row.Clear(); this.get_row_nonzeros(r1i, row); int rN = row.Count; for (int c2i = r1i; c2i < N; c2i++) { double v = 0; // would it be faster to convert cols to mval lists?? for (int ri = 0; ri < rN; ++ri) { int k = row[ri].k; v += row[ri].v * M2[k, c2i]; } if (Math.Abs(v) > MathUtil.ZeroTolerance) { R[r1i, c2i] = v; } } } }
public void Initialize() { ToMeshV = new int[Mesh.MaxVertexID]; ToIndex = new int[Mesh.MaxVertexID]; N = 0; foreach (int vid in Mesh.VertexIndices()) { ToMeshV[N] = vid; ToIndex[vid] = N; N++; } Px = new double[N]; Py = new double[N]; Pz = new double[N]; nbr_counts = new int[N]; M = new SymmetricSparseMatrix(); for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; Vector3d v = Mesh.GetVertex(vid); Px[i] = v.x; Py[i] = v.y; Pz[i] = v.z; nbr_counts[i] = Mesh.GetVtxEdgeCount(vid); } // construct laplacian matrix for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; int n = nbr_counts[i]; double sum_w = 0; foreach (int nbrvid in Mesh.VtxVerticesItr(vid)) { int j = ToIndex[nbrvid]; int n2 = nbr_counts[j]; // weight options //double w = -1; double w = -1.0 / Math.Sqrt(n + n2); //double w = -1.0 / n; M.Set(i, j, w); sum_w += w; } sum_w = -sum_w; M.Set(vid, vid, sum_w); } // transpose(L) * L, but matrix is symmetric... if (UseSoftConstraintNormalEquations) { //M = M.Multiply(M); M = M.Square(); // only works if M is symmetric } // construct packed version of M matrix PackedM = new PackedSparseMatrix(M); // compute laplacian vectors of initial mesh positions MLx = new double[N]; MLy = new double[N]; MLz = new double[N]; M.Multiply(Px, MLx); M.Multiply(Py, MLy); M.Multiply(Pz, MLz); // zero out... for (int i = 0; i < Px.Length; ++i) { MLx[i] = 0; MLy[i] = 0; MLz[i] = 0; } // allocate memory for internal buffers Preconditioner = new DiagonalMatrix(N); WeightsM = new DiagonalMatrix(N); Cx = new double[N]; Cy = new double[N]; Cz = new double[N]; Bx = new double[N]; By = new double[N]; Bz = new double[N]; Sx = new double[N]; Sy = new double[N]; Sz = new double[N]; UpdateForSolve(); }
public void Initialize() { ToMeshV = new int[Mesh.MaxVertexID]; ToIndex = new int[Mesh.MaxVertexID]; N = 0; foreach (int vid in Mesh.VertexIndices()) { ToMeshV[N] = vid; ToIndex[vid] = N; N++; } Px = new double[N]; Py = new double[N]; Pz = new double[N]; nbr_counts = new int[N]; SymmetricSparseMatrix M = new SymmetricSparseMatrix(); for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; Vector3d v = Mesh.GetVertex(vid); Px[i] = v.x; Py[i] = v.y; Pz[i] = v.z; nbr_counts[i] = Mesh.GetVtxEdgeCount(vid); } // construct laplacian matrix for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; int n = nbr_counts[i]; double sum_w = 0; foreach (int nbrvid in Mesh.VtxVerticesItr(vid)) { int j = ToIndex[nbrvid]; int n2 = nbr_counts[j]; // weight options //double w = -1; double w = -1.0 / Math.Sqrt(n + n2); //double w = -1.0 / n; M.Set(i, j, w); sum_w += w; } sum_w = -sum_w; // TODO: Investigate: is this ia bug? // Source https://github.com/ZelimDamian/geometry3Sharp/commit/7a50d8de10faad762e726e60956acc4bdc5456b5 // makes the following line M.Set(i, i, sum_w); M.Set(vid, vid, sum_w); } // transpose(L) * L, but matrix is symmetric... if (UseSoftConstraintNormalEquations) { //M = M.Multiply(M); // only works if M is symmetric!! PackedM = M.SquarePackedParallel(); } else { PackedM = new PackedSparseMatrix(M); } // compute laplacian vectors of initial mesh positions MLx = new double[N]; MLy = new double[N]; MLz = new double[N]; PackedM.Multiply(Px, MLx); PackedM.Multiply(Py, MLy); PackedM.Multiply(Pz, MLz); // allocate memory for internal buffers Preconditioner = new DiagonalMatrix(N); WeightsM = new DiagonalMatrix(N); Cx = new double[N]; Cy = new double[N]; Cz = new double[N]; Bx = new double[N]; By = new double[N]; Bz = new double[N]; Sx = new double[N]; Sy = new double[N]; Sz = new double[N]; need_solve_update = true; UpdateForSolve(); }
public void Initialize() { ToMeshV = new int[Mesh.MaxVertexID]; ToIndex = new int[Mesh.MaxVertexID]; N = 0; foreach (int vid in Mesh.VertexIndices()) { ToMeshV[N] = vid; ToIndex[vid] = N; N++; } Px = new double[N]; Py = new double[N]; Pz = new double[N]; nbr_counts = new int[N]; M = new SymmetricSparseMatrix(); for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; Vector3d v = Mesh.GetVertex(vid); Px[i] = v.x; Py[i] = v.y; Pz[i] = v.z; nbr_counts[i] = Mesh.GetVtxEdgeCount(vid); } // construct laplacian matrix for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; int n = nbr_counts[i]; double sum_w = 0; foreach (int nbrvid in Mesh.VtxVerticesItr(vid)) { int j = ToIndex[nbrvid]; int n2 = nbr_counts[j]; // weight options //double w = -1; double w = -1.0 / Math.Sqrt(n + n2); //double w = -1.0 / n; M.Set(i, j, w); sum_w += w; } sum_w = -sum_w; M.Set(vid, vid, sum_w); } // compute laplacian vectors of initial mesh positions MLx = new double[N]; MLy = new double[N]; MLz = new double[N]; M.Multiply(Px, MLx); M.Multiply(Py, MLy); M.Multiply(Pz, MLz); // allocate memory for internal buffers Preconditioner = new DiagonalMatrix(N); WeightsM = new DiagonalMatrix(N); Cx = new double[N]; Cy = new double[N]; Cz = new double[N]; Bx = new double[N]; By = new double[N]; Bz = new double[N]; Sx = new double[N]; Sy = new double[N]; Sz = new double[N]; UpdateForSolve(); }
public void Initialize() { int NV = Curve.VertexCount; ToCurveV = new int[NV]; ToIndex = new int[NV]; N = 0; for (int k = 0; k < NV; k++) { int vid = k; ToCurveV[N] = vid; ToIndex[vid] = N; N++; } Px = new double[N]; Py = new double[N]; Pz = new double[N]; nbr_counts = new int[N]; SymmetricSparseMatrix M = new SymmetricSparseMatrix(); for (int i = 0; i < N; ++i) { int vid = ToCurveV[i]; Vector3d v = Curve.GetVertex(vid); Px[i] = v.x; Py[i] = v.y; Pz[i] = v.z; nbr_counts[i] = (i == 0 || i == N - 1) ? 1 : 2; } // construct laplacian matrix for (int i = 0; i < N; ++i) { int vid = ToCurveV[i]; int n = nbr_counts[i]; Index2i nbrs = Curve.Neighbours(vid); double sum_w = 0; for (int k = 0; k < 2; ++k) { int nbrvid = nbrs[k]; if (nbrvid == -1) { continue; } int j = ToIndex[nbrvid]; int n2 = nbr_counts[j]; // weight options double w = -1; //double w = -1.0 / Math.Sqrt(n + n2); //double w = -1.0 / n; M.Set(i, j, w); sum_w += w; } sum_w = -sum_w; M.Set(vid, vid, sum_w); } // transpose(L) * L, but matrix is symmetric... if (UseSoftConstraintNormalEquations) { //M = M.Multiply(M); // only works if M is symmetric!! PackedM = M.SquarePackedParallel(); } else { PackedM = new PackedSparseMatrix(M); } // compute laplacian vectors of initial mesh positions MLx = new double[N]; MLy = new double[N]; MLz = new double[N]; PackedM.Multiply(Px, MLx); PackedM.Multiply(Py, MLy); PackedM.Multiply(Pz, MLz); // allocate memory for internal buffers Preconditioner = new DiagonalMatrix(N); WeightsM = new DiagonalMatrix(N); Cx = new double[N]; Cy = new double[N]; Cz = new double[N]; Bx = new double[N]; By = new double[N]; Bz = new double[N]; Sx = new double[N]; Sy = new double[N]; Sz = new double[N]; need_solve_update = true; UpdateForSolve(); }
public SymmetricSparseMatrix(SymmetricSparseMatrix m) { N = m.N; d = new Dictionary <Index2i, double>(m.d); }