/* Initialize a sparse Jacobian for the solver. */ int KINKluSetJacGraph(KINMem kin_memory, cs_di *jac){ //check inputs if(!kin_memory||!jac) return 1; //grab the linear solver memory block KINKluMem kin_klu_mem=(KINKluMem)kin_memory->kin_lmem; if(!kin_klu_mem) return 1; //grab needed kinklu objects cs_di *kin_klu_jac=kin_klu_mem->jac; //check whether the jacobian data has already been allocated. if so, free it. if(kin_klu_jac){ cs_di_spfree(kin_klu_jac); kin_klu_jac=NULL; } //check if the input jacobian is in triplet form. compress if so. if(CS_TRIPLET(jac)){ kin_klu_jac=cs_di_compress(jac); if(!kin_klu_jac) return 1; cs_di_spfree(jac); jac = kin_klu_jac; return 0; } //assign the input jacobian to the kinklu jacobian kin_klu_mem->jac=jac; //return success return 0; };
/* free workspace for demo3 */ static int done3 (int ok, cs_dis *S, cs_din *N, double *y, cs_di *W, cs_di *E, int *p) { cs_di_sfree (S) ; cs_di_nfree (N) ; cs_di_free (y) ; cs_di_spfree (W) ; cs_di_spfree (E) ; cs_di_free (p) ; return (ok) ; }
/* free a problem */ problem *free_problem (problem *Prob) { if (!Prob) return (NULL) ; cs_di_spfree (Prob->A) ; if (Prob->sym) cs_di_spfree (Prob->C) ; cs_di_free (Prob->b) ; cs_di_free (Prob->x) ; cs_di_free (Prob->resid) ; return (cs_di_free (Prob)) ; }
void freeAllocationsDC(void) { if (circuit_simulation.matrix_sparsity == SPARSE) { if (circuit_simulation.method == DIRECT) { cs_di_sfree( S ); cs_di_nfree( N ); } else { cs_di_spfree( G2 ); } } else { free( matrix_G ); if (circuit_simulation.method == DIRECT && circuit_simulation.matrix_type == NONSPD) { free( transposition ); } } if (circuit_simulation.method == ITERATIVE) { free( inv_preconditioner ); } free( vector_x ); free( vector_b ); }
/* read a problem from a file; use %g for integers to avoid int conflicts */ problem *get_problem (FILE *f, double tol) { cs_di *T, *A, *C ; int sym, m, n, mn, nz1, nz2 ; problem *Prob ; Prob = cs_di_calloc (1, sizeof (problem)) ; if (!Prob) return (NULL) ; T = cs_di_load (f) ; /* load triplet matrix T from a file */ Prob->A = A = cs_di_compress (T) ; /* A = compressed-column form of T */ cs_di_spfree (T) ; /* clear T */ if (!cs_di_dupl (A)) return (free_problem (Prob)) ; /* sum up duplicates */ Prob->sym = sym = is_sym (A) ; /* determine if A is symmetric */ m = A->m ; n = A->n ; mn = CS_MAX (m,n) ; nz1 = A->p [n] ; cs_di_dropzeros (A) ; /* drop zero entries */ nz2 = A->p [n] ; if (tol > 0) cs_di_droptol (A, tol) ; /* drop tiny entries (just to test) */ Prob->C = C = sym ? make_sym (A) : A ; /* C = A + triu(A,1)', or C=A */ if (!C) return (free_problem (Prob)) ; printf ("\n--- Matrix: %g-by-%g, nnz: %g (sym: %g: nnz %g), norm: %8.2e\n", (double) m, (double) n, (double) (A->p [n]), (double) sym, (double) (sym ? C->p [n] : 0), cs_di_norm (C)) ; if (nz1 != nz2) printf ("zero entries dropped: %g\n", (double) (nz1 - nz2)); if (nz2 != A->p [n]) printf ("tiny entries dropped: %g\n", (double) (nz2 - A->p [n])) ; Prob->b = cs_di_malloc (mn, sizeof (double)) ; Prob->x = cs_di_malloc (mn, sizeof (double)) ; Prob->resid = cs_di_malloc (mn, sizeof (double)) ; return ((!Prob->b || !Prob->x || !Prob->resid) ? free_problem (Prob) : Prob) ; }
/* Free memory used by KLU */ void FreeKINKlu(KINMem kin_memory){ /* do memory deallocation from the bottom up. first, deallocate memory used by the KLU memory block. */ //grab the KLU memory block KINKluMem kin_klu_mem = (KINKluMem)kin_memory->kin_lmem; if(!kin_klu_mem) return; //free the jacobian matrix if(kin_klu_mem->jac) cs_di_spfree(kin_klu_mem->jac); //free the klu objects if(kin_klu_mem->symbolic) klu_free_symbolic(&(kin_klu_mem->symbolic), &(kin_klu_mem->klu_comm)); if(kin_klu_mem->numeric) klu_free_numeric(&(kin_klu_mem->numeric), &(kin_klu_mem->klu_comm)); //now release the klu memory block free(kin_klu_mem); kin_memory->kin_lmem = NULL; //return return; };
void freeAllocationsTransient(void) { int i; for(i = 0; i < circuit_simulation.number_of_elements[CURRENT_SOURCE] + circuit_simulation.group2_elements; i++) { if(sources[i]->transient != NULL) { free(sources[i]->transient->vals); } } free( sources ); if (circuit_simulation.matrix_sparsity == SPARSE) { cs_di_spfree( C2 ); } else { free( matrix_C ); } if (circuit_simulation.matrix_sparsity == SPARSE) { if (circuit_simulation.method == DIRECT) { cs_di_sfree( S ); cs_di_nfree( N ); } else { cs_di_spfree( G2 ); } } else { free( matrix_G ); if (circuit_simulation.method == DIRECT && circuit_simulation.matrix_type == NONSPD) { free( transposition ); } } }
/* C = A + triu(A,1)' */ static cs_di *make_sym (cs_di *A) { cs_di *AT, *C ; AT = cs_di_transpose (A, 1) ; /* AT = A' */ cs_di_fkeep (AT, &dropdiag, NULL) ; /* drop diagonal entries from AT */ C = cs_di_add (A, AT, 1, 1) ; /* C = A+AT */ cs_di_spfree (AT) ; return (C) ; }
void CholeskyDecomposition(void) { int k, i, j; unsigned int dimension; double sum, temp; #if DEBUG int l; #endif dimension = circuit_simulation.number_of_nodes + circuit_simulation.group2_elements; if (circuit_simulation.matrix_sparsity == SPARSE) { printf( "\n\nCholesky Decomposition...\n\n" ); S = cs_di_schol( 1, G2 ); N = cs_di_chol( G2, S ); cs_di_spfree( G2 ); if (N == NULL) { printf( "Error, the matrix must be symmetric & positive definite.\n\n" ); printf( "Terminating.\n" ); exit( -1 ); } } else { printf( "\n\nCholesky Decomposition...\n\n" ); for (k = 0; k < dimension; k++) { for (sum = 0, j = 0; j < k; j++) { if (matrix_G[k * dimension + j] != matrix_G[j * dimension + k]) { printf( "Error, the matrix must be symmetric & positive definite.\n\n" ); printf( "Terminating.\n" ); exit( -1 ); } sum += matrix_G[k * dimension + j] * matrix_G[k * dimension + j]; } if ((temp = matrix_G[k * dimension + k] - sum) < 0) { printf( "Error, the matrix must be symmetric & positive definite.\n\n" ); printf( "Terminating.\n" ); exit( -1 ); } matrix_G[k * dimension + k] = sqrt( temp ); for (i = k + 1; i < dimension; i++) { for (sum = 0, j = 0; j < k; j++) { sum += matrix_G[i * dimension + j] * matrix_G[k * dimension + j]; } matrix_G[k * dimension + i] = matrix_G[i * dimension + k] = (matrix_G[k * dimension + i] - sum) / matrix_G[k * dimension + k]; } } } #if DEBUG printf("\nCholesky Decomposition\n~~~~~~~~~~~~~~~~~~~~~~~\n\n"); printf("\nDecomposed Matrix:\n\n"); for(k = 0; k < dimension; k++) { for(l = 0; l < dimension; l++) { if(l == k) { printf(" \\\\"); } if (circuit_simulation.matrix_sparsity == SPARSE) { if(l <= k) { printf("%12lf ", getElementAt(N -> L, k, l)); } else { printf("%12lf ", getElementAt(N -> L, l, k)); } } else { printf("%12lf ", matrix_G[k * dimension + l]); } if(l == k) { printf(" \\\\"); } } printf("\n\n"); } printf("\n\n"); #endif }
void LUDecomposition(void) { #if DEBUG int l; #endif int k, i, m, j; unsigned int dimension; dimension = circuit_simulation.number_of_nodes + circuit_simulation.group2_elements; if (circuit_simulation.matrix_sparsity == SPARSE) { printf( "\n\nLU Decomposition...\n\n" ); S = cs_di_sqr( 2, G2, 0 ); N = cs_di_lu( G2, S, 1 ); cs_di_spfree( G2 ); if (N == NULL) { printf( "Error, the matrix cannot be inverted.\n\n" ); printf( "Terminating.\n" ); exit( -1 ); } } else { transposition = ( int * ) malloc( dimension * sizeof(int) ); if (transposition == NULL) { printf( "Could not allocate matrices.\n" ); printf( "Terminating.\n" ); exit( -1 ); } for (i = 0; i < dimension; i++) { transposition[i] = i; } printf( "\n\nLU Decomposition...\n\n" ); for (k = 0; k < dimension - 1; k++) { for (m = i = k; i < dimension; i++) { if (fabs( matrix_G[i * dimension + k] ) > fabs( matrix_G[m * dimension + k] )) { m = i; } } interchange( m, k ); if (fabs( matrix_G[k * dimension + k] ) == 0) { printf( "Error, the matrix cannot be inverted.\n\n" ); printf( "Terminating.\n" ); exit( -1 ); } for (i = k + 1; i < dimension; i++) { matrix_G[i * dimension + k] /= matrix_G[k * dimension + k]; for (j = k + 1; j < dimension; j++) { matrix_G[i * dimension + j] += -matrix_G[i * dimension + k] * matrix_G[k * dimension + j]; } } } } #if DEBUG printf("\nLU Decomposition\n~~~~~~~~~~~~~~~~~\n\n"); printf("\nDecomposed Matrix:\n\n"); for(k = 0; k < dimension; k++) { for(l = 0; l < dimension; l++) { if(l == k) { printf(" \\\\"); } if (circuit_simulation.matrix_sparsity == SPARSE) { if(l >= k) { printf("%12lf ", getElementAt(N -> U, k, l)); } else { printf("%12lf ", getElementAt(N -> L, k, l)); } } else { printf("%12lf ", matrix_G[k * dimension + l]); } } printf("\n\n"); } printf("\n\n"); printf("\nLine Transposition:\n"); for(k = 0; k < dimension; k++) { if (circuit_simulation.matrix_sparsity == SPARSE) { printf("line %d contains line %d\n", N -> pinv[k], k); } else { printf("line %d contains line %d\n", k, transposition[k]); } } printf("\n\n"); #endif }
/* Cholesky update/downdate */ int demo3 (problem *Prob) { cs_di *A, *C, *W = NULL, *WW, *WT, *E = NULL, *W2 ; int n, k, *Li, *Lp, *Wi, *Wp, p1, p2, *p = NULL, ok ; double *b, *x, *resid, *y = NULL, *Lx, *Wx, s, t, t1 ; cs_dis *S = NULL ; cs_din *N = NULL ; if (!Prob || !Prob->sym || Prob->A->n == 0) return (0) ; A = Prob->A ; C = Prob->C ; b = Prob->b ; x = Prob->x ; resid = Prob->resid; n = A->n ; if (!Prob->sym || n == 0) return (1) ; rhs (x, b, n) ; /* compute right-hand side */ printf ("\nchol then update/downdate ") ; print_order (1) ; y = cs_di_malloc (n, sizeof (double)) ; t = tic () ; S = cs_di_schol (1, C) ; /* symbolic Chol, amd(A+A') */ printf ("\nsymbolic chol time %8.2f\n", toc (t)) ; t = tic () ; N = cs_di_chol (C, S) ; /* numeric Cholesky */ printf ("numeric chol time %8.2f\n", toc (t)) ; if (!S || !N || !y) return (done3 (0, S, N, y, W, E, p)) ; t = tic () ; cs_di_ipvec (S->pinv, b, y, n) ; /* y = P*b */ cs_di_lsolve (N->L, y) ; /* y = L\y */ cs_di_ltsolve (N->L, y) ; /* y = L'\y */ cs_di_pvec (S->pinv, y, x, n) ; /* x = P'*y */ printf ("solve chol time %8.2f\n", toc (t)) ; printf ("original: ") ; print_resid (1, C, x, b, resid) ; /* print residual */ k = n/2 ; /* construct W */ W = cs_di_spalloc (n, 1, n, 1, 0) ; if (!W) return (done3 (0, S, N, y, W, E, p)) ; Lp = N->L->p ; Li = N->L->i ; Lx = N->L->x ; Wp = W->p ; Wi = W->i ; Wx = W->x ; Wp [0] = 0 ; p1 = Lp [k] ; Wp [1] = Lp [k+1] - p1 ; s = Lx [p1] ; srand (1) ; for ( ; p1 < Lp [k+1] ; p1++) { p2 = p1 - Lp [k] ; Wi [p2] = Li [p1] ; Wx [p2] = s * rand () / ((double) RAND_MAX) ; } t = tic () ; ok = cs_di_updown (N->L, +1, W, S->parent) ; /* update: L*L'+W*W' */ t1 = toc (t) ; printf ("update: time: %8.2f\n", t1) ; if (!ok) return (done3 (0, S, N, y, W, E, p)) ; t = tic () ; cs_di_ipvec (S->pinv, b, y, n) ; /* y = P*b */ cs_di_lsolve (N->L, y) ; /* y = L\y */ cs_di_ltsolve (N->L, y) ; /* y = L'\y */ cs_di_pvec (S->pinv, y, x, n) ; /* x = P'*y */ t = toc (t) ; p = cs_di_pinv (S->pinv, n) ; W2 = cs_di_permute (W, p, NULL, 1) ; /* E = C + (P'W)*(P'W)' */ WT = cs_di_transpose (W2,1) ; WW = cs_di_multiply (W2, WT) ; cs_di_spfree (WT) ; cs_di_spfree (W2) ; E = cs_di_add (C, WW, 1, 1) ; cs_di_spfree (WW) ; if (!E || !p) return (done3 (0, S, N, y, W, E, p)) ; printf ("update: time: %8.2f (incl solve) ", t1+t) ; print_resid (1, E, x, b, resid) ; /* print residual */ cs_di_nfree (N) ; /* clear N */ t = tic () ; N = cs_di_chol (E, S) ; /* numeric Cholesky */ if (!N) return (done3 (0, S, N, y, W, E, p)) ; cs_di_ipvec (S->pinv, b, y, n) ; /* y = P*b */ cs_di_lsolve (N->L, y) ; /* y = L\y */ cs_di_ltsolve (N->L, y) ; /* y = L'\y */ cs_di_pvec (S->pinv, y, x, n) ; /* x = P'*y */ t = toc (t) ; printf ("rechol: time: %8.2f (incl solve) ", t) ; print_resid (1, E, x, b, resid) ; /* print residual */ t = tic () ; ok = cs_di_updown (N->L, -1, W, S->parent) ; /* downdate: L*L'-W*W' */ t1 = toc (t) ; if (!ok) return (done3 (0, S, N, y, W, E, p)) ; printf ("downdate: time: %8.2f\n", t1) ; t = tic () ; cs_di_ipvec (S->pinv, b, y, n) ; /* y = P*b */ cs_di_lsolve (N->L, y) ; /* y = L\y */ cs_di_ltsolve (N->L, y) ; /* y = L'\y */ cs_di_pvec (S->pinv, y, x, n) ; /* x = P'*y */ t = toc (t) ; printf ("downdate: time: %8.2f (incl solve) ", t1+t) ; print_resid (1, C, x, b, resid) ; /* print residual */ return (done3 (1, S, N, y, W, E, p)) ; }