void LDLSolve(scs_float *x, scs_float b[], cs * L, scs_float D[], scs_int P[], scs_float * bp) { /* solves PLDL'P' x = b for x */ scs_int n = L->n; if (P == NULL) { if (x != b) /* if they're different addresses */ memcpy(x, b, n * sizeof(scs_float)); LDL_lsolve(n, x, L->p, L->i, L->x); LDL_dsolve(n, x, D); LDL_ltsolve(n, x, L->p, L->i, L->x); } else { LDL_perm(n, bp, b, P); LDL_lsolve(n, bp, L->p, L->i, L->x); LDL_dsolve(n, bp, D); LDL_ltsolve(n, bp, L->p, L->i, L->x); LDL_permt(n, x, bp, P); } }
int main (void) #endif { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ #ifdef USE_AMD double Info [AMD_INFO] ; #endif double r, rnorm, flops, maxrnorm = 0. ; double *Ax, *Lx, *B, *D, *X, *Y ; LDL_int matrix, *Ai, *Ap, *Li, *Lp, *P, *Pinv, *Perm, *PermInv, n, i, j, p, nz, *Flag, *Pattern, *Lnz, *Parent, trial, lnz, d, jumbled ; FILE *f ; char s [LEN] ; /* ---------------------------------------------------------------------- */ /* check the error-checking routines with null matrices */ /* ---------------------------------------------------------------------- */ i = 1 ; n = -1 ; if (LDL_valid_perm (n, (LDL_int *) NULL, &i) || !LDL_valid_perm (0, (LDL_int *) NULL, &i) || LDL_valid_matrix (n, (LDL_int *) NULL, (LDL_int *) NULL) || LDL_valid_matrix (0, &i, &i)) { printf (PROGRAM ": ldl error-checking routine failed\n") ; EXIT_ERROR ; } /* ---------------------------------------------------------------------- */ /* read in a factorize a set of matrices */ /* ---------------------------------------------------------------------- */ for (matrix = 1 ; matrix <= NMATRICES ; matrix++) { /* ------------------------------------------------------------------ */ /* read in the matrix and the permutation */ /* ------------------------------------------------------------------ */ sprintf (s, "../Matrix/A%02d", (int) matrix) ; if ((f = fopen (s, "r")) == (FILE *) NULL) { printf (PROGRAM ": could not open file: %s\n", s) ; EXIT_ERROR ; } fgets (s, LEN, f) ; printf ("\n\n--------------------------------------------------------"); printf ("\nInput matrix: %s", s) ; printf ("--------------------------------------------------------\n\n"); fscanf (f, LDL_ID " " LDL_ID, &n, &jumbled) ; n = (n < 0) ? (0) : (n) ; ALLOC_MEMORY (P, LDL_int, n) ; ALLOC_MEMORY (Ap, LDL_int, n+1) ; for (j = 0 ; j <= n ; j++) { fscanf (f, LDL_ID, &Ap [j]) ; } nz = Ap [n] ; ALLOC_MEMORY (Ai, LDL_int, nz) ; ALLOC_MEMORY (Ax, double, nz) ; for (p = 0 ; p < nz ; p++) { fscanf (f, LDL_ID , &Ai [p]) ; } for (p = 0 ; p < nz ; p++) { fscanf (f, "%lg", &Ax [p]) ; } for (j = 0 ; j < n ; j++) { fscanf (f, LDL_ID , &P [j]) ; } fclose (f) ; /* ------------------------------------------------------------------ */ /* check the matrix A and the permutation P */ /* ------------------------------------------------------------------ */ ALLOC_MEMORY (Flag, LDL_int, n) ; /* To test the error-checking routines, some of the input matrices * are not valid. So this error is expected to occur. */ if (!LDL_valid_matrix (n, Ap, Ai) || !LDL_valid_perm (n, P, Flag)) { printf (PROGRAM ": invalid matrix and/or permutation\n") ; FREE_MEMORY (P, LDL_int) ; FREE_MEMORY (Ap, LDL_int) ; FREE_MEMORY (Ai, LDL_int) ; FREE_MEMORY (Ax, double) ; FREE_MEMORY (Flag, LDL_int) ; continue ; } /* ------------------------------------------------------------------ */ /* get the AMD permutation, if available */ /* ------------------------------------------------------------------ */ #ifdef USE_AMD /* recompute the permutation with AMD */ /* Assume that AMD produces a valid permutation P. */ #ifdef LDL_LONG if (amd_l_order (n, Ap, Ai, P, (double *) NULL, Info) < AMD_OK) { printf (PROGRAM ": call to AMD failed\n") ; EXIT_ERROR ; } amd_l_control ((double *) NULL) ; amd_l_info (Info) ; #else if (amd_order (n, Ap, Ai, P, (double *) NULL, Info) < AMD_OK) { printf (PROGRAM ": call to AMD failed\n") ; EXIT_ERROR ; } amd_control ((double *) NULL) ; amd_info (Info) ; #endif #endif /* ------------------------------------------------------------------ */ /* allocate workspace and the first part of LDL factorization */ /* ------------------------------------------------------------------ */ ALLOC_MEMORY (Pinv, LDL_int, n) ; ALLOC_MEMORY (Y, double, n) ; ALLOC_MEMORY (Pattern, LDL_int, n) ; ALLOC_MEMORY (Lnz, LDL_int, n) ; ALLOC_MEMORY (Lp, LDL_int, n+1) ; ALLOC_MEMORY (Parent, LDL_int, n) ; ALLOC_MEMORY (D, double, n) ; ALLOC_MEMORY (B, double, n) ; ALLOC_MEMORY (X, double, n) ; /* ------------------------------------------------------------------ */ /* factorize twice, with and without permutation */ /* ------------------------------------------------------------------ */ for (trial = 1 ; trial <= 2 ; trial++) { if (trial == 1) { printf ("Factorize PAP'=LDL' and solve Ax=b\n") ; Perm = P ; PermInv = Pinv ; } else { printf ("Factorize A=LDL' and solve Ax=b\n") ; Perm = (LDL_int *) NULL ; PermInv = (LDL_int *) NULL ; } /* -------------------------------------------------------------- */ /* symbolic factorization to get Lp, Parent, Lnz, and Pinv */ /* -------------------------------------------------------------- */ LDL_symbolic (n, Ap, Ai, Lp, Parent, Lnz, Flag, Perm, PermInv) ; lnz = Lp [n] ; /* find # of nonzeros in L, and flop count for LDL_numeric */ flops = 0 ; for (j = 0 ; j < n ; j++) { flops += ((double) Lnz [j]) * (Lnz [j] + 2) ; } printf ("Nz in L: "LDL_ID" Flop count: %g\n", lnz, flops) ; /* -------------------------------------------------------------- */ /* allocate remainder of L, of size lnz */ /* -------------------------------------------------------------- */ ALLOC_MEMORY (Li, LDL_int, lnz) ; ALLOC_MEMORY (Lx, double, lnz) ; /* -------------------------------------------------------------- */ /* numeric factorization to get Li, Lx, and D */ /* -------------------------------------------------------------- */ d = LDL_numeric (n, Ap, Ai, Ax, Lp, Parent, Lnz, Li, Lx, D, Y, Flag, Pattern, Perm, PermInv) ; /* -------------------------------------------------------------- */ /* solve, or report singular case */ /* -------------------------------------------------------------- */ if (d != n) { printf ("Ax=b not solved since D("LDL_ID","LDL_ID") is zero.\n", d, d) ; } else { /* construct the right-hand-side, B */ for (i = 0 ; i < n ; i++) { B [i] = 1 + ((double) i) / 100 ; } /* solve Ax=b */ if (trial == 1) { /* the factorization is LDL' = PAP' */ LDL_perm (n, Y, B, P) ; /* y = Pb */ LDL_lsolve (n, Y, Lp, Li, Lx) ; /* y = L\y */ LDL_dsolve (n, Y, D) ; /* y = D\y */ LDL_ltsolve (n, Y, Lp, Li, Lx) ; /* y = L'\y */ LDL_permt (n, X, Y, P) ; /* x = P'y */ } else { /* the factorization is LDL' = A */ for (i = 0 ; i < n ; i++) /* x = b */ { X [i] = B [i] ; } LDL_lsolve (n, X, Lp, Li, Lx) ; /* x = L\x */ LDL_dsolve (n, X, D) ; /* x = D\x */ LDL_ltsolve (n, X, Lp, Li, Lx) ; /* x = L'\x */ } /* compute the residual y = Ax-b */ /* note that this code can tolerate a jumbled matrix */ for (i = 0 ; i < n ; i++) { Y [i] = -B [i] ; } for (j = 0 ; j < n ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { Y [Ai [p]] += Ax [p] * X [j] ; } } /* rnorm = norm (y, inf) */ rnorm = 0 ; for (i = 0 ; i < n ; i++) { r = (Y [i] > 0) ? (Y [i]) : (-Y [i]) ; rnorm = (r > rnorm) ? (r) : (rnorm) ; } maxrnorm = (rnorm > maxrnorm) ? (rnorm) : (maxrnorm) ; printf ("relative maxnorm of residual: %g\n", rnorm) ; } /* -------------------------------------------------------------- */ /* free the size-lnz part of L */ /* -------------------------------------------------------------- */ FREE_MEMORY (Li, LDL_int) ; FREE_MEMORY (Lx, double) ; } /* free everything */ FREE_MEMORY (P, LDL_int) ; FREE_MEMORY (Ap, LDL_int) ; FREE_MEMORY (Ai, LDL_int) ; FREE_MEMORY (Ax, double) ; FREE_MEMORY (Pinv, LDL_int) ; FREE_MEMORY (Y, double) ; FREE_MEMORY (Flag, LDL_int) ; FREE_MEMORY (Pattern, LDL_int) ; FREE_MEMORY (Lnz, LDL_int) ; FREE_MEMORY (Lp, LDL_int) ; FREE_MEMORY (Parent, LDL_int) ; FREE_MEMORY (D, double) ; FREE_MEMORY (B, double) ; FREE_MEMORY (X, double) ; } printf ("\nLargest residual during all tests: %g\n", maxrnorm) ; if (maxrnorm < 1e-8) { printf ("\n" PROGRAM ": all tests passed\n") ; EXIT_OK ; } else { printf ("\n" PROGRAM ": one more tests failed (residual too high)\n") ; EXIT_ERROR ; } }
/** * Solves the permuted KKT system and returns the unpermuted search directions. * * On entry, the factorization of the permuted KKT matrix, PKPt, * is assumed to be up to date (call kkt_factor beforehand to achieve this). * The right hand side, Pb, is assumed to be already permuted. * * On exit, the resulting search directions are written into dx, dy and dz, * where these variables are permuted back to the original ordering. * * KKT->nitref iterative refinement steps are applied to solve the linear system. * * Returns the number of iterative refinement steps really taken. */ idxint kkt_solve(kkt* KKT, spmat* A, spmat* G, pfloat* Pb, pfloat* dx, pfloat* dy, pfloat* dz, idxint n, idxint p, idxint m, cone* C, idxint isinit, idxint nitref) { #if CONEMODE == 0 #define MTILDE (m+2*C->nsoc) #else #define MTILDE (m) #endif idxint i, k, l, j, kk, kItRef; #if (defined STATICREG) && (STATICREG > 0) idxint dzoffset; #endif idxint* Pinv = KKT->Pinv; pfloat* Px = KKT->work1; pfloat* dPx = KKT->work2; pfloat* e = KKT->work3; pfloat* Pe = KKT->work4; pfloat* truez = KKT->work5; pfloat* Gdx = KKT->work6; pfloat* ex = e; pfloat* ey = e + n; pfloat* ez = e + n+p; pfloat bnorm = 1.0 + norminf(Pb, n+p+MTILDE); pfloat nex = 0; pfloat ney = 0; pfloat nez = 0; pfloat nerr; pfloat nerr_prev; pfloat error_threshold = bnorm*LINSYSACC; idxint nK = KKT->PKPt->n; /* forward - diagonal - backward solves: Px holds solution */ LDL_lsolve2(nK, Pb, KKT->L->jc, KKT->L->ir, KKT->L->pr, Px ); LDL_dsolve(nK, Px, KKT->D); LDL_ltsolve(nK, Px, KKT->L->jc, KKT->L->ir, KKT->L->pr); #if PRINTLEVEL > 2 if( p > 0 ){ PRINTTEXT("\nIR: it ||ex|| ||ey|| ||ez|| (threshold: %4.2e)\n", error_threshold); PRINTTEXT(" --------------------------------------------------\n"); } else { PRINTTEXT("\nIR: it ||ex|| ||ez|| (threshold: %4.2e)\n", error_threshold); PRINTTEXT(" -----------------------------------------\n"); } #endif /* iterative refinement */ for( kItRef=0; kItRef <= nitref; kItRef++ ){ /* unpermute x & copy into arrays */ unstretch(n, p, C, Pinv, Px, dx, dy, dz); /* compute error term */ k=0; j=0; /* 1. error on dx*/ #if (defined STATICREG) && (STATICREG > 0) /* ex = bx - A'*dy - G'*dz - DELTASTAT*dx */ for( i=0; i<n; i++ ){ ex[i] = Pb[Pinv[k++]] - DELTASTAT*dx[i]; } #else /* ex = bx - A'*dy - G'*dz */ for( i=0; i<n; i++ ){ ex[i] = Pb[Pinv[k++]]; } #endif if(A) sparseMtVm(A, dy, ex, 0, 0); sparseMtVm(G, dz, ex, 0, 0); nex = norminf(ex,n); /* error on dy */ if( p > 0 ){ #if (defined STATICREG) && (STATICREG > 0) /* ey = by - A*dx + DELTASTAT*dy */ for( i=0; i<p; i++ ){ ey[i] = Pb[Pinv[k++]] + DELTASTAT*dy[i]; } #else /* ey = by - A*dx */ for( i=0; i<p; i++ ){ ey[i] = Pb[Pinv[k++]]; } #endif sparseMV(A, dx, ey, -1, 0); ney = norminf(ey,p); } /* --> 3. ez = bz - G*dx + V*dz_true */ kk = 0; j=0; #if (defined STATICREG) && (STATICREG > 0) dzoffset=0; #endif sparseMV(G, dx, Gdx, 1, 1); for( i=0; i<C->lpc->p; i++ ){ #if (defined STATICREG) && (STATICREG > 0) ez[kk++] = Pb[Pinv[k++]] - Gdx[j++] + DELTASTAT*dz[dzoffset++]; #else ez[kk++] = Pb[Pinv[k++]] - Gdx[j++]; #endif } for( l=0; l<C->nsoc; l++ ){ for( i=0; i<C->soc[l].p; i++ ){ #if (defined STATICREG) && (STATICREG > 0) ez[kk++] = i<(C->soc[l].p-1) ? Pb[Pinv[k++]] - Gdx[j++] + DELTASTAT*dz[dzoffset++] : Pb[Pinv[k++]] - Gdx[j++] - DELTASTAT*dz[dzoffset++]; #else ez[kk++] = Pb[Pinv[k++]] - Gdx[j++]; #endif } #if CONEMODE == 0 ez[kk] = 0; ez[kk+1] = 0; k += 2; kk += 2; #endif } for( i=0; i<MTILDE; i++) { truez[i] = Px[Pinv[n+p+i]]; } if( isinit == 0 ){ scale2add(truez, ez, C); } else { vadd(MTILDE, truez, ez); } nez = norminf(ez,MTILDE); #if PRINTLEVEL > 2 if( p > 0 ){ PRINTTEXT(" %2d %3.1e %3.1e %3.1e\n", (int)kItRef, nex, ney, nez); } else { PRINTTEXT(" %2d %3.1e %3.1e\n", (int)kItRef, nex, nez); } #endif /* maximum error (infinity norm of e) */ nerr = MAX( nex, nez); if( p > 0 ){ nerr = MAX( nerr, ney ); } /* CHECK WHETHER REFINEMENT BROUGHT DECREASE - if not undo and quit! */ if( kItRef > 0 && nerr > nerr_prev ){ /* undo refinement */ for( i=0; i<nK; i++ ){ Px[i] -= dPx[i]; } kItRef--; break; } /* CHECK WHETHER TO REFINE AGAIN */ if( kItRef == nitref || ( nerr < error_threshold ) || ( kItRef > 0 && nerr_prev < IRERRFACT*nerr ) ){ break; } nerr_prev = nerr; /* permute */ for( i=0; i<nK; i++) { Pe[Pinv[i]] = e[i]; } /* forward - diagonal - backward solves: dPx holds solution */ LDL_lsolve2(nK, Pe, KKT->L->jc, KKT->L->ir, KKT->L->pr, dPx); LDL_dsolve(nK, dPx, KKT->D); LDL_ltsolve(nK, dPx, KKT->L->jc, KKT->L->ir, KKT->L->pr); /* add refinement to Px */ for( i=0; i<nK; i++ ){ Px[i] += dPx[i]; } } #if PRINTLEVEL > 2 PRINTTEXT("\n"); #endif /* copy solution out into the different arrays, permutation included */ unstretch(n, p, C, Pinv, Px, dx, dy, dz); return kItRef; }