Work * scs_init(Data * d, Cone * k, Info * info) { Work * w; timer initTimer; if (!d || !k || !info) { scs_printf("ERROR: Missing Data, Cone or Info input\n"); return NULL; } #ifdef EXTRAVERBOSE printData(d); printConeData(k); #endif #ifndef NOVALIDATE if (validate(d, k) < 0) { scs_printf("ERROR: Validation returned failure\n"); return NULL; } #endif tic(&initTimer); w = initWork(d, k); /* strtoc("init", &initTimer); */ info->setupTime = tocq(&initTimer); if (d->VERBOSE) { scs_printf("Setup time: %1.2es\n", info->setupTime / 1e3); } return w; }
static void printInitHeader(Data * d, Work * w, Cone * k) { idxint i; char * coneStr = getConeHeader(k); char * linSysMethod = getLinSysMethod(d, w->p); _lineLen_ = -1; for (i = 0; i < HEADER_LEN; ++i) { _lineLen_ += (idxint) strlen(HEADER[i]) + 1; } for (i = 0; i < _lineLen_; ++i) { scs_printf("-"); } scs_printf("\n\tSCS v%s - Splitting Conic Solver\n\t(c) Brendan O'Donoghue, Stanford University, 2012\n", SCS_VERSION); for (i = 0; i < _lineLen_; ++i) { scs_printf("-"); } scs_printf("\n"); if (linSysMethod) { scs_printf("Lin-sys: %s\n", linSysMethod); scs_free(linSysMethod); } if (d->NORMALIZE) { scs_printf("EPS = %.2e, ALPHA = %.2f, MAX_ITERS = %i, NORMALIZE = %i, SCALE = %2.2f\n", d->EPS, d->ALPHA, (int) d->MAX_ITERS, (int) d->NORMALIZE, d->SCALE); } else { scs_printf("EPS = %.2e, ALPHA = %.2f, MAX_ITERS = %i, NORMALIZE = %i\n", d->EPS, d->ALPHA, (int) d->MAX_ITERS, (int) d->NORMALIZE); } scs_printf("Variables n = %i, constraints m = %i\n", (int) d->n, (int) d->m); scs_printf("%s", coneStr); scs_free(coneStr); #ifdef MATLAB_MEX_FILE mexEvalString("drawnow;"); #endif }
void printSol(Data * d, Sol * sol, Info * info) { idxint i; scs_printf("%s\n", info->status); if (sol->x != NULL) { for (i = 0; i < d->n; ++i) { scs_printf("x[%i] = %4f\n", (int) i, sol->x[i]); } } if (sol->y != NULL) { for (i = 0; i < d->m; ++i) { scs_printf("y[%i] = %4f\n", (int) i, sol->y[i]); } } }
int main(int argc, char **argv) { FILE * fp; Cone * k; Data * d; Work * w; Sol * sol; Info info = { 0 }; scs_int i; if (openFile(argc, argv, 1, DEMO_PATH, &fp) < 0) return -1; k = scs_calloc(1, sizeof(Cone)); d = scs_calloc(1, sizeof(Data)); sol = scs_calloc(1, sizeof(Sol)); if (readInData(fp, d, k) == -1) { printf("Error reading in data, aborting.\n"); return -1; } fclose(fp); scs_printf("solve once using scs\n"); scs(d, k, sol, &info); if (TEST_WARM_START) { scs_printf("solve %i times with warm-start and (if applicable) factorization caching.\n", NUM_TRIALS); /* warm starts stored in Sol */ w = scs_init(d, k, &info); if (w) { for (i = 0; i < NUM_TRIALS; i++) { /* perturb b and c */ perturbVector(d->b, d->m); perturbVector(d->c, d->n); d->stgs->warm_start = 1; d->stgs->cg_rate = 4; scs_solve(w, d, k, sol, &info); d->stgs->warm_start = 0; d->stgs->cg_rate = 2; scs_solve(w, d, k, sol, &info); } } scs_printf("finished\n"); scs_finish(w); } freeData(d, k); freeSol(sol); return 0; }
scs_int factorize(const AMatrix * A, const Settings * stgs, Priv * p) { scs_float *info; scs_int *Pinv, amd_status, ldl_status; cs *C, *K = formKKT(A, stgs); if (!K) { return -1; } amd_status = LDLInit(K, p->P, &info); if (amd_status < 0) return (amd_status); #if EXTRAVERBOSE > 0 if(stgs->verbose) { scs_printf("Matrix factorization info:\n"); #ifdef DLONG amd_l_info(info); #else amd_info(info); #endif } #endif Pinv = cs_pinv(p->P, A->n + A->m); C = cs_symperm(K, Pinv, 1); ldl_status = LDLFactor(C, NULL, NULL, &p->L, &p->D); cs_spfree(C); cs_spfree(K); scs_free(Pinv); scs_free(info); return (ldl_status); }
static scs_int factorize(const ScsMatrix *A, const ScsSettings *stgs, ScsLinSysWork *p) { scs_float *info; scs_int *Pinv, amd_status, ldl_status; cs *C, *K = form_kkt(A, stgs); if (!K) { return -1; } amd_status = _ldl_init(K, p->P, &info); if (amd_status < 0) { return (amd_status); } #if EXTRA_VERBOSE > 0 if (stgs->verbose) { scs_printf("Matrix factorization info:\n"); #ifdef DLONG amd_l_info(info); #else amd_info(info); #endif } #endif Pinv = SCS(cs_pinv)(p->P, A->n + A->m); C = SCS(cs_symperm)(K, Pinv, 1); ldl_status = _ldl_factor(C, SCS_NULL, SCS_NULL, &p->L, &p->D); SCS(cs_spfree)(C); SCS(cs_spfree)(K); scs_free(Pinv); scs_free(info); return (ldl_status); }
static void printSummary(idxint i, struct residuals *r, timer * solveTimer) { scs_printf("%*i|", (int) strlen(HEADER[0]), (int) i); scs_printf("%*.2e ", (int) HSPACE, r->resPri); scs_printf("%*.2e ", (int) HSPACE, r->resDual); scs_printf("%*.2e ", (int) HSPACE, r->relGap); scs_printf("%*.2e ", (int) HSPACE, r->cTx); scs_printf("%*.2e ", (int) HSPACE, -r->bTy); scs_printf("%*.2e ", (int) HSPACE, r->kap / r->tau); scs_printf("%*.2e ", (int) HSPACE, tocq(solveTimer) / 1e3); scs_printf("\n"); #ifdef MATLAB_MEX_FILE mexEvalString("drawnow;"); #endif }
idxint scs_solve(Work * w, Data * d, Cone * k, Sol * sol, Info * info) { idxint i; timer solveTimer; struct residuals r; if (!d || !k || !sol || !info || !w || !d->b || !d->c) { scs_printf("ERROR: NULL input\n"); return FAILURE; } tic(&solveTimer); info->statusVal = 0; /* not yet converged */ updateWork(d, w, sol); if (d->VERBOSE) printHeader(d, w, k); /* scs: */ for (i = 0; i < d->MAX_ITERS; ++i) { memcpy(w->u_prev, w->u, (d->n + d->m + 1) * sizeof(pfloat)); if (projectLinSys(d, w, i) < 0) return failureDefaultReturn(d, w, sol, info, "error in projectLinSys"); if (projectCones(d, w, k, i) < 0) return failureDefaultReturn(d, w, sol, info, "error in projectCones"); updateDualVars(d, w); if ((info->statusVal = converged(d, w, &r, i)) != 0) break; if (i % PRINT_INTERVAL == 0) { if (d->VERBOSE) { printSummary(i, &r, &solveTimer); #ifdef EXTRAVERBOSE scs_printf("Norm u = %4f, ", calcNorm(w->u, d->n + d->m + 1)); scs_printf("Norm u_t = %4f, ", calcNorm(w->u_t, d->n + d->m + 1)); scs_printf("Norm v = %4f, ", calcNorm(w->v, d->n + d->m + 1)); scs_printf("tau = %4f, ", w->u[d->n + d->m]); scs_printf("kappa = %4f, ", w->v[d->n + d->m]); scs_printf("|u - u_prev| = %4f, ", calcNormDiff(w->u, w->u_prev, d->n + d->m + 1)); scs_printf("|u - u_t| = %4f\n", calcNormDiff(w->u, w->u_t, d->n + d->m + 1)); #endif } } } if (d->VERBOSE) { printSummary(i, &r, &solveTimer); } setSolution(d, w, sol, info); /* populate info */ info->iter = i; getInfo(d, w, sol, info); info->solveTime = tocq(&solveTimer); if (d->VERBOSE) printFooter(d, w, info); /* un-normalize sol, b, c but not A */ if (d->NORMALIZE) unNormalizeSolBC(d, w, sol); return info->statusVal; }
/* M = inv ( diag ( RHO_X * I + A'A ) ) */ void getPreconditioner(const AMatrix * A, const Settings * stgs, Priv * p) { scs_int i; scs_float * M = p->M; #if EXTRAVERBOSE > 0 scs_printf("getting pre-conditioner\n"); #endif for (i = 0; i < A->n; ++i) { M[i] = 1 / (stgs->rho_x + calcNormSq(&(A->x[A->p[i]]), A->p[i + 1] - A->p[i])); /* M[i] = 1; */ } #if EXTRAVERBOSE > 0 scs_printf("finished getting pre-conditioner\n"); #endif }
scs_int solveLinSys(const AMatrix * A, const Settings * stgs, Priv * p, scs_float * b, const scs_float * s, scs_int iter) { /* returns solution to linear system */ /* Ax = b with solution stored in b */ tic(&linsysTimer); LDLSolve(b, b, p->L, p->D, p->P, p->bp); totalSolveTime += tocq(&linsysTimer); #if EXTRAVERBOSE > 0 scs_printf("linsys solve time: %1.2es\n", tocq(&linsysTimer) / 1e3); #endif return 0; }
static scs_int _ldl_factor(cs *A, scs_int P[], scs_int Pinv[], cs **L, scs_float **D) { scs_int kk, n = A->n; scs_int *Parent = (scs_int *)scs_malloc(n * sizeof(scs_int)); scs_int *Lnz = (scs_int *)scs_malloc(n * sizeof(scs_int)); scs_int *Flag = (scs_int *)scs_malloc(n * sizeof(scs_int)); scs_int *Pattern = (scs_int *)scs_malloc(n * sizeof(scs_int)); scs_float *Y = (scs_float *)scs_malloc(n * sizeof(scs_float)); (*L)->p = (scs_int *)scs_malloc((1 + n) * sizeof(scs_int)); /*scs_int Parent[n], Lnz[n], Flag[n], Pattern[n]; */ /*scs_float Y[n]; */ LDL_symbolic(n, A->p, A->i, (*L)->p, Parent, Lnz, Flag, P, Pinv); (*L)->nzmax = *((*L)->p + n); (*L)->x = (scs_float *)scs_malloc((*L)->nzmax * sizeof(scs_float)); (*L)->i = (scs_int *)scs_malloc((*L)->nzmax * sizeof(scs_int)); *D = (scs_float *)scs_malloc(n * sizeof(scs_float)); if (!(*D) || !(*L)->i || !(*L)->x || !Y || !Pattern || !Flag || !Lnz || !Parent) { return -1; } #if EXTRA_VERBOSE > 0 scs_printf("numeric factorization\n"); #endif kk = LDL_numeric(n, A->p, A->i, A->x, (*L)->p, Parent, Lnz, (*L)->i, (*L)->x, *D, Y, Pattern, Flag, P, Pinv); #if EXTRA_VERBOSE > 0 scs_printf("finished numeric factorization\n"); #endif scs_free(Parent); scs_free(Lnz); scs_free(Flag); scs_free(Pattern); scs_free(Y); return (kk - n); }
static void transpose(const AMatrix * A, Priv * p) { scs_int * Ci = p->At->i; scs_int * Cp = p->At->p; scs_float * Cx = p->At->x; scs_int m = A->m; scs_int n = A->n; scs_int * Ap = A->p; scs_int * Ai = A->i; scs_float * Ax = A->x; scs_int i, j, q, *z, c1, c2; #if EXTRAVERBOSE > 0 timer transposeTimer; scs_printf("transposing A\n"); tic(&transposeTimer); #endif z = scs_calloc(m, sizeof(scs_int)); for (i = 0; i < Ap[n]; i++) z[Ai[i]]++; /* row counts */ cs_cumsum(Cp, z, m); /* row pointers */ for (j = 0; j < n; j++) { c1 = Ap[j]; c2 = Ap[j + 1]; for (i = c1; i < c2; i++) { q = z[Ai[i]]; Ci[q] = j; /* place A(i,j) as entry C(j,i) */ Cx[q] = Ax[i]; z[Ai[i]]++; } } scs_free(z); #if EXTRAVERBOSE > 0 scs_printf("finished transposing A, time: %1.2es\n", tocq(&transposeTimer) / 1e3); #endif }
static void updateWork(Data * d, Work * w, Sol * sol) { /* before normalization */ idxint n = d->n; idxint m = d->m; w->nm_b = calcNorm(d->b, m); w->nm_c = calcNorm(d->c, n); #ifdef EXTRAVERBOSE printArray(d->b, d->m, "b"); scs_printf("pre-normalized norm b = %4f\n", calcNorm(d->b, d->m)); printArray(d->c, d->n, "c"); scs_printf("pre-normalized norm c = %4f\n", calcNorm(d->c, d->n)); #endif if (d->NORMALIZE) { normalizeBC(d, w); #ifdef EXTRAVERBOSE printArray(d->b, d->m, "bn"); scs_printf("sc_b = %4f\n", w->sc_b); scs_printf("post-normalized norm b = %4f\n", calcNorm(d->b, d->m)); printArray(d->c, d->n, "cn"); scs_printf("sc_c = %4f\n", w->sc_c); scs_printf("post-normalized norm c = %4f\n", calcNorm(d->c, d->n)); #endif } if (d->WARM_START) { warmStartVars(d, w, sol); } else { coldStartVars(d, w); } memcpy(w->h, d->c, n * sizeof(pfloat)); memcpy(&(w->h[d->n]), d->b, m * sizeof(pfloat)); memcpy(w->g, w->h, (n + m) * sizeof(pfloat)); solveLinSys(d, w->p, w->g, NULL, -1); scaleArray(&(w->g[d->n]), -1, m); w->gTh = innerProd(w->h, w->g, n + m); }
scs_int SCS(solve_lin_sys)(const ScsMatrix *A, const ScsSettings *stgs, ScsLinSysWork *p, scs_float *b, const scs_float *s, scs_int iter) { /* returns solution to linear system */ /* Ax = b with solution stored in b */ SCS(timer) linsys_timer; SCS(tic)(&linsys_timer); _ldl_solve(b, b, p->L, p->D, p->P, p->bp); p->total_solve_time += SCS(tocq)(&linsys_timer); #if EXTRA_VERBOSE > 0 scs_printf("linsys solve time: %1.2es\n", SCS(tocq)(&linsys_timer) / 1e3); #endif return 0; }
static cs *form_kkt(const ScsMatrix *A, const ScsSettings *s) { /* ONLY UPPER TRIANGULAR PART IS STUFFED * forms column compressed KKT matrix * assumes column compressed form A matrix * * forms upper triangular part of [I A'; A -I] */ scs_int j, k, kk; cs *K_cs; /* I at top left */ const scs_int Anz = A->p[A->n]; const scs_int Knzmax = A->n + A->m + Anz; cs *K = SCS(cs_spalloc)(A->m + A->n, A->m + A->n, Knzmax, 1, 1); #if EXTRA_VERBOSE > 0 scs_printf("forming KKT\n"); #endif if (!K) { return SCS_NULL; } kk = 0; for (k = 0; k < A->n; k++) { K->i[kk] = k; K->p[kk] = k; K->x[kk] = s->rho_x; kk++; } /* A^T at top right : CCS: */ for (j = 0; j < A->n; j++) { for (k = A->p[j]; k < A->p[j + 1]; k++) { K->p[kk] = A->i[k] + A->n; K->i[kk] = j; K->x[kk] = A->x[k]; kk++; } } /* -I at bottom right */ for (k = 0; k < A->m; k++) { K->i[kk] = k + A->n; K->p[kk] = k + A->n; K->x[kk] = -1; kk++; } /* assert kk == Knzmax */ K->nz = Knzmax; K_cs = SCS(cs_compress)(K); SCS(cs_spfree)(K); return (K_cs); }
static scs_int pcg(const AMatrix * A, const Settings * stgs, Priv * pr, const scs_float * s, scs_float * b, scs_int max_its, scs_float tol) { scs_int i, n = A->n; scs_float ipzr, ipzrOld, alpha; scs_float *p = pr->p; /* cg direction */ scs_float *Gp = pr->Gp; /* updated CG direction */ scs_float *r = pr->r; /* cg residual */ scs_float *z = pr->z; /* for preconditioning */ scs_float *M = pr->M; /* inverse diagonal preconditioner */ if (s == NULL) { memcpy(r, b, n * sizeof(scs_float)); memset(b, 0, n * sizeof(scs_float)); } else { matVec(A, stgs, pr, s, r); addScaledArray(r, b, n, -1); scaleArray(r, -1, n); memcpy(b, s, n * sizeof(scs_float)); } /* check to see if we need to run CG at all */ if (calcNorm(r, n) < MIN(tol, 1e-18)) { return 0; } applyPreConditioner(M, z, r, n, &ipzr); memcpy(p, z, n * sizeof(scs_float)); for (i = 0; i < max_its; ++i) { matVec(A, stgs, pr, p, Gp); alpha = ipzr / innerProd(p, Gp, n); addScaledArray(b, p, n, alpha); addScaledArray(r, Gp, n, -alpha); if (calcNorm(r, n) < tol) { #if EXTRAVERBOSE > 0 scs_printf("tol: %.4e, resid: %.4e, iters: %li\n", tol, calcNorm(r, n), (long) i+1); #endif return i + 1; } ipzrOld = ipzr; applyPreConditioner(M, z, r, n, &ipzr); scaleArray(p, ipzr / ipzrOld, n); addScaledArray(p, z, n, 1); } return i; }
/* this just calls scs_init, scs_solve, and scs_finish */ idxint scs(Data * d, Cone * k, Sol * sol, Info * info) { #if ( defined _WIN32 || defined _WIN64 ) && !defined MATLAB_MEX_FILE && !defined PYTHON /* sets width of exponent for floating point numbers to 2 instead of 3 */ unsigned int old_output_format = _set_output_format(_TWO_DIGIT_EXPONENT); #endif Work * w = scs_init(d, k, info); #ifdef EXTRAVERBOSE scs_printf("size of idxint = %lu, size of pfloat = %lu\n", sizeof(idxint), sizeof(pfloat)); #endif if (!w) { return failureDefaultReturn(d, NULL, sol, info, "could not initialize work"); } scs_solve(w, d, k, sol, info); scs_finish(d, w); return info->statusVal; }
static idxint validate(Data * d, Cone * k) { if (d->m <= 0 || d->n <= 0) { scs_printf("m and n must both be greater than 0\n"); return -1; } if (d->m < d->n) { scs_printf("m must be greater than or equal to n\n"); return -1; } if (validateLinSys(d) < 0) { scs_printf("invalid linear system input data\n"); return -1; } if (validateCones(d, k) < 0) { scs_printf("invalid cone dimensions\n"); return -1; } if (d->MAX_ITERS <= 0) { scs_printf("MAX_ITERS must be positive\n"); return -1; } if (d->EPS <= 0) { scs_printf("EPS tolerance must be positive\n"); return -1; } if (d->ALPHA <= 0 || d->ALPHA >= 2) { scs_printf("ALPHA must be in (0,2)\n"); return -1; } if (d->RHO_X <= 0) { scs_printf("RHO_X must be positive (1e-3 works well).\n"); return -1; } if (d->SCALE <= 0) { scs_printf("SCALE must be positive (1 works well).\n"); return -1; } return 0; }
static Work * initWork(Data *d, Cone * k) { Work * w = scs_calloc(1, sizeof(Work)); idxint l = d->n + d->m + 1; if (d->VERBOSE) { printInitHeader(d, w, k); } if (!w) { scs_printf("ERROR: allocating work failure\n"); return NULL; } /* allocate workspace: */ w->u = scs_malloc(l * sizeof(pfloat)); w->v = scs_malloc(l * sizeof(pfloat)); w->u_t = scs_malloc(l * sizeof(pfloat)); w->u_prev = scs_malloc(l * sizeof(pfloat)); w->h = scs_malloc((l - 1) * sizeof(pfloat)); w->g = scs_malloc((l - 1) * sizeof(pfloat)); w->pr = scs_malloc(d->m * sizeof(pfloat)); w->dr = scs_malloc(d->n * sizeof(pfloat)); if (!w->u || !w->v || !w->u_t || !w->u_prev || !w->h || !w->g || !w->pr || !w->dr) { scs_printf("ERROR: work memory allocation failure\n"); scs_finish(d, w); return NULL; } if (d->NORMALIZE) { normalizeA(d, w, k); #ifdef EXTRAVERBOSE printArray(w->D, d->m, "D"); scs_printf("norm D = %4f\n", calcNorm(w->D, d->m)); printArray(w->E, d->n, "E"); scs_printf("norm E = %4f\n", calcNorm(w->E, d->n)); #endif } else { w->D = NULL; w->E = NULL; } if (initCone(k) < 0) { scs_printf("ERROR: initCone failure\n"); scs_finish(d, w); return NULL; } w->p = initPriv(d); if (!w->p) { scs_printf("ERROR: initPriv failure\n"); scs_finish(d, w); return NULL; } return w; }
static idxint failureDefaultReturn(Data * d, Work * w, Sol * sol, Info * info, char * msg) { info->relGap = NAN; info->resPri = NAN; info->resDual = NAN; info->pobj = NAN; info->dobj = NAN; info->iter = -1; info->statusVal = FAILURE; info->solveTime = NAN; strcpy(info->status, "Failure"); if (!sol->x) sol->x = scs_malloc(sizeof(pfloat) * d->n); scaleArray(sol->x, NAN, d->n); if (!sol->y) sol->y = scs_malloc(sizeof(pfloat) * d->m); scaleArray(sol->y, NAN, d->m); if (!sol->s) sol->s = scs_malloc(sizeof(pfloat) * d->m); scaleArray(sol->s, NAN, d->m); scs_printf("FAILURE:%s\n", msg); return FAILURE; }
static void printHeader(Data * d, Work * w, Cone * k) { idxint i; if (d->WARM_START) scs_printf("SCS using variable warm-starting\n"); for (i = 0; i < _lineLen_; ++i) { scs_printf("-"); } scs_printf("\n"); for (i = 0; i < HEADER_LEN - 1; ++i) { scs_printf("%s|", HEADER[i]); } scs_printf("%s\n", HEADER[HEADER_LEN - 1]); for (i = 0; i < _lineLen_; ++i) { scs_printf("-"); } scs_printf("\n"); #ifdef MATLAB_MEX_FILE mexEvalString("drawnow;"); #endif }
scs_int solveLinSys(const AMatrix * A, const Settings * stgs, Priv * p, scs_float * b, const scs_float * s, scs_int iter) { scs_int cgIts; scs_float cgTol = calcNorm(b, A->n) * (iter < 0 ? CG_BEST_TOL : CG_MIN_TOL / POWF((scs_float) iter + 1, stgs->cg_rate)); tic(&linsysTimer); /* solves Mx = b, for x but stores result in b */ /* s contains warm-start (if available) */ accumByAtrans(A, p, &(b[A->n]), b); /* solves (I+A'A)x = b, s warm start, solution stored in b */ cgIts = pcg(A, stgs, p, s, b, A->n, MAX(cgTol, CG_BEST_TOL)); scaleArray(&(b[A->n]), -1, A->m); accumByA(A, p, b, &(b[A->n])); if (iter >= 0) { totCgIts += cgIts; } totalSolveTime += tocq(&linsysTimer); #if EXTRAVERBOSE > 0 scs_printf("linsys solve time: %1.2es\n", tocq(&linsysTimer) / 1e3); #endif return 0; }
static void printFooter(Data * d, Work * w, Info * info) { idxint i; char * linSysStr = getLinSysSummary(w->p, info); char * coneStr = getConeSummary(info); for (i = 0; i < _lineLen_; ++i) { scs_printf("-"); } scs_printf("\nStatus: %s\n", info->status); if (info->iter == d->MAX_ITERS) { scs_printf("Hit MAX_ITERS, solution may be inaccurate\n"); } scs_printf("Timing: Total solve time: %1.2es\n", info->solveTime / 1e3); if (linSysStr) { scs_printf("%s", linSysStr); scs_free(linSysStr); } if (coneStr) { scs_printf("%s", coneStr); scs_free(coneStr); } for (i = 0; i < _lineLen_; ++i) { scs_printf("-"); } scs_printf("\n"); if (info->statusVal == INFEASIBLE) { scs_printf("Certificate of primal infeasibility:\n"); scs_printf("|A'y|_2 * |b|_2 = %.4e\n", info->resDual); scs_printf("dist(y, K*) = 0\n"); scs_printf("b'y = %.4f\n", info->dobj); } else if (info->statusVal == UNBOUNDED) { scs_printf("Certificate of dual infeasibility:\n"); scs_printf("|Ax + s|_2 * |c|_2 = %.4e\n", info->resPri); scs_printf("dist(s, K) = 0\n"); scs_printf("c'x = %.4f\n", info->pobj); } else { scs_printf("Error metrics:\n"); scs_printf("|Ax + s - b|_2 / (1 + |b|_2) = %.4e\n", info->resPri); scs_printf("|A'y + c|_2 / (1 + |c|_2) = %.4e\n", info->resDual); scs_printf("|c'x + b'y| / (1 + |c'x| + |b'y|) = %.4e\n", info->relGap); scs_printf("dist(s, K) = 0, dist(y, K*) = 0, s'y = 0\n"); for (i = 0; i < _lineLen_; ++i) { scs_printf("-"); } scs_printf("\n"); scs_printf("c'x = %.4f, -b'y = %.4f\n", info->pobj, info->dobj); } for (i = 0; i < _lineLen_; ++i) { scs_printf("="); } scs_printf("\n"); #ifdef MATLAB_MEX_FILE mexEvalString("drawnow;"); #endif }
int main(int argc, char **argv) { scs_int n, m, col_nnz, nnz, i, q_total, q_num_rows, max_q; Cone * k; Data * d; Sol * sol, * opt_sol; Info info = { 0 }; scs_float p_f, p_l; int seed = 0; /* default parameters */ p_f = 0.1; p_l = 0.3; seed = time(SCS_NULL); switch (argc) { case 5: seed = atoi(argv[4]); /* no break */ case 4: p_f = atof(argv[2]); p_l = atof(argv[3]); /* no break */ case 2: n = atoi(argv[1]); break; default: scs_printf("usage:\t%s n p_f p_l s\n" "\tcreates an SOCP with n variables where p_f fraction of rows correspond\n" "\tto equality constraints, p_l fraction of rows correspond to LP constraints,\n" "\tand the remaining percentage of rows are involved in second-order\n" "\tcone constraints. the random number generator is seeded with s.\n" "\tnote that p_f + p_l should be less than or equal to 1, and that\n" "\tp_f should be less than .33, since that corresponds to as many equality\n" "\tconstraints as variables.\n", argv[0]); scs_printf("\nusage:\t%s n p_f p_l\n" "\tdefaults the seed to the system time\n", argv[0]); scs_printf("\nusage:\t%s n\n" "\tdefaults to using p_f = 0.1 and p_l = 0.3\n", argv[0]); return 0; } srand(seed); scs_printf("seed : %i\n", seed); k = scs_calloc(1, sizeof(Cone)); d = scs_calloc(1, sizeof(Data)); d->stgs = scs_calloc(1, sizeof(Settings)); sol = scs_calloc(1, sizeof(Sol)); opt_sol = scs_calloc(1, sizeof(Sol)); m = 3 * n; col_nnz = (int) ceil(sqrt(n)); nnz = n * col_nnz; max_q = (scs_int) ceil(3 * n / log(3 * n)); if (p_f + p_l > 1.0) { printf("error: p_f + p_l > 1.0!\n"); return 1; } k->f = (scs_int) floor(3 * n * p_f); k->l = (scs_int) floor(3 * n * p_l); k->qsize = 0; q_num_rows = 3 * n - k->f - k->l; k->q = scs_malloc(q_num_rows * sizeof(scs_int)); while (q_num_rows > max_q) { int size; size = (rand() % max_q) + 1; k->q[k->qsize] = size; k->qsize++; q_num_rows -= size; } if (q_num_rows > 0) { k->q[k->qsize] = q_num_rows; k->qsize++; } q_total = 0; for (i = 0; i < k->qsize; i++) { q_total += k->q[i]; } k->s = SCS_NULL; k->ssize = 0; k->ep = 0; k->ed = 0; scs_printf("\nA is %ld by %ld, with %ld nonzeros per column.\n", (long) m, (long) n, (long) col_nnz); scs_printf("A has %ld nonzeros (%f%% dense).\n", (long) nnz, 100 * (scs_float) col_nnz / m); scs_printf("Nonzeros of A take %f GB of storage.\n", ((scs_float) nnz * sizeof(scs_float)) / POWF(2, 30)); scs_printf("Row idxs of A take %f GB of storage.\n", ((scs_float) nnz * sizeof(scs_int)) / POWF(2, 30)); scs_printf("Col ptrs of A take %f GB of storage.\n\n", ((scs_float) n * sizeof(scs_int)) / POWF(2, 30)); printf("Cone information:\n"); printf("Zero cone rows: %ld\n", (long) k->f); printf("LP cone rows: %ld\n", (long) k->l); printf("Number of second-order cones: %ld, covering %ld rows, with sizes\n[", (long) k->qsize, (long) q_total); for (i = 0; i < k->qsize; i++) { printf("%ld, ", (long) k->q[i]); } printf("]\n"); printf("Number of rows covered is %ld out of %ld.\n\n", (long) (q_total + k->f + k->l), (long) m); /* set up SCS structures */ d->m = m; d->n = n; genRandomProbData(nnz, col_nnz, d, k, opt_sol); setDefaultSettings(d); scs_printf("true pri opt = %4f\n", innerProd(d->c, opt_sol->x, d->n)); scs_printf("true dua opt = %4f\n", -innerProd(d->b, opt_sol->y, d->m)); /* solve! */ scs(d, k, sol, &info); scs_printf("true pri opt = %4f\n", innerProd(d->c, opt_sol->x, d->n)); scs_printf("true dua opt = %4f\n", -innerProd(d->b, opt_sol->y, d->m)); if (sol->x) { scs_printf("scs pri obj= %4f\n", innerProd(d->c, sol->x, d->n)); } if (sol->y) { scs_printf("scs dua obj = %4f\n", -innerProd(d->b, sol->y, d->m)); } freeData(d, k); freeSol(sol); freeSol(opt_sol); return 0; }
scs_int validateCones(const Data * d, const Cone * k) { scs_int i; if (getFullConeDims(k) != d->m) { scs_printf("cone dimensions %li not equal to num rows in A = m = %li\n", (long) getFullConeDims(k), (long) d->m); return -1; } if (k->f && k->f < 0) { scs_printf("free cone error\n"); return -1; } if (k->l && k->l < 0) { scs_printf("lp cone error\n"); return -1; } if (k->qsize && k->q) { if (k->qsize < 0) { scs_printf("soc cone error\n"); return -1; } for (i = 0; i < k->qsize; ++i) { if (k->q[i] < 0) { scs_printf("soc cone error\n"); return -1; } } } if (k->ssize && k->s) { if (k->ssize < 0) { scs_printf("sd cone error\n"); return -1; } for (i = 0; i < k->ssize; ++i) { if (k->s[i] < 0) { scs_printf("sd cone error\n"); return -1; } } } if (k->ed && k->ed < 0) { scs_printf("ep cone error\n"); return -1; } if (k->ep && k->ep < 0) { scs_printf("ed cone error\n"); return -1; } if (k->psize && k->p) { if (k->psize < 0) { scs_printf("power cone error\n"); return -1; } for (i = 0; i<k->psize; ++i) { if (k->p[i] < -1 || k->p[i] > 1) { scs_printf("power cone error, values must be in [-1,1]\n"); return -1; } } } return 0; }
LDL_int LDL_numeric /* returns n if successful, k if D (k,k) is zero */ ( LDL_int n, /* A and L are n-by-n, where n >= 0 */ LDL_int Ap [ ], /* input of size n+1, not modified */ LDL_int Ai [ ], /* input of size nz=Ap[n], not modified */ scs_float Ax [ ], /* input of size nz=Ap[n], not modified */ LDL_int Lp [ ], /* input of size n+1, not modified */ LDL_int Parent [ ], /* input of size n, not modified */ LDL_int Lnz [ ], /* output of size n, not defn. on input */ LDL_int Li [ ], /* output of size lnz=Lp[n], not defined on input */ scs_float Lx [ ], /* output of size lnz=Lp[n], not defined on input */ scs_float D [ ], /* output of size n, not defined on input */ scs_float Y [ ], /* workspace of size n, not defn. on input or output */ LDL_int Pattern [ ],/* workspace of size n, not defn. on input or output */ LDL_int Flag [ ], /* workspace of size n, not defn. on input or output */ LDL_int P [ ], /* optional input of size n */ LDL_int Pinv [ ] /* optional input of size n */ ) { scs_float yi, l_ki ; LDL_int i, k, p, kk, p2, len, top ; for (k = 0 ; k < n ; k++) { if(isInterrupted()) { scs_printf("interrupt detected in factorization\n"); return -1; } /* compute nonzero Pattern of kth row of L, in topological order */ Y [k] = 0.0 ; /* Y(0:k) is now all zero */ top = n ; /* stack for pattern is empty */ Flag [k] = k ; /* mark node k as visited */ Lnz [k] = 0 ; /* count of nonzeros in column k of L */ kk = (P) ? (P [k]) : (k) ; /* kth original, or permuted, column */ p2 = Ap [kk+1] ; for (p = Ap [kk] ; p < p2 ; p++) { i = (Pinv) ? (Pinv [Ai [p]]) : (Ai [p]) ; /* get A(i,k) */ if (i <= k) { Y [i] += Ax [p] ; /* scatter A(i,k) into Y (sum duplicates) */ for (len = 0 ; Flag [i] != k ; i = Parent [i]) { Pattern [len++] = i ; /* L(k,i) is nonzero */ Flag [i] = k ; /* mark i as visited */ } while (len > 0) Pattern [--top] = Pattern [--len] ; } } /* compute numerical values kth row of L (a sparse triangular solve) */ D [k] = Y [k] ; /* get D(k,k) and clear Y(k) */ Y [k] = 0.0 ; for ( ; top < n ; top++) { i = Pattern [top] ; /* Pattern [top:n-1] is pattern of L(:,k) */ yi = Y [i] ; /* get and clear Y(i) */ Y [i] = 0.0 ; p2 = Lp [i] + Lnz [i] ; for (p = Lp [i] ; p < p2 ; p++) { Y [Li [p]] -= Lx [p] * yi ; } l_ki = yi / D [i] ; /* the nonzero entry L(k,i) */ D [k] -= l_ki * yi ; Li [p] = k ; /* store L(k,i) in column form of L */ Lx [p] = l_ki ; Lnz [i]++ ; /* increment count of nonzeros in col i */ } if (D [k] == 0.0) return (k) ; /* failure, D(k,k) is zero */ } return (n) ; /* success, diagonal of D is all nonzero */ }
QDLDL_int QDLDL_factor(const QDLDL_int n, const QDLDL_int* Ap, const QDLDL_int* Ai, const QDLDL_float* Ax, QDLDL_int* Lp, QDLDL_int* Li, QDLDL_float* Lx, QDLDL_float* D, QDLDL_float* Dinv, const QDLDL_int* Lnz, const QDLDL_int* etree, QDLDL_bool* bwork, QDLDL_int* iwork, QDLDL_float* fwork){ QDLDL_int i,j,k,nnzY, bidx, cidx, nextIdx, nnzE, tmpIdx; QDLDL_int *yIdx, *elimBuffer, *LNextSpaceInCol; QDLDL_float *yVals; QDLDL_float yVals_cidx; QDLDL_bool *yMarkers; QDLDL_int positiveValuesInD = 0; //partition working memory into pieces yMarkers = bwork; yIdx = iwork; elimBuffer = iwork + n; LNextSpaceInCol = iwork + n*2; yVals = fwork; Lp[0] = 0; //first column starts at index zero for(i = 0; i < n; i++){ //compute L column indices Lp[i+1] = Lp[i] + Lnz[i]; //cumsum, total at the end // set all Yidx to be 'unused' initially //in each column of L, the next available space //to start is just the first space in the column yMarkers[i] = QDLDL_UNUSED; yVals[i] = 0.0; D[i] = 0.0; LNextSpaceInCol[i] = Lp[i]; } // First element of the diagonal D. D[0] = Ax[0]; if(D[0] == 0.0){return -1;} if(D[0] > 0.0){positiveValuesInD++;} Dinv[0] = 1/D[0]; //Start from 1 here. The upper LH corner is trivially 0 //in L b/c we are only computing the subdiagonal elements for(k = 1; k < n; k++){ if(scs_is_interrupted()) { scs_printf("interrupt detected in factorization\n"); return -1; } //NB : For each k, we compute a solution to //y = L(0:(k-1),0:k-1))\b, where b is the kth //column of A that sits above the diagonal. //The solution y is then the kth row of L, //with an implied '1' at the diagonal entry. //number of nonzeros in this row of L nnzY = 0; //number of elements in this row //This loop determines where nonzeros //will go in the kth row of L, but doesn't //compute the actual values tmpIdx = Ap[k+1]; for(i = Ap[k]; i < tmpIdx; i++){ bidx = Ai[i]; // we are working on this element of b //Initialize D[k] as the element of this column //corresponding to the diagonal place. Don't use //this element as part of the elimination step //that computes the k^th row of L if(bidx == k){ D[k] = Ax[i]; continue; } yVals[bidx] = Ax[i]; // initialise y(bidx) = b(bidx) // use the forward elimination tree to figure // out which elements must be eliminated after // this element of b nextIdx = bidx; if(yMarkers[nextIdx] == QDLDL_UNUSED){ //this y term not already visited yMarkers[nextIdx] = QDLDL_USED; //I touched this one elimBuffer[0] = nextIdx; // It goes at the start of the current list nnzE = 1; //length of unvisited elimination path from here nextIdx = etree[bidx]; while(nextIdx != QDLDL_UNKNOWN && nextIdx < k){ if(yMarkers[nextIdx] == QDLDL_USED) break; yMarkers[nextIdx] = QDLDL_USED; //I touched this one elimBuffer[nnzE] = nextIdx; //It goes in the current list nnzE++; //the list is one longer than before nextIdx = etree[nextIdx]; //one step further along tree } //end while // now I put the buffered elimination list into // my current ordering in reverse order while(nnzE){ yIdx[nnzY++] = elimBuffer[--nnzE]; } //end while } //end if } //end for i //This for loop places nonzeros values in the k^th row for(i = (nnzY-1); i >=0; i--){ //which column are we working on? cidx = yIdx[i]; // loop along the elements in this // column of L and subtract to solve to y tmpIdx = LNextSpaceInCol[cidx]; yVals_cidx = yVals[cidx]; for(j = Lp[cidx]; j < tmpIdx; j++){ yVals[Li[j]] -= Lx[j]*yVals_cidx; } //Now I have the cidx^th element of y = L\b. //so compute the corresponding element of //this row of L and put it into the right place Li[tmpIdx] = k; Lx[tmpIdx] = yVals_cidx *Dinv[cidx]; //D[k] -= yVals[cidx]*yVals[cidx]*Dinv[cidx]; D[k] -= yVals_cidx*Lx[tmpIdx]; LNextSpaceInCol[cidx]++; //reset the yvalues and indices back to zero and QDLDL_UNUSED //once I'm done with them yVals[cidx] = 0.0; yMarkers[cidx] = QDLDL_UNUSED; } //end for i //Maintain a count of the positive entries //in D. If we hit a zero, we can't factor //this matrix, so abort if(D[k] == 0.0){return -1;} if(D[k] > 0.0){positiveValuesInD++;} //compute the inverse of the diagonal Dinv[k]= 1/D[k]; } //end for k return positiveValuesInD; }