private void *Factorization(CCSMatrix C)
 {
     fixed(int *ri = C.RowIndex, ci = C.ColIndex)
     fixed(double *val = C.Values)
     return(CreaterCholeskySolver(C.ColumnSize, C.NumNonZero, ri, ci, val));
 }
        private CCSMatrix MultiplyATA(ColMatrix A)
        {
            int[] count = new int[A.RowSize];
            for (int i = 0; i < count.Length; i++)
            {
                count[i] = 0;
            }
            foreach (int[] r in A.rowIndex)
            {
                foreach (int ri in r)
                {
                    count[ri]++;
                }
            }

            int[][] colIndex  = new int[A.RowSize][];
            int[][] listIndex = new int[A.RowSize][];
            for (int i = 0; i < A.RowSize; i++)
            {
                colIndex[i]  = new int[count[i]];
                listIndex[i] = new int[count[i]];
            }
            for (int i = 0; i < count.Length; i++)
            {
                count[i] = 0;
            }

            for (int i = 0; i < A.values.Length; i++)
            {
                int[] row = A.rowIndex[i];
                for (int j = 0; j < row.Length; j++)
                {
                    int r = row[j];
                    int c = count[r];
                    colIndex[r][c]  = i;
                    listIndex[r][c] = j;
                    count[r]++;
                }
            }
            count = null;

            CCSMatrix ATA = new CCSMatrix(A.ColumnSize, A.ColumnSize);
            Set <int> set = new Set <int>();

            double[]      tmp          = new double[A.ColumnSize];
            List <int>    ATA_RowIndex = new List <int>();
            List <double> ATA_Value    = new List <double>();

            for (int i = 0; i < A.ColumnSize; i++)
            {
                tmp[i] = 0;
            }

            for (int j = 0; j < A.ColumnSize; j++)
            {
                for (int ri = 0; ri < A.rowIndex[j].Length; ri++)
                {
                    int    k   = A.rowIndex[j][ri];
                    double val = A.values[j][ri];

                    for (int k2 = 0; k2 < colIndex[k].Length; k2++)
                    {
                        int i = colIndex[k][k2];
                        if (i < j)
                        {
                            continue;
                        }
                        set.Add(i);
                        tmp[i] += val * A.values[i][listIndex[k][k2]];
                    }
                }

                int[] s  = set.ToArray(); Array.Sort(s);
                int   cc = 0;
                foreach (int k in s)
                {
                    if (tmp[k] == 0)
                    {
                        continue;
                    }
                    ATA_RowIndex.Add(k);
                    ATA_Value.Add(tmp[k]);
                    tmp[k] = 0;
                    cc++;
                }
                ATA.ColIndex[j + 1] = ATA.ColIndex[j] + cc;
                set.Clear();
            }

            ATA.RowIndex = ATA_RowIndex.ToArray(); ATA_RowIndex = null;
            ATA.Values   = ATA_Value.ToArray(); ATA_Value = null;
            return(ATA);
        }
        public double[][] SolveSystem(double[] lapWeight, double[] posWeight)
        {
            int vn = mesh.VertexCount;
            int fn = mesh.FaceCount;

            double[][] pos = new double[3][];
            pos[0] = new double[vn];
            pos[1] = new double[vn];
            pos[2] = new double[vn];
//          for (int i = 0; i < simplifiedMeshes[0].Count; i++)
//          {
//              int j = simplifiedMeshes[0][i].index;
//              pos[0][j] = mesh.VertexPos[j * 3];
//              pos[1][j] = mesh.VertexPos[j * 3 + 1];
//              pos[2][j] = mesh.VertexPos[j * 3 + 2];
//          }
            for (int i = 0; i < vn; i++)
            {
                int j = i;
                pos[0][j] = mesh.VertexPos[j * 3];
                pos[1][j] = mesh.VertexPos[j * 3 + 1];
                pos[2][j] = mesh.VertexPos[j * 3 + 2];
            }

            this.originalArea = new double[vn];
            for (int i = 0; i < vn; i++)
            {
                originalArea[i] = 0;
            }
            for (int i = 0, j = 0; i < fn; i++, j += 3)
            {
                int    c1   = mesh.FaceIndex[j];
                int    c2   = mesh.FaceIndex[j + 1];
                int    c3   = mesh.FaceIndex[j + 2];
                double area = mesh.ComputeFaceArea(i);
                originalArea[c1] += area;
                originalArea[c2] += area;
                originalArea[c3] += area;
            }

            double weightAdjustment = Math.Pow((simplificationRatio), simplifiedMeshes.Count - 1);

            weightAdjustment = 1.0;
            for (int level = 0; level < simplifiedMeshes.Count; level++)
            {
                ColMatrix colA   = BuildMatrixA(simplifiedMeshes[level], faceRecords[level], lapWeight, posWeight, weightAdjustment);
                CCSMatrix ccsATA = MultiplyATA(colA);
                //CCSMatrix ccsA = new CCSMatrix(A);
                //RowBasedMatrix rbA = new RowBasedMatrix(A); A = null;
                List <VertexRecord> records = simplifiedMeshes[level];
                int      n      = records.Count;
                double[] x      = new double[n];
                double[] b      = new double[n * 2];
                double[] ATb    = new double[n];
                double[] inv    = null;
                void *   solver = null;
                string   s      = "";
                s += weightAdjustment.ToString();
                //weightAdjustment /= (simplificationRatio);

                if (level == 0)
                {
                    solver = Factorization(ccsATA);
                    if (solver == null)
                    {
                        throw new Exception();
                    }
                }

                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        b[j] = 0;
                        int k = records[j].index;
                        b[j + n] = mesh.VertexPos[k * 3 + i] * posWeight[k] * (currentArea[j] / originalArea[k]);
                        //b[j + n] = mesh.VertexPos[k * 3 + i] * posWeight[k];
                        //x[j] = mesh.VertexPos[k * 3 + i];
                        x[j] = pos[i][k];
                    }
                    colA.PreMultiply(b, ATb);

                    if (level == 0)
                    {
                        fixed(double *_x = x, _ATb = ATb)
                        Solve(solver, _x, _ATb);
                    }
                    else
                    {
                        int iter = colA.ATACG(x, ATb, convergeRatio, n);
                        s += " " + iter;
                    }

                    //if (level == 0)
                    for (int j = 0; j < n; j++)
                    {
                        int k = records[j].index;
                        pos[i][k] = x[j];
                        //Program.PrintText(x[j].ToString());
                    }
                }

                if (solver != null)
                {
                    FreeSolver(solver);
                    solver = null;
                }

                if (level < simplifiedMeshes.Count - 1)
                {
                    //Program.PrintText(collapsedRecords[level].Count.ToString());
                    foreach (EdgeRecord rec in collapsedRecords[level])
                    {
                        Vector3d p = new Vector3d();
                        foreach (int j in rec.adjV)
                        {
                            p.x += pos[0][j];
                            p.y += pos[1][j];
                            p.z += pos[2][j];
                        }
                        pos[0][rec.vIndex] = p.x /= rec.adjV.Count;
                        pos[1][rec.vIndex] = p.y /= rec.adjV.Count;
                        pos[2][rec.vIndex] = p.z /= rec.adjV.Count;
                    }
                }
                Program.PrintText(s);
            }
            return(pos);
        }
        private CCSMatrix MultiplyATA(CCSMatrix A)
        {
            int[] last     = new int[A.RowSize];
            int[] next     = new int[A.NumNonZero];
            int[] colIndex = new int[A.NumNonZero];
            for (int i = 0; i < last.Length; i++)
            {
                last[i] = -1;
            }
            for (int i = 0; i < next.Length; i++)
            {
                next[i] = -1;
            }
            for (int i = 0; i < A.ColumnSize; i++)
            {
                for (int j = A.ColIndex[i]; j < A.ColIndex[i + 1]; j++)
                {
                    int k = A.RowIndex[j];
                    if (last[k] != -1)
                    {
                        next[last[k]] = j;
                    }
                    last[k]     = j;
                    colIndex[j] = i;
                }
            }
            last = null;

            CCSMatrix ATA = new CCSMatrix(A.ColumnSize, A.ColumnSize);
            Set <int> set = new Set <int>();

            double[]      tmp          = new double[A.ColumnSize];
            List <int>    ATA_RowIndex = new List <int>();
            List <double> ATA_Value    = new List <double>();

            for (int i = 0; i < A.ColumnSize; i++)
            {
                tmp[i] = 0;
            }

            for (int j = 0; j < A.ColumnSize; j++)
            {
                for (int col = A.ColIndex[j]; col < A.ColIndex[j + 1]; col++)
                {
                    int    k   = A.RowIndex[col];
                    double val = A.Values[col];

                    int curr = col;
                    while (true)
                    {
                        int i = colIndex[curr];
                        set.Add(i);
                        tmp[i] += val * A.Values[curr];
                        if (next[curr] != -1)
                        {
                            curr = next[curr];
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                int[] s     = set.ToArray(); Array.Sort(s);
                int   count = 0;
                foreach (int k in s)
                {
                    if (tmp[k] == 0)
                    {
                        continue;
                    }
                    ATA_RowIndex.Add(k);
                    ATA_Value.Add(tmp[k]);
                    tmp[k] = 0;
                    count++;
                }
                ATA.ColIndex[j + 1] = ATA.ColIndex[j] + count;
                set.Clear();
            }

            ATA.RowIndex = ATA_RowIndex.ToArray(); ATA_RowIndex = null;
            ATA.Values   = ATA_Value.ToArray(); ATA_Value = null;
            return(ATA);
        }
        public double[][] SolveSystem(double[] lapWeight, double[] posWeight)
        {
            #region Init Variables
            int        vn  = mesh.VertexCount;
            int        fn  = mesh.FaceCount;
            double[][] pos = new double[3][];
            pos[0] = new double[vn];
            pos[1] = new double[vn];
            pos[2] = new double[vn];
            for (int i = 0, j = 0; i < vn; i++, j += 3)
            {
                pos[0][i] = mesh.VertexPos[j];
                pos[1][i] = mesh.VertexPos[j + 1];
                pos[2][i] = mesh.VertexPos[j + 2];
            }
            #endregion

            for (int level = 0; level < resolutions.Count; level++)
            {
                Resolution r = resolutions[level];

                // build matrix
                ColMatrix colA   = BuildMatrixA(r, lapWeight, posWeight);
                CCSMatrix ccsATA = MultiplyATA(colA);
                string    s      = "#: " + r.vertexList.Length + " iter: ";

                // solve system
                int      n      = r.vertexList.Length;
                double[] x      = new double[n];
                double[] b      = new double[n * 2];
                double[] ATb    = new double[n];
                void *   solver = null;
                if (level == 0)
                {
                    solver = Factorization(ccsATA);
                }

                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        b[j] = 0;
                        int k = r.vertexList[j];
                        //b[j + n] = mesh.VertexPos[k * 3 + i] * posWeight[k] * (currentArea[j] / originalArea[k]);
                        b[j + n] = mesh.VertexPos[k * 3 + i] * posWeight[k];
                        //x[j] = mesh.VertexPos[k * 3 + i];
                        x[j] = pos[i][k];
                    }
                    colA.PreMultiply(b, ATb);

                    if (level == 0)
                        fixed(double *_x = x, _ATb = ATb)
                        Solve(solver, _x, _ATb);
                    else
                    {
                        int iter = colA.ATACG(x, ATb, convergeRatio, n);
                        s += " " + iter;
                    }

                    //if (level == resolutions.Count-1)
                    for (int j = 0; j < n; j++)
                    {
                        pos[i][r.vertexList[j]] = x[j];
                    }
                }
                Program.PrintText(s);

                // interpolation solution
                if (level < resolutions.Count - 1)
                {
                    for (int i = 0; i < r.collapsedIndex.Length; i++)
                    {
                        int      index     = r.collapsedIndex[i];
                        Vector3d p         = new Vector3d();
                        double   totWeight = 0;
                        foreach (int adj in r.weight[i].Keys)
                        {
                            double w = r.weight[i][adj];
                            p.x       += pos[0][adj] * w;
                            p.y       += pos[1][adj] * w;
                            p.z       += pos[2][adj] * w;
                            totWeight += w;
                        }
                        pos[0][index] = p.x /= totWeight;
                        pos[1][index] = p.y /= totWeight;
                        pos[2][index] = p.z /= totWeight;
                    }
                }
            }

            return(pos);
        }