Пример #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
        /// <summary>
        /// Compute dot product of this.row[r] and M.col[c], where the
        /// column is stored as MTranspose.row[c]
        /// </summary>
        public double DotRowColumn(int r, int c, PackedSparseMatrix MTranspose)
        {
            Debug.Assert(Sorted && MTranspose.Sorted);
            Debug.Assert(Rows.Length == MTranspose.Rows.Length);

            int a = 0;
            int b = 0;

            nonzero[] Row = Rows[r];
            nonzero[] Col = MTranspose.Rows[c];
            int       NA  = Row.Length;
            int       NB  = Col.Length;

            double sum = 0;

            while (a < NA && b < NB)
            {
                if (Row[a].j == Col[b].j)
                {
                    sum += Row[a].d * Col[b].d;
                    a++;
                    b++;
                }
                else if (Row[a].j < Col[b].j)
                {
                    a++;
                }
                else
                {
                    b++;
                }
            }

            return(sum);
        }
Пример #3
0
        /// <summary>
        /// Returns this*this, as a packed sparse matrix. Computes in parallel.
        /// </summary>
        public PackedSparseMatrix SquarePackedParallel()
        {
            PackedSparseMatrix M = new PackedSparseMatrix(this);

            M.Sort();
            return(M.Square());
        }
Пример #4
0
        public PackedSparseMatrix Square()
        {
            if (Rows.Length != Columns)
            {
                throw new Exception("PackedSparseMatrix.Square: matrix is not square!");
            }

            int N = Columns;

            var entries      = new DVector <matrix_entry>();
            var entries_lock = new SpinLock();

            gParallel.BlockStartEnd(0, N - 1, (r_start, r_end) =>
            {
                for (int r1i = r_start; r1i <= r_end; r1i++)
                {
                    // determine which entries of squared matrix might be nonzeros
                    var nbrs = new HashSet <int>();
                    nbrs.Add(r1i);
                    PackedSparseMatrix.nonzero[] row = Rows[r1i];
                    for (int k = 0; k < row.Length; ++k)
                    {
                        if (row[k].j > r1i)
                        {
                            nbrs.Add(row[k].j);
                        }

                        PackedSparseMatrix.nonzero[] row2 = Rows[row[k].j];
                        for (int j = 0; j < row2.Length; ++j)
                        {
                            if (row2[j].j > r1i)                                 // only compute lower-triangular entries
                            {
                                nbrs.Add(row2[j].j);
                            }
                        }
                    }

                    // compute them!
                    foreach (int c2i in nbrs)
                    {
                        double v = DotRowColumn(r1i, c2i, this);
                        if (Math.Abs(v) > MathUtil.ZeroTolerance)
                        {
                            bool taken = false;
                            entries_lock.Enter(ref taken);
                            entries.Add(new matrix_entry()
                            {
                                r = r1i, c = c2i, value = v
                            });
                            entries_lock.Exit();
                        }
                    }
                }
            });

            var R = new PackedSparseMatrix(entries, N, N, true);

            return(R);
        }
Пример #5
0
        /// <summary>
        /// Compute dot product of this.row[r] and M.col[c], where the
        /// column is stored as MTranspose.row[c]
        /// </summary>
        public double DotRowColumn(int r, int c, PackedSparseMatrix MTranspose)
        {
            if (Sorted == false || MTranspose.Sorted == false)
            {
                throw new Exception("PackedSparseMatrix.DotRowColumn: matrices must be sorted!");
            }

            if (Rows.Length != MTranspose.Rows.Length)
            {
                throw new Exception("PackedSparseMatrix.DotRowColumn: matrices are not the same size!");
            }

            Debug.Assert(Sorted && MTranspose.Sorted);
            Debug.Assert(Rows.Length == MTranspose.Rows.Length);

            int ri = 0;
            int ci = 0;

            nonzero[] Row        = Rows[r];
            nonzero[] Col        = MTranspose.Rows[c];
            int       NR         = Row.Length;
            int       NC         = Col.Length;
            int       last_col_j = Col[NC - 1].j;
            int       last_row_j = Row[NR - 1].j;

            double sum = 0;

            while (ri < NR && ci < NC)
            {
                // early out if we passed last nonzero in other array
                if (Row[ri].j > last_col_j || Col[ci].j > last_row_j)
                {
                    break;
                }

                if (Row[ri].j == Col[ci].j)
                {
                    sum += Row[ri].d * Col[ci].d;
                    ri++;
                    ci++;
                }
                else if (Row[ri].j < Col[ci].j)
                {
                    ri++;
                }
                else
                {
                    ci++;
                }
            }

            return(sum);
        }
Пример #6
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);
        }
Пример #7
0
        public PackedSparseMatrix(PackedSparseMatrix copy)
        {
            int N = copy.Rows.Length;

            Rows = new nonzero[N][];
            for (int r = 0; r < N; ++r)
            {
                Rows[r] = new nonzero[copy.Rows[r].Length];
                Array.Copy(copy.Rows[r], Rows[r], Rows[r].Length);
            }
            Columns     = copy.Columns;
            Sorted      = copy.Sorted;
            NumNonZeros = copy.NumNonZeros;
            StorageMode = copy.StorageMode;
            IsSymmetric = copy.IsSymmetric;
        }
Пример #8
0
        /// <summary>
        /// Compute dot product of this.row[r] with all columns of M,
        /// where columns are stored in MTranspose rows.
        /// In theory more efficient than doing DotRowColumn(r,c) for each c,
        /// however so far the difference is negligible...perhaps because
        /// there are quite a few more branches in the inner loop
        /// </summary>
        public void DotRowAllColumns(int r, double[] sums, int[] col_indices, PackedSparseMatrix MTranspose)
        {
            Debug.Assert(Sorted && MTranspose.Sorted);
            Debug.Assert(Rows.Length == MTranspose.Rows.Length);

            int N = Rows.Length;
            int a = 0;

            nonzero[] Row = Rows[r];
            int       NA  = Row.Length;

            Array.Clear(sums, 0, N);
            Array.Clear(col_indices, 0, N);

            while (a < NA)
            {
                int aj = Row[a].j;
                for (int ci = 0; ci < N; ++ci)
                {
                    nonzero[] Col = MTranspose.Rows[ci];

                    int b = col_indices[ci];
                    if (b >= Col.Length)
                    {
                        continue;
                    }

                    while (b < Col.Length && Col[b].j < aj)
                    {
                        b++;
                    }

                    if (b < Col.Length && aj == Col[b].j)
                    {
                        sums[ci] += Row[a].d * Col[b].d;
                        b++;
                    }
                    col_indices[ci] = b;
                }
                a++;
            }
        }
Пример #9
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();
        }
Пример #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();
        }