cholmod_sparse *MultivariateFNormalSufficientSparse::compute_PWP() const
{
      // PWP = PW
      IMP_LOG(TERSE, "MVNsparse:   computing PWP" << std::endl);
      //solve for X in Sigma*X=W
      cholmod_sparse *tmp = cholmod_spsolve(CHOLMOD_A, L_, W_, c_);
      //and then Y in trans(X)=Sigma*Y
      cholmod_sparse *tx = cholmod_transpose(tmp, 1, c_);
      cholmod_free_sparse(&tmp, c_);
      cholmod_sparse *R = cholmod_spsolve(CHOLMOD_A, L_, tx, c_);
      cholmod_free_sparse(&tx, c_);
      IMP_LOG(TERSE, "MVNsparse:   done" << std::endl);
      return R;
}
  cholmod_sparse *MultivariateFNormalSufficientSparse::compute_PTP() const
{
  IMP_LOG(TERSE, "MVNsparse:   computing PTP" << std::endl);
  cholmod_sparse *eps = cholmod_dense_to_sparse(epsilon_, true, c_);
  cholmod_sparse *tmp = cholmod_spsolve(CHOLMOD_A, L_, eps, c_);
  cholmod_sparse *ptp = cholmod_aat(tmp, nullptr, 0, 1, c_);
  cholmod_free_sparse(&eps, c_);
  cholmod_free_sparse(&tmp, c_);
  return ptp;
}
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 #4
0
SEXP CHMfactor_spsolve(SEXP a, SEXP b, SEXP system)
{
    CHM_FR L = AS_CHM_FR(a);
    CHM_SP B = AS_CHM_SP__(b);
    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"));

    // dimnames:
    SEXP dn = PROTECT(allocVector(VECSXP, 2));
    // none from a: our CHMfactor objects have no dimnames
    SET_VECTOR_ELT(dn, 1, duplicate(VECTOR_ELT(GET_SLOT(b, Matrix_DimNamesSym), 1)));
    UNPROTECT(1);

    return chm_sparse_to_SEXP(cholmod_spsolve(sys, L, B, &c),
			      1/*do_free*/, 0/*uploT*/, 0/*Rkind*/, "", dn);
}
  void MultivariateFNormalSufficientSparse::set_Sigma(
          const SparseMatrix<double>& Sigma)
  {
        if (Sigma.cols() != Sigma.rows()) {
            IMP_THROW("need a square matrix!", ModelException);
            }
        //std::cout << "set_sigma" << std::endl;
        if (Sigma_) cholmod_free_sparse(&Sigma_, c_);
        cholmod_sparse A(Eigen::viewAsCholmod(
                            Sigma.selfadjointView<Eigen::Upper>()));
        Sigma_=cholmod_copy_sparse(&A, c_);
        //cholmod_print_sparse(Sigma_,"Sigma",c_);
        IMP_LOG(TERSE, "MVNsparse:   set Sigma to new matrix" << std::endl);
        IMP_LOG(TERSE, "MVNsparse:   computing Cholesky decomposition"
                << std::endl);
        // compute Cholesky decomposition for determinant and inverse
        //c_->final_asis=1; // setup LDLT calculation
        //c_->supernodal = CHOLMOD_SIMPLICIAL;
        // convert matrix to cholmod format
        //symbolic and numeric factorization
        L_ = cholmod_analyze(Sigma_, c_);
        int success = cholmod_factorize(Sigma_, L_, c_);
        //cholmod_print_factor(L_,"L",c_);

        if (success == 0 || L_->minor < L_->n)
            IMP_THROW("Sigma matrix is not positive semidefinite!",
                    ModelException);
        // determinant and derived constants
        cholmod_factor *Lcp(cholmod_copy_factor(L_, c_));
        cholmod_sparse *Lsp(cholmod_factor_to_sparse(Lcp,c_));
        double logDetSigma=0;
        if ((Lsp->itype != CHOLMOD_INT) &&
                (Lsp->xtype != CHOLMOD_REAL))
            IMP_THROW("types are not int and real, update them here first",
                    ModelException);
        int *p=(int*) Lsp->p;
        double *x=(double*) Lsp->x;
        for (size_t i=0; i < (size_t) M_; ++i)
            logDetSigma += std::log(x[p[i]]);
        cholmod_free_sparse(&Lsp,c_);
        cholmod_free_factor(&Lcp,c_);
        IMP_LOG(TERSE, "MVNsparse:   log det(Sigma) = "
                << logDetSigma << std::endl);
        IMP_LOG(TERSE, "MVNsparse:   det(Sigma) = "
                << exp(logDetSigma) << std::endl);
        norm_= std::pow(2*IMP::PI, -double(N_*M_)/2.0)
                    * exp(-double(N_)/2.0*logDetSigma);
        lnorm_=double(N_*M_)/2 * log(2*IMP::PI) + double(N_)/2 * logDetSigma;
        IMP_LOG(TERSE, "MVNsparse:   norm = " << norm_ << " lnorm = "
                << lnorm_ << std::endl);
        //inverse
        IMP_LOG(TERSE, "MVNsparse:   solving for inverse" << std::endl);
        cholmod_sparse* id = cholmod_speye(M_,M_,CHOLMOD_REAL,c_);
        if (P_) cholmod_free_sparse(&P_, c_);
        P_ = cholmod_spsolve(CHOLMOD_A, L_, id, c_);
        cholmod_free_sparse(&id, c_);
        if (!P_) IMP_THROW("Unable to solve for inverse!", ModelException);
        //WP
        IMP_LOG(TERSE, "MVNsparse:   solving for PW" << std::endl);
        if (PW_) cholmod_free_sparse(&PW_, c_);
        PW_ = cholmod_spsolve(CHOLMOD_A, L_, W_, c_);
        if (!PW_) IMP_THROW("Unable to solve for PW!", ModelException);
        IMP_LOG(TERSE, "MVNsparse:   done" << std::endl);
  }
Beispiel #6
0
int main(int argc, char *argv[])
{
	char *name = "main";
	char *seperator = "**********************************************************";

	// Setup the data structure with parameters of the problem
	switch (argc)
	{
		case 1:
				printf("No input file specified. Using dia1P.inp\n");
				dia1P_initialize("dia1P.inp",name);
				break;
		case 2:
				dia1P_initialize(argv[1],name);
				break;
		default: 
				dia1P_errHandler(errCode_TooManyArguments,name,name,errMesg_TooManyArguments);
	}

	// Print the problem to make sure
	dia1P_printPD(name);

	/* The prefix M_ is used for components that can be reused in several 
		failure simulations. For example, it is not necessary to compute 
		the first stiffness matrix M_M or its decomposition M_L for each 
		failure simulation. On the other hand, the matrix of fuse strengths, 
		S, needs to be repopulated every time.
	*/
	
	/* START REUSABLE COMPONENTS DECLARATIONS */

	// Stiffness matrix M
	cholmod_sparse *M_M;

	// J = M_V2C*V; where J = current flowing into the bottom nodes,
	// and V = vector of voltages of all nodes
	cholmod_sparse	*M_V2C;

	// Voltages at top and bottom nodes
	cholmod_sparse *M_vTop, *M_vBot;	

	// Cholesky factor of the stiffness matrix M
	cholmod_factor *M_L;				

	// Cholmod Common object
	cholmod_common Common;	
	
	// Basic scalars, one and minus one
	double one [2] = {1,0}, m1 [2] = {-1,0} ;

	/* END REUSABLE COMPONENTS DECLARATIONS */


	/* START REUSABLE COMPONENTS INITIALIZATIONS */
	
	// Start cholmod, and the cholmod_common object
	cholmod_start(&Common);	

	// Populated the top and bottom node voltages

	// Bottom row is "grounded", thus has zero 
	// voltage by convention. 
	// cholmod_spzeros(NRow,NCol,stype,xtype,*common)	
	M_vBot = cholmod_spzeros(pD.gridSize/2,1,0,CHOLMOD_REAL,&Common);

	// The top row has voltage = 1. Since cholmod has no inbuild
	// function to return a sparse vector of all ones (makes sense)
	// so we first create a dense vector of ones and then 
	// convert it to a sparse vector

	{ // limit the scope of temporary variables
		cholmod_dense *temp;
		temp = cholmod_ones(pD.gridSize/2,1,CHOLMOD_REAL,&Common);
		M_vTop = cholmod_dense_to_sparse(temp,1,&Common);
		cholmod_free_dense(&temp,&Common);
	}

	// Polulate voltage to current matrix and check it for
	// consistency 
	M_V2C = dia1P_voltageToCurrentMatrix(&Common,name);
	cholmod_check_sparse(M_V2C,&Common);

	// Populate stiffness matrix
	M_M = dia1P_stiffnessMatrix(&Common,name);
	// Check it for consistency
	cholmod_check_sparse(M_M,&Common);

	// Analyze and factorise the stiffness matrix
	M_L = cholmod_analyze(M_M,&Common);
	cholmod_factorize(M_M,M_L,&Common);
	// Check the factor for consistency
	cholmod_check_factor(M_L,&Common);
	
	/* END REUSABLE COMPONENTS INITIALIZATIONS */

	// Depending on the mode in which the program is run 
	// various levels of output are given to the user.
	// The three modes implemented so far are:
	// 0: Silent,
	// 1: minimal,
	// 2: normal
	// 3: verbose
	switch (pD.diagMode)
	{
		case 0:	
			break;
		case 1:	
			fprintf(pD.diagFile,"NSim\tnF\t\tnAv\t\tV\t\tC\n");
			fflush(pD.diagFile);
			break;
		case 2:	
			break;
		case 3:	
			fprintf(pD.diagFile,"Initial Stiffness Matrix\n");
			cholmod_write_sparse(pD.diagFile,M_M,NULL,NULL,&Common);
			fflush(pD.diagFile);	
			break;
		default: 
			dia1P_errHandler(errCode_UnknownDiagMode,name,name,errMesg_UnknownDiagMode);
	}

	/* START MAIN SIMULATIONS LOOP */

	// Number of simulations performed
	int countSims = 0;	

	while (countSims < pD.NSim)
	{	
		/* START LOOP COMPONENTS DECLARATIONS */

		// The sampleFailed flag remains zeros as long as 
		// the sample is not broken (a spanning crack is 
		// not encountered; it becomes 1 otherwise.
		int sampleFailed = 0;
	
		// nFail counts the number of bonds snapped till 
		// sample failure
		int nFail = 0;
					
		// Cholesky factor L will hold the cholesky factor that will be updated after each bond snapping
		cholmod_factor *L;

		// Vector of random fuse strengths
		double *S;
		
		// Matrix that maps the node voltages to the vector of
		// currents flowing into the bottom nodes.
		// This matrix is update after every bond breaking
		cholmod_sparse *V2C;

		// Load vector b. This vector is to be updated after 
		// every bond breaking
		cholmod_sparse *b;

		// A data structure that will store information about the 
		// most recently failed bond
		dia1P_failureSite FD;

		// A data structure that will store information about the 
		// sequence of failures in a particular simulation
		dia1P_brokenBonds *BB;	

		/* END LOOP COMPONENTS DECLARATIONS */


		/* START LOOP COMPONENTS INITIALIZATIONS */
	
		// Copy the pre-calculated cholesky factor into the local 
		// cholesky factor
		L = cholmod_copy_factor(M_L,&Common);

		// Populate fuse strength vector
		S = dia1P_strengthVector(name);	
		//FILE *pf = fopen("16.S","r");  S = cholmod_read_sparse(pf,&Common); fclose(pf);
	
		// Copy the initial voltage to current matrix
		V2C = cholmod_copy_sparse(M_V2C,&Common);

		// Initialize the structure for keeping records of broken bonds
		BB = dia1P_initializeBrokenBonds(name);
		
		// Polulate the load vector b
		b = dia1P_loadVector(&Common,name);
		// Check to ensure consistency... 
		cholmod_check_sparse(b,&Common);

		/* END LOOP COMPONENTS INITIALIZATIONS */
		// Write diagonistic output as requested
		switch (pD.diagMode)
		{
			case 0:	break;
			case 1:	break;
			case 2:	
					fprintf(pD.diagFile,"%s\n",seperator);
					fprintf(pD.diagFile,"Starting Simulation Number %d\n",countSims+1);
					fprintf(pD.diagFile,"I\t\tJ\t\tV\t\tC\n");
					fflush(pD.diagFile);
					break;
			case 3:	
					fprintf(pD.diagFile,"%s\n",seperator);
					fprintf(pD.diagFile,"Starting Simulation Number %d\n",countSims+1);
					fprintf(pD.diagFile,"Matrix of Random Fuse Strengths:\n");
					{
						int count = 0;
						for(count = 0; count < (pD.gridSize)*(pD.gridSize); count++)
						{
							int n1, n2;
							dia1P_getNodeNumbers(&n1,&n2,count,name);
							fprintf(pD.diagFile,"%d\t%d\t%G\n",n1,n2,S[count]);
						}
						fprintf(pD.diagFile,"\n");
					}
					//cholmod_write_sparse(pD.diagFile,S,NULL,NULL,&Common);
					fflush(pD.diagFile);
					break;
			default: dia1P_errHandler(errCode_UnknownDiagMode,name,name,errMesg_UnknownDiagMode);
		}

		while(sampleFailed == 0)
		{
			/* START INNER LOOP COMPONENTS INITIALIZATIONS */
			// Vector x will hold the unknown voltages
			cholmod_sparse *x;

			// Vectors VNode_s and VNode_d hold the full set
			// of node voltages (knowns appended to the calculated unknowns)
			cholmod_sparse *VNode_s;
			cholmod_dense *VNode_d;

			// This vector will be used to update the stiffness matrix M
			// as M_new = M_old - stiffUpdate*transpose(stiffUpdate)
			// Ofcouse, M is not update, rather its cholesky factor L is
			cholmod_sparse *stiffUpdate;

			// This vector updates the load vector as 
			// b_new = b_old + loadUpdate
			cholmod_sparse *loadUpdate;

			// This vector is needed for internal cholmod use.
			// We L = PMP^T, where P is the permuation matrix.
			// Thus, if U updates M, then PU will update L. 
			// uper = PU.
			cholmod_sparse *uper;

			/* END INNER LOOP COMPONENTS INITIALIZATIONS */

			// Solve for the unknown voltages
			x = cholmod_spsolve(CHOLMOD_A,L,b,&Common);

			// Append the known vectors top and the bottom 
			// row voltages to x to construct the complete 
			// vector of voltages.
			{	// Limit the score of temporary variables
				cholmod_sparse *temp1;
				temp1 = cholmod_vertcat(M_vBot,x,1,&Common);
				VNode_s = cholmod_vertcat(temp1,M_vTop,1,&Common);
				cholmod_free_sparse(&temp1,&Common);
			}

			// Check if the sample is broken, if it is then
			// we are done
			if(dia1P_isBroken(VNode_s,V2C,&Common,name))
			{
				sampleFailed = 1;
				{
					int count = 0;
					for(count = 0; count < BB->nFail; count++)
					{
						fprintf(pD.outFile,"%d\t%d\t%G\t%G\t%G\n",BB->i[count]+1,BB->j[count]+1,BB->v[count],BB->c[count],BB->bondStrength[count]);
					}
					fprintf(pD.outFile,"%d\t%d\t%G\t%G\t%G\n",0,0,0.f,0.f,0.f);
				}
			}
			else
			{	// If the sample is not broken yet, then we need to 
				// to find which bond will be snapped next.
				
				// Increment the number of failed bonds, since we know
				// that one is going to snap
				nFail++;

				// Make a dense vector of voltages
				VNode_d = cholmod_sparse_to_dense(VNode_s,&Common);
	
				// Find which bond to break and store the information 
				// in the data structure FD.
				dia1P_bondToSnap(S,VNode_d,VNode_s,V2C,BB,&FD,&Common,name);

				// Update the data structure BB, which stores the entire
				// sequence of broken bonds
				dia1P_updateBrokenBonds(BB,&FD,name);

				// Update the voltage to current matrix.
				// This matrix will change only if a fuse connected to the 
				// bottom edge is blown.
				dia1P_updateVoltageToCurrentMatrix(V2C,&FD,&Common,name);

				// Find the vector to update the stiffness matrix. 
				// This vector is never empty, it has either 1 or 2 nonzero components
				// depending on weather a boundary node is involved in the snapping or not
				stiffUpdate = dia1P_stiffnessUpdateVector(&FD,&Common,name);

				// Find the vector to update the load vector.
				// This vector is non-zero only if a fuse connected to the 
				// top edge is blown.
				loadUpdate = dia1P_loadUpdateVector(&FD,&Common,name);
						

				// Update the load vector
				{ // Limit the score of temporary variables
					cholmod_sparse *temp;
					temp = cholmod_copy_sparse(b,&Common);
					// Free the current memory occupied by b before reallocating
					cholmod_free_sparse(&b,&Common);								
					// Reallocate b
					b = cholmod_add(temp,loadUpdate,one,one,1,0,&Common);
					// Free temp
					cholmod_free_sparse(&temp,&Common);
				}

				// Calculate the permuted update vector for updating the cholesky factor
				uper = cholmod_submatrix(stiffUpdate,L->Perm,L->n,NULL,-1,1,1,&Common);
				
				// update (downdate) the cholesky factor
				cholmod_updown(0,uper,L,&Common);

				// Write appropriate diagnostic output
				switch (pD.diagMode)
				{
					case 0:	break;
					case 1:	break;
					case 2:
						fprintf(pD.diagFile,"%d\t\t%d\t\t%.3f\t%.3f\n",FD.node1+1,FD.node2+1,FD.fVol,FD.fCur);
						break;
					case 3:
						fprintf(pD.diagFile,"\nPass No. %d\nUnknown Node Voltages:\n",nFail);
						cholmod_write_sparse(pD.diagFile,x,NULL,NULL,&Common);
						fprintf(pD.diagFile,"\nSnapped Bond: \nI\t\tJ\t\tV\t\tC\n");
						fprintf(pD.diagFile,"%d\t\t%d\t\t%.3f\t%.3f\n\n",FD.node1+1,FD.node2+1,FD.fVol,FD.fCur);
						fprintf(pD.diagFile,"\nStiffNess Update Vector\n");
						cholmod_write_sparse(pD.diagFile,stiffUpdate,NULL,NULL,&Common);
						fprintf(pD.diagFile,"\nLoad Update Vector\n");
						cholmod_write_sparse(pD.diagFile,loadUpdate,NULL,NULL,&Common);
						break;
					default: dia1P_errHandler(errCode_UnknownDiagMode,name,name,errMesg_UnknownDiagMode);
				}

				//Free memory
				cholmod_free_dense(&VNode_d,&Common);
				cholmod_free_sparse(&stiffUpdate,&Common);
				cholmod_free_sparse(&loadUpdate,&Common);
				cholmod_free_sparse(&uper,&Common);
			}//ESLE
			cholmod_free_sparse(&x,&Common);
			cholmod_free_sparse(&VNode_s,&Common);
		}//ELIHW, loop for nth simulation
		
		// Free memory
		free(S);
		cholmod_free_sparse(&b,&Common);
		cholmod_free_sparse(&V2C,&Common);
		cholmod_free_factor(&L,&Common);
		dia1P_freeBrokenBonds(&BB,name);
		countSims++;
	}//ELIHW, main loop for NSim simulations

	// This completes the requested set of NSim simulations. 
	// Free memory
	cholmod_free_sparse(&M_M,&Common);
	cholmod_free_sparse(&M_V2C,&Common);
	cholmod_free_sparse(&M_vBot,&Common);
	cholmod_free_sparse(&M_vTop,&Common);
	cholmod_free_factor(&M_L,&Common);

	// Close dia1P and cholmod
	dia1P_finish(name);
//	cholmod_print_common("FuseNet Statistics",&Common);
	cholmod_finish(&Common);
	return(0);	
}