Beispiel #1
0
int main (void)
{
    cholmod_sparse *A ;
    cholmod_dense *x, *b, *r ;
    cholmod_factor *L ;
    double one [2] = {1,0}, m1 [2] = {-1,0} ;	    /* basic scalars */
    cholmod_common c ;
    cholmod_start (&c) ;			    /* start CHOLMOD */
    A = cholmod_read_sparse (stdin, &c) ;	    /* read in a matrix */
    cholmod_print_sparse (A, "A", &c) ;		    /* print the matrix */
    if (A == NULL || A->stype == 0)		    /* A must be symmetric */
    {
	cholmod_free_sparse (&A, &c) ;
	cholmod_finish (&c) ;
	return (0) ;
    }
    b = cholmod_ones (A->nrow, 1, A->xtype, &c) ;   /* b = ones(n,1) */
    L = cholmod_analyze (A, &c) ;		    /* analyze */
    cholmod_factorize (A, L, &c) ;		    /* factorize */
    x = cholmod_solve (CHOLMOD_A, L, b, &c) ;	    /* solve Ax=b */
    r = cholmod_copy_dense (b, &c) ;		    /* r = b */
    cholmod_sdmult (A, 0, m1, one, x, r, &c) ;	    /* r = r-Ax */
    printf ("norm(b-Ax) %8.1e\n",
	    cholmod_norm_dense (r, 0, &c)) ;	    /* print norm(r) */
    cholmod_free_factor (&L, &c) ;		    /* free matrices */
    cholmod_free_sparse (&A, &c) ;
    cholmod_free_dense (&r, &c) ;
    cholmod_free_dense (&x, &c) ;
    cholmod_free_dense (&b, &c) ;
    cholmod_finish (&c) ;			    /* finish CHOLMOD */
    return (0) ;
}
Beispiel #2
0
int main (int argc, char **argv)
{
    /* ---------------------------------------------------------------------- */
    /* get the file containing the input matrix */
    /* ---------------------------------------------------------------------- */

    FILE *ff = NULL ;
    FILE *fb = NULL ;
    if (argc <= 1)
      {
        printf("Usage is: cholmod_simple A.tri [B.txt (dense)]\n");
        exit(0);
      }
    if (argc > 1)
      ff = fopen(argv[1],"r");
    if (argc > 2)
      fb = fopen(argv[2], "r");

    cholmod_sparse *A ;
    cholmod_dense *x, *b, *r ;
    cholmod_factor *L ;
    double one [2] = {1,0}, m1 [2] = {-1,0} ; // basic scalars 
    cholmod_common c ;
    cholmod_start (&c) ;			    /* start CHOLMOD */
    A = cholmod_read_sparse (ff, &c) ;              /* read in a matrix */
    cholmod_print_sparse (A, (char *)"A", &c) ; /* print the matrix */
    if (A->dtype) printf("A is float\n");
    else printf("A is double\n");
    if (A == NULL || A->stype == 0)		    /* A must be symmetric */
    {
	cholmod_free_sparse (&A, &c) ;
	cholmod_finish (&c) ;
        if (ff) fclose(ff);
        if (fb) fclose(fb);
	return (0) ;
    }
    if (fb)
      b = cholmod_read_dense(fb, &c);
    else
      b = cholmod_ones (A->nrow, 1, A->xtype, &c) ; /* b = ones(n,1) */
    double t0 = CPUTIME;
    L = cholmod_analyze (A, &c) ;		    /* analyze */
    cholmod_factorize (A, L, &c) ;		    /* factorize */
    x = cholmod_solve (CHOLMOD_A, L, b, &c) ;	    /* solve Ax=b */
    double t1 = CPUTIME;
    if (c.dtype) printf("Compute is float\n");
    else printf("Compute is double\n");
    printf("Time: %12.4f \n", t1-t0);
    r = cholmod_copy_dense (b, &c) ;		    /* r = b */
    cholmod_sdmult (A, 0, m1, one, x, r, &c) ;	    /* r = r-Ax */
    printf ("norm(b-Ax) %8.1e\n",
	    cholmod_norm_dense (r, 0, &c)) ;	    /* print norm(r) */
    cholmod_free_factor (&L, &c) ;		    /* free matrices */
    cholmod_free_sparse (&A, &c) ;
    cholmod_free_dense (&r, &c) ;
    cholmod_free_dense (&x, &c) ;
    cholmod_free_dense (&b, &c) ;
    cholmod_finish (&c) ;			    /* finish CHOLMOD */
    return (0) ;
}
Beispiel #3
0
// called from package MatrixModels's R code:
SEXP dgCMatrix_cholsol(SEXP x, SEXP y)
{
    /* Solve Sparse Least Squares X %*% beta ~= y  with dense RHS y,
     * where X = t(x) i.e. we pass  x = t(X)  as argument,
     * via  "Cholesky(X'X)" .. well not really:
     * cholmod_factorize("x", ..) finds L in  X'X = L'L directly */
    CHM_SP cx = AS_CHM_SP(x);
    /* FIXME: extend this to work in multivariate case, i.e. y a matrix with > 1 column ! */
    CHM_DN cy = AS_CHM_DN(coerceVector(y, REALSXP)), rhs, cAns, resid;
    CHM_FR L;
    int n = cx->ncol;/* #{obs.} {x = t(X) !} */
    double one[] = {1,0}, zero[] = {0,0}, neg1[] = {-1,0};
    const char *nms[] = {"L", "coef", "Xty", "resid", ""};
    SEXP ans = PROTECT(Rf_mkNamed(VECSXP, nms));
    R_CheckStack();

    if (n < cx->nrow || n <= 0)
	error(_("dgCMatrix_cholsol requires a 'short, wide' rectangular matrix"));
    if (cy->nrow != n)
	error(_("Dimensions of system to be solved are inconsistent"));
    rhs = cholmod_allocate_dense(cx->nrow, 1, cx->nrow, CHOLMOD_REAL, &c);
    /* cholmod_sdmult(A, transp, alpha, beta, X, Y, &c):
     *		Y := alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y ;
     * here: rhs := 1 * x %*% y + 0 =  x %*% y =  X'y  */
    if (!(cholmod_sdmult(cx, 0 /* trans */, one, zero, cy, rhs, &c)))
	error(_("cholmod_sdmult error (rhs)"));
    L = cholmod_analyze(cx, &c);
    if (!cholmod_factorize(cx, L, &c))
	error(_("cholmod_factorize failed: status %d, minor %d from ncol %d"),
	      c.status, L->minor, L->n);
/* FIXME: Do this in stages so an "effects" vector can be calculated */
    if (!(cAns = cholmod_solve(CHOLMOD_A, L, rhs, &c)))
	error(_("cholmod_solve (CHOLMOD_A) failed: status %d, minor %d from ncol %d"),
	      c.status, L->minor, L->n);
    /* L : */
    SET_VECTOR_ELT(ans, 0, chm_factor_to_SEXP(L, 0));
    /* coef : */
    SET_VECTOR_ELT(ans, 1, allocVector(REALSXP, cx->nrow));
    Memcpy(REAL(VECTOR_ELT(ans, 1)), (double*)(cAns->x), cx->nrow);
    /* X'y : */
/* FIXME: Change this when the "effects" vector is available */
    SET_VECTOR_ELT(ans, 2, allocVector(REALSXP, cx->nrow));
    Memcpy(REAL(VECTOR_ELT(ans, 2)), (double*)(rhs->x), cx->nrow);
    /* resid := y */
    resid = cholmod_copy_dense(cy, &c);
    /* cholmod_sdmult(A, transp, alp, bet, X, Y, &c):
     *		Y := alp*(A*X) + bet*Y or alp*(A'*X) + beta*Y ;
     * here: resid := -1 * x' %*% coef + 1 * y = y - X %*% coef  */
    if (!(cholmod_sdmult(cx, 1/* trans */, neg1, one, cAns, resid, &c)))
	error(_("cholmod_sdmult error (resid)"));
    /* FIXME: for multivariate case, i.e. resid  *matrix* with > 1 column ! */
    SET_VECTOR_ELT(ans, 3, allocVector(REALSXP, n));
    Memcpy(REAL(VECTOR_ELT(ans, 3)), (double*)(resid->x), n);

    cholmod_free_factor(&L, &c);
    cholmod_free_dense(&rhs, &c);
    cholmod_free_dense(&cAns, &c);
    UNPROTECT(1);
    return ans;
}
Beispiel #4
0
/* Uses factorization to solve. */
void
ClpCholeskyUfl::solve (double * region)
{
     cholmod_dense *x, *b;
     b = cholmod_allocate_dense (numberRows_, 1, numberRows_, CHOLMOD_REAL, c_) ;
     CoinMemcpyN(region, numberRows_, (double *) b->x);
     x = cholmod_solve (CHOLMOD_A, L_, b, c_) ;
     CoinMemcpyN((double *) x->x, numberRows_, region);
     cholmod_free_dense (&x, c_) ;
     cholmod_free_dense (&b, c_) ;
}
cholmod_dense *
MultivariateFNormalSufficientSparse::evaluate_derivative_FM() const
{
      // d(-log(p))/d(FM) = - N * P * epsilon
      IMP_LOG(TERSE, "MVNsparse: evaluate_derivative_FM() = " << std::endl);
      cholmod_dense *tmp = cholmod_solve(CHOLMOD_A, L_, epsilon_, c_);
      if (L_->xtype != CHOLMOD_REAL)
          IMP_THROW("matrix type is not real, update the code first",
                ModelException);
      double *x = (double *)tmp->x;
      for (size_t i=0; i<tmp->nzmax; ++i) x[i] *= -N_;
      return tmp;
}
  // compute trans(epsilon)*Sigma^{-1}*epsilon by solving for the
  // rhs product and multiplying by trans(epsilon)
  // could be made more stable by using a LLt factorization and
  // solving for LPepsilon and then multiplying by
  // its transpose.
  double MultivariateFNormalSufficientSparse::mean_dist() const
{
    cholmod_dense *tmp = cholmod_solve(CHOLMOD_A, L_, epsilon_, c_);
    if (tmp->xtype != CHOLMOD_REAL)
          IMP_THROW("matrix type is not real, update code first",
                  ModelException);
    double dist=0;
    double *x1 = (double *) tmp->x;
    double *x2 = (double *) epsilon_->x;
    for (size_t i=0; i<tmp->nzmax; ++i) dist += x1[i]*x2[i];
    cholmod_free_dense(&tmp, c_);
    IMP_LOG(TERSE, "MVNsparse:   mean_dist = " << dist << std::endl);
    return dist;
}
int CholeskyFactorization::solve(Matrix& rhs, Matrix& solution) {
    if (m_matrix_type == Matrix::MATRIX_SPARSE) {
        cholmod_dense *x;

        /* cast the RHS as a cholmod_dense b = rhs */
        if (rhs.m_type == Matrix::MATRIX_DENSE) {

            cholmod_dense *b;
            b = cholmod_allocate_dense(rhs.m_nrows, rhs.m_ncols, rhs.m_nrows, CHOLMOD_REAL, Matrix::cholmod_handle());
            b->x = rhs.m_data;

            /* Solve - rhs is dense*/
            x = cholmod_solve(CHOLMOD_A, m_factor, b, Matrix::cholmod_handle());
            solution = Matrix(rhs.m_nrows, rhs.m_ncols);
            solution.m_delete_data = false;
            memcpy(solution.m_data, static_cast<double*> (x->x), rhs.m_nrows * rhs.m_ncols * sizeof (double));
            cholmod_free_dense(&x, Matrix::cholmod_handle());

        } else if (rhs.m_type == Matrix::MATRIX_SPARSE) {
            // still untested!
            cholmod_sparse * rhs_sparse;
            if (rhs.m_sparse == NULL) {
                const_cast<Matrix&> (rhs)._createSparse();
            }
            rhs_sparse = rhs.m_sparse;
            cholmod_sparse * result = cholmod_spsolve(CHOLMOD_LDLt, m_factor, rhs_sparse, Matrix::cholmod_handle());
            solution = Matrix(rhs.m_nrows, rhs.m_ncols, Matrix::MATRIX_SPARSE);
            solution.m_sparse = result;
            solution._createTriplet();
        } else {
            throw std::logic_error("Not supported");
        }
        return ForBESUtils::STATUS_OK;
    } else { /* the matrix to be factorized is not sparse */
        int info = ForBESUtils::STATUS_UNDEFINED_FUNCTION;
        solution = Matrix(rhs);
        if (m_matrix_type == Matrix::MATRIX_DENSE) {
            info = LAPACKE_dpotrs(LAPACK_COL_MAJOR, 'L', m_matrix_nrows, rhs.m_ncols, m_L, m_matrix_nrows, solution.m_data, m_matrix_nrows);
        } else if (m_matrix_type == Matrix::MATRIX_SYMMETRIC) {
            info = LAPACKE_dpptrs(LAPACK_COL_MAJOR, 'L', m_matrix_nrows, rhs.m_ncols, m_L, solution.m_data, m_matrix_nrows);
        } else {
            throw std::invalid_argument("This matrix type is not supported - only DENSE, SPARSE and SYMMETRIC are supported");
        }
        return info;
    }
}
Beispiel #8
0
SEXP CHMfactor_solve(SEXP a, SEXP b, SEXP system)
{
    CHM_FR L = AS_CHM_FR(a);
    SEXP bb = PROTECT(dup_mMatrix_as_dgeMatrix(b));
    CHM_DN B = AS_CHM_DN(bb), X;
    int sys = asInteger(system);
    R_CheckStack();

    if (!(sys--))		/* align with CHOLMOD defs: R's {1:9} --> {0:8},
				   see ./CHOLMOD/Cholesky/cholmod_solve.c */
	error(_("system argument is not valid"));

    X = cholmod_solve(sys, L, B, &c);
    UNPROTECT(1);
    return chm_dense_to_SEXP(X, 1/*do_free*/, 0/*Rkind*/,
			     GET_SLOT(bb, Matrix_DimNamesSym), FALSE);
}
Beispiel #9
0
SEXP dsCMatrix_matrix_solve(SEXP a, SEXP b)
{
    SEXP Chol = get_factor_pattern(a, "spdCholesky", 3);
    cholmod_factor *L;
    cholmod_dense  *cx,
	*cb = as_cholmod_dense(PROTECT(mMatrix_as_dgeMatrix(b)));
    
    if (Chol == R_NilValue)
	Chol = dsCMatrix_Cholesky(a,
				  ScalarLogical(1),  /* permuted */
				  ScalarLogical(1),  /* LDL' */
				  ScalarLogical(0)); /* simplicial */
    L = as_cholmod_factor(Chol);
    cx = cholmod_solve(CHOLMOD_A, L, cb, &c);
    Free(cb); Free(L);
    UNPROTECT(1);
    return chm_dense_to_SEXP(cx, 1);
}
Beispiel #10
0
// deliver the address of x
void Algebra::solve_CK(Matrix & A, cholmod_dense *&x, cholmod_dense *b, cholmod_common *cm, size_t &peak_mem, size_t &CK_mem){
	cholmod_factor *L;
	cm->final_ll = true; // stay in LL' format
	clock_t t1, t2;
	t1 = clock();
	CK_decomp(A, L, cm, peak_mem, CK_mem);
	t2 = clock();
	clog<<"decomp time for CK is: "<<1.0*(t2-t1) / CLOCKS_PER_SEC<<endl;
	// then solve
	t1 = clock();
	x = cholmod_solve(CHOLMOD_A, L, b, cm);
	t2 = clock();
	clog<<"solve time is: "<<1.0*(t2-t1)/ CLOCKS_PER_SEC<<endl;
	//cholmod_print_dense(x, "x", cm);
	//cholmod_print_dense(b, "b", cm);
	//cholmod_print_factor(L, "L", cm);
	cholmod_free_factor(&L, cm);
	
}
Beispiel #11
0
int main (int argc, char **argv)
{
    double resid, t, ta, tf, ts, tot, bnorm, xnorm, anorm, rnorm, fl, anz, 
	axbnorm, rnorm2, resid2 ;
    FILE *f ;
    cholmod_sparse *A ;
    cholmod_dense *X, *B, *W, *R ;
    double one [2], zero [2], minusone [2], beta [2], xlnz ;
    cholmod_common Common, *cm ;
    cholmod_factor *L ;
    double *Bx, *Rx, *Xx ;
    int i, n, isize, xsize, ordering, xtype, s, ss, lnz ;

    /* ---------------------------------------------------------------------- */
    /* get the file containing the input matrix */
    /* ---------------------------------------------------------------------- */

    ff = NULL ;
    if (argc > 1)
    {
	if ((f = fopen (argv [1], "r")) == NULL)
	{
	    my_handler (CHOLMOD_INVALID, __FILE__, __LINE__,
		    "unable to open file") ;
	}
	ff = f ;
    }
    else
    {
	f = stdin ;
    }

    /* ---------------------------------------------------------------------- */
    /* start CHOLMOD and set parameters */
    /* ---------------------------------------------------------------------- */

    cm = &Common ;
    cholmod_start (cm) ;

    /* use default parameter settings, except for the error handler.  This
     * demo program terminates if an error occurs (out of memory, not positive
     * definite, ...).  It makes the demo program simpler (no need to check
     * CHOLMOD error conditions).  This non-default parameter setting has no
     * effect on performance. */
    cm->error_handler = my_handler ;

    /* Note that CHOLMOD will do a supernodal LL' or a simplicial LDL' by
     * default, automatically selecting the latter if flop/nnz(L) < 40. */

    /* ---------------------------------------------------------------------- */
    /* create basic scalars */
    /* ---------------------------------------------------------------------- */

    zero [0] = 0 ;
    zero [1] = 0 ;
    one [0] = 1 ;
    one [1] = 0 ;
    minusone [0] = -1 ;
    minusone [1] = 0 ;
    beta [0] = 1e-6 ;
    beta [1] = 0 ;

    /* ---------------------------------------------------------------------- */
    /* read in a matrix */
    /* ---------------------------------------------------------------------- */

    printf ("\n---------------------------------- cholmod_demo:\n") ;
    A = cholmod_read_sparse (f, cm) ;
    if (ff != NULL) fclose (ff) ;
    anorm = cholmod_norm_sparse (A, 0, cm) ;
    xtype = A->xtype ;
    printf ("norm (A,inf) = %g\n", anorm) ;
    printf ("norm (A,1)   = %g\n", cholmod_norm_sparse (A, 1, cm)) ;
    cholmod_print_sparse (A, "A", cm) ;

    if (A->nrow > A->ncol)
    {
	/* Transpose A so that A'A+beta*I will be factorized instead */
	cholmod_sparse *C = cholmod_transpose (A, 2, cm) ;
	cholmod_free_sparse (&A, cm) ;
	A = C ;
	printf ("transposing input matrix\n") ;
    }

    /* ---------------------------------------------------------------------- */
    /* create an arbitrary right-hand-side */
    /* ---------------------------------------------------------------------- */

    n = A->nrow ;
    B = cholmod_zeros (n, 1, xtype, cm) ;
    Bx = B->x ;

#if GHS
    {
	/* b = A*ones(n,1), used by Gould, Hu, and Scott in their experiments */
	cholmod_dense *X0 ;
	X0 = cholmod_ones (A->ncol, 1, xtype, cm) ;
	cholmod_sdmult (A, 0, one, zero, X0, B, cm) ;
	cholmod_free_dense (&X0, cm) ;
    }
#else
    if (xtype == CHOLMOD_REAL)
    {
	/* real case */
	for (i = 0 ; i < n ; i++)
	{
	    double x = n ;
	    Bx [i] = 1 + i / x ;
	}
    }
    else
    {
	/* complex case */
	for (i = 0 ; i < n ; i++)
	{
	    double x = n ;
	    Bx [2*i  ] = 1 + i / x ;		/* real part of B(i) */
	    Bx [2*i+1] = (x/2 - i) / (3*x) ;	/* imag part of B(i) */
	}
    }
#endif

    cholmod_print_dense (B, "B", cm) ;
    bnorm = cholmod_norm_dense (B, 0, cm) ;	/* max norm */
    printf ("bnorm %g\n", bnorm) ;

    /* ---------------------------------------------------------------------- */
    /* analyze, factorize, and solve */
    /* ---------------------------------------------------------------------- */

    t = CPUTIME ;
    L = cholmod_analyze (A, cm) ;
    ta = CPUTIME - t ;
    ta = MAX (ta, 0) ;

    printf ("Analyze: flop %g lnz %g\n", cm->fl, cm->lnz) ;

    if (A->stype == 0)
    {
	printf ("Factorizing A*A'+beta*I\n") ;
	t = CPUTIME ;
	cholmod_factorize_p (A, beta, NULL, 0, L, cm) ;
	tf = CPUTIME - t ;
	tf = MAX (tf, 0) ;
    }
    else
    {
	printf ("Factorizing A\n") ;
	t = CPUTIME ;
	cholmod_factorize (A, L, cm) ;
	tf = CPUTIME - t ;
	tf = MAX (tf, 0) ;
    }

    t = CPUTIME ;

    X = cholmod_solve (CHOLMOD_A, L, B, cm) ;
    ts = CPUTIME - t ;
    ts = MAX (ts, 0) ;
    tot = ta + tf + ts ;

    /* ---------------------------------------------------------------------- */
    /* compute the residual */
    /* ---------------------------------------------------------------------- */

    if (A->stype == 0)
    {
	/* (AA'+beta*I)x=b is the linear system that was solved */
	/* W = A'*X */
	W = cholmod_allocate_dense (A->ncol, 1, A->ncol, xtype, cm) ;
	cholmod_sdmult (A, 2, one, zero, X, W, cm) ;
	/* R = B - beta*X */
	R = cholmod_zeros (n, 1, xtype, cm) ;
	Rx = R->x ;
	Xx = X->x ;
	if (xtype == CHOLMOD_REAL)
	{
	    for (i = 0 ; i < n ; i++)
	    {
		Rx [i] = Bx [i] - beta [0] * Xx [i] ;
	    }
	}
	else
	{
	    /* complex case */
	    for (i = 0 ; i < n ; i++)
	    {
		Rx [2*i  ] = Bx [2*i  ] - beta [0] * Xx [2*i  ] ;
		Rx [2*i+1] = Bx [2*i+1] - beta [0] * Xx [2*i+1] ;
	    }
	}
	/* R = A*W - R */
	cholmod_sdmult (A, 0, one, minusone, W, R, cm) ;
	cholmod_free_dense (&W, cm) ;
    }
    else
    {
	/* Ax=b was factorized and solved, R = B-A*X */
	R = cholmod_copy_dense (B, cm) ;
	cholmod_sdmult (A, 0, minusone, one, X, R, cm) ;
    }
    rnorm = cholmod_norm_dense (R, 0, cm) ;	    /* max abs. entry */
    xnorm = cholmod_norm_dense (X, 0, cm) ;	    /* max abs. entry */

    axbnorm = (anorm * xnorm + bnorm + ((n == 0) ? 1 : 0)) ;
    resid = rnorm / axbnorm ;

    /* ---------------------------------------------------------------------- */
    /* iterative refinement (real symmetric case only) */
    /* ---------------------------------------------------------------------- */

    resid2 = -1 ;
    if (A->stype != 0 && A->xtype == CHOLMOD_REAL)
    {
	cholmod_dense *R2 ;

	/* R2 = A\(B-A*X) */
	R2 = cholmod_solve (CHOLMOD_A, L, R, cm) ;
	/* compute X = X + A\(B-A*X) */
	Xx = X->x ;
	Rx = R2->x ;
	for (i = 0 ; i < n ; i++)
	{
	    Xx [i] = Xx [i] + Rx [i] ;
	}
	cholmod_free_dense (&R2, cm) ;
	cholmod_free_dense (&R, cm) ;

	/* compute the new residual, R = B-A*X */
	R = cholmod_copy_dense (B, cm) ;
	cholmod_sdmult (A, 0, minusone, one, X, R, cm) ;
	rnorm2 = cholmod_norm_dense (R, 0, cm) ;
	resid2 = rnorm2 / axbnorm ;
    }

    cholmod_free_dense (&R, cm) ;

    /* ---------------------------------------------------------------------- */
    /* print results */
    /* ---------------------------------------------------------------------- */

    cholmod_print_factor (L, "L", cm) ;

    /* determine the # of integers's and reals's in L.  See cholmod_free */
    if (L->is_super)
    {
	s = L->nsuper + 1 ;
	xsize = L->xsize ;
	ss = L->ssize ;
	isize =
	    n	/* L->Perm */
	    + n	/* L->ColCount, nz in each column of 'pure' L */
	    + s	/* L->pi, column pointers for L->s */
	    + s	/* L->px, column pointers for L->x */
	    + s	/* L->super, starting column index of each supernode */
	    + ss ;	/* L->s, the pattern of the supernodes */
    }
    else
    {
	/* this space can increase if you change parameters to their non-
	 * default values (cm->final_pack, for example). */
	lnz = L->nzmax ;
	xsize = lnz ;
	isize =
	    n	/* L->Perm */
	    + n	/* L->ColCount, nz in each column of 'pure' L */
	    + n+1	/* L->p, column pointers */
	    + lnz	/* L->i, integer row indices */
	    + n	/* L->nz, nz in each column of L */
	    + n+2	/* L->next, link list */
	    + n+2 ;	/* L->prev, link list */
    }

    anz = cm->anz ;
    for (i = 0 ; i < CHOLMOD_MAXMETHODS ; i++)
    {
	fl = cm->method [i].fl ;
	xlnz = cm->method [i].lnz ;
	cm->method [i].fl = -1 ;
	cm->method [i].lnz = -1 ;
	ordering = cm->method [i].ordering ;
	if (fl >= 0)
	{
	    printf ("Ordering: ") ;
	    if (ordering == CHOLMOD_POSTORDERED) printf ("postordered ") ;
	    if (ordering == CHOLMOD_NATURAL)     printf ("natural ") ;
	    if (ordering == CHOLMOD_GIVEN)	     printf ("user    ") ;
	    if (ordering == CHOLMOD_AMD)	     printf ("AMD     ") ;
	    if (ordering == CHOLMOD_METIS)	     printf ("METIS   ") ;
	    if (ordering == CHOLMOD_NESDIS)      printf ("NESDIS  ") ;
	    if (xlnz > 0)
	    {
		printf ("fl/lnz %10.1f", fl / xlnz) ;
	    }
	    if (anz > 0)
	    {
		printf ("  lnz/anz %10.1f", xlnz / anz) ;
	    }
	    printf ("\n") ;
	}
    }

    printf ("ints in L: %d, doubles in L: %d\n", isize, xsize) ;
    printf ("factor flops %g nnz(L) %15.0f (w/no amalgamation)\n",
	    cm->fl, cm->lnz) ;
    if (A->stype == 0)
    {
	printf ("nnz(A):    %15.0f\n", cm->anz) ;
    }
    else
    {
	printf ("nnz(A*A'): %15.0f\n", cm->anz) ;
    }
    if (cm->lnz > 0)
    {
	printf ("flops / nnz(L):  %8.1f\n", cm->fl / cm->lnz) ;
    }
    if (anz > 0)
    {
	printf ("nnz(L) / nnz(A): %8.1f\n", cm->lnz / cm->anz) ;
    }
    printf ("analyze cputime:  %12.4f\n", ta) ;
    printf ("factor  cputime:   %12.4f mflop: %8.1f\n", tf,
	(tf == 0) ? 0 : (1e-6*cm->fl / tf)) ;
    printf ("solve   cputime:   %12.4f mflop: %8.1f\n", ts,
	(ts == 0) ? 0 : (1e-6*4*cm->lnz / ts)) ;
    printf ("overall cputime:   %12.4f mflop: %8.1f\n", 
	    tot, (tot == 0) ? 0 : (1e-6 * (cm->fl + 4 * cm->lnz) / tot)) ;
    printf ("peak memory usage: %12.0f (MB)\n",
	    (double) (cm->memory_usage) / 1048576.) ;
    printf ("residual %8.1e (|Ax-b|/(|A||x|+|b|))\n", resid) ;
    if (resid2 >= 0)
    {
	printf ("residual %8.1e (|Ax-b|/(|A||x|+|b|))"
		" after iterative refinement\n", resid2) ;
    }
    printf ("rcond    %8.1e\n\n", cholmod_rcond (L, cm)) ;
    cholmod_free_factor (&L, cm) ;
    cholmod_free_dense (&X, cm) ;

    /* ---------------------------------------------------------------------- */
    /* free matrices and finish CHOLMOD */
    /* ---------------------------------------------------------------------- */

    cholmod_free_sparse (&A, cm) ;
    cholmod_free_dense (&B, cm) ;
    cholmod_finish (cm) ;
    return (0) ;
}
Beispiel #12
0
void Block::solve_CK(cholmod_common *cm){
	x_ck = cholmod_solve(CHOLMOD_A, L, b_new_ck, cm);
}
void tele2d::computeVectorField(){

	unsigned time1, time2, time3 ;
	time1 = clock() ;

	std::vector<std::vector<double2>>  allcurves = curves ;
	vector_field.clear() ;
	vector_field.resize(resolution*resolution) ;

	// delete too short curves
	for( int i=0; i<allcurves.size(); ++i ){
		if( allcurves[i].size() < 5 )
			allcurves.erase( allcurves.begin() + i ) ;
	}

	if( allcurves.size() == 0 ){
		std::cout<<"no valid curves!" ;
		exit(1) ;
	}

	// mark constrained vertices
	constrained_vertices_mark.clear() ;
	for( int i=0; i<resolution; ++i ) {
		std::vector<int> a ;
		for( int j=0;j<resolution; ++j )
			a.push_back(0) ;
		constrained_vertices_mark.push_back(a) ;
	}
	for( int i=0; i<allcurves.size(); ++ i){
		for( int j =0; j<allcurves[i].size(); ++ j){
			// get x index of closest vertices
			float x = allcurves[i][j].x * resolution - 0.5 ;
			int ix ;
			if( x-floor(x) < 0.5 ) ix = floor(x) ;
			else	ix = ceil( x ) ;
			// get y index of closest vertices
			float y = allcurves[i][j].y * resolution - 0.5 ;
			int iy ;
			if( y-floor(y) < 0.5 ) iy = floor(y) ;
			else	iy = ceil( y ) ;

			if( ix < 0 ) ix = 0;
			if( ix > resolution-1) ix = resolution -1;
			if( iy < 0 ) iy = 0;
			if( iy > resolution-1) iy = resolution -1;

			constrained_vertices_mark[ix][iy] = 1 ;

		}
	}

	// compute b
	std::vector<double2> b ;
	b.resize(resolution*resolution) ;
	for( int i=0; i<resolution; ++i ){
		for( int j=0; j<resolution; ++j){
			
			if(constrained_vertices_mark[i][j] == 0 ){
				b[i+j*resolution].x = 0; 
				b[i+j*resolution].y = 0; 
				continue ;
			}

			// otherwise, the vertex indexed by (i,j) is constrained
			double vx = ((double)i+0.5)/(double)resolution ; 
			double vy = ((double)j+0.5)/(double)resolution ; 
			
			// search for the closest points
			int curveid_record = 0;
			int pointid_record = 0;
			double mindis = 1000.0f ;
			for( int curveid=0; curveid<allcurves.size(); ++curveid ){				
				for( int pointid=0; pointid<allcurves[curveid].size(); ++pointid  ){
					double quadratic_dis = ( allcurves[curveid][pointid].x - vx )*( allcurves[curveid][pointid].x - vx ) + ( allcurves[curveid][pointid].y - vy )*( allcurves[curveid][pointid].y - vy ) ;
					if( quadratic_dis < mindis ){
							mindis = quadratic_dis ;
							curveid_record = curveid ;
							pointid_record = pointid ;
					}
				}
			}

			// compute the vector of the vertex indexed by (i,j)
			int pid1 = pointid_record-1 > 0 ? pointid_record-1 : 0 ;
			int pid2 = pointid_record+1 <  allcurves[curveid_record].size()-1 ? pointid_record+1 : allcurves[curveid_record].size()-1;

			double2 vector_of_vertex ;
			vector_of_vertex.x = allcurves[curveid_record][pid2].x - allcurves[curveid_record][pid1].x ;
			vector_of_vertex.y = allcurves[curveid_record][pid2].y - allcurves[curveid_record][pid1].y ;
			double norm = sqrt( vector_of_vertex.x * vector_of_vertex.x + vector_of_vertex.y * vector_of_vertex.y) ;
			vector_of_vertex.x /= norm ;
			vector_of_vertex.y /= norm ;


			assert( norm > 0 && norm < 1) ;

			//std::cout<<"norm "<<norm<<std::endl;
			
			b[i+j*resolution ] = vector_of_vertex ;


		}
	}


	// compute Pb
	std::vector<double2> Pb = b ;
	for( int i=0; i<Pb.size(); ++i ){
		Pb[i].x *= 1.0e8 ;
		Pb[i].y *= 1.0e8 ;
	}

	// compute L+P
	int vnum =  resolution*resolution  ;
	sparse_matrix L_add_P(vnum) ;  // create a sparse matrix of vnum rows

	// L_add_P <- D - W
	for( int id_x =0; id_x<resolution; ++id_x ){
		for( int id_y =0; id_y<resolution; ++id_y ){
			int vid = id_x + id_y * resolution ;
			if( id_x != 0 && id_x != resolution-1 && id_y != 0 && id_y != resolution-1 ){ // inner area
				//L_add_P[ vid + vid*vnum] += 6.8284 ;
				L_add_P.pluse(vid,vid,6.8284 ) ;
				int neibour_id_1 =  id_x + id_y * resolution - 1 ;
				int neibour_id_2 =  id_x + id_y * resolution + 1 ;
				int neibour_id_3 =  id_x + (id_y-1) * resolution ;
				int neibour_id_4 =  id_x + (id_y+1) * resolution ;
				int neibour_id_5 =  id_x + (id_y+1) * resolution - 1 ;
				int neibour_id_6 =  id_x + (id_y+1) * resolution + 1 ;
				int neibour_id_7 =  id_x + (id_y-1) * resolution - 1 ;
				int neibour_id_8 =  id_x + (id_y-1) * resolution + 1 ;
				//L_add_P[neibour_id_1+vid*vnum] -= 1 ;
				L_add_P.pluse(vid,neibour_id_1, -1 ) ;
				//L_add_P[neibour_id_2+vid*vnum] -= 1 ;
				L_add_P.pluse(vid,neibour_id_2, -1 ) ;
				//L_add_P[neibour_id_3+vid*vnum] -= 1 ;
				L_add_P.pluse(vid,neibour_id_3, -1 ) ;
				//L_add_P[neibour_id_4+vid*vnum] -= 1 ;
				L_add_P.pluse(vid,neibour_id_4, -1 ) ;
				//L_add_P[neibour_id_5+vid*vnum] -=  0.7071;
				L_add_P.pluse(vid,neibour_id_5, -0.7071 ) ;
				//L_add_P[neibour_id_6+vid*vnum] -=  0.7071;
				L_add_P.pluse(vid,neibour_id_6, -0.7071 ) ;
				//L_add_P[neibour_id_7+vid*vnum] -=  0.7071;
				L_add_P.pluse(vid,neibour_id_7, -0.7071 ) ;
				//L_add_P[neibour_id_8+vid*vnum] -=  0.7071;
				L_add_P.pluse(vid,neibour_id_8, -0.7071 ) ;

			}
			else if((id_x == 0 || id_x==resolution-1) && (id_y == 0 || id_y==resolution-1)  ){  // coners
				//L_add_P[ vid + vid*vnum] += 2.7071 ;
				L_add_P.pluse(vid,vid, 2.7071 ) ;
				int neibour_id_1 =  ( id_x == 0 ? ( id_x+id_y * resolution+1) :  ( id_x+id_y * resolution - 1) );
				int neibour_id_2 =  ( id_y == 0 ? ( id_x+ (id_y+1) * resolution) : ( id_x+ (id_y-1) * resolution )) ;
				int neibour_id_3 =  ( id_x == 0 ? 1 : (resolution-2) ) + ( id_y == 0 ? 1 : (resolution - 2)) * resolution ;

				//L_add_P[neibour_id_1+vid*vnum] -= 1 ;
				L_add_P.pluse(vid,neibour_id_1, -1 ) ;
				//L_add_P[neibour_id_2+vid*vnum] -= 1 ;
				L_add_P.pluse(vid,neibour_id_2, -1 ) ;
				//L_add_P[neibour_id_3+vid*vnum] -=  0.7071;
				L_add_P.pluse(vid,neibour_id_3, -0.7071 ) ;

			}
			else {																		// boundaries
				//L_add_P[ vid + vid*vnum] += 4.4142 ;
				L_add_P.pluse(vid,vid, 4.4142 ) ;

				int neibour_id_1, neibour_id_2, neibour_id_3, neibour_id_4, neibour_id_5 ;
				if( id_x == 0){
					neibour_id_1 =  id_x + id_y * resolution + 1 ;
					neibour_id_2 =  id_x + (id_y+1) * resolution ;
					neibour_id_3 =  id_x + (id_y-1) * resolution ;
					neibour_id_4 =  id_x + (id_y+1) * resolution + 1;
					neibour_id_5 =  id_x + (id_y-1) * resolution + 1 ;
				}
				else if( id_x == resolution-1 ){
					neibour_id_1 =  id_x + id_y * resolution - 1 ;
					neibour_id_2 =  id_x + (id_y+1) * resolution ;
					neibour_id_3 =  id_x + (id_y-1) * resolution ;
					neibour_id_4 =  id_x + (id_y+1) * resolution - 1;
					neibour_id_5 =  id_x + (id_y-1) * resolution - 1 ;
				}
				else if( id_y == resolution-1 ){
					neibour_id_1 =  id_x + id_y * resolution + 1 ;
					neibour_id_2 =  id_x + id_y * resolution - 1 ;
					neibour_id_3 =  id_x + (id_y-1) * resolution ;
					neibour_id_4 =  id_x + (id_y-1) * resolution + 1;
					neibour_id_5 =  id_x + (id_y-1) * resolution - 1 ;
				}
				else {
					neibour_id_1 =  id_x + id_y * resolution + 1 ;
					neibour_id_2 =  id_x + id_y * resolution - 1 ;
					neibour_id_3 =  id_x + (id_y+1) * resolution ;
					neibour_id_4 =  id_x + (id_y+1) * resolution + 1;
					neibour_id_5 =  id_x + (id_y+1) * resolution - 1 ;
				}
				//L_add_P[neibour_id_1+vid*vnum] -= 1 ;
				L_add_P.pluse(vid,neibour_id_1, -1 ) ;
				//L_add_P[neibour_id_2+vid*vnum] -= 1 ;
				L_add_P.pluse(vid,neibour_id_2, -1 ) ;
				//L_add_P[neibour_id_3+vid*vnum] -= 1 ;
				L_add_P.pluse(vid,neibour_id_3, -1 ) ;
				//L_add_P[neibour_id_4+vid*vnum] -=  0.7071;
				L_add_P.pluse(vid,neibour_id_4, -0.7071) ;
				//L_add_P[neibour_id_5+vid*vnum] -=  0.7071;
				L_add_P.pluse(vid,neibour_id_5, -0.7071 ) ;

			}

		}
	}
	// L_add_P <- D - W + P
	for( int i=0; i<resolution; ++i ){
		for( int j=0; j<resolution; ++j){
			if(constrained_vertices_mark[i][j] == 1  ){
				int vid = i + j*resolution ;
				//L_add_P[vid+vid*vnum]+=1e8 ; 
				L_add_P.pluse(vid,vid, 1.0e8  ) ;

			}
		}
	}




	// solve the linear system with cholmod
	cholmod_sparse *A ;
	cholmod_dense *x, *y, *b1 ;
	double one [2] = {1,0}, m1 [2] = {-1,0} ; /* basic scalars */
	cholmod_factor *L ;
	cholmod_common c ;
	cholmod_start (&c) ;; /* start CHOLMOD */
	
	//A = cholmod_read_sparse (pFile, &c) ; /* read in a matrix */
	CMatrix  *SM = new CMatrix( vnum, true, &c) ;
	//for( int i=0; i<vnum; ++i ){
	//	for( int j=0; j<vnum; ++j ){
	//		if( L_add_P.getValue(j,i)!=0 )
	//			SM->set_coef(i, j,L_add_P.getValue(j,i) ) ;
	//	}
	//}
	for( int i=0; i<L_add_P.data.size(); ++i){
		for( int j=0; j<L_add_P.data[i].size(); ++j)
			SM->set_coef(L_add_P.data[i][j].row, i,  L_add_P.data[i][j].val ) ;
	}

	A =(cholmod_sparse *) SM->get_cholmod_sparse();


	time2 = clock() ;

	//cholmod_print_sparse (A, "A", &c) ; /* print the matrix */

	if (A == NULL || A->stype == 0) /* A must be symmetric */
	{
		cholmod_free_sparse (&A, &c) ;
		cholmod_finish (&c) ;
		std::cout << "fail to load the matrix or it's not symmeric!"<<std::endl;
		exit(1) ;
	}

	b1 = cholmod_zeros(vnum, 1, CHOLMOD_REAL, &c);


	// --------------------- x demension -----------------------
	for( int i =0 ;i<Pb.size(); ++i ){
		((double*)(b1->x))[i] = Pb[i].x ;
	}
	L = cholmod_analyze (A, &c) ; /* analyze */
	cholmod_factorize (A, L, &c) ; /* factorize */
	x = cholmod_solve (CHOLMOD_A, L, b1, &c) ; /* solve Ax=b */


	// write x-values
	for( int i=0; i<vector_field.size(); ++i)
		vector_field[i].x = ((double*)(x->x))[i] ;
	// --------------------- y demension -----------------------
	for( int i =0 ;i<Pb.size(); ++i ){
		((double*)(b1->x))[i] = Pb[i].y ;
	}
	y = cholmod_solve (CHOLMOD_A, L, b1, &c) ; /* solve Ay=b */
	// write y-values
	for( int i=0; i<vector_field.size(); ++i)
		vector_field[i].y = ((double*)(y->x))[i] ;



	cholmod_free_factor (&L, &c) ; 
	cholmod_free_dense (&x, &c) ;
	cholmod_free_dense (&y, &c) ;
	cholmod_free_dense (&b1, &c) ;
	//delete L_add_P ;
	delete SM ;
	cholmod_finish (&c) ; /* finish CHOLMOD */



	double normx2, normy2 ;
	normx2 = normy2 = 0.0 ;

	for( int i=0; i<vnum; ++i ){
		normx2 += vector_field[i].x * vector_field[i].x ; 
		normy2 += vector_field[i].y * vector_field[i].y ; 
	}

	//std::cout<<"|x| = "<<sqrt(normx2) <<"\n|y| = "<<sqrt(normy2) <<std::endl;


	// normalize vector field
	for( int i=0; i<vector_field.size(); ++i){
		double norm = sqrt( vector_field[i].x * vector_field[i].x + vector_field[i].y * vector_field[i].y) ;
		vector_field[i].x /= norm ;
		vector_field[i].y /= norm ;

	}

	time3 = clock() ;


	//std::cout<<"time consumed by computing A and b: " << (double)(time2-time1)/CLOCKS_PER_SEC <<" s" <<std::endl ;
	//std::cout<<"time consumed by solving the system: " << (double)(time3-time2)/CLOCKS_PER_SEC <<" s" <<std::endl ;

	//std::cout<<"vector field computing completed."<<std::endl; ;
	int count = 0;
	for( int i=0; i<L_add_P.data.size(); ++i)
		count += L_add_P.data[i].size() ;

	//std::cout << "nonzero number: " << count <<std::endl; 

}
Beispiel #14
0
int main(void)
{
    int N = 2 ;
    int i, j, n ;
    int nz = 0;
    double *Ax ;
    double x, error ;
    cholmod_dense *A, *invK, *spinvK, *I ;
    cholmod_sparse *K, *V ;
    cholmod_factor *L ;
    cholmod_common Common,*cm ;
    clock_t start, end;
    double cpu_time_used;
    cm=&Common;
    // Start using CHOLMOD
    cholmod_start(cm) ;
    cm->print=5;
    /* SPARSE COVARIANCE MATRIX CONSTRUCTION */

    // Generate random symmetric positive (semi)definite matrix
    A = cholmod_zeros(N, N, CHOLMOD_REAL, &Common) ;
    Ax =(double*) A->x ;
    nz = N ;

    // Make positive-definite by adding something positive to the
    // diagonal
    for (n = 0; n < N; n++)
    {
        Ax[n+n*N] += 5;
    }

    // Make the matrix sparse
    K = cholmod_dense_to_sparse(A, TRUE, &Common) ;
    K->stype = 1 ; // NEED TO MAKE THE MATRIX SYMMETRIC

    // Identity matrix
    I = cholmod_eye(N,N,CHOLMOD_REAL,&Common) ;

    /* SIMPLICIAL */

    // Factorize
    Common.supernodal = CHOLMOD_SIMPLICIAL ;
    L = cholmod_analyze(K, &Common) ;
    cholmod_factorize(K, L, &Common) ;
    invK = cholmod_solve(CHOLMOD_A, L, I, &Common) ;

    // Compute the sparse inverse and the full inverse
    start = clock();
    V = cholmod_spinv(L, &Common) ;
    end = clock();
    cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;

    // Show results
    cholmod_print_sparse(K,"Original",&Common) ;
    cholmod_print_factor(L,"Factor",&Common) ;
    cholmod_print_sparse(V,"Sparse inverse",&Common) ;
    cholmod_print_dense(invK,"Dense inverse",&Common);

    // Free memory
    cholmod_free_factor(&L, &Common) ;
    cholmod_free_sparse(&K, &Common) ;
    cholmod_free_dense(&I, &Common) ;
    cholmod_free_dense(&A, &Common) ;
    cholmod_finish(&Common) ;
    return 0 ;
}
Beispiel #15
0
 static cholmod_dense* solve(int sys, cholmod_factor* L, cholmod_dense* B, cholmod_common* c) {
   return cholmod_solve(sys, L, B, c);
 }
int main (int argc, char **argv)
{
    double resid [4], t, ta, tf, ts [3], tot, bnorm, xnorm, anorm, rnorm, fl,
        anz, axbnorm, rnorm2, resid2, rcond ;
    FILE *f ;
    cholmod_sparse *A ;
    cholmod_dense *X = NULL, *B, *W, *R ;
    double one [2], zero [2], minusone [2], beta [2], xlnz ;
    cholmod_common Common, *cm ;
    cholmod_factor *L ;
    double *Bx, *Rx, *Xx ;
    int i, n, isize, xsize, ordering, xtype, s, ss, lnz ;
    int trial, method, L_is_super ;
    int ver [3] ;

    ts[0] = 0.;
    ts[1] = 0.;
    ts[2] = 0.;

    /* ---------------------------------------------------------------------- */
    /* get the file containing the input matrix */
    /* ---------------------------------------------------------------------- */

    ff = NULL ;
    if (argc > 1)
    {
	if ((f = fopen (argv [1], "r")) == NULL)
	{
	    my_handler (CHOLMOD_INVALID, __FILE__, __LINE__,
		    "unable to open file") ;
	}
	ff = f ;
    }
    else
    {
	f = stdin ;
    }

    /* ---------------------------------------------------------------------- */
    /* start CHOLMOD and set parameters */
    /* ---------------------------------------------------------------------- */

    cm = &Common ;
    cholmod_start (cm) ;
    CHOLMOD_FUNCTION_DEFAULTS (cm) ;    /* just for testing (not required) */

    /* use default parameter settings, except for the error handler.  This
     * demo program terminates if an error occurs (out of memory, not positive
     * definite, ...).  It makes the demo program simpler (no need to check
     * CHOLMOD error conditions).  This non-default parameter setting has no
     * effect on performance. */
    cm->error_handler = my_handler ;

    /* Note that CHOLMOD will do a supernodal LL' or a simplicial LDL' by
     * default, automatically selecting the latter if flop/nnz(L) < 40. */

    /* ---------------------------------------------------------------------- */
    /* create basic scalars */
    /* ---------------------------------------------------------------------- */

    zero [0] = 0 ;
    zero [1] = 0 ;
    one [0] = 1 ;
    one [1] = 0 ;
    minusone [0] = -1 ;
    minusone [1] = 0 ;
    beta [0] = 1e-6 ;
    beta [1] = 0 ;

    /* ---------------------------------------------------------------------- */
    /* read in a matrix */
    /* ---------------------------------------------------------------------- */

    printf ("\n---------------------------------- cholmod_demo:\n") ;
    cholmod_version (ver) ;
    printf ("cholmod version %d.%d.%d\n", ver [0], ver [1], ver [2]) ;
    SuiteSparse_version (ver) ;
    printf ("SuiteSparse version %d.%d.%d\n", ver [0], ver [1], ver [2]) ;
    A = cholmod_read_sparse (f, cm) ;
    if (ff != NULL)
    {
        fclose (ff) ;
        ff = NULL ;
    }
    anorm = cholmod_norm_sparse (A, 0, cm) ;
    xtype = A->xtype ;
    printf ("norm (A,inf) = %g\n", anorm) ;
    printf ("norm (A,1)   = %g\n", cholmod_norm_sparse (A, 1, cm)) ;
    cholmod_print_sparse (A, "A", cm) ;

    if (A->nrow > A->ncol)
    {
	/* Transpose A so that A'A+beta*I will be factorized instead */
	cholmod_sparse *C = cholmod_transpose (A, 2, cm) ;
	cholmod_free_sparse (&A, cm) ;
	A = C ;
	printf ("transposing input matrix\n") ;
    }

    /* ---------------------------------------------------------------------- */
    /* create an arbitrary right-hand-side */
    /* ---------------------------------------------------------------------- */

    n = A->nrow ;
    B = cholmod_zeros (n, 1, xtype, cm) ;
    Bx = B->x ;

#if GHS
    {
	/* b = A*ones(n,1), used by Gould, Hu, and Scott in their experiments */
	cholmod_dense *X0 ;
	X0 = cholmod_ones (A->ncol, 1, xtype, cm) ;
	cholmod_sdmult (A, 0, one, zero, X0, B, cm) ;
	cholmod_free_dense (&X0, cm) ;
    }
#else
    if (xtype == CHOLMOD_REAL)
    {
	/* real case */
	for (i = 0 ; i < n ; i++)
	{
	    double x = n ;
	    Bx [i] = 1 + i / x ;
	}
    }
    else
    {
	/* complex case */
	for (i = 0 ; i < n ; i++)
	{
	    double x = n ;
	    Bx [2*i  ] = 1 + i / x ;		/* real part of B(i) */
	    Bx [2*i+1] = (x/2 - i) / (3*x) ;	/* imag part of B(i) */
	}
    }
#endif

    cholmod_print_dense (B, "B", cm) ;
    bnorm = cholmod_norm_dense (B, 0, cm) ;	/* max norm */
    printf ("bnorm %g\n", bnorm) ;

    /* ---------------------------------------------------------------------- */
    /* analyze and factorize */
    /* ---------------------------------------------------------------------- */

    t = CPUTIME ;
    L = cholmod_analyze (A, cm) ;
    ta = CPUTIME - t ;
    ta = MAX (ta, 0) ;

    printf ("Analyze: flop %g lnz %g\n", cm->fl, cm->lnz) ;

    if (A->stype == 0)
    {
	printf ("Factorizing A*A'+beta*I\n") ;
	t = CPUTIME ;
	cholmod_factorize_p (A, beta, NULL, 0, L, cm) ;
	tf = CPUTIME - t ;
	tf = MAX (tf, 0) ;
    }
    else
    {
	printf ("Factorizing A\n") ;
	t = CPUTIME ;
	cholmod_factorize (A, L, cm) ;
	tf = CPUTIME - t ;
	tf = MAX (tf, 0) ;
    }

    cholmod_print_factor (L, "L", cm) ;

    /* determine the # of integers's and reals's in L.  See cholmod_free */
    if (L->is_super)
    {
	s = L->nsuper + 1 ;
	xsize = L->xsize ;
	ss = L->ssize ;
	isize =
	    n	/* L->Perm */
	    + n	/* L->ColCount, nz in each column of 'pure' L */
	    + s	/* L->pi, column pointers for L->s */
	    + s	/* L->px, column pointers for L->x */
	    + s	/* L->super, starting column index of each supernode */
	    + ss ;	/* L->s, the pattern of the supernodes */
    }
    else
    {
	/* this space can increase if you change parameters to their non-
	 * default values (cm->final_pack, for example). */
	lnz = L->nzmax ;
	xsize = lnz ;
	isize =
	    n	/* L->Perm */
	    + n	/* L->ColCount, nz in each column of 'pure' L */
	    + n+1	/* L->p, column pointers */
	    + lnz	/* L->i, integer row indices */
	    + n	/* L->nz, nz in each column of L */
	    + n+2	/* L->next, link list */
	    + n+2 ;	/* L->prev, link list */
    }

    /* solve with Bset will change L from simplicial to supernodal */
    rcond = cholmod_rcond (L, cm) ;
    L_is_super = L->is_super ;

    /* ---------------------------------------------------------------------- */
    /* solve */
    /* ---------------------------------------------------------------------- */

    for (method = 0 ; method <= 3 ; method++)
    {
        double x = n ;

        if (method == 0)
        {
            /* basic solve, just once */
            t = CPUTIME ;
            X = cholmod_solve (CHOLMOD_A, L, B, cm) ;
            ts [0] = CPUTIME - t ;
            ts [0] = MAX (ts [0], 0) ;
        }
        else if (method == 1)
        {
            /* basic solve, many times, but keep the last one */
            t = CPUTIME ;
            for (trial = 0 ; trial < NTRIALS ; trial++)
            {
                cholmod_free_dense (&X, cm) ;
                Bx [0] = 1 + trial / x ;        /* tweak B each iteration */
                X = cholmod_solve (CHOLMOD_A, L, B, cm) ;
            }
            ts [1] = CPUTIME - t ;
            ts [1] = MAX (ts [1], 0) / NTRIALS ;
        }
        else if (method == 2)
        {
            /* solve with reused workspace */
            cholmod_dense *Ywork = NULL, *Ework = NULL ;
            cholmod_free_dense (&X, cm) ;

            t = CPUTIME ;
            for (trial = 0 ; trial < NTRIALS ; trial++)
            {
                Bx [0] = 1 + trial / x ;        /* tweak B each iteration */
                cholmod_solve2 (CHOLMOD_A, L, B, NULL, &X, NULL,
                    &Ywork, &Ework, cm) ;
            }
            cholmod_free_dense (&Ywork, cm) ;
            cholmod_free_dense (&Ework, cm) ;
            ts [2] = CPUTIME - t ;
            ts [2] = MAX (ts [2], 0) / NTRIALS ;
        }
        else
        {
            /* solve with reused workspace and sparse Bset */
            cholmod_dense *Ywork = NULL, *Ework = NULL ;
            cholmod_dense *X2 = NULL, *B2 = NULL ;
            cholmod_sparse *Bset, *Xset = NULL ;
            int *Bsetp, *Bseti, *Xsetp, *Xseti, xlen, j, k, *Lnz ;
            double *X1x, *X2x, *B2x, err ;
            FILE *timelog = fopen ("timelog.m", "w") ;
            if (timelog) fprintf (timelog, "results = [\n") ;

            B2 = cholmod_zeros (n, 1, xtype, cm) ;
            B2x = B2->x ;

            Bset = cholmod_allocate_sparse (n, 1, 1, FALSE, TRUE, 0,
                CHOLMOD_PATTERN, cm) ;
            Bsetp = Bset->p ;
            Bseti = Bset->i ;
            Bsetp [0] = 0 ;     /* nnz(B) is 1 (it can be anything) */
            Bsetp [1] = 1 ;
            resid [3] = 0 ;

            for (i = 0 ; i < MIN (100,n) ; i++)
            {
                /* B (i) is nonzero, all other entries are ignored
                   (implied to be zero) */
                Bseti [0] = i ;
                if (xtype == CHOLMOD_REAL)
                {
                    B2x [i] = 3.1 * i + 0.9 ;
                }
                else
                {
                    B2x [2*i  ] = i + 0.042 ;
                    B2x [2*i+1] = i - 92.7 ;
                }

                /* first get the entire solution, to compare against */
                cholmod_solve2 (CHOLMOD_A, L, B2, NULL, &X, NULL,
                    &Ywork, &Ework, cm) ;

                /* now get the sparse solutions; this will change L from
                   supernodal to simplicial */

                if (i == 0)
                {
                    /* first solve can be slower because it has to allocate
                       space for X2, Xset, etc, and change L.
                       So don't time it */
                    cholmod_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset,
                        &Ywork, &Ework, cm) ;
                }

                t = CPUTIME ;
                for (trial = 0 ; trial < NTRIALS ; trial++)
                {
                    /* solve Ax=b but only to get x(i).
                       b is all zero except for b(i).
                       This takes O(xlen) time */
                    cholmod_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset,
                        &Ywork, &Ework, cm) ;
                }
                t = CPUTIME - t ;
                t = MAX (t, 0) / NTRIALS ;

                /* check the solution and log the time */
                Xsetp = Xset->p ;
                Xseti = Xset->i ;
                xlen = Xsetp [1] ;
                X1x = X->x ;
                X2x = X2->x ;
                Lnz = L->nz ;

                /*
                printf ("\ni %d xlen %d  (%p %p)\n", i, xlen, X1x, X2x) ;
                */

                if (xtype == CHOLMOD_REAL)
                {
                    fl = 2 * xlen ;
                    for (k = 0 ; k < xlen ; k++)
                    {
                        j = Xseti [k] ;
                        fl += 4 * Lnz [j] ;
                        err = X1x [j] - X2x [j] ;
                        err = ABS (err) ;
                        resid [3] = MAX (resid [3], err) ;
                    }
                }
                else
                {
                    fl = 16 * xlen ;
                    for (k = 0 ; k < xlen ; k++)
                    {
                        j = Xseti [k] ;
                        fl += 16 * Lnz [j] ;
                        err = X1x [2*j  ] - X2x [2*j  ] ;
                        err = ABS (err) ;
                        resid [3] = MAX (resid [3], err) ;
                        err = X1x [2*j+1] - X2x [2*j+1] ;
                        err = ABS (err) ;
                        resid [3] = MAX (resid [3], err) ;
                    }
                }
                if (timelog) fprintf (timelog, "%g %g %g %g\n",
                    (double) i, (double) xlen, fl, t);

                /* clear B for the next test */
                if (xtype == CHOLMOD_REAL)
                {
                    B2x [i] = 0 ;
                }
                else
                {
                    B2x [2*i  ] = 0 ;
                    B2x [2*i+1] = 0 ;
                }

            }

            if (timelog)
            {
                fprintf (timelog, "] ; resid = %g ;\n", resid [3]) ;
                fprintf (timelog, "lnz = %g ;\n", cm->lnz) ;
                fprintf (timelog, "t = %g ;   %% dense solve time\n", ts [2]) ;
                fclose (timelog) ;
            }

            resid [3] = resid [3] / cholmod_norm_dense (X, 1, cm) ;

            cholmod_free_dense (&Ywork, cm) ;
            cholmod_free_dense (&Ework, cm) ;
            cholmod_free_dense (&X2, cm) ;
            cholmod_free_dense (&B2, cm) ;
            cholmod_free_sparse (&Xset, cm) ;
            cholmod_free_sparse (&Bset, cm) ;
        }

        /* ------------------------------------------------------------------ */
        /* compute the residual */
        /* ------------------------------------------------------------------ */

        if (method < 3)
        {

            if (A->stype == 0)
            {
                /* (AA'+beta*I)x=b is the linear system that was solved */
                /* W = A'*X */
                W = cholmod_allocate_dense (A->ncol, 1, A->ncol, xtype, cm) ;
                cholmod_sdmult (A, 2, one, zero, X, W, cm) ;
                /* R = B - beta*X */
                R = cholmod_zeros (n, 1, xtype, cm) ;
                Rx = R->x ;
                Xx = X->x ;
                if (xtype == CHOLMOD_REAL)
                {
                    for (i = 0 ; i < n ; i++)
                    {
                        Rx [i] = Bx [i] - beta [0] * Xx [i] ;
                    }
                }
                else
                {
                    /* complex case */
                    for (i = 0 ; i < n ; i++)
                    {
                        Rx [2*i  ] = Bx [2*i  ] - beta [0] * Xx [2*i  ] ;
                        Rx [2*i+1] = Bx [2*i+1] - beta [0] * Xx [2*i+1] ;
                    }
                }
                /* R = A*W - R */
                cholmod_sdmult (A, 0, one, minusone, W, R, cm) ;
                cholmod_free_dense (&W, cm) ;
            }
            else
            {
                /* Ax=b was factorized and solved, R = B-A*X */
                R = cholmod_copy_dense (B, cm) ;
                cholmod_sdmult (A, 0, minusone, one, X, R, cm) ;
            }
            rnorm = cholmod_norm_dense (R, 0, cm) ;	    /* max abs. entry */
            xnorm = cholmod_norm_dense (X, 0, cm) ;	    /* max abs. entry */

            axbnorm = (anorm * xnorm + bnorm + ((n == 0) ? 1 : 0)) ;
            resid [method] = rnorm / axbnorm ;
        }
    }

    tot = ta + tf + ts [0] ;

    /* ---------------------------------------------------------------------- */
    /* iterative refinement (real symmetric case only) */
    /* ---------------------------------------------------------------------- */

    resid2 = -1 ;
    if (A->stype != 0 && A->xtype == CHOLMOD_REAL)
    {
	cholmod_dense *R2 ;

	/* R2 = A\(B-A*X) */
	R2 = cholmod_solve (CHOLMOD_A, L, R, cm) ;
	/* compute X = X + A\(B-A*X) */
	Xx = X->x ;
	Rx = R2->x ;
	for (i = 0 ; i < n ; i++)
	{
	    Xx [i] = Xx [i] + Rx [i] ;
	}
	cholmod_free_dense (&R2, cm) ;
	cholmod_free_dense (&R, cm) ;

	/* compute the new residual, R = B-A*X */
	R = cholmod_copy_dense (B, cm) ;
	cholmod_sdmult (A, 0, minusone, one, X, R, cm) ;
	rnorm2 = cholmod_norm_dense (R, 0, cm) ;
	resid2 = rnorm2 / axbnorm ;
    }

    cholmod_free_dense (&R, cm) ;

    /* ---------------------------------------------------------------------- */
    /* print results */
    /* ---------------------------------------------------------------------- */

    anz = cm->anz ;
    for (i = 0 ; i < CHOLMOD_MAXMETHODS ; i++)
    {
	fl = cm->method [i].fl ;
	xlnz = cm->method [i].lnz ;
	cm->method [i].fl = -1 ;
	cm->method [i].lnz = -1 ;
	ordering = cm->method [i].ordering ;
	if (fl >= 0)
	{
	    printf ("Ordering: ") ;
	    if (ordering == CHOLMOD_POSTORDERED) printf ("postordered ") ;
	    if (ordering == CHOLMOD_NATURAL)     printf ("natural ") ;
	    if (ordering == CHOLMOD_GIVEN)	     printf ("user    ") ;
	    if (ordering == CHOLMOD_AMD)	     printf ("AMD     ") ;
	    if (ordering == CHOLMOD_METIS)	     printf ("METIS   ") ;
	    if (ordering == CHOLMOD_NESDIS)      printf ("NESDIS  ") ;
	    if (xlnz > 0)
	    {
		printf ("fl/lnz %10.1f", fl / xlnz) ;
	    }
	    if (anz > 0)
	    {
		printf ("  lnz/anz %10.1f", xlnz / anz) ;
	    }
	    printf ("\n") ;
	}
    }

    printf ("ints in L: %15.0f, doubles in L: %15.0f\n",
        (double) isize, (double) xsize) ;
    printf ("factor flops %g nnz(L) %15.0f (w/no amalgamation)\n",
	    cm->fl, cm->lnz) ;
    if (A->stype == 0)
    {
	printf ("nnz(A):    %15.0f\n", cm->anz) ;
    }
    else
    {
	printf ("nnz(A*A'): %15.0f\n", cm->anz) ;
    }
    if (cm->lnz > 0)
    {
	printf ("flops / nnz(L):  %8.1f\n", cm->fl / cm->lnz) ;
    }
    if (anz > 0)
    {
	printf ("nnz(L) / nnz(A): %8.1f\n", cm->lnz / cm->anz) ;
    }
    printf ("analyze cputime:  %12.4f\n", ta) ;
    printf ("factor  cputime:   %12.4f mflop: %8.1f\n", tf,
	(tf == 0) ? 0 : (1e-6*cm->fl / tf)) ;
    printf ("solve   cputime:   %12.4f mflop: %8.1f\n", ts [0],
	(ts [0] == 0) ? 0 : (1e-6*4*cm->lnz / ts [0])) ;
    printf ("overall cputime:   %12.4f mflop: %8.1f\n", 
	    tot, (tot == 0) ? 0 : (1e-6 * (cm->fl + 4 * cm->lnz) / tot)) ;
    printf ("solve   cputime:   %12.4f mflop: %8.1f (%d trials)\n", ts [1],
	(ts [1] == 0) ? 0 : (1e-6*4*cm->lnz / ts [1]), NTRIALS) ;
    printf ("solve2  cputime:   %12.4f mflop: %8.1f (%d trials)\n", ts [2],
	(ts [2] == 0) ? 0 : (1e-6*4*cm->lnz / ts [2]), NTRIALS) ;
    printf ("peak memory usage: %12.0f (MB)\n",
	    (double) (cm->memory_usage) / 1048576.) ;
    printf ("residual (|Ax-b|/(|A||x|+|b|)): ") ;
    for (method = 0 ; method <= 3 ; method++)
    {
        printf ("%8.2e ", resid [method]) ;
    }
    printf ("\n") ;
    if (resid2 >= 0)
    {
	printf ("residual %8.1e (|Ax-b|/(|A||x|+|b|))"
		" after iterative refinement\n", resid2) ;
    }

    printf ("rcond    %8.1e\n\n", rcond) ;

    if (L_is_super)
    {
        cholmod_gpu_stats (cm) ;
    }

    cholmod_free_factor (&L, cm) ;
    cholmod_free_dense (&X, cm) ;

    /* ---------------------------------------------------------------------- */
    /* free matrices and finish CHOLMOD */
    /* ---------------------------------------------------------------------- */

    cholmod_free_sparse (&A, cm) ;
    cholmod_free_dense (&B, cm) ;
    cholmod_finish (cm) ;
    
    return (0) ;
}
void KVFModel::calculateVF(const std::set<DisplacedVertex> &disps, double alpha1)
{
    TimeMeasurment total,t;
    cholmod_common* cm = cholmod_get_common();

    unsigned int numFaces = getNumFaces();
    unsigned int numVertices = getNumVertices();

    this->disps = disps;
    std::set<DisplacedVertex> allDisplacements = disps;

    for (auto iter = pinnedVertexes.begin(); iter != pinnedVertexes.end() ; iter++)
    	allDisplacements.insert(DisplacedVertex(*iter, Vector2(0,0)));

    if (allDisplacements.size() <= 1)
    	return;

    if (allDisplacements.size() != lastDispsSize) {
    	cholmod_free_factor(&L1, cholmod_get_common());
    	lastDispsSize = allDisplacements.size();
    }

    /************************************************/
    /* BUILD P matrix */

    P.startMatrixFill();
    P.reshape(3*numFaces,2*numVertices,12*numFaces);

    for (unsigned int f = 0; f < numFaces; f++)
    {
        int i = (*faces)[f][0];
        int j = (*faces)[f][1];
        int k = (*faces)[f][2];

        if (i > j) { std::swap(i,j); }
        if (i > k) { std::swap(i,k); }
        if (j > k) { std::swap(j,k); }

        Vector2 d1 = vertices[i] - vertices[k];
        Vector2 d2 = vertices[j] - vertices[i];

        double area = fabs(d1[1]*d2[0] - d1[0]*d2[1]);

        Vector2 c1(-d1[1]/area,d1[0]/area);
        Vector2 c2(-d2[1]/area,d2[0]/area);

        double gix = -c1[0] - c2[0], gjx = c1[0], gkx = c2[0];
        double giy = -c1[1] - c2[1], gjy = c1[1], gky = c2[1];

        P.addElement(3*f+0,i,gix*2);
        P.addElement(3*f+0,j,gjx*2);
        P.addElement(3*f+0,k,gkx*2);

        P.addElement(3*f+1,i,giy*M_SQRT2);
        P.addElement(3*f+1,j,gjy*M_SQRT2);
        P.addElement(3*f+1,k,gky*M_SQRT2);

        P.addElement(3*f+1,i+numVertices,gix*M_SQRT2);
        P.addElement(3*f+1,j+numVertices,gjx*M_SQRT2);
        P.addElement(3*f+1,k+numVertices,gkx*M_SQRT2);

        P.addElement(3*f+2,i+numVertices,giy*2);
        P.addElement(3*f+2,j+numVertices,gjy*2);
        P.addElement(3*f+2,k+numVertices,gky*2);
    }

    Pcopy.copy(P);

    printf("KVF: P construct time: %f msec\n", t.measure_msec());

    /*++++++++++++++++++++++++++++++++++++++++++++++*/

    CholmodVector B = CholmodVector(2*numVertices);
    std::vector<int> indices2;

    double alpha = alpha1 / (2*allDisplacements.size()) * P.infinityNorm();

    for (auto iter = allDisplacements.begin() ; iter != allDisplacements.end() ; iter++)
    {
        indices2.push_back(iter->v);
        indices2.push_back(iter->v + numVertices);

    	B[iter->v] 				= iter->displacement[0]*alpha*alpha;
    	B[iter->v+numVertices]  = iter->displacement[1]*alpha*alpha;
    }

    P.addConstraint(indices2, alpha);

    printf("KVF: P constraint adding time: %f msec\n", t.measure_msec());

    /*++++++++++++++++++++++++++++++++++++++++++++++*/

    cholmod_sparse cSparse;
    P.getCholmodMatrix(cSparse);
    if (!L1) L1 = cholmod_analyze(&cSparse, cm);
    cholmod_factorize(&cSparse, L1, cm);
    cholmod_dense * Xcholmod = cholmod_solve(CHOLMOD_A, L1, B, cm);
    double* Xx = (double*)Xcholmod->x;

	for (unsigned int i = 0; i < numVertices; i++)
		vfOrig[i] = Vector2D<double>(Xx[i],Xx[i+numVertices]);

    printf("KVF: Solve time: %f msec\n", t.measure_msec());

    /*+++++DIRICHLET SOLVE +++++++++++++++++++++++++++++++++++++++++*/

    CholmodVector boundaryRHS = CholmodVector(2*numVertices);
    for (std::set<int>::iterator it = boundaryVertices->begin(); it != boundaryVertices->end(); ++it)
    {
    	boundaryRHS[*it] = Xx[*it];
    	boundaryRHS[*it + numVertices] = Xx[*it + numVertices];
    }

    CholmodVector rhsMove(Pcopy.numRows());

    Pcopy.multiply(boundaryRHS, rhsMove);
    for (unsigned int i = 0; i < rhsMove.size(); i++)
        rhsMove[i] *= -1;

    Pcopy.zeroOutColumns(*boundaryVertices, 0);
    Pcopy.zeroOutColumns(*boundaryVertices, numVertices);

    Pcopy.transposeMultiply(rhsMove,B);

    std::vector<int> constrained;
    for (std::set<int>::iterator it = boundaryVertices->begin(); it != boundaryVertices->end(); ++it)
    {
        int bv = *it;
        constrained.push_back(*it);
        constrained.push_back(*it+numVertices);
        B[bv] 			  += Xx[bv];
        B[bv+numVertices] += Xx[bv+numVertices];
    }

    Pcopy.addConstraint(constrained,1);


    printf("KVF: Dirichlet prepare time: %f msec\n", t.measure_msec());

    /*++++++++++++++++++++++++++++++++++++++++++++++*/

    Pcopy.getCholmodMatrix(cSparse);
    if (!L2) L2 = cholmod_analyze(&cSparse, cm);
    cholmod_factorize(&cSparse, L2, cm);
    cholmod_dense *Xcholmod2 = cholmod_solve(CHOLMOD_A, L2, B, cm);
    Xx = (double*)Xcholmod2->x;

    printf("KVF: Dirichlet solve time: %f msec\n", t.measure_msec());

	for (unsigned int i = 0; i < numVertices; i++)
		vf[i] = Vector2D<double>(Xx[i],Xx[i+numVertices]);

    cholmod_free_dense(&Xcholmod, cm);
    cholmod_free_dense(&Xcholmod2, cm);

    printf("KVF: Fini time:  %f msec\n", t.measure_msec());

    lastVFCalcTime = total.measure_msec();
}
BasicMesh MeshTransferer::transfer(const vector<PhGUtils::Matrix3x3d> &S1grad)
{
  if( !(S0set && T0set) ) {
    throw "S0 or T0 not set.";
  }

  auto &S = S1grad;
  auto &T = T0grad;

  int nfaces = S0.faces.nrow;
  int nverts = S0.verts.nrow;

  // assemble sparse matrix A
  int nrowsA = nfaces * 3;
  int nsv = stationary_vertices.size();
  int nrowsC = nsv;
  int nrows = nrowsA + nrowsC;
  int ncols = nverts;
  int ntermsA = nfaces*9;
  int ntermsC = stationary_vertices.size();
  int nterms = ntermsA + ntermsC;
  SparseMatrix A(nrows, ncols, nterms);
  // fill in the deformation gradient part
  for(int i=0, ioffset=0;i<nfaces;++i) {
    /*
     * Ai:
     *     1 2 3 4 5 ... nfaces*3
     *     1 2 3 4 5 ... nfaces*3
     *     1 2 3 4 5 ... nfaces*3
     * Ai = reshape(Ai, 1, nfaces*9)
     *
     * Aj = reshape(repmat(S0.faces', 3, 1), 1, nfaces*9)
     * Av = reshape(cell2mat(T)', 1, nfaces*9)
     */
    int *f = S0.faces.rowptr(i);

    auto Ti = T[i];

    A.append(ioffset, f[0], Ti(0));
    A.append(ioffset, f[1], Ti(1));
    A.append(ioffset, f[2], Ti(2));
    ++ioffset;

    A.append(ioffset, f[0], Ti(3));
    A.append(ioffset, f[1], Ti(4));
    A.append(ioffset, f[2], Ti(5));
    ++ioffset;

    A.append(ioffset, f[0], Ti(6));
    A.append(ioffset, f[1], Ti(7));
    A.append(ioffset, f[2], Ti(8));
    ++ioffset;
  }

  // fill in the lower part of A, stationary vertices part
  for(int i=0;i<nsv;++i) {
    A.append(nrowsA+i, stationary_vertices[i], 1);
  }

  ofstream fA("A.txt");
  fA<<A;
  fA.close();

  // fill in c matrix
  DenseMatrix c(nrows, 3);
  for(int i=0;i<3;++i) {
    for(int j=0, joffset=0;j<nfaces;++j) {
      auto &Sj = S[j];
      c(joffset, i) = Sj(0, i); ++joffset;
      c(joffset, i) = Sj(1, i); ++joffset;
      c(joffset, i) = Sj(2, i); ++joffset;
    }
  }
  for(int i=0;i<3;++i) {
    for(int j=0, joffset=nrowsA;j<nsv;++j,++joffset) {
      auto vj = T0.verts.rowptr(stationary_vertices[j]);
      c(joffset, i) = vj[i];
    }
  }

  cholmod_sparse *G = A.to_sparse();
  cholmod_sparse *Gt = cholmod_transpose(G, 2, global::cm);

  // compute GtD
  // just multiply Dsi to corresponding elemenets
  double *Gtx = (double*)Gt->x;
  const int* Gtp = (const int*)(Gt->p);
  for(int i=0;i<nrowsA;++i) {
    int fidx = i/3;
    for(int j=Gtp[i];j<Gtp[i+1];++j) {
      Gtx[j] *= Ds(fidx);
    }
  }

  // compute GtDG
  cholmod_sparse *GtDG = cholmod_ssmult(Gt, G, 0, 1, 1, global::cm);
  GtDG->stype = 1;

  // compute GtD * c
  cholmod_dense *GtDc = cholmod_allocate_dense(ncols, 3, ncols, CHOLMOD_REAL, global::cm);
  double alpha[2] = {1, 0}; double beta[2] = {0, 0};
  cholmod_sdmult(Gt, 0, alpha, beta, c.to_dense(), GtDc, global::cm);

  // solve for GtDG \ GtDc
  cholmod_factor *L = cholmod_analyze(GtDG, global::cm);
  cholmod_factorize(GtDG, L, global::cm);
  cholmod_dense *x = cholmod_solve(CHOLMOD_A, L, GtDc, global::cm);

  // make a copy of T0
  BasicMesh Td = T0;

  // change the vertices with x
  double *Vx = (double*)x->x;
  for(int i=0;i<nverts;++i) {
    Td.verts(i, 0) = Vx[i];
    Td.verts(i, 1) = Vx[i+nverts];
    Td.verts(i, 2) = Vx[i+nverts*2];
  }

  // release memory
  cholmod_free_sparse(&G, global::cm);
  cholmod_free_sparse(&Gt, global::cm);
  cholmod_free_sparse(&GtDG, global::cm);
  cholmod_free_dense(&GtDc, global::cm);
  cholmod_free_factor(&L, global::cm);
  cholmod_free_dense(&x, global::cm);

  return Td;
}