예제 #1
0
        /// <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;
                        }
                    }
                }
            }
        }
예제 #2
0
        public SymmetricSparseMatrix Multiply(SymmetricSparseMatrix M2)
        {
            SymmetricSparseMatrix R = new SymmetricSparseMatrix();

            Multiply(M2, ref R);
            return(R);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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;
        }
예제 #5
0
        // 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);
        }
예제 #6
0
 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);
 }
예제 #7
0
        /// <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;
                    }
                }
            }
        }
예제 #8
0
        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();
        }
예제 #10
0
        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();
        }
예제 #11
0
        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();
        }
예제 #12
0
 public SymmetricSparseMatrix(SymmetricSparseMatrix m)
 {
     N = m.N;
     d = new Dictionary <Index2i, double>(m.d);
 }