cholmod_sparse *
 MultivariateFNormalSufficientSparse::evaluate_derivative_Sigma() const
 {
     //d(-log(p))/dSigma = 1/2 (N P - N P epsilon transpose(epsilon) P - P W P)
     IMP_LOG(TERSE, "MVNsparse: evaluate_derivative_Sigma() = " << std::endl);
     cholmod_sparse *ptp(compute_PTP());
     cholmod_sparse *pwp(compute_PWP());
     //std::cout << " ptp " << std::endl << ptp << std::endl << std::endl;
     //std::cout << " pwp " << std::endl << pwp << std::endl << std::endl;
     static double one[2]={1,0};
     static double minusone[2]={-1,0};
     cholmod_sparse *tmp =
         cholmod_add(P_, ptp, one, minusone, true, false, c_);
     double enn[2]={0.5*N_,0};
     static double ptfive[2]={-0.5,0};
     cholmod_sparse *R = cholmod_add(tmp, pwp, enn, ptfive, true, false, c_);
     cholmod_free_sparse(&ptp, c_);
     cholmod_free_sparse(&pwp, c_);
     cholmod_free_sparse(&tmp, c_);
     return R;
 }
Ejemplo n.º 2
0
void get_ordering(cholmod_sparse* const NNE,
                  const int MIS_method,
                  const bool directed,
                  std::list<int>& ordering,
                  cholmod_common* const cholmod_c) {

  cholmod_sparse* adja_mat;
  switch(MIS_method) {
    case FSTPOWORDER:
      if (directed) {
        // adja_mat = NNE | t(NNE)
        cholmod_sparse* NNEt = cholmod_transpose(NNE, CHOLMOD_PATTERN, cholmod_c);
        adja_mat = cholmod_add(NNE, NNEt, NULL, NULL, false, false, cholmod_c);
        cholmod_free_sparse(&NNEt, cholmod_c);
      } else {
        // adja_mat = NNE
        adja_mat = cholmod_copy_sparse(NNE, cholmod_c);
      }
      break;

    case SNDPOWORDER:
    case HEURISTIC:
      adja_mat = get_second_power(NNE, directed, cholmod_c);
      break;

    default:
      error("Unknown MIS method.");
  }

  // adja_mat_p: array with pointer to elements for each column
  // where `i' is start and `i+1' is finish.
  // Can thus be used to get col sums.
  const int* const adja_mat_p = static_cast<const int*>(adja_mat->p);
  std::list<std::pair<int,int> > tmp_order;

  int n_vertices = static_cast<int>(NNE->ncol);
  for (int i = 0; i < n_vertices; ++i) {
    tmp_order.push_back(std::make_pair(adja_mat_p[i + 1] - adja_mat_p[i], i));
  }
  cholmod_free_sparse(&adja_mat, cholmod_c);

  // sorts first according to colsum (i.e., first el)
  // then by vertex id. As ID is unique, sorting is stable.
  tmp_order.sort();

  for (std::list<std::pair<int,int> >::const_iterator it = tmp_order.begin();
       it != tmp_order.end(); ++it) {
    ordering.push_back(it->second);
  }
}
Ejemplo n.º 3
0
cholmod_sparse* get_second_power(cholmod_sparse* const NNE,
                                 const bool directed,
                                 cholmod_common* const cholmod_c) {

  cholmod_sparse* out;
  if (directed) {
    // out = (NNE | t(NNE) | t(NNE) %*% NNE) & !I
    cholmod_sparse* NNEt = cholmod_transpose(NNE, CHOLMOD_PATTERN, cholmod_c);
    cholmod_sparse* NNEtNNE = cholmod_aat(NNEt, NULL, 0, -1, cholmod_c); // -1 = no diagnol
    cholmod_sparse* tmp = cholmod_add(NNE, NNEt, NULL, NULL, false, false, cholmod_c);
    cholmod_free_sparse(&NNEt, cholmod_c);
    out = cholmod_add(tmp, NNEtNNE, NULL, NULL, false, false, cholmod_c);
    cholmod_free_sparse(&NNEtNNE, cholmod_c);
    cholmod_free_sparse(&tmp, cholmod_c);

  } else {
    // out = (NNE | t(NNE) %*% NNE) & !I
    cholmod_sparse* NNEtNNE = cholmod_aat(NNE, NULL, 0, -1, cholmod_c); // -1 = no diagnol
    out = cholmod_add(NNE, NNEtNNE, NULL, NULL, false, false, cholmod_c);
    cholmod_free_sparse(&NNEtNNE, cholmod_c);
  }

  return out;
}
Ejemplo n.º 4
0
SEXP Csparse_diagU2N(SEXP x)
{
    const char *cl = class_P(x);
    /* dtCMatrix, etc; [1] = the second character =?= 't' for triangular */
    if (cl[1] != 't' || *diag_P(x) != 'U') {
	/* "trivially fast" when not triangular (<==> no 'diag' slot),
	   or not *unit* triangular */
	return (x);
    }
    else { /* unit triangular (diag='U'): "fill the diagonal" & diag:= "N" */
	CHM_SP chx = AS_CHM_SP__(x);
	CHM_SP eye = cholmod_speye(chx->nrow, chx->ncol, chx->xtype, &c);
	double one[] = {1, 0};
	CHM_SP ans = cholmod_add(chx, eye, one, one, TRUE, TRUE, &c);
	int uploT = (*uplo_P(x) == 'U') ? 1 : -1;
	int Rkind = (chx->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;

	R_CheckStack();
	cholmod_free_sparse(&eye, &c);
	return chm_sparse_to_SEXP(ans, 1, uploT, Rkind, "N",
				  GET_SLOT(x, Matrix_DimNamesSym));
    }
}
Ejemplo n.º 5
0
int get_blocking_internal(const int n_vertices,
                          const int n_edges,
                          const SEXP NNE_R,
                          const bool directed,
                          const int MIS_method,
                          const int unassinged_method,
                          std::list<int>& seeds,
                          int* const blocks) {

  cholmod_common cholmod_c;
  cholmod_start(&cholmod_c);

  cholmod_sparse* NNE = get_cholmod_NNE(n_vertices, n_edges, NNE_R, &cholmod_c);

  if (!directed) {
    // NNE = NNE | t(NNE)
    cholmod_sparse* NNEt = cholmod_transpose(NNE, CHOLMOD_PATTERN, &cholmod_c);
    cholmod_sparse* NNE_tmp = cholmod_add(NNE, NNEt, NULL, NULL, false, false, &cholmod_c);
    cholmod_free_sparse(&NNEt, &cholmod_c);
    NNE->i = NULL; // Remove pointer to R object before freeing memory
    cholmod_free_sparse(&NNE, &cholmod_c);
    NNE = NNE_tmp;
  }

  switch(MIS_method) {
    case LEXICAL:
      findMIS_in_sp_lex(NNE, seeds);
      break;

    case FSTPOWORDER:
    case SNDPOWORDER:
    case HEURISTIC:
      {
        std::list<int> ordering;
        get_ordering(NNE, MIS_method, directed, ordering, &cholmod_c);
        if (MIS_method == HEURISTIC) {
          heuristic_search(NNE, ordering, seeds);
        } else {
          findMIS_in_sp_order(NNE, ordering, seeds);
        }
      }
      break;

    case MAXIS:
      findMaxIS_in_sp(NNE, directed, seeds, &cholmod_c);
      break;

    default:
      error("Unknown MIS method.");
  }

  const int* const NNE_p = static_cast<const int*>(NNE->p);
  const int* const NNE_i = static_cast<const int*>(NNE->i);
  int n_unassigned = n_vertices;

  int block_label = 1;
  for (std::list<int>::const_iterator it = seeds.begin();
       it != seeds.end(); ++it, ++block_label) {
    // Set block for seed
    blocks[*it] = block_label;
    --n_unassigned;

    // Set block for adjacent to seed
    const int* const a_stop = NNE_i + NNE_p[*it + 1];
    for (const int* a = NNE_i + NNE_p[*it]; a != a_stop; ++a) {
      blocks[*a] = block_label;
      --n_unassigned;
    }
  }


  if (unassinged_method == ADJACENT_S) {
    // Assign unassigned to the block that contains
    // a neighbor in the NNE. Set to negative first as
    // unassigned cannot be match to another unassigned
    // that just been assigned.

    // If NNE is directed, it is ordered by closeness.
    // I.e. the unassigned will be assigned to the blocks
    // that contain their closest neighbor.
    // When NNE is undirected, the matrix multiplication
    // has scrambled the ordering. Then the unassigned are
    // assigned to neighbors lexically.
    if (directed) {
      for (int i = 0; i < n_vertices; ++i) {
        if (blocks[i] == 0) {
          --n_unassigned;
          const int* const a_stop = NNE_i + NNE_p[i + 1];
          for (const int* a = NNE_i + NNE_p[i]; a != a_stop; ++a) {
            if (blocks[*a] > 0) {
              blocks[i] = -blocks[*a];
              break;
            }
          }
        }
      }

    } else {
      for (int i = 0; i < n_vertices; ++i) {
        if (blocks[i] == 0) {
          --n_unassigned;
          int lowest_adjacent = n_vertices;
          const int* const a_stop = NNE_i + NNE_p[i + 1];
          for (const int* a = NNE_i + NNE_p[i]; a != a_stop; ++a) {
            if (*a < lowest_adjacent && blocks[*a] > 0) {
              blocks[i] = -blocks[*a];
              lowest_adjacent = *a;
            }
          }
        }
      }
    }

    for (int i = 0; i < n_vertices; ++i) {
      if (blocks[i] < 0) {
        blocks[i] = -blocks[i];
      }
    }
  }

  if (directed) { // This is already done for undirected case
    NNE->i = NULL; // Remove pointer to R object before freeing memory
  }
  cholmod_free_sparse(&NNE, &cholmod_c);
  cholmod_finish(&cholmod_c);

  return n_unassigned;
}
Ejemplo n.º 6
0
/**
 * Populate ans with the pointers from x and modify its scalar
 * elements accordingly. Note that later changes to the contents of
 * ans will change the contents of the SEXP.
 *
 * In most cases this function is called through the macros
 * AS_CHM_SP() or AS_CHM_SP__().  It is unusual to call it directly.
 *
 * @param ans a CHM_SP pointer
 * @param x pointer to an object that inherits from CsparseMatrix
 * @param check_Udiag boolean - should a check for (and consequent
 *  expansion of) a unit diagonal be performed.
 * @param sort_in_place boolean - if the i and x slots are to be sorted
 *  should they be sorted in place?  If the i and x slots are pointers
 *  to an input SEXP they should not be modified.
 *
 * @return ans containing pointers to the slots of x, *unless*
 *	check_Udiag and x is unitriangular.
 */
CHM_SP as_cholmod_sparse(CHM_SP ans, SEXP x,
			 Rboolean check_Udiag, Rboolean sort_in_place)
{
    static const char *valid[] = { MATRIX_VALID_Csparse, ""};
    int *dims = INTEGER(GET_SLOT(x, Matrix_DimSym)),
	ctype = R_check_class_etc(x, valid);
    SEXP islot = GET_SLOT(x, Matrix_iSym);

    if (ctype < 0) error(_("invalid class of object to as_cholmod_sparse"));
    if (!isValid_Csparse(x))
	error(_("invalid object passed to as_cholmod_sparse"));
    memset(ans, 0, sizeof(cholmod_sparse)); /* zero the struct */

    ans->itype = CHOLMOD_INT;	/* characteristics of the system */
    ans->dtype = CHOLMOD_DOUBLE;
    ans->packed = TRUE;
				/* slots always present */
    ans->i = INTEGER(islot);
    ans->p = INTEGER(GET_SLOT(x, Matrix_pSym));
				/* dimensions and nzmax */
    ans->nrow = dims[0];
    ans->ncol = dims[1];
    /* Allow for over-allocation of the i and x slots.  Needed for
     * sparse X form in lme4.  Right now it looks too difficult to
     * check for the length of the x slot, because of the xpt
     * utility, but the lengths of x and i should agree. */
    ans->nzmax = LENGTH(islot);
				/* values depending on ctype */
    ans->x = xpt(ctype, x);
    ans->stype = stype(ctype, x);
    ans->xtype = xtype(ctype);

    /* are the columns sorted (increasing row numbers) ?*/
    ans->sorted = check_sorted_chm(ans);
    if (!(ans->sorted)) { /* sort columns */
	if(sort_in_place) {
	    if (!cholmod_sort(ans, &c))
		error(_("in_place cholmod_sort returned an error code"));
	    ans->sorted = 1;
	}
	else {
	    CHM_SP tmp = cholmod_copy_sparse(ans, &c);
	    if (!cholmod_sort(tmp, &c))
		error(_("cholmod_sort returned an error code"));

#ifdef DEBUG_Matrix
	    /* This "triggers" exactly for return values of dtCMatrix_sparse_solve():*/
	    /* Don't want to translate this: want it report */
	    Rprintf("Note: as_cholmod_sparse() needed cholmod_sort()ing\n");
#endif
	    chm2Ralloc(ans, tmp);
	    cholmod_free_sparse(&tmp, &c);
	}
    }

    if (check_Udiag && ctype % 3 == 2 // triangular
	&& (*diag_P(x) == 'U')) { /* diagU2N(.)  "in place" : */
	double one[] = {1, 0};
	CHM_SP eye = cholmod_speye(ans->nrow, ans->ncol, ans->xtype, &c);
	CHM_SP tmp = cholmod_add(ans, eye, one, one, TRUE, TRUE, &c);

#ifdef DEBUG_Matrix_verbose /* happens quite often, e.g. in ../tests/indexing.R : */
	Rprintf("Note: as_cholmod_sparse(<ctype=%d>) - diagU2N\n", ctype);
#endif
	chm2Ralloc(ans, tmp);
	cholmod_free_sparse(&tmp, &c);
	cholmod_free_sparse(&eye, &c);
    } /* else :
       * NOTE: if(*diag_P(x) == 'U'), the diagonal is lost (!);
       * ---- that may be ok, e.g. if we are just converting from/to Tsparse,
       *      but is *not* at all ok, e.g. when used before matrix products */

    return ans;
}
Ejemplo n.º 7
0
int klu_cholmod
(
    /* inputs */
    int n,		    /* A is n-by-n */
    int Ap [ ],		    /* column pointers */
    int Ai [ ],		    /* row indices */
    /* outputs */
    int Perm [ ],	    /* fill-reducing permutation */
    /* user-defined */
    klu_common *Common	    /* user-defined data is in Common->user_data */
)
{
    double one [2] = {1,0}, zero [2] = {0,0}, lnz = 0 ;
    cholmod_sparse Amatrix, *A, *AT, *S ;
    cholmod_factor *L ;
    cholmod_common cm ;
    int *P ;
    int k, symmetric ;

    if (Ap == NULL || Ai == NULL || Perm == NULL || n < 0)
    {
	/* invalid inputs */
	return (0) ;
    }

    /* start CHOLMOD */
    cholmod_start (&cm) ;
    cm.supernodal = CHOLMOD_SIMPLICIAL ;
    cm.print = 0 ;

    /* use KLU memory management routines for CHOLMOD */
    cm.malloc_memory = Common->malloc_memory ;
    cm.realloc_memory = Common->realloc_memory ;
    cm.calloc_memory = Common->calloc_memory ;
    cm.free_memory = Common->free_memory ;

    /* construct a CHOLMOD version of the input matrix A */
    A = &Amatrix ;
    A->nrow = n ;		    /* A is n-by-n */
    A->ncol = n ;
    A->nzmax = Ap [n] ;		    /* with nzmax entries */
    A->packed = TRUE ;		    /* there is no A->nz array */
    A->stype = 0 ;		    /* A is unsymmetric */
    A->itype = CHOLMOD_INT ;
    A->xtype = CHOLMOD_PATTERN ;
    A->dtype = CHOLMOD_DOUBLE ;
    A->nz = NULL ;
    A->p = Ap ;			    /* column pointers */
    A->i = Ai ;			    /* row indices */
    A->x = NULL ;		    /* no numerical values */
    A->z = NULL ;
    A->sorted = FALSE ;		    /* columns of A are not sorted */

    /* get the user_data; default is symmetric if user_data is NULL */
    symmetric = (Common->user_data == NULL) ? TRUE :
	(((int *) (Common->user_data)) [0] != 0) ;

    /* AT = pattern of A' */
    AT = cholmod_transpose (A, 0, &cm) ;
    if (symmetric)
    {
	/* S = the symmetric pattern of A+A' */
	S = cholmod_add (A, AT, one, zero, FALSE, FALSE, &cm) ;
	cholmod_free_sparse (&AT, &cm) ;
	if (S != NULL)
	{
	    S->stype = 1 ;
	}
    }
    else
    {
	/* S = A'.  CHOLMOD will order S*S', which is A'*A */
	S = AT ;
    }

    /* order and analyze S or S*S' */
    L = cholmod_analyze (S, &cm) ;

    /* copy the permutation from L to the output */
    if (L != NULL)
    {
	P = L->Perm ;
	for (k = 0 ; k < n ; k++)
	{
	    Perm [k] = P [k] ;
	}
	lnz = cm.lnz ;
    }

    cholmod_free_sparse (&S, &cm) ;
    cholmod_free_factor (&L, &cm) ;
    cholmod_finish (&cm) ;
    return (lnz) ;
}
Ejemplo n.º 8
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);	
}