LCOV - code coverage report
Current view: top level - src - scs.c (source / functions) Hit Total Coverage
Test: SuperSCS Unit Tests Lines: 1007 1050 95.9 %
Date: 2018-05-30 Functions: 54 54 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * The MIT License (MIT)
       3             :  *
       4             :  * Copyright (c) 2017 Pantelis Sopasakis (https://alphaville.github.io),
       5             :  *                    Krina Menounou (https://www.linkedin.com/in/krinamenounou), 
       6             :  *                    Panagiotis Patrinos (http://homes.esat.kuleuven.be/~ppatrino)
       7             :  * Copyright (c) 2012 Brendan O'Donoghue (bodonoghue85@gmail.com)
       8             :  *
       9             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      10             :  * of this software and associated documentation files (the "Software"), to deal
      11             :  * in the Software without restriction, including without limitation the rights
      12             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      13             :  * copies of the Software, and to permit persons to whom the Software is
      14             :  * furnished to do so, subject to the following conditions:
      15             :  *
      16             :  * The above copyright notice and this permission notice shall be included in all
      17             :  * copies or substantial portions of the Software.
      18             :  *
      19             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      22             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      24             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      25             :  * SOFTWARE.
      26             :  * 
      27             :  */
      28             : #include "scs.h"
      29             : #include "normalize.h"
      30             : #include "directions.h"
      31             : #include "linsys/amatrix.h"
      32             : #include <time.h>
      33             : 
      34             : /* if verbose print summary output every this num iterations */
      35             : #define SCS_PRINT_INTERVAL 100
      36             : /* check for convergence every this num iterations */
      37             : #define SCS_CONVERGED_INTERVAL 1
      38             : 
      39             : /* tolerance at which we declare problem indeterminate */
      40             : #define SCS_INDETERMINATE_TOL 1e-9
      41             : 
      42             : /**
      43             :  *  \brief Structure to hold residual information (unnormalized) 
      44             :  */
      45             : struct scs_residuals {
      46             :     /**
      47             :      * \brief The last iteration when the residuals were updated.
      48             :      */
      49             :     scs_int last_iter;
      50             :     /**
      51             :      * \brief Dual residual
      52             :      * 
      53             :      * \f[
      54             :      * \text{resdual} = \frac{E(A'y + \tau c)}{\tau(1+\|c\|)\cdot \text{scale}_c\cdot \text{scale}}
      55             :      * \f]
      56             :      */
      57             :     scs_float res_dual;
      58             :     /**
      59             :      * \brief Primal residual
      60             :      * 
      61             :      * \f[
      62             :      *  \text{respri} = \frac{\|D(Ax+s-\tau b)\|}{\tau(1+\|b\|)(\text{scale}_b\cdot \text{scale})}
      63             :      * \f]
      64             :      */
      65             :     scs_float res_pri;
      66             :     /**
      67             :      * \brief Infeasibility residual
      68             :      * 
      69             :      * \f[
      70             :      *  \text{infres} = -\frac{\|Db\| \|EA'y\|}{b'y \cdot \text{scale}}
      71             :      * \f]
      72             :      */
      73             :     scs_float res_infeas;
      74             :     /**
      75             :      * \brief Unboundedness
      76             :      * 
      77             :      * \f[
      78             :      * \text{unbdd} = -\frac{\|Ec\| \|D(Ax+s)}{c'x\cdot \text{scale}}
      79             :      * \f]
      80             :      */
      81             :     scs_float res_unbdd;
      82             :     /**
      83             :      * \brief Relative duality gap defined as 
      84             :      * 
      85             :      * \f[
      86             :      *  \text{relgap} = \frac{c'x + b'y}{1+|c'x|+|b'y|}
      87             :      * \f]
      88             :      */
      89             :     scs_float rel_gap;
      90             :     scs_float cTx_by_tau; /* not divided by tau */
      91             :     scs_float bTy_by_tau; /* not divided by tau */
      92             :     /**
      93             :      * Variable \f$\tau\f$ (\f$\bar{\tau}\f$ in SuperSCS)
      94             :      */
      95             :     scs_float tau; /* for superSCS it's tau_b */
      96             :     /**
      97             :      * Variable \f$\kappa\f$ (\f$\bar{\kappa}\f$ in SuperSCS)
      98             :      */
      99             :     scs_float kap; /* for superSCS it's kap_b */
     100             : };
     101             : /* printing header */
     102             : static const char *SCS_HEADER[] = {
     103             :     " Iter ", " pri res ", " dua res ", " rel gap ",
     104             :     " pri obj ", " dua obj ", " kap/tau ", "   FPR   ", " time (s)"
     105             : };
     106             : static const scs_int scs_hspace = 9;
     107             : static const scs_int scs_header_length = 9;
     108             : static const scs_int scs_header_line_length = 87;
     109             : 
     110             : static scs_int scs_isnan(scs_float x) {
     111          42 :     return (isnan(x)); /* `isnan` works both for `float` and `double` types */
     112             : }
     113             : 
     114         321 : static ScsDirectionCache * scs_init_direction_cache(scs_int memory, scs_int l, scs_int print_mode, ScsDirectionType dir_type) {
     115         321 :     ScsDirectionCache * RESTRICT cache = scs_calloc(1, sizeof (*cache));
     116         321 :     scs_int length_S = 0, length_U = 0, length_S_minus_U = 0, length_t = 0, length_ws = 0;
     117             : 
     118             : 
     119         321 :     if (cache == SCS_NULL) {
     120             :         /* LCOV_EXCL_START */
     121             :         scs_special_print(print_mode, stderr, "ERROR: allocating YSCache failure\n");
     122             :         return SCS_NULL;
     123             :         /* LCOV_EXCL_STOP */
     124             :     }
     125             : 
     126         321 :     cache->ls_wspace_length = 0;
     127         321 :     cache->current_mem = 0;
     128             : 
     129         321 :     switch (dir_type) {
     130             :         case restarted_broyden:
     131             :             /* we allocate one extra memory position because it's needed */
     132         318 :             length_S = (1 + memory) * l;
     133         318 :             length_U = (1 + memory) * l;
     134         318 :             break;
     135             :         case anderson_acceleration:
     136           3 :             length_S = memory * l;
     137           3 :             length_U = memory * l;
     138           3 :             length_S_minus_U = memory * l;
     139             :             /* -----------------------------------------------------------------
     140             :              * Although t is a vector of dimension 'memory', we allocate space
     141             :              * of length 'l' because we first need to store the residual 'R'
     142             :              * therein (see directions.c: scs_compute_dir_anderson).
     143             :              * Note: we give some additional space because the BLAS documentation
     144             :              * says that we should give **at least** this much memory.
     145             :              * ----------------------------------------------------------------- */
     146           3 :             length_t = l;
     147             : #ifdef SVD_ACTIVATED
     148           3 :             cache->ls_wspace_length = 1000 + scs_svd_workspace_size(l, memory);
     149             :             /* -----------------------------------------------------------------
     150             :              * In Anderson's acceleration, we solve a least squares problem
     151             :              * using lapack's SVD-based 'sgelss' (see svdls). This requires a
     152             :              * workspace whose size is given by 'cache->ls_wspace_length' (above).
     153             :              * To that we add another 'memory' memory positions to store the
     154             :              * singular values of the LHS matrix and another 'l*memory'
     155             :              * memory positions to make a copy of the Y-cache; this is
     156             :              * because 'sgelss' modified the LHS (i.e., the Y-cache).
     157             :              * ----------------------------------------------------------------- */
     158           3 :             length_ws = (cache->ls_wspace_length) + memory * (1 + l);
     159             : #else
     160             :             cache->ls_wspace_length = 1000 + scs_qr_workspace_size(l, memory);
     161             :             /* -----------------------------------------------------------------
     162             :              * In Anderson's acceleration, we solve a least squares problem
     163             :              * using lapack's SVD-based 'sgelss' (see svdls). This requires a
     164             :              * workspace whose size is given by 'cache->ls_wspace_length' (above).
     165             :              * To that we add another 'l*memory'
     166             :              * memory positions to make a copy of the Y-cache; this is
     167             :              * because 'sgelss' modified the LHS (i.e., the Y-cache).
     168             :              * ----------------------------------------------------------------- */
     169             :             length_ws = (cache->ls_wspace_length) + memory * l;
     170             : #endif
     171           3 :             break;
     172             :         default:
     173             :             break;
     174             :     }
     175             : 
     176         321 :     cache->S = scs_malloc(length_S * sizeof (scs_float));
     177         321 :     cache->U = scs_malloc(length_U * sizeof (scs_float));
     178         321 :     cache->S_minus_Y = scs_malloc(length_S_minus_U * sizeof (scs_float));
     179         321 :     cache->t = scs_malloc(length_t * sizeof (scs_float));
     180         321 :     cache->ls_wspace = scs_malloc(length_ws * sizeof (scs_float));
     181             : 
     182             :     /* the cache must know its memory length */
     183         321 :     cache->mem = memory;
     184             : 
     185             :     /* initial active memory is 0 */
     186         321 :     scs_reset_direction_cache(cache);
     187         321 :     return cache;
     188             : }
     189             : 
     190         326 : static void scs_free_direction_cache(ScsDirectionCache * RESTRICT cache) {
     191         326 :     if (cache == SCS_NULL)
     192         326 :         return;
     193         321 :     scs_free(cache->S);
     194         321 :     scs_free(cache->U);
     195         321 :     scs_free(cache->S_minus_Y);
     196         321 :     scs_free(cache->t);
     197         321 :     scs_free(cache->ls_wspace);
     198         321 :     scs_free(cache);
     199             : }
     200             : 
     201         329 : static void scs_free_work(ScsWork * RESTRICT work) {
     202         658 :     if (work == SCS_NULL) return;
     203         329 :     scs_free(work->u);
     204         329 :     scs_free(work->v);
     205         329 :     scs_free(work->u_t);
     206         329 :     scs_free(work->u_prev);
     207         329 :     scs_free(work->h);
     208         329 :     scs_free(work->g);
     209         329 :     scs_free(work->b);
     210         329 :     scs_free(work->c);
     211         329 :     scs_free(work->pr);
     212         329 :     scs_free(work->dr);
     213         329 :     if (work->scal != SCS_NULL) {
     214         326 :         scs_free(work->scal->D);
     215         326 :         scs_free(work->scal->E);
     216         326 :         scs_free(work->scal);
     217             :     }
     218         329 :     scs_free(work->u_b);
     219             : 
     220         329 :     if (work->stgs->do_super_scs == 1) {
     221         326 :         scs_free(work->R);
     222         326 :         scs_free(work->R_prev);
     223         326 :         scs_free(work->dir);
     224         326 :         scs_free(work->dut);
     225         326 :         scs_free(work->Sk);
     226         326 :         scs_free(work->Yk);
     227         326 :         scs_free(work->wu);
     228         326 :         scs_free(work->wu_t);
     229         326 :         scs_free(work->wu_b);
     230         326 :         scs_free(work->Rwu);
     231         326 :         scs_free_direction_cache(work->direction_cache);
     232         326 :         scs_free(work->s_b);
     233         326 :         scs_free(work->H);
     234             :     }
     235         329 :     scs_free(work);
     236             : }
     237             : 
     238             : /* LCOV_EXCL_START */
     239             : static void scs_print_init_header(
     240             :         const ScsData * RESTRICT data,
     241             :         const ScsCone * RESTRICT cone) {
     242             :     scs_int i;
     243             :     ScsSettings * RESTRICT stgs = data->stgs;
     244             :     char *RESTRICT coneStr = scs_get_cone_header(cone);
     245             :     char *RESTRICT linSysMethod = scs_get_linsys_method(data->A, data->stgs);
     246             :     FILE * RESTRICT stream = stgs->output_stream;
     247             :     scs_int print_mode = stgs->do_override_streams;
     248             :     for (i = 0; i < scs_header_line_length; ++i) {
     249             :         scs_special_print(print_mode, stream, "-");
     250             :     }
     251             :     scs_special_print(print_mode, stream, "\n\tSCS v%s - Superlinear Splitting Conic Solver (SuperSCS)\n\t"
     252             :             "Web: https://kul-forbes.github.io/scs\n\t"
     253             :             "(c) P. Sopasakis, K. Menounou, P. Patrinos, KU Leuven, 2017-8\n\t"
     254             :             "(c) Brendan O'Donoghue, Stanford University, 2012-2016\n",
     255             :             scs_version());
     256             :     for (i = 0; i < scs_header_line_length; ++i) {
     257             :         scs_special_print(print_mode, stream, "-");
     258             :     }
     259             :     scs_special_print(print_mode, stream, "\n");
     260             :     if (linSysMethod) {
     261             :         scs_special_print(print_mode, stream, "Lin-sys: %s\n", linSysMethod);
     262             :         scs_free(linSysMethod);
     263             :     }
     264             :     if (stgs->normalize) {
     265             :         scs_special_print(print_mode, stream, "eps = %.2e, alpha = %.2f, max_iters = %i, normalize = %i, "
     266             :                 "scale = %2.2f\n",
     267             :                 stgs->eps, stgs->alpha, (int) stgs->max_iters,
     268             :                 (int) stgs->normalize, stgs->scale);
     269             :     } else {
     270             :         scs_special_print(print_mode, stream, "eps = %.2e, alpha = %.2f, max_iters = %i, normalize = %i\n",
     271             :                 stgs->eps, stgs->alpha, (int) stgs->max_iters,
     272             :                 (int) stgs->normalize);
     273             :     }
     274             :     scs_special_print(print_mode, stream, "do_super_scs = %i, direction = %i, "
     275             :             "memory = %i\n", (int) stgs->do_super_scs, (int) stgs->direction,
     276             :             (int) stgs->memory);
     277             :     scs_special_print(print_mode, stream, "Variables n = %i, constraints m = %i\n", (int) data->n, (int) data->m);
     278             :     scs_special_print(print_mode, stream, "%s", coneStr);
     279             :     scs_free(coneStr);
     280             : #ifdef MATLAB_MEX_FILE
     281             :     mexEvalString("drawnow;");
     282             : #endif
     283             : }
     284             : 
     285             : /* LCOV_EXCL_STOP */
     286             : 
     287          12 : static void scs_populate_on_failure(
     288             :         scs_int m,
     289             :         scs_int n,
     290             :         ScsSolution * RESTRICT sol,
     291             :         ScsInfo * RESTRICT info,
     292             :         scs_int statusVal,
     293             :         const char *RESTRICT msg) {
     294          12 :     if (info) {
     295          12 :         info->relGap = NAN;
     296          12 :         info->resPri = NAN;
     297          12 :         info->resDual = NAN;
     298          12 :         info->pobj = NAN;
     299          12 :         info->dobj = NAN;
     300          12 :         info->iter = -1;
     301          12 :         info->statusVal = statusVal;
     302          12 :         info->solveTime = NAN;
     303          12 :         strncpy(info->status, msg, SCS_INFO_STATUS_MSG_LENGTH);
     304             :     }
     305          12 :     if (sol) {
     306          12 :         if (n > 0) {
     307          12 :             if (sol->x == SCS_NULL)
     308           1 :                 sol->x = scs_malloc(sizeof (scs_float) * n);
     309          12 :             scs_scale_array(sol->x, NAN, n);
     310             :         }
     311          12 :         if (m > 0) {
     312          12 :             if (sol->y == SCS_NULL)
     313           1 :                 sol->y = scs_malloc(sizeof (scs_float) * m);
     314          12 :             scs_scale_array(sol->y, NAN, m);
     315          12 :             if (sol->s == SCS_NULL)
     316           1 :                 sol->s = scs_malloc(sizeof (scs_float) * m);
     317          12 :             scs_scale_array(sol->s, NAN, m);
     318             :         }
     319             :     }
     320          12 : }
     321             : 
     322          12 : static scs_int scs_failure(
     323             :         ScsWork * RESTRICT work,
     324             :         scs_int m,
     325             :         scs_int n,
     326             :         ScsSolution * RESTRICT sol,
     327             :         ScsInfo * RESTRICT info,
     328             :         scs_int stint,
     329             :         const char *RESTRICT msg,
     330             :         const char *RESTRICT ststr,
     331             :         scs_int print_mode) {
     332          12 :     scs_int status = stint;
     333          12 :     scs_populate_on_failure(m, n, sol, info, status, ststr);
     334          12 :     scs_special_print(print_mode, stderr, "Failure:%s\n", msg);
     335          12 :     endInterruptListener();
     336          12 :     return status;
     337             : }
     338             : 
     339           2 : static void scs_warm_start_vars(
     340             :         ScsWork * RESTRICT work,
     341             :         const ScsSolution * RESTRICT sol) {
     342             :     scs_int i;
     343           2 :     scs_int n = work->n;
     344           2 :     scs_int m = work->m;
     345           2 :     scs_float * RESTRICT Ax = SCS_NULL;
     346           2 :     scs_float * RESTRICT ATy = SCS_NULL;
     347             : 
     348           2 :     if (work->stgs->do_super_scs == 0) {
     349           1 :         memset(work->v, 0, n * sizeof (scs_float));
     350           1 :         memcpy(work->u, sol->x, n * sizeof (scs_float));
     351           1 :         memcpy(&(work->u[n]), sol->y, m * sizeof (scs_float));
     352           1 :         memcpy(&(work->v[n]), sol->s, m * sizeof (scs_float));
     353           1 :         work->v[n + m] = 0.0;
     354           1 :         work->u[n + m] = 1.0;
     355             :     } else {
     356           1 :         memcpy(work->u_t, sol->x, n * sizeof (scs_float));
     357           1 :         memcpy(&(work->u_t[n]), sol->y, m * sizeof (scs_float));
     358           1 :         work->u_t[n + m] = 1.0;
     359             :     }
     360             : #ifndef NOVALIDATE
     361           2 :     if (work->stgs->do_super_scs == 0) {
     362          17 :         for (i = 0; i < n + m + 1; ++i) {
     363          34 :             if (scs_isnan(work->u[i])) {
     364           0 :                 work->u[i] = 0;
     365             :             }
     366          34 :             if (scs_isnan(work->v[i])) {
     367           0 :                 work->v[i] = 0;
     368             :             }
     369             :         }
     370             :     } else {
     371           8 :         for (i = 0; i < n + m + 1; ++i) {
     372          16 :             if (scs_isnan(work->u_t[i])) {
     373           0 :                 work->u_t[i] = 0;
     374             :             }
     375             :         }
     376             :     }
     377             : #endif
     378           2 :     if (work->stgs->normalize) {
     379           1 :         scs_normalize_warm_start(work);
     380             :     }
     381           2 :     if (work->stgs->do_super_scs) {
     382           1 :         Ax = scs_calloc(m, sizeof (scs_float));
     383           1 :         ATy = scs_calloc(n, sizeof (scs_float));
     384             : 
     385           1 :         scs_accum_by_a(work->A, work->p, work->u_t, Ax); /* Ax_t = A*x_t */
     386           1 :         scs_accum_by_a_trans(work->A, work->p, &(work->u_t[n]), ATy); /* ATy_t = AT*y_t */
     387           4 :         for (i = 0; i < n; ++i) {
     388             :             /* rho_x*x_t  + ATy_t + c*tau_t */
     389           3 :             work->u[i] = work->u_t[i] + ATy[i] + work->c[i] * work->u_t[n + m];
     390             :         }
     391           4 :         for (i = 0; i < m; ++i) {
     392             :             /* -Ax_t  + y_t + b*tau_t */
     393           4 :             work->u[i + n] = -Ax[i] + work->u_t[i + n] + work->b[i] * work->u_t[n + m];
     394             :         }
     395             :         /* -cTx_t - BTy_t + tau_t */
     396           2 :         work->u[n + m] = -scs_inner_product(work->c, work->u_t, work->n)
     397           1 :                 - scs_inner_product(work->b, &(work->u_t[n]), work->m)
     398           1 :                 + work->u_t[n + m];
     399             :     }
     400           2 :     if (Ax != SCS_NULL) {
     401           1 :         scs_free(Ax);
     402             :     }
     403           2 :     if (ATy != SCS_NULL) {
     404           1 :         scs_free(ATy);
     405             :     }
     406           2 : }
     407             : 
     408         201 : static scs_float scs_calc_primal_resid(
     409             :         ScsWork * RESTRICT work,
     410             :         const scs_float * RESTRICT x,
     411             :         const scs_float * RESTRICT s,
     412             :         const scs_float tau,
     413             :         scs_float * RESTRICT nmAxs) {
     414             :     scs_int i;
     415         201 :     scs_float pres = 0, scale, *RESTRICT pr = work->pr;
     416         201 :     *nmAxs = 0;
     417         201 :     memset(pr, 0, work->m * sizeof (scs_float));
     418         201 :     scs_accum_by_a(work->A, work->p, x, pr);
     419         201 :     scs_add_scaled_array(pr, s, work->m, 1.0); /* pr = Ax + s */
     420     1941208 :     for (i = 0; i < work->m; ++i) {
     421     1941007 :         scale =
     422     1941007 :                 work->stgs->normalize ? work->scal->D[i] / (work->sc_b * work->stgs->scale) : 1;
     423     1941007 :         scale = scale * scale;
     424     1941007 :         *nmAxs += (pr[i] * pr[i]) * scale;
     425     1941007 :         pres += (pr[i] - work->b[i] * tau) * (pr[i] - work->b[i] * tau) * scale;
     426             :     }
     427         201 :     *nmAxs = SQRTF(*nmAxs);
     428         201 :     return SQRTF(pres); /* norm(Ax + s - b * tau), for superSCS: norm(Ax_b + s_b - b * tau_b) */
     429             : }
     430             : 
     431         201 : static scs_float scs_calc_dual_resid(
     432             :         ScsWork * RESTRICT work,
     433             :         const scs_float * RESTRICT y,
     434             :         const scs_float tau,
     435             :         scs_float * RESTRICT nmATy) {
     436             :     scs_int i;
     437         201 :     scs_float dres = 0, scale, *dr = work->dr;
     438         201 :     *nmATy = 0;
     439         201 :     memset(dr, 0, work->n * sizeof (scs_float));
     440         201 :     scs_accum_by_a_trans(work->A, work->p, y, dr); /* dr = A'y */
     441      970668 :     for (i = 0; i < work->n; ++i) {
     442      970467 :         scale =
     443      970467 :                 work->stgs->normalize ? (work->scal->E[i] / (work->sc_c * work->stgs->scale)) : 1;
     444      970467 :         scale = scale * scale;
     445      970467 :         *nmATy += (dr[i] * dr[i]) * scale;
     446      970467 :         dres += (dr[i] + work->c[i] * tau) * (dr[i] + work->c[i] * tau) * scale;
     447             :     }
     448         201 :     *nmATy = SQRTF(*nmATy);
     449         201 :     return SQRTF(dres); /* norm(A'y + c * tau), for superSCS: norm(A'y_b + c * tau_b)*/
     450             : }
     451             : 
     452             : /* calculates un-normalized quantities */
     453         203 : static void scs_calc_residuals(
     454             :         ScsWork * RESTRICT work,
     455             :         struct scs_residuals * RESTRICT res,
     456             :         scs_int iter) {
     457             :     scs_float * RESTRICT x;
     458             :     scs_float * RESTRICT y;
     459             :     scs_float * RESTRICT s;
     460             :     scs_float nmpr_tau;
     461             :     scs_float nmdr_tau;
     462             :     scs_float nmAxs_tau;
     463             :     scs_float nmATy_tau;
     464             :     scs_float cTx, bTy;
     465         203 :     scs_int n = work->n, m = work->m;
     466             : 
     467             :     /* checks if the residuals are unchanged by checking iteration */
     468         203 :     if (res->last_iter == iter) {
     469           2 :         return;
     470             :     }
     471         201 :     res->last_iter = iter;
     472             : 
     473         201 :     s = &(work->v[work->n]);
     474         201 :     x = work->u;
     475         201 :     y = &(work->u[work->n]);
     476             : 
     477         201 :     res->tau = ABS(work->u[n + m]);
     478         402 :     res->kap = ABS(work->v[n + m]) /
     479         201 :             (work->stgs->normalize ? (work->stgs->scale * work->sc_c * work->sc_b) : 1);
     480             : 
     481         201 :     nmpr_tau = scs_calc_primal_resid(work, x, s, res->tau, &nmAxs_tau);
     482         201 :     nmdr_tau = scs_calc_dual_resid(work, y, res->tau, &nmATy_tau);
     483             : 
     484         201 :     res->bTy_by_tau =
     485         402 :             scs_inner_product(y, work->b, m) /
     486         201 :             (work->stgs->normalize ? (work->stgs->scale * work->sc_c * work->sc_b) : 1);
     487         201 :     res->cTx_by_tau =
     488         402 :             scs_inner_product(x, work->c, n) /
     489         201 :             (work->stgs->normalize ? (work->stgs->scale * work->sc_c * work->sc_b) : 1);
     490             : 
     491         201 :     res->res_infeas =
     492         201 :             res->bTy_by_tau < 0 ? work->nm_b * nmATy_tau / -res->bTy_by_tau : NAN;
     493         201 :     res->res_unbdd =
     494         201 :             res->cTx_by_tau < 0 ? work->nm_c * nmAxs_tau / -res->cTx_by_tau : NAN;
     495             : 
     496         201 :     bTy = res->bTy_by_tau / res->tau;
     497         201 :     cTx = res->cTx_by_tau / res->tau;
     498             : 
     499         201 :     res->res_pri = nmpr_tau / (1 + work->nm_b) / res->tau;
     500         201 :     res->res_dual = nmdr_tau / (1 + work->nm_c) / res->tau;
     501         201 :     res->rel_gap = ABS(cTx + bTy) / (1 + ABS(cTx) + ABS(bTy));
     502             : }
     503             : 
     504       30542 : static void scs_calc_residuals_superscs(
     505             :         ScsWork * RESTRICT work,
     506             :         struct scs_residuals * RESTRICT residuals,
     507             :         scs_int iter) {
     508             :     scs_float * RESTRICT xb;
     509             :     scs_float * RESTRICT yb;
     510             :     scs_float * RESTRICT sb;
     511             :     scs_float cTx;
     512             :     scs_float bTy;
     513       30542 :     scs_float * RESTRICT pr = work->pr;
     514       30542 :     scs_float * RESTRICT dr = work->dr;
     515       30542 :     scs_int n = work->n;
     516       30542 :     scs_int m = work->m;
     517             :     scs_int i;
     518             :     scs_float norm_D_A_x_plus_s; /* norm of D*(Ax+s), intermediate variable */
     519             :     scs_float norm_E_Atran_yb; /* norm of E*A'*y,   intermediate variable */
     520             :     scs_float tmp__c_times_x; /* c'x */
     521             :     scs_float tmp__b_times_yb; /* b'y */
     522       30542 :     const scs_float temp1 = work->sc_b * work->stgs->scale; /* auxiliary variable #1 */
     523       30542 :     const scs_float temp2 = work->sc_c * temp1; /* auxiliary variable #2 */
     524       30542 :     const scs_float temp3 = work->sc_c * work->stgs->scale; /* auxiliary variable #3 */
     525             : 
     526             : 
     527             :     /* checks if the residuals are unchanged by checking iteration */
     528       30542 :     if (residuals->last_iter == iter) {
     529       30542 :         return;
     530             :     }
     531       29901 :     residuals->last_iter = iter;
     532             : 
     533       29901 :     sb = work->s_b;
     534       29901 :     xb = work->u_b;
     535       29901 :     yb = &(work->u_b[n]);
     536             : 
     537       29901 :     residuals->kap = work->kap_b;
     538       29901 :     residuals->tau = work->u_b[n + m]; /* it's actually tau_b */
     539       29901 :     memset(pr, 0, work->m * sizeof (scs_float)); /* pr = 0 */
     540       29901 :     memset(dr, 0, work->n * sizeof (scs_float)); /* dr = 0 */
     541             : 
     542       29901 :     scs_accum_by_a(work->A, work->p, xb, pr); /* pr = A xb */
     543       29901 :     scs_add_scaled_array(pr, sb, work->m, 1.0); /* pr = A xb + sb */
     544             :     /* --- compute ||D(Ax + s)|| --- */
     545       29901 :     norm_D_A_x_plus_s = 0;
     546       29901 :     if (work->stgs->normalize) {
     547      557968 :         for (i = 0; i < m; ++i) {
     548      557968 :             scs_float tmp = work->scal->D[i] * pr[i];
     549      557968 :             norm_D_A_x_plus_s += tmp * tmp;
     550             :         }
     551             :     } else {
     552         100 :         norm_D_A_x_plus_s = scs_norm_squared(pr, m);
     553             :     }
     554       29901 :     norm_D_A_x_plus_s = SQRTF(norm_D_A_x_plus_s);
     555       29901 :     scs_add_scaled_array(pr, work->b, m, -residuals->tau); /* pr = A xb + sb - b taub */
     556             : 
     557       29901 :     scs_accum_by_a_trans(work->A, work->p, yb, dr); /* dr = A' yb */
     558             : 
     559             : 
     560             :     /* --- compute ||E A' yb|| --- */
     561       29901 :     norm_E_Atran_yb = 0.0;
     562       29901 :     if (work->stgs->normalize) {
     563      290822 :         for (i = 0; i < n; ++i) {
     564      290822 :             scs_float tmp = work->scal->E[i] * dr[i];
     565      290822 :             norm_E_Atran_yb += tmp * tmp;
     566             :         }
     567             :     } else {
     568         100 :         norm_E_Atran_yb = scs_norm_squared(dr, n);
     569             :     }
     570       29901 :     norm_E_Atran_yb = SQRTF(norm_E_Atran_yb);
     571       29901 :     scs_add_scaled_array(dr, work->c, work->n, residuals->tau); /* dr = A' yb + c taub */
     572             : 
     573             :     /*
     574             :      * bTy_by_tau = b'yb / (scale*sc_c*sc_b)
     575             :      * cTx_by_tau = c'xb / (scale*sc_c*sc_b)
     576             :      */
     577       29901 :     tmp__b_times_yb = scs_inner_product(yb, work->b, m);
     578       29901 :     residuals->bTy_by_tau = tmp__b_times_yb / (work->stgs->normalize ? (temp2) : 1);
     579       29901 :     tmp__c_times_x = scs_inner_product(xb, work->c, n);
     580       29901 :     residuals->cTx_by_tau = tmp__c_times_x / (work->stgs->normalize ? (temp2) : 1);
     581             : 
     582             :     /*
     583             :      * bTy = b'yb / (scale*sc_c*sc_b) / taub
     584             :      * cTx = c'xb / (scale*sc_c*sc_b) / taub
     585             :      */
     586       29901 :     bTy = residuals->bTy_by_tau / residuals->tau;
     587       29901 :     cTx = residuals->cTx_by_tau / residuals->tau;
     588             : 
     589             :     /* PRIMAL RESIDUAL */
     590       29901 :     if (work->stgs->normalize) {
     591       29801 :         residuals->res_pri = 0;
     592      587769 :         for (i = 0; i < m; ++i) {
     593      557968 :             scs_float tmp = work->scal->D[i] * pr[i];
     594      557968 :             residuals->res_pri += (tmp * tmp);
     595             :         }
     596       29801 :         residuals->res_pri = SQRTF(residuals->res_pri) / residuals->tau;
     597       29801 :         residuals->res_pri /= ((1 + work->nm_b) * temp1);
     598             :     } else {
     599         100 :         residuals->res_pri = scs_norm(pr, m) / residuals->tau;
     600         100 :         residuals->res_pri /= (1 + work->nm_b);
     601             :     }
     602             : 
     603             :     /* DUAL RESIDUAL */
     604       29901 :     if (work->stgs->normalize) {
     605       29801 :         residuals->res_dual = 0;
     606      320623 :         for (i = 0; i < n; ++i) {
     607      290822 :             scs_float tmp = work->scal->E[i] * dr[i];
     608      290822 :             residuals->res_dual += (tmp * tmp);
     609             :         }
     610       29801 :         residuals->res_dual = SQRTF(residuals->res_dual) / residuals->tau;
     611       29801 :         residuals->res_dual /= ((1 + work->nm_c) * temp3);
     612             :     } else {
     613         100 :         residuals->res_dual = scs_norm(dr, n) / residuals->tau;
     614         100 :         residuals->res_dual /= (1 + work->nm_c);
     615             :     }
     616             : 
     617             :     /* UNBOUNDEDNESS */
     618       29901 :     if (tmp__c_times_x < 0) {
     619       28371 :         scs_float norm_Ec = 0;
     620       28371 :         if (work->stgs->normalize) {
     621       98759 :             for (i = 0; i < n; ++i) {
     622       98759 :                 scs_float tmp = work->scal->E[i] * work->c[i];
     623       98759 :                 norm_Ec += (tmp * tmp);
     624             :             }
     625             :         } else {
     626         100 :             norm_Ec += scs_norm_squared(work->c, n);
     627             :         }
     628       28371 :         residuals->res_unbdd = -SQRTF(norm_Ec) * norm_D_A_x_plus_s / tmp__c_times_x;
     629       28371 :         residuals->res_unbdd /= (work->stgs->normalize ? work->stgs->scale : 1);
     630             :     } else {
     631        1530 :         residuals->res_unbdd = NAN; /* not unbounded */
     632             :     }
     633             : 
     634             : 
     635             :     /* INFEASIBILITY */
     636       29901 :     if (tmp__b_times_yb < 0) {
     637         119 :         scs_float norm_Db_squared = 0;
     638         119 :         if (work->stgs->normalize) {
     639      432503 :             for (i = 0; i < m; ++i) {
     640      432503 :                 scs_float tmp = work->scal->D[i] * work->b[i];
     641      432503 :                 norm_Db_squared += (tmp * tmp);
     642             :             }
     643             :         } else {
     644           0 :             norm_Db_squared += scs_norm_squared(work->b, m);
     645             :         }
     646         119 :         residuals->res_infeas = -SQRTF(norm_Db_squared) * norm_E_Atran_yb / tmp__b_times_yb;
     647         119 :         residuals->res_infeas /= (work->stgs->normalize ? work->stgs->scale : 1);
     648             :     } else {
     649       29782 :         residuals->res_infeas = NAN; /* not infeasible */
     650             :     }
     651       29901 :     residuals->rel_gap = ABS(cTx + bTy) / (1 + ABS(cTx) + ABS(bTy));
     652             : }
     653             : 
     654         327 : static void scs_cold_start_vars(ScsWork * RESTRICT work) {
     655         327 :     scs_int l = work->l;
     656         327 :     memset(work->u, 0, l * sizeof (scs_float));
     657         327 :     work->u[l - 1] = SQRTF((scs_float) l);
     658         327 :     if (work->stgs->do_super_scs == 0) {
     659           2 :         memset(work->v, 0, l * sizeof (scs_float));
     660           2 :         work->v[l - 1] = SQRTF((scs_float) l);
     661             :     }
     662         327 : }
     663             : 
     664             : /* status < 0 indicates failure */
     665         200 : static scs_int scs_project_lin_sys(
     666             :         ScsWork * RESTRICT work,
     667             :         scs_int iter) {
     668             :     /* ut = u + v */
     669         200 :     scs_int n = work->n, m = work->m, l = n + m + 1, status;
     670         200 :     memcpy(work->u_t, work->u, l * sizeof (scs_float));
     671         200 :     scs_add_scaled_array(work->u_t, work->v, l, 1.0);
     672             : 
     673         200 :     scs_scale_array(work->u_t, work->stgs->rho_x, n);
     674             : 
     675         200 :     scs_add_scaled_array(work->u_t, work->h, l - 1, -work->u_t[l - 1]);
     676         200 :     scs_add_scaled_array(work->u_t, work->h, l - 1,
     677         200 :             -scs_inner_product(work->u_t, work->g, l - 1) / (work->gTh + 1));
     678         200 :     scs_scale_array(&(work->u_t[n]), -1, m);
     679             : 
     680         200 :     status = scs_solve_lin_sys(work->A, work->stgs, work->p, work->u_t, work->u, iter);
     681             : 
     682         200 :     work->u_t[l - 1] += scs_inner_product(work->u_t, work->h, l - 1);
     683             : 
     684         200 :     return status;
     685             : }
     686             : 
     687             : /* status < 0 indicates failure */
     688       48779 : static scs_int superscs_project_lin_sys(
     689             :         scs_float * RESTRICT u_t,
     690             :         scs_float * RESTRICT u,
     691             :         ScsWork * RESTRICT work,
     692             :         scs_int iter) {
     693             :     scs_int status;
     694       48779 :     const scs_int l = work->l;
     695             : 
     696             :     /* x_t = rho_x * x_t */
     697       48779 :     memcpy(u_t + work->n, u + work->n, (work->m + 1) * sizeof (scs_float));
     698       48779 :     scs_set_as_scaled_array(u_t, u, work->stgs->rho_x, work->n);
     699             : 
     700             :     /* (x_t, y_t) -= tau_t * h                   */
     701       48779 :     scs_add_scaled_array(u_t, work->h, l - 1, -u_t[l - 1]);
     702             : 
     703             :     /* u_t -= scalar * h                         */
     704       48779 :     scs_add_scaled_array(u_t, work->h, l - 1,
     705       48779 :             -scs_inner_product(u_t, work->g, l - 1) / (work->gTh + 1));
     706             : 
     707             :     /* y_t *= (-1)                               */
     708       48779 :     scs_scale_array(u_t + work->n, -1, work->m);
     709             : 
     710             :     /* call `scs_solve_lin_sys` to update (x_t, y_t)   */
     711       48779 :     status = scs_solve_lin_sys(work->A, work->stgs, work->p, u_t, u, iter);
     712             : 
     713             :     /* tau_t += h'*(x_t, y_t)                    */
     714       48779 :     u_t[l - 1] += scs_inner_product(u_t, work->h, l - 1);
     715             : 
     716       48779 :     return status;
     717             : }
     718             : 
     719             : /* LCOV_EXCL_START */
     720             : void scs_print_sol(
     721             :         ScsWork * RESTRICT work,
     722             :         ScsSolution * RESTRICT sol,
     723             :         ScsInfo * RESTRICT info) {
     724             :     scs_int i;
     725             :     FILE * RESTRICT stream = work->stgs->output_stream;
     726             :     scs_int print_mode = work->stgs->do_override_streams;
     727             :     scs_special_print(print_mode, stream, "%s\n", info->status);
     728             :     if (sol->x != SCS_NULL) {
     729             :         for (i = 0; i < work->n; ++i) {
     730             :             scs_special_print(print_mode, stream, "x[%i] = %4f\n", (int) i, sol->x[i]);
     731             :         }
     732             :     }
     733             :     if (sol->y != SCS_NULL) {
     734             :         for (i = 0; i < work->m; ++i) {
     735             :             scs_special_print(print_mode, stream, "y[%i] = %4f\n", (int) i, sol->y[i]);
     736             :         }
     737             :     }
     738             : }
     739             : 
     740             : /* LCOV_EXCL_STOP */
     741             : 
     742         200 : static void scs_update_dual_vars(ScsWork * RESTRICT work) {
     743         200 :     scs_int n = work->n, l = n + work->m + 1;
     744             :     /* this does not relax 'x' variable */
     745         200 :     scs_add_array(work->v, work->u, l);
     746         200 :     scs_add_scaled_array(work->v, work->u_t, l, -work->stgs->alpha);
     747         200 :     scs_add_scaled_array(work->v, work->u_prev, l, -1.0 + work->stgs->alpha);
     748         200 : }
     749             : 
     750             : /* Calculates the fixed point residual R */
     751             : static void scs_calc_FPR(
     752             :         scs_float * RESTRICT fpr,
     753             :         scs_float * RESTRICT u_t,
     754             :         scs_float * RESTRICT u_b,
     755             :         scs_int l) {
     756       79458 :     scs_axpy(fpr, u_t, u_b, 1.0, -1.0, l);
     757             : }
     758             : 
     759             : /* status < 0 indicates failure */
     760         200 : static scs_int scs_project_cones(
     761             :         ScsWork * RESTRICT work,
     762             :         const ScsCone * RESTRICT cone,
     763             :         scs_int iter) {
     764         200 :     scs_int i, n = work->n, l = n + work->m + 1, status;
     765             :     /* this does not relax 'x' variable */
     766      960666 :     for (i = 0; i < n; ++i) {
     767      960466 :         work->u[i] = work->u_t[i] - work->v[i];
     768             :     }
     769     1921203 :     for (i = n; i < l; ++i) {
     770     5763609 :         work->u[i] = work->stgs->alpha * work->u_t[i] +
     771     3842406 :                 (1 - work->stgs->alpha) * work->u_prev[i] - work->v[i];
     772             :     }
     773             :     /* u = [x;y;tau] */
     774         200 :     status = scs_project_dual_cone(&(work->u[n]), cone, work->coneWork, &(work->u_prev[n]), iter);
     775         200 :     if (work->u[l - 1] < 0.0)
     776          29 :         work->u[l - 1] = 0.0;
     777             : 
     778         200 :     return status;
     779             : }
     780             : 
     781             : /* status < 0 indicates failure */
     782       79458 : static scs_int superscs_project_cones(
     783             :         scs_float * RESTRICT u_b,
     784             :         scs_float * RESTRICT u_t,
     785             :         scs_float * RESTRICT u,
     786             :         ScsWork * RESTRICT work,
     787             :         const ScsCone * RESTRICT cone,
     788             :         scs_int iter) {
     789       79458 :     scs_int n = work->n;
     790       79458 :     scs_int l = n + work->m + 1;
     791             :     scs_int status;
     792             :     /* this does not relax 'x' variable */
     793       79458 :     scs_axpy(u_b, u_t, u, 2.0, -1.0, l);
     794             : 
     795             :     /* u = [x;y;tau] */
     796       79458 :     status = scs_project_dual_cone(&(u_b[n]), cone, work->coneWork, &(work->u_prev[n]), iter);
     797       79458 :     if (u_b[l - 1] < 0.0) {
     798        3565 :         u_b[l - 1] = 0.0;
     799             :     }
     800       79458 :     return status;
     801             : }
     802             : 
     803             : /* LCOV_EXCL_START */
     804             : static scs_int scs_indeterminate(
     805             :         ScsWork * RESTRICT w,
     806             :         ScsSolution * RESTRICT sol,
     807             :         ScsInfo * RESTRICT info) {
     808             :     strncpy(info->status, "Indeterminate", SCS_INFO_STATUS_MSG_LENGTH);
     809             :     scs_scale_array(sol->x, NAN, w->n);
     810             :     scs_scale_array(sol->y, NAN, w->m);
     811             :     scs_scale_array(sol->s, NAN, w->m);
     812             :     return SCS_INDETERMINATE;
     813             : }
     814             : 
     815             : /* LCOV_EXCL_STOP */
     816             : 
     817         323 : static scs_int scs_solved(
     818             :         ScsWork * RESTRICT work,
     819             :         ScsSolution * RESTRICT sol,
     820             :         ScsInfo * RESTRICT info,
     821             :         scs_float tau) {
     822         323 :     scs_scale_array(sol->x, 1.0 / tau, work->n);
     823         323 :     scs_scale_array(sol->y, 1.0 / tau, work->m);
     824         323 :     scs_scale_array(sol->s, 1.0 / tau, work->m);
     825         323 :     if (info->statusVal == 0) {
     826          11 :         strncpy(info->status, "Solved/Inaccurate", SCS_INFO_STATUS_MSG_LENGTH);
     827             :         return SCS_SOLVED_INACCURATE;
     828             :     }
     829         312 :     strncpy(info->status, "Solved", SCS_INFO_STATUS_MSG_LENGTH);
     830             :     return SCS_SOLVED;
     831             : }
     832             : 
     833           1 : static scs_int scs_infeasible(
     834             :         ScsWork * RESTRICT work,
     835             :         ScsSolution * RESTRICT sol,
     836             :         ScsInfo * RESTRICT info,
     837             :         scs_float bTy) {
     838           1 :     scs_scale_array(sol->y, -1 / bTy, work->m);
     839           1 :     scs_scale_array(sol->x, NAN, work->n);
     840           1 :     scs_scale_array(sol->s, NAN, work->m);
     841           1 :     if (info->statusVal == 0) {
     842           0 :         strncpy(info->status, "Infeasible/Inaccurate", SCS_INFO_STATUS_MSG_LENGTH);
     843             :         return SCS_INFEASIBLE_INACCURATE;
     844             :     }
     845           1 :     strncpy(info->status, "Infeasible", SCS_INFO_STATUS_MSG_LENGTH);
     846             :     return SCS_INFEASIBLE;
     847             : }
     848             : 
     849           5 : static scs_int scs_unbounded(
     850             :         ScsWork * RESTRICT work,
     851             :         ScsSolution * RESTRICT sol,
     852             :         ScsInfo * RESTRICT info,
     853             :         scs_float cTx) {
     854           5 :     scs_scale_array(sol->x, -1 / cTx, work->n);
     855           5 :     scs_scale_array(sol->s, -1 / cTx, work->m);
     856           5 :     scs_scale_array(sol->y, NAN, work->m);
     857           5 :     if (info->statusVal == 0) {
     858           3 :         strncpy(info->status, "Unbounded/Inaccurate", SCS_INFO_STATUS_MSG_LENGTH);
     859             :         return SCS_UNBOUNDED_INACCURATE;
     860             :     }
     861           2 :     strncpy(info->status, "Unbounded", SCS_INFO_STATUS_MSG_LENGTH);
     862             :     return SCS_UNBOUNDED;
     863             : }
     864             : 
     865         329 : static void scs_set_y(ScsWork * RESTRICT work, ScsSolution * RESTRICT sol) {
     866         329 :     if (sol->y == SCS_NULL) {
     867          18 :         sol->y = scs_malloc(sizeof (scs_float) * work->m);
     868             :     }
     869         329 :     if (work->stgs->do_super_scs == 0) {
     870           3 :         memcpy(sol->y, &(work->u[work->n]), work->m * sizeof (scs_float));
     871             :     } else {
     872         326 :         memcpy(sol->y, &(work->u_b[work->n]), work->m * sizeof (scs_float));
     873             :     }
     874         329 : }
     875             : 
     876         329 : static void scs_set_s(ScsWork * RESTRICT work, ScsSolution * RESTRICT sol) {
     877         329 :     if (sol->s == SCS_NULL) {
     878          18 :         sol->s = scs_malloc(sizeof (scs_float) * work->m);
     879             :     }
     880         329 :     if (work->stgs->do_super_scs == 0) {
     881           3 :         memcpy(sol->s, &(work->v[work->n]), work->m * sizeof (scs_float));
     882             :     } else {
     883         326 :         memcpy(sol->s, work->s_b, work->m * sizeof (scs_float));
     884             :     }
     885         329 : }
     886             : 
     887         329 : static void scs_set_x(ScsWork * RESTRICT work, ScsSolution * RESTRICT sol) {
     888         329 :     if (sol->x == SCS_NULL)
     889          18 :         sol->x = scs_malloc(sizeof (scs_float) * work->n);
     890         329 :     if (work->stgs->do_super_scs == 0) {
     891           3 :         memcpy(sol->x, work->u, work->n * sizeof (scs_float));
     892             :     } else {
     893         326 :         memcpy(sol->x, work->u_b, work->n * sizeof (scs_float));
     894             :     }
     895         329 : }
     896             : 
     897         644 : scs_int scs_is_solved_status(scs_int status) {
     898         644 :     return status == SCS_SOLVED || status == SCS_SOLVED_INACCURATE;
     899             : }
     900             : 
     901           6 : scs_int scs_is_infeasible_status(scs_int status) {
     902           6 :     return status == SCS_INFEASIBLE || status == SCS_INFEASIBLE_INACCURATE;
     903             : }
     904             : 
     905           8 : scs_int scs_is_unbounded_status(scs_int status) {
     906           8 :     return status == SCS_UNBOUNDED || status == SCS_UNBOUNDED_INACCURATE;
     907             : }
     908             : 
     909         329 : static void scs_get_info(
     910             :         ScsWork * RESTRICT work,
     911             :         ScsSolution * RESTRICT sol,
     912             :         ScsInfo * RESTRICT info,
     913             :         struct scs_residuals * RESTRICT residuals,
     914             :         scs_int iter) {
     915         329 :     info->iter = iter;
     916         329 :     info->resInfeas = residuals->res_infeas;
     917         329 :     info->resUnbdd = residuals->res_unbdd;
     918         329 :     if (scs_is_solved_status(info->statusVal)) {
     919         323 :         info->relGap = residuals->rel_gap;
     920         323 :         info->resPri = residuals->res_pri;
     921         323 :         info->resDual = residuals->res_dual;
     922         323 :         info->pobj = residuals->cTx_by_tau / residuals->tau;
     923         323 :         info->dobj = -residuals->bTy_by_tau / residuals->tau;
     924           6 :     } else if (scs_is_unbounded_status(info->statusVal)) {
     925           5 :         info->relGap = NAN;
     926           5 :         info->resPri = NAN;
     927           5 :         info->resDual = NAN;
     928           5 :         info->pobj = -INFINITY;
     929           5 :         info->dobj = -INFINITY;
     930           1 :     } else if (scs_is_infeasible_status(info->statusVal)) {
     931           1 :         info->relGap = NAN;
     932           1 :         info->resPri = NAN;
     933           1 :         info->resDual = NAN;
     934           1 :         info->pobj = INFINITY;
     935           1 :         info->dobj = INFINITY;
     936             :     }
     937         329 : }
     938             : 
     939             : /* sets solutions, re-scales by inner prods if infeasible or unbounded */
     940         329 : static void scs_get_solution(
     941         328 :         ScsWork * RESTRICT work,
     942             :         ScsSolution * RESTRICT sol,
     943             :         ScsInfo * RESTRICT info,
     944             :         struct scs_residuals * RESTRICT r,
     945             :         scs_int iter) {
     946         329 :     scs_int l = work->l;
     947         329 :     if (work->stgs->do_super_scs == 0) {
     948           3 :         scs_calc_residuals(work, r, iter);
     949             :     } else {
     950         326 :         scs_calc_residuals_superscs(work, r, iter);
     951         652 :         r->kap = ABS(work->kap_b) /
     952         326 :                 (work->stgs->normalize ? (work->stgs->scale * work->sc_c * work->sc_b) : 1.0);
     953             :     }
     954         329 :     scs_set_x(work, sol);
     955         329 :     scs_set_y(work, sol);
     956         329 :     scs_set_s(work, sol);
     957         329 :     if (info->statusVal == SCS_UNFINISHED) {
     958             :         /* not yet converged, take best guess */
     959          14 :         if (r->tau > SCS_INDETERMINATE_TOL && r->tau > r->kap) {
     960          22 :             info->statusVal = scs_solved(work, sol, info, r->tau);
     961           6 :         } else if (scs_norm(work->u, l) <
     962           3 :                 SCS_INDETERMINATE_TOL * SQRTF((scs_float) l)) {
     963           0 :             info->statusVal = scs_indeterminate(work, sol, info);
     964           3 :         } else if (r->bTy_by_tau < r->cTx_by_tau) {
     965           0 :             info->statusVal = scs_infeasible(work, sol, info, r->bTy_by_tau);
     966             :         } else {
     967           6 :             info->statusVal = scs_unbounded(work, sol, info, r->cTx_by_tau);
     968             :         }
     969         315 :     } else if (scs_is_solved_status(info->statusVal)) {
     970         624 :         info->statusVal = scs_solved(work, sol, info, r->tau);
     971           3 :     } else if (scs_is_infeasible_status(info->statusVal)) {
     972           1 :         info->statusVal = scs_infeasible(work, sol, info, r->bTy_by_tau);
     973             :     } else {
     974           4 :         info->statusVal = scs_unbounded(work, sol, info, r->cTx_by_tau);
     975             :     }
     976         329 :     if (work->stgs->normalize) {
     977         326 :         scs_unnormalize_sol(work, sol);
     978             :     }
     979         329 :     scs_get_info(work, sol, info, r, iter);
     980         329 : }
     981             : 
     982             : /* LCOV_EXCL_START */
     983             : static void scs_print_summary(
     984             :         ScsWork * RESTRICT work,
     985             :         scs_int i,
     986             :         struct scs_residuals * RESTRICT residuals,
     987             :         ScsTimer * RESTRICT solveTimer) {
     988             :     FILE * RESTRICT stream = work->stgs->output_stream;
     989             :     scs_int print_mode = work->stgs->do_override_streams;
     990             :     scs_special_print(print_mode, stream, "%*i|", (int) strlen(SCS_HEADER[0]), (int) i);
     991             :     scs_special_print(print_mode, stream, "%*.2e ", (int) scs_hspace, residuals->res_pri);
     992             :     scs_special_print(print_mode, stream, "%*.2e ", (int) scs_hspace, residuals->res_dual);
     993             :     scs_special_print(print_mode, stream, "%*.2e ", (int) scs_hspace, residuals->rel_gap);
     994             :     scs_special_print(print_mode, stream, "%*.2e ", (int) scs_hspace, residuals->cTx_by_tau / residuals->tau);
     995             :     scs_special_print(print_mode, stream, "%*.2e ", (int) scs_hspace, -residuals->bTy_by_tau / residuals->tau);
     996             :     scs_special_print(print_mode, stream, "%*.2e ", (int) scs_hspace, residuals->kap / residuals->tau);
     997             :     if (work->stgs->do_super_scs) {
     998             :         scs_special_print(print_mode, stream, "%*.2e ", (int) scs_hspace, work->nrmR_con);
     999             :     }
    1000             :     scs_special_print(print_mode, stream, "%*.2e ", (int) scs_hspace, scs_toc_quiet(solveTimer) / 1e3);
    1001             :     scs_special_print(print_mode, stream, "\n");
    1002             : 
    1003             : #ifdef MATLAB_MEX_FILE
    1004             :     mexEvalString("drawnow;");
    1005             : #endif
    1006             : }
    1007             : 
    1008             : static void scs_print_header(
    1009             :         ScsWork * RESTRICT work,
    1010             :         const ScsCone * RESTRICT cone) {
    1011             :     scs_int i;
    1012             :     FILE * RESTRICT stream = work->stgs->output_stream;
    1013             :     scs_int print_mode = work->stgs->do_override_streams;
    1014             :     if (work->stgs->warm_start)
    1015             :         scs_special_print(print_mode, stream, "SCS using variable warm-starting\n");
    1016             :     for (i = 0; i < scs_header_line_length; ++i) {
    1017             :         scs_special_print(print_mode, stream, "-");
    1018             :     }
    1019             :     scs_special_print(print_mode, stream, "\n");
    1020             :     for (i = 0; i < scs_header_length - 2; ++i) {
    1021             :         scs_special_print(print_mode, stream, "%s|", SCS_HEADER[i]);
    1022             :     }
    1023             :     if (work->stgs->do_super_scs) {
    1024             :         scs_special_print(print_mode, stream, "%s|", SCS_HEADER[scs_header_length - 2]);
    1025             :     }
    1026             :     scs_special_print(print_mode, stream, "%s\n", SCS_HEADER[scs_header_length - 1]);
    1027             :     for (i = 0; i < scs_header_line_length; ++i) {
    1028             :         scs_special_print(print_mode, stream, "-");
    1029             :     }
    1030             :     scs_special_print(print_mode, stream, "\n");
    1031             : #ifdef MATLAB_MEX_FILE
    1032             :     mexEvalString("drawnow;");
    1033             : #endif
    1034             : }
    1035             : 
    1036             : /* LCOV_EXCL_STOP */
    1037             : 
    1038           2 : scs_float scs_get_dual_cone_dist(
    1039             :         const scs_float * RESTRICT y,
    1040             :         const ScsCone * RESTRICT k,
    1041             :         ScsConeWork * RESTRICT cone_workspace,
    1042             :         scs_int m) {
    1043             :     scs_float dist;
    1044           2 :     scs_float * RESTRICT t = scs_malloc(sizeof (scs_float) * m);
    1045           2 :     memcpy(t, y, m * sizeof (scs_float));
    1046           2 :     scs_project_dual_cone(t, k, cone_workspace, SCS_NULL, -1);
    1047           2 :     dist = scs_norm_infinity_difference(t, y, m);
    1048           2 :     scs_free(t);
    1049           2 :     return dist;
    1050             : }
    1051             : 
    1052             : /* via moreau */
    1053           2 : scs_float scs_get_primal_cone_dist(
    1054             :         const scs_float * RESTRICT s,
    1055             :         const ScsCone * RESTRICT cone,
    1056             :         ScsConeWork * RESTRICT cone_workspace,
    1057             :         scs_int m) {
    1058             :     scs_float dist;
    1059           2 :     scs_float * RESTRICT t = scs_malloc(sizeof (scs_float) * m);
    1060           2 :     memcpy(t, s, m * sizeof (scs_float));
    1061           2 :     scs_scale_array(t, -1.0, m);
    1062           2 :     scs_project_dual_cone(t, cone, cone_workspace, SCS_NULL, -1);
    1063           2 :     dist = scs_norm_infinity(t, m); /* ||s - Pi_c(s)|| = ||Pi_c*(-s)|| */
    1064           2 :     scs_free(t);
    1065           2 :     return dist;
    1066             : }
    1067             : 
    1068           6 : void scs_millis_to_time(scs_float time,
    1069             :         scs_int * hours,
    1070             :         scs_int * minutes,
    1071             :         scs_int * secs,
    1072             :         scs_float * sec_rest) {
    1073             :     scs_float integral;
    1074           6 :     scs_float time_seconds = time / 1e3;
    1075           6 :     *sec_rest = (scs_float) modf((double) time_seconds, &integral);
    1076           6 :     *secs = (scs_int) time_seconds;
    1077           6 :     *minutes = *secs / 60;
    1078           6 :     *secs %= 60;
    1079           6 :     if (*minutes >= 60) {
    1080           2 :         *hours = *minutes / 60;
    1081           2 :         *minutes %= 60;
    1082             :     } else {
    1083           4 :         *hours = 0;
    1084             :     }
    1085           6 : }
    1086             : 
    1087             : /* LCOV_EXCL_START */
    1088             : static void scs_print_footer(
    1089             :         const ScsData * RESTRICT data,
    1090             :         const ScsCone * RESTRICT cone,
    1091             :         ScsSolution * RESTRICT sol,
    1092             :         ScsWork * RESTRICT work,
    1093             :         ScsInfo * RESTRICT info) {
    1094             :     scs_int i;
    1095             :     scs_int hours, minutes, seconds;
    1096             :     scs_float millis;
    1097             : 
    1098             :     char *linSysStr = scs_get_linsys_summary(work->p, info);
    1099             :     char *coneStr = scs_get_cone_summary(info, work->coneWork);
    1100             :     FILE * stream = work->stgs->output_stream;
    1101             :     scs_int print_mode = work->stgs->do_override_streams;
    1102             :     for (i = 0; i < scs_header_line_length; ++i) {
    1103             :         scs_special_print(print_mode, stream, "-");
    1104             :     }
    1105             :     scs_special_print(print_mode, stream, "\nStatus: %s\n", info->status);
    1106             :     if (info->iter == work->stgs->max_iters) {
    1107             :         scs_special_print(print_mode, stream, "Hit max_iters, solution may be inaccurate\n");
    1108             :     }
    1109             : 
    1110             :     scs_millis_to_time(info->solveTime, &hours, &minutes, &seconds, &millis);
    1111             :     scs_special_print(print_mode, stream, "Timing: Solve time: %02d:%02d:%02d.%d\n",
    1112             :             hours, minutes, seconds, (scs_int) round(1e4 * millis) / 10);
    1113             : 
    1114             :     if (linSysStr) {
    1115             :         scs_special_print(print_mode, stream, "%s", linSysStr);
    1116             :         scs_free(linSysStr);
    1117             :     }
    1118             : 
    1119             :     if (coneStr) {
    1120             :         scs_special_print(print_mode, stream, "%s", coneStr);
    1121             :         scs_free(coneStr);
    1122             :     }
    1123             : 
    1124             :     for (i = 0; i < scs_header_line_length; ++i) {
    1125             :         scs_special_print(print_mode, stream, "-");
    1126             :     }
    1127             :     scs_special_print(print_mode, stream, "\n");
    1128             : 
    1129             :     if (scs_is_infeasible_status(info->statusVal)) {
    1130             :         scs_special_print(print_mode, stream, "Certificate of primal infeasibility:\n");
    1131             :         scs_special_print(print_mode, stream, "dist(y, K*) = %.4e\n",
    1132             :                 scs_get_dual_cone_dist(sol->y, cone, work->coneWork, data->m));
    1133             :         scs_special_print(print_mode, stream, "|A'y|_2 * |b|_2 = %.4e\n", info->resInfeas);
    1134             :         scs_special_print(print_mode, stream, "b'y = %.4f\n", scs_inner_product(data->b, sol->y, data->m));
    1135             :     } else if (scs_is_unbounded_status(info->statusVal)) {
    1136             :         scs_special_print(print_mode, stream, "Certificate of dual infeasibility:\n");
    1137             :         scs_special_print(print_mode, stream, "dist(s, K) = %.4e\n",
    1138             :                 scs_get_primal_cone_dist(sol->s, cone, work->coneWork, data->m));
    1139             :         scs_special_print(print_mode, stream, "|Ax + s|_2 * |c|_2 = %.4e\n", info->resUnbdd);
    1140             :         scs_special_print(print_mode, stream, "c'x = %.4f\n", scs_inner_product(data->c, sol->x, data->n));
    1141             :     } else {
    1142             :         scs_special_print(print_mode, stream, "Error metrics:\n");
    1143             :         scs_special_print(print_mode, stream, "dist(s, K) = %.4e, dist(y, K*) = %.4e, s'y/|s||y| = %.4e\n",
    1144             :                 scs_get_primal_cone_dist(sol->s, cone, work->coneWork, data->m),
    1145             :                 scs_get_dual_cone_dist(sol->y, cone, work->coneWork, data->m),
    1146             :                 scs_inner_product(sol->s, sol->y, data->m) / scs_norm(sol->s, data->m) /
    1147             :                 scs_norm(sol->y, data->m));
    1148             :         scs_special_print(print_mode, stream, "|Ax + s - b|_2 / (1 + |b|_2) = %.4e\n", info->resPri);
    1149             :         scs_special_print(print_mode, stream, "|A'y + c|_2 / (1 + |c|_2) = %.4e\n", info->resDual);
    1150             :         scs_special_print(print_mode, stream, "|c'x + b'y| / (1 + |c'x| + |b'y|) = %.4e\n", info->relGap);
    1151             :         for (i = 0; i < scs_header_line_length; ++i) {
    1152             :             scs_special_print(print_mode, stream, "-");
    1153             :         }
    1154             :         scs_special_print(print_mode, stream, "\n");
    1155             :         scs_special_print(print_mode, stream, "c'x = %.4f, -b'y = %.4f\n", info->pobj, info->dobj);
    1156             :     }
    1157             :     for (i = 0; i < scs_header_line_length; ++i) {
    1158             :         scs_special_print(print_mode, stream, "=");
    1159             :     }
    1160             :     scs_special_print(print_mode, stream, "\n");
    1161             : #ifdef MATLAB_MEX_FILE
    1162             :     mexEvalString("drawnow;");
    1163             : #endif
    1164             : }
    1165             : 
    1166             : /* LCOV_EXCL_STOP */
    1167             : 
    1168             : static scs_int scs_has_converged(
    1169             :         ScsWork * RESTRICT work,
    1170             :         struct scs_residuals * RESTRICT residuals,
    1171             :         scs_int iter) {
    1172       30088 :     scs_float eps = work->stgs->eps;
    1173       30088 :     if (residuals->res_pri < eps && residuals->res_dual < eps && residuals->rel_gap < eps) {
    1174             :         return SCS_SOLVED;
    1175             :     }
    1176       29776 :     if (residuals->res_unbdd < eps) {
    1177             :         return SCS_UNBOUNDED;
    1178             :     }
    1179       29774 :     if (residuals->res_infeas < eps) {
    1180             :         return SCS_INFEASIBLE;
    1181             :     }
    1182             :     return 0;
    1183             : }
    1184             : 
    1185         339 : static scs_int scs_validate_superscs_settings(const ScsData *data) {
    1186         339 :     ScsSettings * stgs = data->stgs;
    1187         339 :     scs_int print_mode = stgs->do_override_streams;
    1188             : 
    1189         339 :     if (stgs->do_super_scs == 0) return 0;
    1190             : 
    1191         336 :     if (stgs->thetabar < 0 || stgs->thetabar > 1) {
    1192             :         /* LCOV_EXCL_START */
    1193             :         scs_special_print(print_mode, stderr, "Parameters `thetabar` must "
    1194             :                 "be a scalar between 0 and 1 (thetabar=%g)\n", stgs->thetabar);
    1195             :         return SCS_FAILED;
    1196             :         /* LCOV_EXCL_STOP */
    1197             :     }
    1198         672 :     if ((stgs->direction == restarted_broyden
    1199         336 :             || stgs->direction == anderson_acceleration)
    1200         331 :             && stgs->memory <= 1) {
    1201             :         /* LCOV_EXCL_START */
    1202             :         scs_special_print(print_mode, stderr, "Quasi-Newton memory length "
    1203             :                 "(mem=%ld) is too low; choose an integer at least equal to 2.\n",
    1204             :                 (long) stgs->memory);
    1205             :         return SCS_FAILED;
    1206             :         /* LCOV_EXCL_STOP */
    1207             :     }
    1208         336 :     if (stgs->direction == anderson_acceleration && stgs->memory > data->m + data->n + 1) {
    1209           0 :         scs_special_print(print_mode, stderr, "Quasi-Newton memory length (mem=%ld) "
    1210             :                 "is too high for Anderson's method (l=%d).\n",
    1211             :                 (long) stgs->memory, data->m + data->n + 1);
    1212             :         return SCS_FAILED;
    1213             :     }
    1214         336 :     if (stgs->beta >= 1 || stgs->beta <= 0) {
    1215             :         /* LCOV_EXCL_START */
    1216             :         scs_special_print(print_mode, stderr, "Stepsize reduction factor (beta=%g) out of bounds.\n", stgs->beta);
    1217             :         return SCS_FAILED;
    1218             :         /* LCOV_EXCL_STOP */
    1219             :     }
    1220         334 :     if (stgs->ls < 0) {
    1221             :         /* LCOV_EXCL_START */
    1222             :         scs_special_print(print_mode, stderr, "Illegal maximum number of line search iterations (ls=%ld).\n", (long) stgs->ls);
    1223             :         return SCS_FAILED;
    1224             :         /* LCOV_EXCL_STOP */
    1225             :     }
    1226         333 :     if (stgs->ls >= 40) {
    1227             :         /* LCOV_EXCL_START */
    1228             :         scs_special_print(print_mode, stderr, "WARNING! The value ls=%ld is too high. The maximum allowed "
    1229             :                 "number of line search iteration is 40. We recommend a value about 10.\n", (long) stgs->ls);
    1230             :         return SCS_FAILED;
    1231             :         /* LCOV_EXCL_STOP */
    1232             :     }
    1233         332 :     if (stgs->ls > 10) {
    1234             :         /* LCOV_EXCL_START */
    1235             :         scs_special_print(print_mode, stderr, "WARNING! The value ls=%ld is too high. We highly recommend"
    1236             :                 "the maximum number of line search iterations to be at most 10.\n", (long) stgs->ls);
    1237             :         /* LCOV_EXCL_STOP */
    1238             :     }
    1239         332 :     if (stgs->sigma < 0) {
    1240             :         /* LCOV_EXCL_START */
    1241             :         scs_special_print(print_mode, stderr, "Parameter sigma of the line search (sigma=%g) cannot be negative.\n", stgs->sigma);
    1242             :         return SCS_FAILED;
    1243             :         /* LCOV_EXCL_STOP */
    1244             :     }
    1245         331 :     if (stgs->c_bl < 0 || stgs->c_bl >= 1) {
    1246             :         /* LCOV_EXCL_START */
    1247             :         scs_special_print(print_mode, stderr, "Parameter (c_0=%g) for blind updates out of bounds.\n", stgs->c_bl);
    1248             :         return SCS_FAILED;
    1249             :         /* LCOV_EXCL_STOP */
    1250             :     }
    1251         330 :     if (stgs->c1 < 0 || stgs->c1 >= 1) {
    1252             :         /* LCOV_EXCL_START */
    1253             :         scs_special_print(print_mode, stderr, "Parameter (c1=%g) for step K1 out of bounds.\n", stgs->c1);
    1254             :         return SCS_FAILED;
    1255             :         /* LCOV_EXCL_STOP */
    1256             :     }
    1257         329 :     if (stgs->sse < 0 || stgs->sse >= 1) {
    1258             :         /* LCOV_EXCL_START */
    1259             :         scs_special_print(print_mode, stderr, "Parameter (sse=%g) for step K1 out of bounds.\n", stgs->sse);
    1260             :         return SCS_FAILED;
    1261             :         /* LCOV_EXCL_STOP */
    1262             :     }
    1263         329 :     if (stgs->k0 != 0 && stgs->k0 != 1) {
    1264             :         /* LCOV_EXCL_START */
    1265             :         scs_special_print(print_mode, stderr, "Parameter (k0=%d) can be eiter 0 (k0: off) or 1 (k0: on).\n", (int) stgs->k0);
    1266             :         return SCS_FAILED;
    1267             :         /* LCOV_EXCL_STOP */
    1268             :     }
    1269         328 :     if (stgs->k1 != 0 && stgs->k1 != 1) {
    1270             :         /* LCOV_EXCL_START */
    1271             :         scs_special_print(print_mode, stderr, "Parameter (k1=%d) can be eiter 0 (k1: off) or 1 (k1: on).\n", (int) stgs->k1);
    1272             :         return SCS_FAILED;
    1273             :         /* LCOV_EXCL_STOP */
    1274             :     }
    1275         327 :     if (stgs->k2 != 0 && stgs->k2 != 1) {
    1276             :         /* LCOV_EXCL_START */
    1277             :         scs_special_print(print_mode, stderr, "Parameter (k2=%d) can be eiter 0 (k2: off) or 1 (k2: on).\n", (int) stgs->k2);
    1278             :         return SCS_FAILED;
    1279             :         /* LCOV_EXCL_STOP */
    1280             :     }
    1281         652 :     if (stgs->direction != restarted_broyden
    1282         326 :             && stgs->direction != fixed_point_residual
    1283           3 :             && stgs->direction != anderson_acceleration
    1284           0 :             && stgs->direction != full_broyden) {
    1285             :         /* LCOV_EXCL_START */
    1286             :         scs_special_print(print_mode, stderr, "Invalid direction (%ld).\n",
    1287             :                 (long) stgs->direction);
    1288             :         return SCS_FAILED;
    1289             :         /* LCOV_EXCL_STOP */
    1290             :     }
    1291             :     return 0;
    1292             : }
    1293             : 
    1294         341 : static scs_int scs_validate_general_settings(const ScsData *data) {
    1295         341 :     ScsSettings * stgs = data->stgs;
    1296         341 :     scs_int print_mode = stgs->do_override_streams;
    1297         341 :     if (stgs->max_iters <= 0) {
    1298             :         /* LCOV_EXCL_START */
    1299             :         scs_special_print(print_mode, stderr, "max_iters must be positive (max_iters=%ld)\n", (long) stgs->max_iters);
    1300             :         return SCS_FAILED;
    1301             :         /* LCOV_EXCL_STOP */
    1302             :     }
    1303         341 :     if (stgs->eps <= 0) {
    1304             :         /* LCOV_EXCL_START */
    1305             :         scs_special_print(print_mode, stderr, "eps tolerance must be positive (eps=%g)\n", stgs->eps);
    1306             :         return SCS_FAILED;
    1307             :         /* LCOV_EXCL_STOP */
    1308             :     }
    1309         341 :     if (stgs->alpha <= 0 || stgs->alpha >= 2) {
    1310             :         /* LCOV_EXCL_START */
    1311             :         scs_special_print(print_mode, stderr, "alpha must be in (0,2) (alpha=%g)\n", stgs->alpha);
    1312             :         return SCS_FAILED;
    1313             :         /* LCOV_EXCL_STOP */
    1314             :     }
    1315         339 :     if (stgs->rho_x <= 0) {
    1316             :         /* LCOV_EXCL_START */
    1317             :         scs_special_print(print_mode, stderr, "rho_x must be positive (1e-3 works well) (rho_x=%g).\n", stgs->rho_x);
    1318             :         return SCS_FAILED;
    1319             :         /* LCOV_EXCL_STOP */
    1320             :     }
    1321         339 :     if (stgs->scale <= 0) {
    1322             :         /* LCOV_EXCL_START */
    1323             :         scs_special_print(print_mode, stderr, "Parameter `scale` must be positive (1 works well).\n");
    1324             :         return SCS_FAILED;
    1325             :         /* LCOV_EXCL_STOP */
    1326             :     }
    1327         339 :     if (stgs->do_super_scs != 0 && stgs->do_super_scs != 1) {
    1328             :         /* LCOV_EXCL_START */
    1329             :         scs_special_print(print_mode, stderr, "do_super_scs (=%d) can be either 0 or 1.\n", (int) stgs->do_super_scs);
    1330             :         return SCS_FAILED;
    1331             :         /* LCOV_EXCL_STOP */
    1332             :     }
    1333             : 
    1334             :     return 0;
    1335             : }
    1336             : 
    1337         341 : static scs_int scs_validate(
    1338        1358 :         const ScsData * RESTRICT data,
    1339             :         const ScsCone * RESTRICT cone) {
    1340         341 :     ScsSettings *stgs = data->stgs;
    1341         341 :     scs_int print_mode = stgs->do_override_streams;
    1342         341 :     if (data->m <= 0 || data->n <= 0) {
    1343             :         /* LCOV_EXCL_START */
    1344             :         scs_special_print(print_mode, stderr, "m and n must both be greater than 0; m = %li, n = %li\n",
    1345             :                 (long) data->m, (long) data->n);
    1346             :         return -1;
    1347             :         /* LCOV_EXCL_STOP */
    1348             :     }
    1349         341 :     if (data->m < data->n) {
    1350             :         /* LCOV_EXCL_START */
    1351             :         scs_special_print(print_mode, stderr, "WARN: m less than n, problem likely degenerate\n");
    1352             :         /* LCOV_EXCL_STOP */
    1353             :     }
    1354         341 :     if (scs_validate_linsys(data->A) < 0) {
    1355             :         /* LCOV_EXCL_START */
    1356             :         scs_special_print(print_mode, stderr, "invalid linear system input data\n");
    1357             :         return SCS_FAILED;
    1358             :         /* LCOV_EXCL_STOP */
    1359             :     }
    1360         341 :     if (scs_validate_cones(data, cone) < 0) {
    1361             :         /* LCOV_EXCL_START */
    1362             :         scs_special_print(print_mode, stderr, "cone validation error\n");
    1363             :         return SCS_FAILED;
    1364             :         /* LCOV_EXCL_STOP */
    1365             :     }
    1366             : 
    1367         341 :     if (scs_validate_general_settings(data) != 0
    1368        1017 :             || scs_validate_superscs_settings(data) != 0)
    1369             :         return SCS_FAILED;
    1370             : 
    1371             :     return 0;
    1372             : }
    1373             : 
    1374         329 : static ScsWork * scs_init_work(
    1375             :         const ScsData * RESTRICT data,
    1376             :         const ScsCone * RESTRICT cone) {
    1377         329 :     ScsWork *work = scs_calloc(1, sizeof (*work));
    1378         329 :     const scs_int l = data->n + data->m + 1;
    1379         329 :     scs_int print_mode = data->stgs->do_override_streams;
    1380         329 :     if (data->stgs->verbose) {
    1381           2 :         scs_print_init_header(data, cone);
    1382             :     }
    1383         329 :     if (work == SCS_NULL) {
    1384           0 :         scs_special_print(print_mode, stderr, "ERROR: allocating work failure\n");
    1385           0 :         return SCS_NULL;
    1386             :     }
    1387             : 
    1388             :     /* get settings and dims from data struct */
    1389         329 :     work->stgs = data->stgs;
    1390         329 :     work->m = data->m;
    1391         329 :     work->n = data->n;
    1392         329 :     work->l = l; /* total dimension */
    1393             : 
    1394             :     /* -------------------------------------
    1395             :      * Workspace allocation:
    1396             :      *
    1397             :      * After every call to scs_malloc or scs_calloc
    1398             :      * we check whether the allocation has been
    1399             :      * successful.
    1400             :      * ------------------------------------- */
    1401         329 :     work->u = scs_calloc(l, sizeof (scs_float));
    1402         329 :     if (work->u == SCS_NULL) {
    1403             :         /* LCOV_EXCL_START */
    1404             :         scs_special_print(print_mode, stderr, "ERROR: `u` memory allocation failure\n");
    1405             :         return SCS_NULL;
    1406             :         /* LCOV_EXCL_STOP */
    1407             :     }
    1408         329 :     work->u_b = scs_calloc(l, sizeof (scs_float));
    1409         329 :     if (work->u_b == SCS_NULL) {
    1410             :         /* LCOV_EXCL_START */
    1411             :         scs_special_print(print_mode, stderr, "ERROR: `u_b` memory allocation failure\n");
    1412             :         return SCS_NULL;
    1413             :         /* LCOV_EXCL_STOP */
    1414             :     }
    1415         329 :     if (work->stgs->do_super_scs == 0) {
    1416           3 :         work->v = scs_calloc(l, sizeof (scs_float));
    1417           3 :         if (work->v == SCS_NULL) {
    1418             :             /* LCOV_EXCL_START */
    1419             :             scs_special_print(print_mode, stderr, "ERROR: `v` memory allocation failure\n");
    1420             :             return SCS_NULL;
    1421             :             /* LCOV_EXCL_STOP */
    1422             :         }
    1423             :     }
    1424         329 :     work->u_t = scs_malloc(l * sizeof (scs_float));
    1425         329 :     if (work->u_t == SCS_NULL) {
    1426             :         /* LCOV_EXCL_START */
    1427             :         scs_special_print(print_mode, stderr, "ERROR: `u_t` memory allocation failure\n");
    1428             :         return SCS_NULL;
    1429             :         /* LCOV_EXCL_STOP */
    1430             :     }
    1431         329 :     work->u_prev = scs_malloc(l * sizeof (scs_float));
    1432         329 :     if (work->u_prev == SCS_NULL) {
    1433             :         /* LCOV_EXCL_START */
    1434             :         scs_special_print(print_mode, stderr, "ERROR: `u_prev` memory allocation failure\n");
    1435             :         return SCS_NULL;
    1436             :         /* LCOV_EXCL_STOP */
    1437             :     }
    1438         329 :     work->h = scs_malloc((l - 1) * sizeof (scs_float));
    1439         329 :     if (work->h == SCS_NULL) {
    1440             :         /* LCOV_EXCL_START */
    1441             :         scs_special_print(print_mode, stderr, "ERROR: `h` memory allocation failure\n");
    1442             :         return SCS_NULL;
    1443             :         /* LCOV_EXCL_STOP */
    1444             :     }
    1445         329 :     work->g = scs_malloc((l - 1) * sizeof (scs_float));
    1446         329 :     if (work->g == SCS_NULL) {
    1447             :         /* LCOV_EXCL_START */
    1448             :         scs_special_print(print_mode, stderr, "ERROR: `g` memory allocation failure\n");
    1449             :         return SCS_NULL;
    1450             :         /* LCOV_EXCL_STOP */
    1451             :     }
    1452         329 :     work->pr = scs_malloc(data->m * sizeof (scs_float));
    1453         329 :     if (work->pr == SCS_NULL) {
    1454             :         /* LCOV_EXCL_START */
    1455             :         scs_special_print(print_mode, stderr, "ERROR: `pr` memory allocation failure\n");
    1456             :         return SCS_NULL;
    1457             :         /* LCOV_EXCL_STOP */
    1458             :     }
    1459         329 :     work->dr = scs_malloc(data->n * sizeof (scs_float));
    1460         329 :     if (work->dr == SCS_NULL) {
    1461             :         /* LCOV_EXCL_START */
    1462             :         scs_special_print(print_mode, stderr, "ERROR: `dr` memory allocation failure\n");
    1463             :         return SCS_NULL;
    1464             :         /* LCOV_EXCL_STOP */
    1465             :     }
    1466         329 :     work->b = scs_malloc(data->m * sizeof (scs_float));
    1467         329 :     if (work->b == SCS_NULL) {
    1468             :         /* LCOV_EXCL_START */
    1469             :         scs_special_print(print_mode, stderr, "ERROR: `b` memory allocation failure\n");
    1470             :         return SCS_NULL;
    1471             :         /* LCOV_EXCL_STOP */
    1472             :     }
    1473         329 :     work->c = scs_malloc(data->n * sizeof (scs_float));
    1474         329 :     if (work->c == SCS_NULL) {
    1475             :         /* LCOV_EXCL_START */
    1476             :         scs_special_print(print_mode, stderr, "ERROR: `c` memory allocation failure\n");
    1477             :         return SCS_NULL;
    1478             :         /* LCOV_EXCL_STOP */
    1479             :     }
    1480             : 
    1481             : 
    1482             : 
    1483         329 :     if (work->stgs->do_super_scs == 1) {
    1484             :         /* -------------------------------------
    1485             :          * Additional memory needs to be allocated
    1486             :          * in SuperSCS
    1487             :          * ------------------------------------- */
    1488         326 :         work->R = scs_calloc(l, sizeof (scs_float));
    1489         326 :         if (work->R == SCS_NULL) {
    1490             :             /* LCOV_EXCL_START */
    1491             :             scs_special_print(print_mode, stderr, "ERROR: `R` memory allocation failure\n");
    1492             :             return SCS_NULL;
    1493             :             /* LCOV_EXCL_STOP */
    1494             :         }
    1495         326 :         work->R_prev = scs_calloc(l, sizeof (scs_float));
    1496         326 :         if (work->R_prev == SCS_NULL) {
    1497             :             /* LCOV_EXCL_START */
    1498             :             scs_special_print(print_mode, stderr, "ERROR: `R_prev` memory allocation failure\n");
    1499             :             return SCS_NULL;
    1500             :             /* LCOV_EXCL_STOP */
    1501             :         }
    1502         326 :         work->dir = scs_malloc(l * sizeof (scs_float));
    1503         326 :         if (work->dir == SCS_NULL) {
    1504             :             /* LCOV_EXCL_START */
    1505             :             scs_special_print(print_mode, stderr, "ERROR: `dir` memory allocation failure\n");
    1506             :             return SCS_NULL;
    1507             :             /* LCOV_EXCL_STOP */
    1508             :         }
    1509         326 :         work->dut = scs_malloc(l * sizeof (scs_float));
    1510         326 :         if (work->dut == SCS_NULL) {
    1511             :             /* LCOV_EXCL_START */
    1512             :             scs_special_print(print_mode, stderr, "ERROR: `dut` memory allocation failure\n");
    1513             :             return SCS_NULL;
    1514             :             /* LCOV_EXCL_STOP */
    1515             :         }
    1516         326 :         work->s_b = scs_malloc(data->m * sizeof (scs_float));
    1517         326 :         if (work->s_b == SCS_NULL) {
    1518             :             /* LCOV_EXCL_START */
    1519             :             scs_special_print(print_mode, stderr, "ERROR: `s_b` memory allocation failure\n");
    1520             :             return SCS_NULL;
    1521             :             /* LCOV_EXCL_STOP */
    1522             :         }
    1523             : 
    1524         326 :         work->stepsize = 1.0;
    1525             : 
    1526             :         /* -------------------------------------
    1527             :          * Restarted Broyden requires the allocation
    1528             :          * of an (S,U)-cache.
    1529             :          * ------------------------------------- */
    1530         652 :         if ((work->stgs->direction == restarted_broyden
    1531         326 :                 || work->stgs->direction == anderson_acceleration)
    1532         321 :                 && work->stgs->memory > 0) {
    1533         321 :             work->direction_cache = scs_init_direction_cache(work->stgs->memory, l, print_mode, work->stgs->direction);
    1534         321 :             if (work->direction_cache == SCS_NULL) {
    1535             :                 /* LCOV_EXCL_START */
    1536             :                 scs_special_print(print_mode, stderr,
    1537             :                         "ERROR: `direction_cache` memory allocation failure\n");
    1538             :                 return SCS_NULL;
    1539             :                 /* LCOV_EXCL_STOP */
    1540             :             }
    1541             :         } else {
    1542           5 :             work->direction_cache = SCS_NULL;
    1543             :         }
    1544             : 
    1545             :         /* -------------------------------------
    1546             :          * Allocate memory for the full Broyden
    1547             :          * method
    1548             :          * ------------------------------------- */
    1549         326 :         if (work->stgs->direction == full_broyden) {
    1550             :             scs_int i;
    1551           0 :             work->H = scs_malloc(l * l * sizeof (scs_float));
    1552           0 :             if (work->H == SCS_NULL) {
    1553             :                 /* LCOV_EXCL_START */
    1554             :                 scs_special_print(print_mode, stderr, "ERROR: `H` memory allocation failure\n");
    1555             :                 return SCS_NULL;
    1556             :                 /* LCOV_EXCL_STOP */
    1557             :             }
    1558             :             /* H = I */
    1559           0 :             for (i = 0; i < l; ++i) {
    1560           0 :                 work->H[i * (l + 1)] = 1.0;
    1561             :             }
    1562             :         } else {
    1563         326 :             work->H = SCS_NULL;
    1564             :         }
    1565             : 
    1566         326 :         work->Sk = scs_malloc(l * sizeof (scs_float));
    1567         326 :         if (work->Sk == SCS_NULL) {
    1568             :             /* LCOV_EXCL_START */
    1569             :             scs_special_print(print_mode, stderr, "ERROR: `Sk` memory allocation failure\n");
    1570             :             return SCS_NULL;
    1571             :             /* LCOV_EXCL_STOP */
    1572             :         }
    1573         326 :         work->Yk = scs_malloc(l * sizeof (scs_float));
    1574         326 :         if (work->Yk == SCS_NULL) {
    1575             :             /* LCOV_EXCL_START */
    1576             :             scs_special_print(print_mode, stderr, "ERROR: `Yk` memory allocation failure\n");
    1577             :             return SCS_NULL;
    1578             :             /* LCOV_EXCL_STOP */
    1579             :         }
    1580             : 
    1581         326 :         if (work->stgs->ls > 0) {
    1582         322 :             work->wu = scs_malloc(l * sizeof (scs_float));
    1583         322 :             if (work->wu == SCS_NULL) {
    1584             :                 /* LCOV_EXCL_START */
    1585             :                 scs_special_print(print_mode, stderr, "ERROR: `wu` memory allocation failure\n");
    1586             :                 return SCS_NULL;
    1587             :                 /* LCOV_EXCL_STOP */
    1588             :             }
    1589         322 :             work->Rwu = scs_malloc(l * sizeof (scs_float));
    1590         322 :             if (work->Rwu == SCS_NULL) {
    1591             :                 /* LCOV_EXCL_START */
    1592             :                 scs_special_print(print_mode, stderr, "ERROR: `Rwu` memory allocation failure\n");
    1593             :                 return SCS_NULL;
    1594             :                 /* LCOV_EXCL_STOP */
    1595             :             }
    1596         322 :             work->wu_t = scs_malloc(l * sizeof (scs_float));
    1597         322 :             if (work->wu_t == SCS_NULL) {
    1598             :                 /* LCOV_EXCL_START */
    1599             :                 scs_special_print(print_mode, stderr, "ERROR: `wu_t` memory allocation failure\n");
    1600             :                 return SCS_NULL;
    1601             :                 /* LCOV_EXCL_STOP */
    1602             :             }
    1603         322 :             work->wu_b = scs_malloc(l * sizeof (scs_float));
    1604         322 :             if (work->wu_b == SCS_NULL) {
    1605             :                 /* LCOV_EXCL_START */
    1606             :                 scs_special_print(print_mode, stderr, "ERROR: `wu_b` memory allocation failure\n");
    1607             :                 return SCS_NULL;
    1608             :                 /* LCOV_EXCL_STOP */
    1609             :             }
    1610             :         }
    1611             :     } else {
    1612             :         /* -------------------------------------
    1613             :          * In SCS, the pointers which correspond to
    1614             :          * SuperSCS are set to SCS_NULL and are
    1615             :          * inactive.
    1616             :          * ------------------------------------- */
    1617           3 :         work->R = SCS_NULL;
    1618           3 :         work->R_prev = SCS_NULL;
    1619           3 :         work->dir = SCS_NULL;
    1620           3 :         work->dut = SCS_NULL;
    1621           3 :         work->s_b = SCS_NULL;
    1622           3 :         work->direction_cache = SCS_NULL;
    1623           3 :         work->Yk = SCS_NULL;
    1624           3 :         work->Sk = SCS_NULL;
    1625           3 :         work->wu = SCS_NULL;
    1626           3 :         work->Rwu = SCS_NULL;
    1627           3 :         work->wu_t = SCS_NULL;
    1628           3 :         work->wu_b = SCS_NULL;
    1629             :     }
    1630             : 
    1631         329 :     work->A = data->A;
    1632         329 :     if (work->stgs->normalize) {
    1633             : #ifdef COPYAMATRIX
    1634         326 :         if (scs_copy_a_matrix(&(work->A), data->A) == 0) {
    1635             :             /* LCOV_EXCL_START */
    1636             :             scs_special_print(print_mode, stderr, "ERROR: copy A matrix failed\n");
    1637             :             return SCS_NULL;
    1638             :             /* LCOV_EXCL_STOP */
    1639             :         }
    1640             : #endif
    1641         326 :         work->scal = scs_malloc(sizeof (ScsScaling));
    1642         326 :         scs_normalize_a(work->A, work->stgs, cone, work->scal);
    1643             :     } else {
    1644           3 :         work->scal = SCS_NULL;
    1645             :     }
    1646         329 :     if ((work->coneWork = scs_init_conework(cone)) == SCS_NULL) {
    1647             :         /* LCOV_EXCL_START */
    1648             :         scs_special_print(print_mode, stderr, "ERROR: initCone failure\n");
    1649             :         return SCS_NULL;
    1650             :         /* LCOV_EXCL_STOP */
    1651             :     }
    1652         329 :     work->p = scs_init_priv(work->A, work->stgs);
    1653         329 :     if (work->p == SCS_NULL) {
    1654             :         /* LCOV_EXCL_START */
    1655             :         scs_special_print(print_mode, stderr, "ERROR: scs_init_priv failure\n");
    1656             :         return SCS_NULL;
    1657             :         /* LCOV_EXCL_STOP */
    1658             :     }
    1659             :     return work;
    1660             : }
    1661             : 
    1662         329 : static scs_int scs_update_work(
    1663             :         const ScsData * RESTRICT data,
    1664             :         ScsWork * RESTRICT work,
    1665             :         const ScsSolution * RESTRICT sol) {
    1666             :     /* before normalization */
    1667         329 :     scs_int n = data->n;
    1668         329 :     scs_int m = data->m;
    1669             : 
    1670         329 :     work->nm_b = scs_norm(data->b, m);
    1671         329 :     work->nm_c = scs_norm(data->c, n);
    1672         329 :     memcpy(work->b, data->b, data->m * sizeof (scs_float));
    1673         329 :     memcpy(work->c, data->c, data->n * sizeof (scs_float));
    1674             : 
    1675         329 :     if (work->stgs->normalize) {
    1676         326 :         scs_normalize_bc(work);
    1677             :     }
    1678         329 :     if (work->stgs->warm_start) {
    1679           2 :         scs_warm_start_vars(work, sol);
    1680             :     } else {
    1681         327 :         scs_cold_start_vars(work);
    1682             :     }
    1683         329 :     memcpy(work->h, work->c, n * sizeof (scs_float));
    1684         329 :     memcpy(&(work->h[n]), work->b, m * sizeof (scs_float));
    1685         329 :     memcpy(work->g, work->h, (n + m) * sizeof (scs_float));
    1686         329 :     scs_solve_lin_sys(work->A, work->stgs, work->p, work->g, SCS_NULL, -1);
    1687         329 :     scs_scale_array(&(work->g[n]), -1, m);
    1688         329 :     work->gTh = scs_inner_product(work->h, work->g, n + m);
    1689         329 :     return 0;
    1690             : }
    1691             : 
    1692             : static scs_int scs_validate_solve_input(
    1693             :         const ScsWork * RESTRICT work,
    1694             :         const ScsData * RESTRICT data,
    1695             :         const ScsCone * RESTRICT cone,
    1696             :         const ScsSolution * RESTRICT sol,
    1697             :         const ScsInfo * RESTRICT info) {
    1698         329 :     return ((data == SCS_NULL
    1699         329 :             || cone == SCS_NULL
    1700         329 :             || sol == SCS_NULL
    1701         329 :             || info == SCS_NULL
    1702         329 :             || work == SCS_NULL
    1703         329 :             || data->b == SCS_NULL
    1704         658 :             || data->c == SCS_NULL));
    1705             : }
    1706             : 
    1707         329 : static scs_int scs_init_progress_data(
    1708             :         ScsInfo * RESTRICT info,
    1709             :         ScsWork * RESTRICT work) {
    1710             :     /* --------------------------------------------------------------
    1711             :      * As the might be successive calls to superSCS (superscs_solve)
    1712             :      * with different values of `do_record_progress`, we nee to make
    1713             :      * sure that we neither allocate memory for the same array twice,
    1714             :      * nor do we set any arrays to SCS_NULL unnecessarily. Note that,
    1715             :      * provided that `info` has  been initialized with scs_init_info (this
    1716             :      * is highly recommended), all pointers are initially set to SCS_NULL.
    1717             :      * -------------------------------------------------------------- */
    1718         329 :     if (work->stgs->do_record_progress) {
    1719           8 :         const scs_int max_history_alloc = work->stgs->max_iters;
    1720             : 
    1721             :         /* ----------------------------------------
    1722             :          * If a pointer is SCS_NULL, it means that
    1723             :          * no memory has been allocated for that
    1724             :          * previously.
    1725             :          * ---------------------------------------- */
    1726           8 :         if (info->progress_relgap == SCS_NULL) {
    1727           3 :             info->progress_relgap = scs_malloc(sizeof (scs_float) * max_history_alloc);
    1728           3 :             if (info->progress_relgap == SCS_NULL) return -1;
    1729             :         }
    1730           8 :         if (info->progress_respri == SCS_NULL) {
    1731           3 :             info->progress_respri = scs_malloc(sizeof (scs_float) * max_history_alloc);
    1732           3 :             if (info->progress_respri == SCS_NULL) return -2;
    1733             :         }
    1734           8 :         if (info->progress_resdual == SCS_NULL) {
    1735           3 :             info->progress_resdual = scs_malloc(sizeof (scs_float) * max_history_alloc);
    1736           3 :             if (info->progress_resdual == SCS_NULL) return -3;
    1737             :         }
    1738           8 :         if (info->progress_pcost == SCS_NULL) {
    1739           3 :             info->progress_pcost = scs_malloc(sizeof (scs_float) * max_history_alloc);
    1740           3 :             if (info->progress_pcost == SCS_NULL) return -4;
    1741             :         }
    1742           8 :         if (info->progress_dcost == SCS_NULL) {
    1743           3 :             info->progress_dcost = scs_malloc(sizeof (scs_float) * max_history_alloc);
    1744           3 :             if (info->progress_dcost == SCS_NULL) return -5;
    1745             :         }
    1746           8 :         if (info->progress_iter == SCS_NULL) {
    1747           3 :             info->progress_iter = scs_malloc(sizeof (scs_int) * max_history_alloc);
    1748           3 :             if (info->progress_iter == SCS_NULL) return -6;
    1749             :         }
    1750           8 :         if (info->progress_norm_fpr == SCS_NULL) {
    1751           3 :             info->progress_norm_fpr = scs_malloc(sizeof (scs_float) * max_history_alloc);
    1752           3 :             if (info->progress_norm_fpr == SCS_NULL) return -7;
    1753             :         }
    1754           8 :         if (info->progress_time == SCS_NULL) {
    1755           3 :             info->progress_time = scs_malloc(sizeof (scs_float) * max_history_alloc);
    1756           3 :             if (info->progress_time == SCS_NULL) return -8;
    1757             :         }
    1758           8 :         if (info->progress_mode == SCS_NULL) {
    1759           3 :             info->progress_mode = scs_malloc(sizeof (scs_int) * max_history_alloc);
    1760           3 :             if (info->progress_mode == SCS_NULL) return -9;
    1761             :         }
    1762           8 :         if (info->progress_ls == SCS_NULL) {
    1763           3 :             info->progress_ls = scs_malloc(sizeof (scs_int) * max_history_alloc);
    1764           3 :             if (info->progress_ls == SCS_NULL) return -10;
    1765             :         }
    1766             : 
    1767             :         /* ---------------------------------------------------------
    1768             :          * If `do_record_progress` is true, and there has
    1769             :          * been a previous allocation, but now the maximum
    1770             :          * number of iterations has increased
    1771             :          *
    1772             :          * Note: if the current `max_iters` is smaller than
    1773             :          * the previous value, it means that more than adequate
    1774             :          * memory space has been allocated for the progress arrays.
    1775             :          * However, we will not use `realloc` to size it down.
    1776             :          * --------------------------------------------------------- */
    1777           8 :         if (work->stgs->previous_max_iters != -1
    1778           6 :                 && max_history_alloc > work->stgs->previous_max_iters) {
    1779             :             /* ------------------------------------
    1780             :              * We don't check for NULL values here
    1781             :              * because `realloc` on NULL pointers
    1782             :              * behaves like `malloc`
    1783             :              * ------------------------------------
    1784             :              */
    1785           5 :             info->progress_relgap = realloc(info->progress_relgap, sizeof (scs_float) * max_history_alloc);
    1786           5 :             if (info->progress_relgap == SCS_NULL) return -100;
    1787             : 
    1788           5 :             info->progress_respri = realloc(info->progress_respri, sizeof (scs_float) * max_history_alloc);
    1789           5 :             if (info->progress_respri == SCS_NULL) return -101;
    1790             : 
    1791           5 :             info->progress_resdual = realloc(info->progress_resdual, sizeof (scs_float) * max_history_alloc);
    1792           5 :             if (info->progress_resdual == SCS_NULL) return -102;
    1793             : 
    1794           5 :             info->progress_pcost = realloc(info->progress_pcost, sizeof (scs_float) * max_history_alloc);
    1795           5 :             if (info->progress_pcost == SCS_NULL) return -103;
    1796             : 
    1797           5 :             info->progress_dcost = realloc(info->progress_dcost, sizeof (scs_float) * max_history_alloc);
    1798           5 :             if (info->progress_dcost == SCS_NULL) return -104;
    1799             : 
    1800           5 :             info->progress_iter = realloc(info->progress_iter, sizeof (scs_int) * max_history_alloc);
    1801           5 :             if (info->progress_iter == SCS_NULL) return -105;
    1802             : 
    1803           5 :             info->progress_norm_fpr = realloc(info->progress_norm_fpr, sizeof (scs_float) * max_history_alloc);
    1804           5 :             if (info->progress_norm_fpr == SCS_NULL) return -106;
    1805             : 
    1806           5 :             info->progress_time = realloc(info->progress_time, sizeof (scs_float) * max_history_alloc);
    1807           5 :             if (info->progress_time == SCS_NULL) return -107;
    1808             : 
    1809           5 :             info->progress_mode = realloc(info->progress_mode, sizeof (scs_int) * max_history_alloc);
    1810           5 :             if (info->progress_mode == SCS_NULL) return -108;
    1811             : 
    1812           5 :             info->progress_ls = realloc(info->progress_ls, sizeof (scs_int) * max_history_alloc);
    1813           5 :             if (info->progress_ls == SCS_NULL) return -109;
    1814             :         }
    1815             :     }
    1816             :     return 0;
    1817             : }
    1818             : 
    1819         987 : static void scs_record_progress_data(
    1820             :         ScsInfo * info,
    1821             :         struct scs_residuals * res,
    1822             :         const ScsWork * work,
    1823             :         ScsTimer * solveTimer,
    1824             :         scs_int iter) {
    1825         987 :     scs_int idx_progress = iter / SCS_CONVERGED_INTERVAL;
    1826         987 :     info->progress_iter[idx_progress] = iter;
    1827         987 :     info->progress_relgap[idx_progress] = res->rel_gap;
    1828         987 :     info->progress_respri[idx_progress] = res->res_pri;
    1829         987 :     info->progress_resdual[idx_progress] = res->res_dual;
    1830         987 :     info->progress_pcost[idx_progress] = res->cTx_by_tau / res->tau;
    1831         987 :     info->progress_dcost[idx_progress] = -res->bTy_by_tau / res->tau;
    1832         987 :     info->progress_norm_fpr[idx_progress] = work->nrmR_con;
    1833         987 :     info->progress_time[idx_progress] = scs_toc_quiet(solveTimer);
    1834         987 : }
    1835             : 
    1836           3 : scs_int scs_solve(
    1837         200 :         ScsWork * RESTRICT work,
    1838             :         const ScsData * RESTRICT data,
    1839             :         const ScsCone * RESTRICT cone,
    1840             :         ScsSolution * RESTRICT sol,
    1841             :         ScsInfo * RESTRICT info) {
    1842             :     scs_int i;
    1843             :     ScsTimer solveTimer;
    1844             :     struct scs_residuals r;
    1845           3 :     scs_int print_mode = work->stgs->do_override_streams;
    1846           3 :     const scs_float max_runtime_millis = work->stgs->max_time_milliseconds;
    1847             : 
    1848           3 :     if ((i = scs_init_progress_data(info, work)) < 0) {
    1849             :         /* LCOV_EXCL_START */
    1850             :         scs_special_print(print_mode, stderr, "Memory allocation error (progress arrays), code: %d\n", (int) i);
    1851             :         return SCS_FAILED;
    1852             :         /* LCOV_EXCL_STOP */
    1853             :     }
    1854             : 
    1855           3 :     if (scs_validate_solve_input(work, data, cone, sol, info)) {
    1856           0 :         scs_special_print(print_mode, stderr, "ERROR: SCS_NULL input\n");
    1857           0 :         return SCS_FAILED;
    1858             :     }
    1859             :     /* initialize ctrl-c support */
    1860           3 :     startInterruptListener();
    1861           3 :     scs_tic(&solveTimer);
    1862           3 :     info->statusVal = SCS_UNFINISHED; /* not yet converged */
    1863           3 :     r.last_iter = -1;
    1864           3 :     scs_update_work(data, work, sol);
    1865             : 
    1866           3 :     if (work->stgs->verbose)
    1867           0 :         scs_print_header(work, cone);
    1868             :     /* scs: */
    1869         198 :     for (i = 0; i < work->stgs->max_iters && scs_toc_quiet(&solveTimer) < max_runtime_millis; ++i) {
    1870         200 :         memcpy(work->u_prev, work->u, work->l * sizeof (scs_float));
    1871             : 
    1872         200 :         if (scs_project_lin_sys(work, i) < 0) {
    1873           0 :             return scs_failure(work, work->m, work->n, sol, info, SCS_FAILED,
    1874             :                     "error in projectLinSys", "Failure", print_mode);
    1875             :         }
    1876         200 :         if (scs_project_cones(work, cone, i) < 0) {
    1877           0 :             return scs_failure(work, work->m, work->n, sol, info, SCS_FAILED,
    1878             :                     "error in projectCones", "Failure", print_mode);
    1879             :         }
    1880             : 
    1881         200 :         scs_update_dual_vars(work);
    1882             : 
    1883         200 :         if (isInterrupted()) {
    1884           0 :             return scs_failure(work, work->m, work->n, sol, info, SCS_SIGINT, "Interrupted",
    1885             :                     "Interrupted", print_mode);
    1886             :         }
    1887             :         if (i % SCS_CONVERGED_INTERVAL == 0) {
    1888         200 :             scs_calc_residuals(work, &r, i);
    1889         200 :             if (work->stgs->do_record_progress) scs_record_progress_data(info, &r, work, &solveTimer, i);
    1890         400 :             if ((info->statusVal = scs_has_converged(work, &r, i)) != 0) break;
    1891             :         }
    1892             : 
    1893         198 :         if (work->stgs->verbose && i % SCS_PRINT_INTERVAL == 0) {
    1894           0 :             scs_calc_residuals(work, &r, i);
    1895           0 :             scs_print_summary(work, i, &r, &solveTimer);
    1896             :         }
    1897             :     }
    1898           3 :     if (work->stgs->verbose) {
    1899           0 :         scs_calc_residuals(work, &r, i);
    1900           0 :         scs_print_summary(work, i, &r, &solveTimer);
    1901             :     }
    1902             :     /* populate solution vectors (unnormalized) and info */
    1903           3 :     scs_get_solution(work, sol, info, &r, i);
    1904           3 :     info->solveTime = scs_toc_quiet(&solveTimer);
    1905             : 
    1906           3 :     if (work->stgs->verbose)
    1907             :         scs_print_footer(data, cone, sol, work, info); /* LCOV_EXCL_LINE */
    1908           3 :     endInterruptListener();
    1909           3 :     info->history_length = i / SCS_CONVERGED_INTERVAL;
    1910             : 
    1911           3 :     return info->statusVal;
    1912             : }
    1913             : 
    1914       29901 : static void scs_compute_sb_kapb(
    1915             :         ScsWork * RESTRICT work) {
    1916       29901 :     scs_axpy(work->s_b, work->u_b + work->n, work->u_t + work->n, 1.0, -2.0, work->m);
    1917       29901 :     scs_add_array(work->s_b, work->u + work->n, work->m);
    1918       29901 :     work->kap_b = work->u_b[work->l - 1] - 2.0 * work->u_t[work->l - 1] + work->u[work->l - 1];
    1919       29901 : }
    1920             : 
    1921        5097 : static void scs_step_k1(
    1922             :         ScsWork * RESTRICT work,
    1923             :         scs_float nrmRw_con_current,
    1924             :         scs_float * r_safe,
    1925             :         scs_float q_to_power_iter_times_nrm_R_init,
    1926             :         scs_int * how) {
    1927        5097 :     memcpy(work->u, work->wu, work->l * sizeof (scs_float)); /* u   = wu   */
    1928        5097 :     memcpy(work->u_t, work->wu_t, work->l * sizeof (scs_float)); /* u_t = wu_t */
    1929        5097 :     memcpy(work->u_b, work->wu_b, work->l * sizeof (scs_float)); /* u_b = wu_b */
    1930        5097 :     memcpy(work->R, work->Rwu, work->l * sizeof (scs_float)); /* R   = Rw   */
    1931        5097 :     scs_compute_sb_kapb(work);
    1932        5097 :     work->nrmR_con = nrmRw_con_current;
    1933        5097 :     *r_safe = work->nrmR_con + q_to_power_iter_times_nrm_R_init;
    1934        5097 :     *how = (scs_int) 1;
    1935        5097 : }
    1936             : 
    1937       24944 : static scs_int scs_step_k2(
    1938             :         ScsWork * RESTRICT work,
    1939             :         scs_float nrmRw_con,
    1940             :         scs_int * how) {
    1941             : 
    1942       24944 :     scs_int do_break_loop = 0;
    1943             :     scs_float slack;
    1944             :     scs_float rhs;
    1945       49888 :     slack = nrmRw_con * nrmRw_con - work->stepsize * (
    1946       24944 :             scs_inner_product(work->dir + work->n, work->Rwu + work->n, work->m + 1)
    1947       24944 :             + work->stgs->rho_x * scs_inner_product(work->dir, work->Rwu, work->n));
    1948       24944 :     rhs = work->stgs->sigma * work->nrmR_con * nrmRw_con;
    1949       24944 :     if (slack >= rhs) {
    1950             :         scs_float stepsize2;
    1951       12563 :         stepsize2 = (work->stgs->alpha * (slack / (nrmRw_con * nrmRw_con)));
    1952       12563 :         scs_add_scaled_array(work->u, work->Rwu, work->l, -stepsize2);
    1953       12563 :         *how = 2;
    1954       12563 :         do_break_loop = 1;
    1955             :     }
    1956       24944 :     return do_break_loop;
    1957             : }
    1958             : 
    1959       29120 : static void scs_update_caches(
    1960             :         ScsWork * RESTRICT work,
    1961             :         scs_float sqrt_rhox,
    1962             :         scs_int how) {
    1963       29120 :     if (how == 0 || work->stgs->ls == 0) {
    1964        5310 :         scs_axpy(work->Sk, work->u, work->u_prev, 1.0, -1.0, work->l); /* Sk = u - u_prev */
    1965        5310 :         scs_axpy(work->Yk, work->R, work->R_prev, sqrt_rhox, -1.0, work->n); /* Yk = sqrt_rhox * R - R_prev */
    1966        5310 :         scs_axpy(work->Yk + work->n, work->R + work->n, work->R_prev + work->n, 1.0, -1.0, work->m + 1);
    1967        5310 :         scs_scale_array(work->Sk, sqrt_rhox, work->n); /* Sk *= sqrt_rhox */
    1968             :     } else {
    1969       23810 :         scs_axpy(work->Sk, work->wu, work->u_prev, sqrt_rhox, -sqrt_rhox, work->n);
    1970       23810 :         scs_axpy(work->Sk + work->n, work->wu + work->n, work->u_prev + work->n, 1.0, -1.0, work->m + 1);
    1971       23810 :         scs_axpy(work->Yk, work->Rwu, work->R_prev, sqrt_rhox, -1.0, work->n);
    1972       23810 :         scs_axpy(work->Yk + work->n, work->Rwu + work->n, work->R_prev + work->n, 1.0, -1.0, work->m + 1);
    1973             :     }
    1974       29120 : }
    1975             : 
    1976       24478 : static scs_int scs_exit_loop_without_k1(
    1977             :         ScsWork * RESTRICT work,
    1978             :         ScsSolution * RESTRICT sol,
    1979             :         ScsInfo * RESTRICT info,
    1980             :         const ScsCone * RESTRICT cone,
    1981             :         scs_int i,
    1982             :         scs_int print_mode) {
    1983       24478 :     if (superscs_project_lin_sys(work->u_t, work->u, work, i) < 0) {
    1984           0 :         return scs_failure(work, work->m, work->n, sol, info, SCS_FAILED,
    1985             :                 "error in projectLinSysv2", "Failure", print_mode);
    1986             :     }
    1987             :     /* u_bar = proj_C(2u_t - u) */
    1988       24478 :     if (superscs_project_cones(work->u_b, work->u_t, work->u, work, cone, i) < 0) {
    1989           0 :         return scs_failure(work, work->m, work->n, sol, info, SCS_FAILED,
    1990             :                 "error in projectConesv2", "Failure", print_mode);
    1991             :     }
    1992       24478 :     scs_compute_sb_kapb(work);
    1993       24478 :     scs_calc_FPR(work->R, work->u_t, work->u_b, work->l);
    1994       24478 :     work->nrmR_con = SQRTF(
    1995       24478 :             work->stgs->rho_x * scs_norm_squared(work->R, work->n)
    1996       24478 :             + scs_norm_squared(work->R + work->n, work->m + 1)
    1997             :             );
    1998       24478 :     return 0;
    1999             : }
    2000             : 
    2001         326 : scs_int superscs_solve(
    2002       29888 :         ScsWork * RESTRICT work,
    2003             :         const ScsData * RESTRICT data,
    2004             :         const ScsCone * RESTRICT cone,
    2005             :         ScsSolution * RESTRICT sol,
    2006             :         ScsInfo * RESTRICT info) {
    2007             :     scs_int i; /* i indexes the (outer) iterations */
    2008         326 :     scs_int how = 0; /* -1:unsuccessful backtracking, 0:K0, 1:K1, 2:K2 */
    2009             :     scs_float eta;
    2010             :     scs_float nrm_R_0;
    2011             :     scs_float r_safe;
    2012             :     scs_float nrmRw_con; /* norm of FP res at line-search */
    2013             :     scs_float nrmR_con_old; /* keeps previous FP res */
    2014         326 :     scs_float q_to_power_iter_times_nrmR0 = work->stgs->sse; /* sse^(iter) */
    2015         326 :     const scs_float rhox = work->stgs->rho_x;
    2016         326 :     const scs_float sqrt_rhox = SQRTF(rhox);
    2017         326 :     const scs_float q0 = work->stgs->sse;
    2018         326 :     const scs_int n = work->n;
    2019         326 :     const scs_int m = work->m;
    2020         326 :     const scs_int l = work->l;
    2021             :     ScsTimer solveTimer;
    2022             :     struct scs_residuals r;
    2023         326 :     scs_int print_mode = work->stgs->do_override_streams;
    2024             :     /* ------------------------------------
    2025             :      * Store some pointers in function-scope
    2026             :      * variables for performance.
    2027             :      * ------------------------------------ */
    2028         326 :     ScsSettings * RESTRICT settings = work->stgs;
    2029         326 :     scs_float alpha = settings->alpha;
    2030         326 :     scs_float * RESTRICT dir = work->dir;
    2031         326 :     scs_float * RESTRICT R = work->R;
    2032         326 :     scs_float * RESTRICT R_prev = work->R_prev;
    2033         326 :     scs_float * RESTRICT Rwu = work->Rwu;
    2034         326 :     scs_float * RESTRICT u = work->u;
    2035         326 :     scs_float * RESTRICT u_t = work->u_t;
    2036         326 :     scs_float * RESTRICT u_b = work->u_b;
    2037         326 :     scs_float * RESTRICT u_prev = work->u_prev;
    2038         326 :     scs_float * RESTRICT wu = work->wu;
    2039         326 :     scs_float * RESTRICT wu_t = work->wu_t;
    2040         326 :     scs_float * RESTRICT wu_b = work->wu_b;
    2041         326 :     scs_float * RESTRICT dut = work->dut;
    2042             : 
    2043         326 :     if ((i = scs_init_progress_data(info, work)) < 0) {
    2044             :         /* LCOV_EXCL_START */
    2045             :         scs_special_print(print_mode, stderr, "Memory allocation error (progress arrays), code: %d\n", (int) i);
    2046             :         return SCS_FAILED;
    2047             :         /* LCOV_EXCL_STOP */
    2048             :     }
    2049         326 :     settings->previous_max_iters = settings->max_iters;
    2050             : 
    2051         326 :     if (scs_validate_solve_input(work, data, cone, sol, info)) {
    2052           0 :         scs_special_print(print_mode, stderr, "ERROR: SCS_NULL input\n");
    2053           0 :         return SCS_FAILED;
    2054             :     }
    2055             : 
    2056             :     /* initialize ctrl-c support */
    2057         326 :     startInterruptListener();
    2058         326 :     scs_tic(&solveTimer);
    2059         326 :     info->statusVal = SCS_UNFINISHED; /* not yet converged */
    2060         326 :     r.last_iter = -1;
    2061         326 :     scs_update_work(data, work, sol);
    2062             : 
    2063         326 :     if (settings->verbose > 0) scs_print_header(work, cone);
    2064             : 
    2065             :     /* Initialize: */
    2066         326 :     i = 0; /* Needed for the next two functions */
    2067         326 :     if (superscs_project_lin_sys(u_t, u, work, i) < 0) { /* u_t = (I+Q)^{-1} u*/
    2068           0 :         return scs_failure(work, m, n, sol, info, SCS_FAILED,
    2069             :                 "error in projectLinSysv2", "Failure", print_mode);
    2070             :     }
    2071         326 :     if (superscs_project_cones(u_b, u_t, u, work, cone, i) < 0) { /* u_bar = proj_C(2u_t - u) */
    2072           0 :         return scs_failure(work, m, n, sol, info, SCS_FAILED,
    2073             :                 "error in projectConesv2", "Failure", print_mode);
    2074             :     }
    2075         326 :     scs_compute_sb_kapb(work); /* compute s_b and kappa_b */
    2076             :     scs_calc_FPR(R, u_t, u_b, l); /* compute Ru */
    2077             :     /* initialize eta = |Ru^0| (norm of R using rho_x)... */
    2078         326 :     eta = SQRTF(rhox * scs_norm_squared(R, n) + scs_norm_squared(R + n, m + 1));
    2079         326 :     r_safe = eta;
    2080         326 :     work->nrmR_con = eta;
    2081         326 :     nrm_R_0 = MIN(1.0, eta);
    2082         326 :     q_to_power_iter_times_nrmR0 *= nrm_R_0;
    2083             : 
    2084             :     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    2085             :      * 
    2086             :      * MAIN SUPER SCS LOOP 
    2087             :      * 
    2088             :      * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    2089       30227 :     for (i = 0; i < settings->max_iters
    2090       59464 :             && scs_toc_quiet(&solveTimer) < work->stgs->max_time_milliseconds; ++i) {
    2091       29888 :         scs_int j_iter_ls = 0; /* j indexes the line search iterations */
    2092             : 
    2093       29888 :         if (isInterrupted()) {
    2094           0 :             return scs_failure(work, m, n, sol, info, SCS_SIGINT, "Interrupted",
    2095             :                     "Interrupted", print_mode);
    2096             :         }
    2097             : 
    2098             :         /* Convergence checks */
    2099             :         if (i % SCS_CONVERGED_INTERVAL == 0) {
    2100       29888 :             scs_calc_residuals_superscs(work, &r, i);
    2101       29888 :             if (settings->do_record_progress) scs_record_progress_data(info, &r, work, &solveTimer, i);
    2102       59776 :             if ((info->statusVal = scs_has_converged(work, &r, i)) != 0) break;
    2103             :         }
    2104             : 
    2105             :         /* Prints results every PRINT_INTERVAL iterations */
    2106       29575 :         if (settings->verbose && i % SCS_PRINT_INTERVAL == 0) {
    2107           2 :             scs_calc_residuals_superscs(work, &r, i);
    2108           2 :             scs_print_summary(work, i, &r, &solveTimer);
    2109             :         }
    2110             : 
    2111       29575 :         if (settings->ls > 0 || settings->k0 == 1) {
    2112       29441 :             q_to_power_iter_times_nrmR0 *= q0; /* q = q0^i = sse^i */
    2113       29441 :             if (i == 0) {
    2114             :                 /* -------------------------------------------
    2115             :                  * At i=0, the direction is defined using the
    2116             :                  * FPR: dir^0 = -R
    2117             :                  * -------------------------------------------- */
    2118         321 :                 scs_set_as_scaled_array(dir, R, -sqrt_rhox, n);
    2119         321 :                 scs_set_as_scaled_array(dir + n, R + n, -1, m + 1);
    2120             : 
    2121             :             } else {
    2122       29120 :                 scs_update_caches(work, sqrt_rhox, how);
    2123       29120 :                 scs_scale_array(R, sqrt_rhox, n); /* R *= sqrt_rhox */
    2124       29120 :                 if (scs_compute_direction(work, i) < 0) { /* compute direction */
    2125             :                     /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2126             :                      * Function `scs_compute_direction` is invoked at iterations i>=1.
    2127             :                      * At i=1, the first pair (S,Y) has been computed (see work).
    2128             :                      *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    2129           0 :                     return scs_failure(work, m, n, sol, info, SCS_FAILED,
    2130             :                             "error in scs_compute_direction", "Failure", print_mode);
    2131             :                 }
    2132       29120 :                 scs_scale_array(R, 1 / sqrt_rhox, n); /* R = R/sqrt_rhox */
    2133             :             }
    2134             :             /* -------------------------------------------
    2135             :              * Scale the x-part of dir using sqrt_rhox
    2136             :              * -------------------------------------------- */
    2137       29441 :             scs_scale_array(dir, 1 / sqrt_rhox, n);
    2138             :         }
    2139             : 
    2140       29575 :         memcpy(u_prev, u, l * sizeof (scs_float)); /* u_prev = u */
    2141       29575 :         memcpy(R_prev, R, l * sizeof (scs_float)); /* R_prev = R */
    2142       29575 :         scs_scale_array(R_prev, sqrt_rhox, n);
    2143       29575 :         how = -1; /* no backtracking (yet) */
    2144       29575 :         nrmR_con_old = work->nrmR_con;
    2145             : 
    2146       29575 :         if (i >= settings->warm_start) {
    2147             :             /* ------------------------------------------------
    2148             :              *   Blind updates (K0)
    2149             :              * ------------------------------------------------ */
    2150       29575 :             if (settings->k0 == 1 && work->nrmR_con <= settings->c_bl * eta) {
    2151        5466 :                 scs_add_array(u, dir, l); /* u += dir */
    2152        5466 :                 how = 0;
    2153        5466 :                 eta = work->nrmR_con;
    2154        5466 :                 work->stepsize = 1.0;
    2155       24109 :             } else if (settings->ls > 0) {
    2156       23975 :                 if (superscs_project_lin_sys(dut, dir, work, i) < 0) {
    2157           0 :                     return scs_failure(work, m, n, sol, info, SCS_FAILED, "error in superscs_project_lin_sys", "Failure", print_mode);
    2158             :                 }
    2159       23975 :                 work->stepsize = 2.0;
    2160             : 
    2161             :                 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2162             :                  *   Line search 
    2163             :                  *   Main computational burden: 1 projection
    2164             :                  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    2165       60969 :                 for (j_iter_ls = 0; j_iter_ls < settings->ls; ++j_iter_ls) {
    2166       54654 :                     work->stepsize *= settings->beta;
    2167       54654 :                     scs_axpy(wu, u, dir, 1.0, work->stepsize, l); /* wu = u + step * dir */
    2168       54654 :                     scs_axpy(wu_t, u_t, dut, 1.0, work->stepsize, l); /* wut = u_t + step * dut */
    2169             : 
    2170       54654 :                     if (superscs_project_cones(wu_b, wu_t, wu, work, cone, i) < 0) {
    2171           0 :                         return scs_failure(work, m, n, sol, info, SCS_FAILED, "error in superscs_project_cones", "Failure", print_mode);
    2172             :                     }
    2173             :                     scs_calc_FPR(Rwu, wu_t, wu_b, l); /* calculate FPR on scaled vectors */
    2174             : 
    2175       54654 :                     nrmRw_con = SQRTF(scs_norm_squared(Rwu + n, m + 1) + rhox * scs_norm_squared(Rwu, n));
    2176             : 
    2177             :                     /* K1 */
    2178       54654 :                     if (settings->k1
    2179       21108 :                             && nrmRw_con <= settings->c1 * nrmR_con_old
    2180        7050 :                             && work->nrmR_con <= r_safe) {
    2181        5097 :                         scs_step_k1(work, nrmRw_con, &r_safe, q_to_power_iter_times_nrmR0, &how);
    2182        5097 :                         break;
    2183             :                     }
    2184             : 
    2185             :                     /* K2 */
    2186       49557 :                     if (settings->k2 && scs_step_k2(work, nrmRw_con, &how)) break;
    2187             :                 } /* end of line-search */
    2188       23975 :                 j_iter_ls++; /* to get the number of LS iterations */
    2189             :             } /* end of `else if` block (when !K1 OR no blind update) */
    2190             :         } /* IF-block: iterated after warm start */
    2191             : 
    2192       29575 :         if (how == -1) { /* means that R didn't change */
    2193             :             /* x -= alpha*Rx */
    2194        6449 :             scs_add_scaled_array(u, R, l, -alpha);
    2195             :         } /* how == -1 */
    2196       29575 :         if (how != 1) { /* exited with other than K1 */
    2197       24478 :             scs_int status = scs_exit_loop_without_k1(work, sol, info, cone, i, print_mode);
    2198       24478 :             if (status < 0)
    2199             :                 return status;
    2200             :         } /* how != 1 */
    2201             : 
    2202             :         /* -------------------------------------------
    2203             :          * Record some more progress information
    2204             :          * -------------------------------------------*/
    2205       29575 :         if (settings->do_record_progress && i % SCS_CONVERGED_INTERVAL == 0) {
    2206         905 :             scs_int idx_progress = i / SCS_CONVERGED_INTERVAL;
    2207         905 :             info->progress_mode[idx_progress] = how;
    2208         905 :             info->progress_ls[idx_progress] = j_iter_ls;
    2209             :         }
    2210             : 
    2211             :     } /* main for loop */
    2212             : 
    2213             : 
    2214         326 :     info->cg_total_iters = scs_linsys_total_cg_iters(work->p);
    2215         326 :     info->linsys_total_solve_time_ms = scs_linsys_total_solve_time_ms(work->p);
    2216             : 
    2217         326 :     scs_calc_residuals_superscs(work, &r, i);
    2218             : 
    2219             :     /* prints summary of last iteration */
    2220         326 :     if (settings->verbose) scs_print_summary(work, i, &r, &solveTimer);
    2221             : 
    2222             :     /* populate solution vectors (unnormalized) and info */
    2223             :     /* update u, denormalize, etc */
    2224         326 :     scs_get_solution(work, sol, info, &r, i);
    2225         326 :     info->iter = i;
    2226         326 :     info->solveTime = scs_toc_quiet(&solveTimer);
    2227         326 :     info->history_length = i / SCS_CONVERGED_INTERVAL;
    2228             : 
    2229         326 :     if (settings->verbose)
    2230             :         scs_print_footer(data, cone, sol, work, info); /* LCOV_EXCL_LINE */
    2231         326 :     endInterruptListener();
    2232             : 
    2233         326 :     return info->statusVal;
    2234             : }
    2235             : 
    2236         341 : void scs_finish(ScsWork * RESTRICT w) {
    2237         341 :     if (w != SCS_NULL) {
    2238         329 :         scs_finish_cone(w->coneWork);
    2239         329 :         if (w->stgs != SCS_NULL && w->stgs->normalize != 0) {
    2240             : #ifndef COPYAMATRIX
    2241             :             scs_unnormalize_a(w->A, w->stgs, w->scal);
    2242             : #else
    2243         326 :             scs_free_a_matrix(w->A);
    2244             : #endif
    2245             :         }
    2246         329 :         if (w->p != SCS_NULL)
    2247         329 :             scs_free_priv(w->p);
    2248         329 :         scs_free_work(w);
    2249             :     }
    2250         341 : }
    2251             : 
    2252         341 : ScsWork * scs_init(
    2253             :         const ScsData * RESTRICT data,
    2254             :         const ScsCone * RESTRICT cone,
    2255             :         ScsInfo * RESTRICT info) {
    2256             :     ScsWork * RESTRICT work;
    2257             :     ScsTimer initTimer;
    2258         341 :     startInterruptListener();
    2259         682 :     if (data == SCS_NULL
    2260         341 :             || cone == SCS_NULL
    2261         341 :             || info == SCS_NULL) {
    2262             :         /* LCOV_EXCL_START */
    2263             :         scs_special_print(data->stgs->do_override_streams, stderr, "ERROR: Missing Data, Cone or Info input\n");
    2264             :         return SCS_NULL;
    2265             :         /* LCOV_EXCL_STOP */
    2266             :     }
    2267             : #ifndef NOVALIDATE
    2268         341 :     if (scs_validate(data, cone) < 0) {
    2269          12 :         scs_special_print(data->stgs->do_override_streams, stderr, "ERROR: Validation returned failure\n");
    2270          12 :         return SCS_NULL;
    2271             :     }
    2272             : #endif
    2273         329 :     scs_tic(&initTimer);
    2274         329 :     work = scs_init_work(data, cone);
    2275             :     /* strtoc("init", &initTimer); */
    2276         329 :     info->setupTime = scs_toc_quiet(&initTimer);
    2277         329 :     if (data->stgs->verbose) {
    2278           4 :         scs_special_print(work->stgs->do_override_streams,
    2279           2 :                 work->stgs->output_stream, "Setup time: %1.2es\n", info->setupTime / 1e3);
    2280             :     }
    2281         329 :     endInterruptListener();
    2282         329 :     return work;
    2283             : }
    2284             : 
    2285           2 : static void scs_compute_allocated_memory(
    2286             :         const ScsWork * RESTRICT work,
    2287             :         const ScsCone * RESTRICT k,
    2288             :         const ScsData * RESTRICT data,
    2289             :         ScsInfo * RESTRICT info) {
    2290           2 :     blasint temp_n_max = 0;
    2291             :     unsigned long long allocated_memory;
    2292             :     size_t i;
    2293           2 :     size_t float_size = (scs_int) sizeof (scs_float);
    2294           2 :     size_t int_size = (scs_int) sizeof (scs_int);
    2295           2 :     size_t l = data->m + data->n + 1;
    2296           2 :     long mem = work->stgs->memory;
    2297             : 
    2298           2 :     for (i = 0; i < k->ssize; ++i) {
    2299           0 :         if (k->s[i] > temp_n_max) {
    2300           0 :             temp_n_max = (blasint) k->s[i];
    2301             :         }
    2302             :     }
    2303             : 
    2304           2 :     allocated_memory =
    2305           4 :             float_size * (2 * data->A->p[data->A->n]
    2306           2 :             + 6 * data->m
    2307           2 :             + 9 * data->n
    2308           2 :             + k->qsize
    2309           2 :             + k->psize
    2310           2 :             + k->ssize
    2311           2 :             + 2 * temp_n_max * temp_n_max
    2312           2 :             + temp_n_max
    2313           2 :             + work->coneWork->lwork
    2314           2 :             + 10 * l)
    2315           4 :             + int_size * (2 * data->A->p[data->A->n]
    2316           2 :             + data->n
    2317           2 :             + work->coneWork->liwork
    2318           2 :             + data->m + 2);
    2319             : 
    2320           2 :     if (work->stgs->ls > 0) {
    2321           2 :         allocated_memory += float_size * 4 * l;
    2322             :     }
    2323           2 :     if (work->stgs->direction == restarted_broyden && mem > 0) {
    2324           2 :         allocated_memory += float_size * 2 * l * (mem + 1);
    2325             :     }
    2326           2 :     if (work->stgs->direction == anderson_acceleration) {
    2327           0 :         allocated_memory += float_size * (4 * l * mem + l
    2328           0 :                 + mem + scs_svd_workspace_size(l, mem));
    2329             :     }
    2330             : 
    2331           2 :     if (work->stgs->normalize) {
    2332           1 :         allocated_memory += float_size * (data->m + data->n);
    2333             :     }
    2334           2 :     info->allocated_memory = allocated_memory;
    2335           2 : }
    2336             : 
    2337             : #define SCS_BYTE_UNIT_STR_LEN 3
    2338             : 
    2339           2 : static void scs_units_allocated_mem(
    2340             :         const ScsInfo * RESTRICT info,
    2341             :         scs_float * memory,
    2342             :         char *unit_of_measurement) {
    2343           2 :     if (info->allocated_memory > 1e9) {
    2344             :         strncpy(unit_of_measurement, "GB", SCS_BYTE_UNIT_STR_LEN);
    2345           0 :         *memory = info->allocated_memory / 1e9;
    2346           2 :     } else if (info->allocated_memory > 1e6) {
    2347             :         strncpy(unit_of_measurement, "MB", SCS_BYTE_UNIT_STR_LEN);
    2348           0 :         *memory = info->allocated_memory / 1e6;
    2349           2 :     } else if (info->allocated_memory > 1e3) {
    2350             :         strncpy(unit_of_measurement, "kB", SCS_BYTE_UNIT_STR_LEN);
    2351           2 :         *memory = info->allocated_memory / 1e3;
    2352             :     } else {
    2353             :         strncpy(unit_of_measurement, "B", SCS_BYTE_UNIT_STR_LEN);
    2354           0 :         *memory = info->allocated_memory;
    2355             :     }
    2356           2 :     unit_of_measurement[SCS_BYTE_UNIT_STR_LEN - 1] = '\0';
    2357           2 : }
    2358             : 
    2359             : #define SCS_DIRECTION_STRING_LENGTH 24
    2360             : 
    2361           1 : static void scs_print_parameter_details(const ScsData * RESTRICT data) {
    2362           1 :     scs_int print_mode = data->stgs->do_override_streams;
    2363           1 :     FILE * stream = data->stgs->output_stream;
    2364             :     char dir_string[SCS_DIRECTION_STRING_LENGTH];
    2365           1 :     switch (data->stgs->direction) {
    2366             :         case anderson_acceleration:
    2367             :             strncpy(dir_string, "anderson", SCS_DIRECTION_STRING_LENGTH);
    2368             :             break;
    2369             :         case restarted_broyden:
    2370             :             strncpy(dir_string, "restarted broyden", SCS_DIRECTION_STRING_LENGTH);
    2371             :             break;
    2372             :         case fixed_point_residual:
    2373             :             strncpy(dir_string, "fixed point residual", SCS_DIRECTION_STRING_LENGTH);
    2374             :             break;
    2375             :         case full_broyden:
    2376             :             strncpy(dir_string, "full broyden", SCS_DIRECTION_STRING_LENGTH);
    2377             :             break;
    2378             :         default:
    2379             :             strncpy(dir_string, "unknown", SCS_DIRECTION_STRING_LENGTH);
    2380             :     }
    2381           3 :     scs_special_print(
    2382             :             print_mode,
    2383             :             stream,
    2384             :             "\nSettings:\n"
    2385             :             ".....................................................................\n"
    2386             :             "alpha          : %2.1f\t\t"
    2387             :             "beta           : %2.1f\n"
    2388             :             "c1             : %2.1f\t\t"
    2389             :             "c_bl           : %g\n"
    2390             :             "cg_rate        : %g\t\t"
    2391             :             "dir            : %s\n"
    2392             :             "superscs       : %s\t\t"
    2393             :             "eps            : %g\n"
    2394             :             "(k0, k1, k2)   : (%d, %d, %d)\t"
    2395             :             "ls             : %d\n"
    2396             :             "max_iters      : %d\t\t"
    2397             :             "max_time (min) : %g\n"
    2398             :             "memory         : %d\t\t"
    2399             :             "normalize      : %d\n"
    2400             :             "rho_x          : %g\t\t"
    2401             :             "scale          : %g\n"
    2402             :             "sigma          : %g\t\t"
    2403             :             "sse            : %g\n"
    2404             :             "thetabar       : %g\t\t"
    2405             :             "warm_start     : %d\n"
    2406             :             ".....................................................................\n\n",
    2407             :             (double) data->stgs->alpha,
    2408             :             (double) data->stgs->beta,
    2409             :             (double) data->stgs->c1,
    2410             :             (double) data->stgs->c_bl,
    2411             :             (double) data->stgs->cg_rate,
    2412             :             dir_string,
    2413           1 :             data->stgs->do_super_scs == 1 ? "yes" : "no",
    2414             :             (double) data->stgs->eps,
    2415             :             (int) data->stgs->k0,
    2416             :             (int) data->stgs->k1,
    2417             :             (int) data->stgs->k2,
    2418             :             (int) data->stgs->ls,
    2419             :             (int) data->stgs->max_iters,
    2420           1 :             (double) data->stgs->max_time_milliseconds / 60000,
    2421             :             (int) data->stgs->memory,
    2422             :             (int) data->stgs->normalize,
    2423             :             (double) data->stgs->rho_x,
    2424             :             (double) data->stgs->scale,
    2425             :             (double) data->stgs->sigma,
    2426             :             (double) data->stgs->sse,
    2427             :             (double) data->stgs->thetabar,
    2428             :             (int) data->stgs->warm_start);
    2429           1 : }
    2430             : 
    2431           2 : static void scs_print_allocated_memory(
    2432             :         const ScsData * RESTRICT data,
    2433             :         const ScsInfo * RESTRICT info) {
    2434           2 :     scs_int print_mode = data->stgs->do_override_streams;
    2435           2 :     FILE * stream = data->stgs->output_stream;
    2436           2 :     scs_float mem = 0;
    2437             :     char unit_mem[SCS_BYTE_UNIT_STR_LEN];
    2438           2 :     scs_units_allocated_mem(info, &mem, unit_mem);
    2439           2 :     scs_special_print(print_mode, stream, "Allocated Memory: %5.2f%s\n", (double) mem, unit_mem);
    2440           2 : }
    2441             : 
    2442             : /* this just calls scs_init, scs_solve, and scs_finish */
    2443         341 : scs_int scs(
    2444           2 :         const ScsData * RESTRICT data,
    2445             :         const ScsCone * RESTRICT cone,
    2446             :         ScsSolution * RESTRICT sol,
    2447             :         ScsInfo * RESTRICT info) {
    2448             :     scs_int status;
    2449             :     /* --------------------------------------------------
    2450             :      * Create a Work object. It may happen that scs_init
    2451             :      * returns SCS_NULL (e.g., if some parameter is out
    2452             :      * of range, or memory could not be allocated).
    2453             :      * -------------------------------------------------- */
    2454         341 :     if (data->stgs->verbose >= 2) scs_print_parameter_details(data);
    2455         341 :     ScsWork *work = scs_init(data, cone, info);
    2456         341 :     scs_int print_mode = data->stgs->do_override_streams;
    2457         341 :     FILE * stream = data->stgs->output_stream;
    2458             : 
    2459         341 :     if (work != SCS_NULL) {
    2460         329 :         if (work->stgs->do_super_scs) {
    2461             :             /* solve with SuperSCS*/
    2462         326 :             if (work->stgs->verbose > 0) {
    2463           2 :                 scs_special_print(print_mode, stream, "\nRunning SuperSCS...\n");
    2464           2 :                 scs_compute_allocated_memory(work, cone, data, info);
    2465           2 :                 scs_print_allocated_memory(data, info);
    2466             :             }
    2467         326 :             superscs_solve(work, data, cone, sol, info);
    2468             :         } else {
    2469             :             /* solve with SCS */
    2470           3 :             if (work->stgs->verbose > 0)
    2471           0 :                 scs_special_print(print_mode, stream, "Running Standard SCS...\n");
    2472           3 :             scs_solve(work, data, cone, sol, info);
    2473             :         }
    2474         329 :         status = info->statusVal;
    2475             :     } else {
    2476          12 :         status = scs_failure(SCS_NULL, data ? data->m : -1, data ? data->n : -1, sol, info,
    2477             :                 SCS_FAILED, "could not initialize work", "Failure", print_mode);
    2478             :     }
    2479         341 :     scs_finish(work);
    2480         341 :     return status;
    2481             : }
    2482             : 
    2483          19 : ScsSolution * scs_init_sol() {
    2484          19 :     ScsSolution * RESTRICT sol = scs_calloc(1, sizeof (* sol));
    2485          19 :     if (sol == SCS_NULL) {
    2486             :         /* LCOV_EXCL_START */
    2487             :         printf("ERROR: allocating sol failure\n");
    2488             :         return SCS_NULL;
    2489             :         /* LCOV_EXCL_STOP */
    2490             :     }
    2491          19 :     sol->s = SCS_NULL;
    2492          19 :     sol->x = SCS_NULL;
    2493          19 :     sol->y = SCS_NULL;
    2494          19 :     return sol;
    2495             : }
    2496             : 
    2497          19 : ScsInfo * scs_init_info() {
    2498          19 :     ScsInfo * RESTRICT info = scs_calloc(1, sizeof (*info));
    2499          19 :     if (info == SCS_NULL) {
    2500             :         /* LCOV_EXCL_START */
    2501             :         printf("ERROR: allocating info failure\n");
    2502             :         return SCS_NULL;
    2503             :         /* LCOV_EXCL_STOP */
    2504             :     }
    2505          19 :     info->pobj = NAN;
    2506          19 :     info->dobj = NAN;
    2507          19 :     info->iter = -1;
    2508          19 :     info->cg_total_iters = -1;
    2509          19 :     info->linsys_total_solve_time_ms = -1;
    2510          19 :     info->relGap = NAN;
    2511          19 :     info->resDual = NAN;
    2512          19 :     info->resInfeas = NAN;
    2513          19 :     info->resPri = NAN;
    2514          19 :     info->resUnbdd = NAN;
    2515          19 :     info->setupTime = NAN;
    2516          19 :     info->solveTime = NAN;
    2517          19 :     info->statusVal = SCS_INDETERMINATE;
    2518          19 :     info->progress_iter = SCS_NULL;
    2519          19 :     info->progress_dcost = SCS_NULL;
    2520          19 :     info->progress_pcost = SCS_NULL;
    2521          19 :     info->progress_relgap = SCS_NULL;
    2522          19 :     info->progress_resdual = SCS_NULL;
    2523          19 :     info->progress_respri = SCS_NULL;
    2524          19 :     info->progress_norm_fpr = SCS_NULL;
    2525          19 :     info->progress_time = SCS_NULL;
    2526          19 :     info->progress_mode = SCS_NULL;
    2527          19 :     info->progress_ls = SCS_NULL;
    2528          19 :     return info;
    2529             : }
    2530             : 
    2531          45 : ScsData * scs_init_data() {
    2532          45 :     ScsData * RESTRICT data = scs_malloc(sizeof (*data));
    2533             : 
    2534          45 :     if (data == SCS_NULL) {
    2535             :         /* LCOV_EXCL_START */
    2536             :         printf("ERROR: allocating data failure\n");
    2537             :         return SCS_NULL;
    2538             :         /* LCOV_EXCL_STOP */
    2539             :     }
    2540             : 
    2541          45 :     data->A = SCS_NULL;
    2542          45 :     data->b = SCS_NULL;
    2543          45 :     data->c = SCS_NULL;
    2544          45 :     data->m = 0;
    2545          45 :     data->n = 0;
    2546             : 
    2547          45 :     data->stgs = scs_malloc(sizeof (ScsSettings));
    2548          45 :     scs_set_default_settings(data);
    2549             : 
    2550          45 :     return data;
    2551             : }
    2552             : 

Generated by: LCOV version 1.10