LCOV - code coverage report
Current view: top level - src - linAlg.c (source / functions) Hit Total Coverage
Test: SuperSCS Unit Tests Lines: 139 139 100.0 %
Date: 2018-05-30 Functions: 20 20 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 "linAlg.h"
      29             : #include <math.h>
      30             : #include <stdio.h>
      31             : 
      32             : 
      33             : #ifdef LAPACK_LIB_FOUND
      34             : 
      35             : #define SCS_NO_SUFFIX 
      36             : #define SCS_IAMAX stitch__(i, BLAS(amax), SCS_NO_SUFFIX)
      37             : 
      38             : extern blasint SCS_IAMAX(
      39             :         const blasint *n,
      40             :         const scs_float *x,
      41             :         const blasint *inc_x);
      42             : 
      43             : extern scs_float BLAS(nrm2)(
      44             :         const blasint *n,
      45             :         const scs_float *x,
      46             :         const blasint *incx);
      47             : 
      48             : /* y += ax */
      49             : extern void BLAS(axpy)(
      50             :         const blasint* n,
      51             :         const scs_float* alpha,
      52             :         const scs_float* x,
      53             :         const blasint* inc_x,
      54             :         scs_float* y,
      55             :         const blasint* inc_y);
      56             : 
      57             : extern void BLAS(scal)(
      58             :         const blasint* n,
      59             :         const scs_float* alpha,
      60             :         scs_float* x,
      61             :         const blasint* inc_x);
      62             : 
      63             : extern scs_float BLAS(dot)(
      64             :         const blasint* n,
      65             :         const scs_float* x,
      66             :         const blasint* inc_x,
      67             :         const scs_float* y,
      68             :         const blasint* inc_y);
      69             : 
      70             : extern void BLAS(gemm)(
      71             :         const char* trans_a,
      72             :         const char* trans_b,
      73             :         const blasint* m,
      74             :         const blasint* n,
      75             :         const blasint* k,
      76             :         const scs_float* alpha,
      77             :         const scs_float* A,
      78             :         const blasint* lda,
      79             :         const scs_float* B,
      80             :         const blasint* ldb,
      81             :         const scs_float* beta,
      82             :         scs_float* C,
      83             :         const blasint* ldc);
      84             : 
      85             : extern void LPCK(gels)(
      86             :         const char* trans,
      87             :         const blasint* m,
      88             :         const blasint* n,
      89             :         const blasint* nrhs,
      90             :         const scs_float* a,
      91             :         const blasint* lda,
      92             :         scs_float* b,
      93             :         const blasint* ldb,
      94             :         scs_float* work,
      95             :         blasint* lwork,
      96             :         blasint* info);
      97             : 
      98             : extern void LPCK(gelss)(
      99             :         const blasint* m,
     100             :         const blasint* n,
     101             :         const blasint* nrhs,
     102             :         const scs_float* A,
     103             :         const blasint* lda,
     104             :         scs_float* b,
     105             :         const blasint* ldb,
     106             :         scs_float* S,
     107             :         const scs_float* rcond,
     108             :         blasint* rank,
     109             :         scs_float* work,
     110             :         blasint* lwork,
     111             :         blasint* info);
     112             : 
     113             : #define scs_iamax_ SCS_IAMAX
     114             : #define scs_nrm2_  BLAS(nrm2)
     115             : #define scs_axpy_  BLAS(axpy)
     116             : #define scs_scal_  BLAS(scal)
     117             : #define scs_dot_  BLAS(dot)
     118             : #define scs_gemm_ BLAS(gemm)
     119             : #define scs_gels_ LPCK(gels)
     120             : #define scs_dgelss_ LPCK(gelss)
     121             : #endif
     122             : 
     123             : /* static void printVec(char** name, int len, scs_float* x) {
     124             :     int i;
     125             :     for (i = 0; i < len; ++i) {
     126             :          printf("%s[%d]=%g\n", name, i, x[i]);
     127             :     }
     128             :     printf("\n");
     129             : }*/
     130             : 
     131             : 
     132             : /* LCOV_EXCL_START */
     133             : #define SCS_DGEMM_NN_MC  384
     134             : #define SCS_DGEMM_NN_KC  384
     135             : #define SCS_DGEMM_NN_NC  4096
     136             : 
     137             : #define SCS_DGEMM_NN_MR  4
     138             : #define SCS_DGEMM_NN_NR  4
     139             : 
     140             : /* 
     141             :  *   Local buffers for storing panels from A, B and C
     142             :  */
     143             : static double SCS_DGEMM_NN__A[SCS_DGEMM_NN_MC*SCS_DGEMM_NN_KC];
     144             : static double SCS_DGEMM_NN__B[SCS_DGEMM_NN_KC*SCS_DGEMM_NN_NC];
     145             : static double SCS_DGEMM_NN__C[SCS_DGEMM_NN_MR*SCS_DGEMM_NN_NR];
     146             : 
     147             : /*
     148             :  *  Packing complete panels from A (i.e. without padding)
     149             :  */
     150             : static void
     151             : scs_pack_MRxk(int k, const double *A, int incRowA, int incColA,
     152             :         double *buffer) {
     153             :     int i, j;
     154             : 
     155             :     for (j = 0; j < k; ++j) {
     156             :         for (i = 0; i < SCS_DGEMM_NN_MR; ++i) {
     157             :             buffer[i] = A[i * incRowA];
     158             :         }
     159             :         buffer += SCS_DGEMM_NN_MR;
     160             :         A += incColA;
     161             :     }
     162             : }
     163             : 
     164             : /*
     165             :  *  Packing panels from A with padding if required
     166             :  */
     167             : static void
     168             : scs_pack_A(int mc, int kc, const double *A, int incRowA, int incColA,
     169             :         double *buffer) {
     170             :     int mp = mc / SCS_DGEMM_NN_MR;
     171             :     int _mr = mc % SCS_DGEMM_NN_MR;
     172             : 
     173             :     int i;
     174             : 
     175             :     for (i = 0; i < mp; ++i) {
     176             :         scs_pack_MRxk(kc, A, incRowA, incColA, buffer);
     177             :         buffer += kc*SCS_DGEMM_NN_MR;
     178             :         A += SCS_DGEMM_NN_MR*incRowA;
     179             :     }
     180             :     if (_mr > 0) {
     181             :         int j;
     182             :         for (j = 0; j < kc; ++j) {
     183             :             for (i = 0; i < _mr; ++i) {
     184             :                 buffer[i] = A[i * incRowA];
     185             :             }
     186             :             for (i = _mr; i < SCS_DGEMM_NN_MR; ++i) {
     187             :                 buffer[i] = 0.0;
     188             :             }
     189             :             buffer += SCS_DGEMM_NN_MR;
     190             :             A += incColA;
     191             :         }
     192             :     }
     193             : }
     194             : 
     195             : /*
     196             :  *  Packing complete panels from B (i.e. without padding)
     197             :  */
     198             : static void
     199             : scs_pack_kxNR(int k, const double *B, int incRowB, int incColB,
     200             :         double *buffer) {
     201             :     int i, j;
     202             : 
     203             :     for (i = 0; i < k; ++i) {
     204             :         for (j = 0; j < SCS_DGEMM_NN_NR; ++j) {
     205             :             buffer[j] = B[j * incColB];
     206             :         }
     207             :         buffer += SCS_DGEMM_NN_NR;
     208             :         B += incRowB;
     209             :     }
     210             : }
     211             : 
     212             : /*
     213             :  *  Packing panels from B with padding if required
     214             :  */
     215             : static void
     216             : scs_pack_B(int kc, int nc, const double *B, int incRowB, int incColB,
     217             :         double *buffer) {
     218             :     int np = nc / SCS_DGEMM_NN_NR;
     219             :     int _nr = nc % SCS_DGEMM_NN_NR;
     220             : 
     221             :     int j;
     222             : 
     223             :     for (j = 0; j < np; ++j) {
     224             :         scs_pack_kxNR(kc, B, incRowB, incColB, buffer);
     225             :         buffer += kc*SCS_DGEMM_NN_NR;
     226             :         B += SCS_DGEMM_NN_NR*incColB;
     227             :     }
     228             :     if (_nr > 0) {
     229             :         int i;
     230             :         for (i = 0; i < kc; ++i) {
     231             :             for (j = 0; j < _nr; ++j) {
     232             :                 buffer[j] = B[j * incColB];
     233             :             }
     234             :             for (j = _nr; j < SCS_DGEMM_NN_NR; ++j) {
     235             :                 buffer[j] = 0.0;
     236             :             }
     237             :             buffer += SCS_DGEMM_NN_NR;
     238             :             B += incRowB;
     239             :         }
     240             :     }
     241             : }
     242             : 
     243             : /*
     244             :  *  Micro kernel for multiplying panels from A and B.
     245             :  */
     246             : static void
     247             : scs_dgemm_micro_kernel(int kc,
     248             :         double alpha, const double *A, const double *B,
     249             :         double beta,
     250             :         double *C, int incRowC, int incColC) {
     251             :     double AB[SCS_DGEMM_NN_MR * SCS_DGEMM_NN_NR];
     252             : 
     253             :     int i, j, l;
     254             : 
     255             :     /*  Compute AB = A*B */
     256             :     for (l = 0; l < SCS_DGEMM_NN_MR * SCS_DGEMM_NN_NR; ++l) {
     257             :         AB[l] = 0;
     258             :     }
     259             :     for (l = 0; l < kc; ++l) {
     260             :         for (j = 0; j < SCS_DGEMM_NN_NR; ++j) {
     261             :             for (i = 0; i < SCS_DGEMM_NN_MR; ++i) {
     262             :                 AB[i + j * SCS_DGEMM_NN_MR] += A[i] * B[j];
     263             :             }
     264             :         }
     265             :         A += SCS_DGEMM_NN_MR;
     266             :         B += SCS_DGEMM_NN_NR;
     267             :     }
     268             : 
     269             :     /*
     270             :      *  Update C <- beta*C
     271             :      */
     272             :     if (beta == 0.0) {
     273             :         for (j = 0; j < SCS_DGEMM_NN_NR; ++j) {
     274             :             for (i = 0; i < SCS_DGEMM_NN_MR; ++i) {
     275             :                 C[i * incRowC + j * incColC] = 0.0;
     276             :             }
     277             :         }
     278             :     } else if (beta != 1.0) {
     279             :         for (j = 0; j < SCS_DGEMM_NN_NR; ++j) {
     280             :             for (i = 0; i < SCS_DGEMM_NN_MR; ++i) {
     281             :                 C[i * incRowC + j * incColC] *= beta;
     282             :             }
     283             :         }
     284             :     }
     285             : 
     286             :     /*
     287             :      *  Update C <- C + alpha*AB (note: the case alpha==0.0 was already treated in
     288             :      *                                  the above layer dgemm_nn)
     289             :      */
     290             :     if (alpha == 1.0) {
     291             :         for (j = 0; j < SCS_DGEMM_NN_NR; ++j) {
     292             :             for (i = 0; i < SCS_DGEMM_NN_MR; ++i) {
     293             :                 C[i * incRowC + j * incColC] += AB[i + j * SCS_DGEMM_NN_MR];
     294             :             }
     295             :         }
     296             :     } else {
     297             :         for (j = 0; j < SCS_DGEMM_NN_NR; ++j) {
     298             :             for (i = 0; i < SCS_DGEMM_NN_MR; ++i) {
     299             :                 C[i * incRowC + j * incColC] += alpha * AB[i + j * SCS_DGEMM_NN_MR];
     300             :             }
     301             :         }
     302             :     }
     303             : }
     304             : 
     305             : /*
     306             :  *  Compute Y += alpha*X
     307             :  */
     308             : static void
     309             : scs_dgeaxpy(int m,
     310             :         int n,
     311             :         double alpha,
     312             :         const double *X,
     313             :         int incRowX,
     314             :         int incColX,
     315             :         double *Y,
     316             :         int incRowY,
     317             :         int incColY) {
     318             :     int i, j;
     319             : 
     320             : 
     321             :     if (alpha != 1.0) {
     322             :         for (j = 0; j < n; ++j) {
     323             :             for (i = 0; i < m; ++i) {
     324             :                 Y[i * incRowY + j * incColY] += alpha * X[i * incRowX + j * incColX];
     325             :             }
     326             :         }
     327             :     } else {
     328             :         for (j = 0; j < n; ++j) {
     329             :             for (i = 0; i < m; ++i) {
     330             :                 Y[i * incRowY + j * incColY] += X[i * incRowX + j * incColX];
     331             :             }
     332             :         }
     333             :     }
     334             : }
     335             : 
     336             : /*
     337             :  *  Compute X *= alpha
     338             :  */
     339             : static void
     340             : scs_dgescal(int m,
     341             :         int n,
     342             :         double alpha,
     343             :         double *X,
     344             :         int incRowX,
     345             :         int incColX) {
     346             :     int i, j;
     347             : 
     348             :     if (alpha != 0.0) {
     349             :         for (j = 0; j < n; ++j) {
     350             :             for (i = 0; i < m; ++i) {
     351             :                 X[i * incRowX + j * incColX] *= alpha;
     352             :             }
     353             :         }
     354             :     } else {
     355             :         for (j = 0; j < n; ++j) {
     356             :             for (i = 0; i < m; ++i) {
     357             :                 X[i * incRowX + j * incColX] = 0.0;
     358             :             }
     359             :         }
     360             :     }
     361             : }
     362             : 
     363             : /*
     364             :  * Macro Kernel for the multiplication of blocks of A and B.  We assume that
     365             :  *  these blocks were previously packed to buffers _A and _B.
     366             :  */
     367             : static void
     368             : scs_dgemm_macro_kernel(int mc,
     369             :         int nc,
     370             :         int kc,
     371             :         double alpha,
     372             :         double beta,
     373             :         double *C,
     374             :         int incRowC,
     375             :         int incColC) {
     376             :     int mp = (mc + SCS_DGEMM_NN_MR - 1) / SCS_DGEMM_NN_MR;
     377             :     int np = (nc + SCS_DGEMM_NN_NR - 1) / SCS_DGEMM_NN_NR;
     378             : 
     379             :     int _mr = mc % SCS_DGEMM_NN_MR;
     380             :     int _nr = nc % SCS_DGEMM_NN_NR;
     381             : 
     382             :     int mr;
     383             :     int i, j;
     384             : 
     385             :     for (j = 0; j < np; ++j) {
     386             :         int nr;
     387             :         nr = (j != np - 1 || _nr == 0) ? SCS_DGEMM_NN_NR : _nr;
     388             : 
     389             :         for (i = 0; i < mp; ++i) {
     390             :             mr = (i != mp - 1 || _mr == 0) ? SCS_DGEMM_NN_MR : _mr;
     391             : 
     392             :             if (mr == SCS_DGEMM_NN_MR && nr == SCS_DGEMM_NN_NR) {
     393             :                 scs_dgemm_micro_kernel(kc, alpha, &SCS_DGEMM_NN__A[i * kc * SCS_DGEMM_NN_MR], &SCS_DGEMM_NN__B[j * kc * SCS_DGEMM_NN_NR],
     394             :                         beta,
     395             :                         &C[i * SCS_DGEMM_NN_MR * incRowC + j * SCS_DGEMM_NN_NR * incColC],
     396             :                         incRowC, incColC);
     397             :             } else {
     398             :                 scs_dgemm_micro_kernel(kc, alpha, &SCS_DGEMM_NN__A[i * kc * SCS_DGEMM_NN_MR], &SCS_DGEMM_NN__B[j * kc * SCS_DGEMM_NN_NR],
     399             :                         0.0,
     400             :                         SCS_DGEMM_NN__C, 1, SCS_DGEMM_NN_MR);
     401             :                 scs_dgescal(mr, nr, beta,
     402             :                         &C[i * SCS_DGEMM_NN_MR * incRowC + j * SCS_DGEMM_NN_NR * incColC], incRowC, incColC);
     403             :                 scs_dgeaxpy(mr, nr, 1.0, SCS_DGEMM_NN__C, 1, SCS_DGEMM_NN_MR,
     404             :                         &C[i * SCS_DGEMM_NN_MR * incRowC + j * SCS_DGEMM_NN_NR * incColC], incRowC, incColC);
     405             :             }
     406             :         }
     407             :     }
     408             : }
     409             : 
     410             : /*  Compute C <- beta*C + alpha*A*B */
     411             : 
     412             : /**
     413             :  * Perofrms the operation
     414             :  * \f[
     415             :  *    C \leftarrow \beta C + \alpha A B
     416             :  * \f]
     417             :  * 
     418             :  * @param m number of rows of matrix \f$A\f$
     419             :  * @param n number of columns of matrix \f$B\f$
     420             :  * @param k number of rows of matrix \f$B\f$ (columns of \f$A\f$)
     421             :  * @param alpha coefficient \f$\alpha\f$
     422             :  * @param A pointer to matrix \f$A\f$
     423             :  * @param incRowA increment in traversing the rows of \f$A\f$
     424             :  * @param incColA increment in traversing the columns of \f$A\f$
     425             :  * @param B pointer to matrix \f$B\f$
     426             :  * @param incRowB increment in traversing the rows of \f$B\f$
     427             :  * @param incColB increment in traversing the columns of \f$B\f$
     428             :  * @param beta coefficient \f$\beta\f$
     429             :  * @param C pointer to matrix \f$C\f$
     430             :  * @param incRowC increment in traversing the rows of \f$C\f$
     431             :  * @param incColC increment in traversing the columns of \f$C\f$
     432             :  * 
     433             :  * @see ::scs_matrix_multiply
     434             :  * 
     435             :  * \note The implementation of this method is that of 
     436             :  * [ULMBLAS](http://apfel.mathematik.uni-ulm.de/~lehn/sghpc/gemm/page13/index.html).
     437             :  * 
     438             :  * \note The original source code is available at 
     439             :  * [this link](http://apfel.mathematik.uni-ulm.de/~lehn/sghpc/gemm/page13/index.html).
     440             :  * 
     441             :  * \note The [ULMBLAS project](https://github.com/michael-lehn/ulmBLAS) is available
     442             :  * on github and is licensed with the 
     443             :  * [new BSD licence](https://github.com/michael-lehn/ulmBLAS/blob/master/LICENSE).
     444             :  * 
     445             :  * \warning This function works only with \c double precision data.
     446             :  * 
     447             :  */
     448             : void
     449             : scs_dgemm_nn(int m,
     450             :         int n,
     451             :         int k,
     452             :         double alpha,
     453             :         const double *A,
     454             :         int incRowA,
     455             :         int incColA,
     456             :         const double *B,
     457             :         int incRowB,
     458             :         int incColB,
     459             :         double beta,
     460             :         double *C,
     461             :         int incRowC,
     462             :         int incColC) {
     463             :     int mb = (m + SCS_DGEMM_NN_MC - 1) / SCS_DGEMM_NN_MC;
     464             :     int nb = (n + SCS_DGEMM_NN_NC - 1) / SCS_DGEMM_NN_NC;
     465             :     int kb = (k + SCS_DGEMM_NN_KC - 1) / SCS_DGEMM_NN_KC;
     466             : 
     467             :     int _mc = m % SCS_DGEMM_NN_MC;
     468             :     int _nc = n % SCS_DGEMM_NN_NC;
     469             :     int _kc = k % SCS_DGEMM_NN_KC;
     470             : 
     471             :     int mc, kc;
     472             :     int i, j, l;
     473             : 
     474             :     double _beta;
     475             : 
     476             :     if (alpha == 0.0 || k == 0) {
     477             :         scs_dgescal(m, n, beta, C, incRowC, incColC);
     478             :         return;
     479             :     }
     480             : 
     481             :     for (j = 0; j < nb; ++j) {
     482             :         int nc;
     483             :         nc = (j != nb - 1 || _nc == 0) ? SCS_DGEMM_NN_NC : _nc;
     484             : 
     485             :         for (l = 0; l < kb; ++l) {
     486             :             kc = (l != kb - 1 || _kc == 0) ? SCS_DGEMM_NN_KC : _kc;
     487             :             _beta = (l == 0) ? beta : 1.0;
     488             : 
     489             :             scs_pack_B(kc, nc,
     490             :                     &B[l * SCS_DGEMM_NN_KC * incRowB + j * SCS_DGEMM_NN_NC * incColB], incRowB, incColB,
     491             :                     SCS_DGEMM_NN__B);
     492             : 
     493             :             for (i = 0; i < mb; ++i) {
     494             :                 mc = (i != mb - 1 || _mc == 0) ? SCS_DGEMM_NN_MC : _mc;
     495             : 
     496             :                 scs_pack_A(mc, kc,
     497             :                         &A[i * SCS_DGEMM_NN_MC * incRowA + l * SCS_DGEMM_NN_KC * incColA], incRowA, incColA,
     498             :                         SCS_DGEMM_NN__A);
     499             : 
     500             :                 scs_dgemm_macro_kernel(mc, nc, kc, alpha, _beta,
     501             :                         &C[i * SCS_DGEMM_NN_MC * incRowC + j * SCS_DGEMM_NN_NC * incColC],
     502             :                         incRowC, incColC);
     503             :             }
     504             :         }
     505             :     }
     506             : }
     507             : 
     508             : /* LCOV_EXCL_STOP */
     509             : 
     510             : 
     511             : 
     512          56 : void scs_matrix_multiply(
     513             :         scs_int m,
     514             :         scs_int n,
     515             :         scs_int k,
     516             :         scs_float alpha,
     517             :         const scs_float * RESTRICT A,
     518             :         scs_float beta,
     519             :         const scs_float * RESTRICT B,
     520             :         scs_float *C) {
     521             : #ifdef LAPACK_LIB_FOUND
     522             :     /* Use BLAS to multiply the two matrices */
     523          56 :     const char no_transpose = 'N';
     524          56 :     const blasint m_ = m;
     525          56 :     const blasint n_ = n;
     526          56 :     const blasint k_ = k;
     527          56 :     scs_gemm_(&no_transpose, &no_transpose,
     528             :             &m_, &n_, &k_, &alpha, A, &m_, B, &k_, &beta, C, &m_);
     529             : #else
     530             :     scs_dgemm_nn(m, n, k, alpha, A, 1, m, B, 1, k, beta, C, 1, m);
     531             : #endif
     532             : 
     533          56 : }
     534             : 
     535          15 : void scs_matrix_transpose_multiply(
     536             :         scs_int m,
     537             :         scs_int n,
     538             :         scs_int k,
     539             :         scs_float alpha,
     540             :         const scs_float *A,
     541             :         scs_float beta,
     542             :         const scs_float *B,
     543             :         scs_float *C) {
     544             : 
     545             : #ifdef LAPACK_LIB_FOUND
     546          15 :     const char no_transpose = 'N';
     547          15 :     const char transpose = 'T';
     548          15 :     const blasint m_ = m;
     549          15 :     const blasint n_ = n;
     550          15 :     const blasint k_ = k;
     551          15 :     scs_gemm_(&transpose, &no_transpose,
     552             :             &m_, &n_, &k_, &alpha, A, &k_, B, &k_, &beta, C, &m_);
     553             : #else
     554             :     scs_dgemm_nn(m, n, k, alpha, A, k, 1, B, 1, k, beta, C, 1, m);
     555             : #endif
     556             : 
     557             : 
     558          15 : }
     559             : 
     560             : /* x = b*a */
     561      200159 : void scs_set_as_scaled_array(
     562             :         scs_float * RESTRICT x,
     563             :         const scs_float * RESTRICT a,
     564             :         const scs_float b,
     565             :         scs_int len) {
     566             : #ifdef LAPACK_LIB_FOUND
     567      200159 :     memcpy(x, a, len * sizeof (*x));
     568      200159 :     scs_scale_array(x, b, len);
     569             : #else
     570             :     register scs_int j;
     571             :     const scs_int block_size = 4;
     572             :     const scs_int block_len = len >> 2;
     573             :     const scs_int remaining = len % block_size;
     574             :     j = 0;
     575             :     while (j < block_len * block_size) {
     576             :         x[j] = b * a[j];
     577             :         ++j;
     578             :         x[j] = b * a[j];
     579             :         ++j;
     580             :         x[j] = b * a[j];
     581             :         ++j;
     582             :         x[j] = b * a[j];
     583             :         ++j;
     584             :     }
     585             :     j = block_size * block_len;
     586             :     switch (remaining) {
     587             :         case 3: x[j + 2] = b * a[j + 2];
     588             :         case 2: x[j + 1] = b * a[j + 1];
     589             :         case 1: x[j] = b * a[j];
     590             :         case 0:;
     591             :     }
     592             : #endif
     593      200159 : }
     594             : 
     595             : /* a *= b */
     596      474909 : void scs_scale_array(scs_float * RESTRICT a, const scs_float b, scs_int len) {
     597             : #ifdef LAPACK_LIB_FOUND
     598      474909 :     const blasint one = 1;
     599      474909 :     const blasint len_ = len;
     600      474909 :     scs_scal_(&len_, &b, a, &one);
     601             : #else
     602             :     register scs_int j;
     603             :     const scs_int block_size = 4;
     604             :     const scs_int block_len = len >> 2;
     605             :     const scs_int remaining = len % block_size;
     606             :     j = 0;
     607             :     while (j < block_len * block_size) {
     608             :         a[j] *= b;
     609             :         ++j;
     610             :         a[j] *= b;
     611             :         ++j;
     612             :         a[j] *= b;
     613             :         ++j;
     614             :         a[j] *= b;
     615             :         ++j;
     616             :     }
     617             :     j = block_size * block_len;
     618             :     switch (remaining) {
     619             :         case 3: a[j + 2] *= b;
     620             :         case 2: a[j + 1] *= b;
     621             :         case 1: a[j] *= b;
     622             :         case 0:;
     623             :     }
     624             : #endif    
     625      474909 : }
     626             : 
     627             : /* x'*y */
     628      778615 : scs_float scs_inner_product(
     629             :         const scs_float * RESTRICT x,
     630             :         const scs_float * RESTRICT y,
     631             :         scs_int len) {
     632             : #ifdef LAPACK_LIB_FOUND
     633      778615 :     blasint one = 1;
     634      778615 :     const blasint len_ = len;
     635      778615 :     scs_float dot_product = scs_dot_(&len_, x, &one, y, &one);
     636      778615 :     return dot_product;
     637             : #else
     638             :     register scs_int j;
     639             :     register scs_float ip = 0.;
     640             :     register scs_float s0 = 0.;
     641             :     register scs_float s1 = 0.;
     642             :     register scs_float s2 = 0.;
     643             :     register scs_float s3 = 0.;
     644             :     static const scs_int block_size = 4;
     645             :     const scs_int block_len = len >> 2;
     646             :     const scs_int remaining = len % block_size;
     647             : 
     648             :     j = 0;
     649             :     while (j < block_len * block_size) {
     650             :         s0 += x[j] * y[j];
     651             :         ++j;
     652             :         s1 += x[j] * y[j];
     653             :         ++j;
     654             :         s2 += x[j] * y[j];
     655             :         ++j;
     656             :         s3 += x[j] * y[j];
     657             :         ++j;
     658             :     }
     659             :     ip = s0 + s1 + s2 + s3;
     660             :     j = block_size * block_len;
     661             :     switch (remaining) {
     662             :         case 3: ip += x[j + 2] * y[j + 2];
     663             :         case 2: ip += x[j + 1] * y[j + 1];
     664             :         case 1: ip += x[j] * y[j];
     665             :         case 0:;
     666             :     }
     667             :     return ip;
     668             : #endif
     669             : }
     670             : 
     671             : /* ||v||_2^2 */
     672      193729 : scs_float scs_norm_squared(const scs_float * RESTRICT v, scs_int len) {
     673      193729 :     return scs_inner_product(v, v, len);
     674             : }
     675             : 
     676             : /* ||v||_2 */
     677      123947 : scs_float scs_norm(const scs_float * RESTRICT v, scs_int len) {
     678             : #ifdef LAPACK_LIB_FOUND
     679      123947 :     blasint one = 1;
     680      123947 :     blasint len_ = len;
     681      123947 :     return scs_nrm2_(&len_, v, &one);
     682             : #else
     683             :     return SQRTF(scs_norm_squared(v, len));
     684             : #endif
     685             : }
     686             : 
     687           2 : scs_float scs_norm_infinity(
     688             :         const scs_float * RESTRICT a,
     689             :         scs_int l) {
     690             : #ifdef LAPACK_LIB_FOUND
     691           2 :     blasint one = 1;
     692           2 :     blasint len_ = l;
     693           2 :     blasint idx_max = scs_iamax_(&len_, a, &one);
     694           2 :     return a[idx_max];
     695             : #else
     696             :     scs_float tmp, max = 0.0;
     697             :     scs_int i;
     698             :     for (i = 0; i < l; ++i) {
     699             :         tmp = ABS(a[i]);
     700             :         if (tmp > max)
     701             :             max = tmp;
     702             :     }
     703             :     return max;
     704             : #endif
     705             : }
     706             : 
     707             : /* saxpy a += sc*b */
     708      997518 : void scs_add_scaled_array(
     709             :         scs_float * RESTRICT a,
     710             :         const scs_float * RESTRICT b,
     711             :         scs_int len,
     712             :         const scs_float sc) {
     713             : #ifdef LAPACK_LIB_FOUND    
     714      997518 :     blasint one = 1;
     715      997518 :     const blasint len_ = len;
     716      997518 :     scs_axpy_(&len_, &sc, b, &one, a, &one);
     717             : #else
     718             :     register scs_int j;
     719             :     const scs_int block_size = 4;
     720             :     const scs_int block_len = len >> 2; /* divide by 4*/
     721             :     const scs_int remaining = len % block_size;
     722             :     j = 0;
     723             :     while (j < block_len * block_size) {
     724             :         a[j] += sc * b[j];
     725             :         ++j;
     726             :         a[j] += sc * b[j];
     727             :         ++j;
     728             :         a[j] += sc * b[j];
     729             :         ++j;
     730             :         a[j] += sc * b[j];
     731             :         ++j;
     732             :     }
     733             :     j = block_size * block_len;
     734             :     switch (remaining) {
     735             :         case 3: a[j + 2] += sc * b[j + 2];
     736             :         case 2: a[j + 1] += sc * b[j + 1];
     737             :         case 1: a[j] += sc * b[j];
     738             :         case 0:;
     739             :     }
     740             : #endif
     741      997518 : }
     742             : 
     743      412485 : void scs_axpy(
     744             :         scs_float * RESTRICT x,
     745             :         const scs_float * RESTRICT u,
     746             :         const scs_float * RESTRICT v,
     747             :         scs_float alpha,
     748             :         scs_float beta,
     749             :         scs_int n) {
     750             : #ifdef LAPACK_LIB_FOUND
     751      412485 :     scs_float tol = 1e-16;
     752      412485 :     if (x != u) {
     753      409342 :         if (ABS(alpha - 1) > tol) {
     754             :             /* x = a * u */
     755      116109 :             scs_set_as_scaled_array(x, u, alpha, n);
     756             :         } else {
     757      293233 :             memcpy(x, u, n * sizeof (*x));
     758             :         }
     759             :     } else {
     760        3143 :         scs_scale_array(x, alpha, n);
     761             :     }
     762             :     /* x += b * v */
     763      412485 :     scs_add_scaled_array(x, v, n, beta);
     764             : #else
     765             :     register scs_int j;
     766             :     const scs_int block_size = 4;
     767             :     const scs_int block_len = n >> 2; /* divide by 4*/
     768             :     const scs_int remaining = n % block_size;
     769             :     j = 0;
     770             :     while (j < block_len * block_size) {
     771             :         x[j] = alpha * u[j] + beta * v[j];
     772             :         ++j;
     773             :         x[j] = alpha * u[j] + beta * v[j];
     774             :         ++j;
     775             :         x[j] = alpha * u[j] + beta * v[j];
     776             :         ++j;
     777             :         x[j] = alpha * u[j] + beta * v[j];
     778             :         ++j;
     779             :     }
     780             :     j = block_size * block_len;
     781             :     switch (remaining) {
     782             :         case 3: x[j + 2] = alpha * u[j + 2] + beta * v[j + 2];
     783             :         case 2: x[j + 1] = alpha * u[j + 1] + beta * v[j + 1];
     784             :         case 1: x[j] = alpha * u[j] + beta * v[j];
     785             :         case 0:;
     786             :     }
     787             : #endif
     788      412485 : }
     789             : 
     790       35567 : void scs_add_array(
     791             :         scs_float * RESTRICT a,
     792             :         const scs_float * RESTRICT b,
     793             :         scs_int len) {
     794             : #ifdef LAPACK_LIB_FOUND
     795       35567 :     scs_add_scaled_array(a, b, len, 1.0);
     796             : #else
     797             :     register scs_int j = 0;
     798             :     const scs_int block_size = 4;
     799             :     const scs_int block_len = len >> 2;
     800             :     const scs_int remaining = len % block_size;
     801             :     while (j < block_len * block_size) {
     802             :         a[j] += b[j];
     803             :         ++j;
     804             :         a[j] += b[j];
     805             :         ++j;
     806             :         a[j] += b[j];
     807             :         ++j;
     808             :         a[j] += b[j];
     809             :         ++j;
     810             :     }
     811             :     j = block_size * block_len;
     812             :     switch (remaining) {
     813             :         case 3: a[j + 2] += b[j + 2];
     814             :         case 2: a[j + 1] += b[j + 1];
     815             :         case 1: a[j] += b[j];
     816             :         case 0:;
     817             :     }
     818             : #endif
     819       35567 : }
     820             : 
     821           9 : void scs_subtract_array(
     822             :         scs_float * RESTRICT a,
     823             :         const scs_float * RESTRICT b,
     824             :         scs_int len) {
     825             : #ifdef LAPACK_LIB_FOUND
     826           9 :     scs_add_scaled_array(a, b, len, -1.0);
     827             : #else
     828             :     register scs_int j = 0;
     829             :     const scs_int block_size = 4;
     830             :     const scs_int block_len = len >> 2;
     831             :     const scs_int remaining = len % block_size;
     832             : 
     833             :     j = 0;
     834             :     while (j < block_len * block_size) {
     835             :         a[j] -= b[j];
     836             :         ++j;
     837             :         a[j] -= b[j];
     838             :         ++j;
     839             :         a[j] -= b[j];
     840             :         ++j;
     841             :         a[j] -= b[j];
     842             :         ++j;
     843             :     }
     844             :     j = block_size * block_len;
     845             :     switch (remaining) {
     846             :         case 3: a[j + 2] -= b[j + 2];
     847             :         case 2: a[j + 1] -= b[j + 1];
     848             :         case 1: a[j] -= b[j];
     849             :         case 0:;
     850             :     }
     851             : #endif
     852           9 : }
     853             : 
     854           1 : scs_float scs_norm_difference(
     855             :         const scs_float * RESTRICT a,
     856             :         const scs_float * RESTRICT b,
     857             :         scs_int l) {
     858           1 :     scs_float nmDiff = 0.0, tmp;
     859             :     scs_int i;
     860          11 :     for (i = 0; i < l; ++i) {
     861          10 :         tmp = (a[i] - b[i]);
     862          10 :         nmDiff += tmp * tmp;
     863             :     }
     864           1 :     return SQRTF(nmDiff);
     865             : }
     866             : 
     867          66 : scs_float scs_norm_infinity_difference(
     868             :         const scs_float * RESTRICT a,
     869             :         const scs_float * RESTRICT b,
     870             :         scs_int l) {
     871          66 :     scs_float tmp, max = 0.0;
     872             :     scs_int i;
     873       11435 :     for (i = 0; i < l; ++i) {
     874       11369 :         tmp = ABS(a[i] - b[i]);
     875       11369 :         if (tmp > max)
     876          58 :             max = tmp;
     877             :     }
     878          66 :     return max;
     879             : }
     880             : 
     881           3 : scs_float * scs_cgls_malloc_workspace(scs_int m, scs_int n) {
     882           3 :     const scs_int maxmn = m > n ? m : n;
     883           3 :     if (m <= 0 || n <= 0) {
     884             :         return SCS_NULL;
     885             :     }
     886           3 :     return malloc((maxmn + m + 2 * n) * sizeof (scs_float));
     887             : }
     888             : 
     889           3 : scs_int scs_cgls(
     890             :         scs_int m,
     891             :         scs_int n,
     892             :         const scs_float * RESTRICT A,
     893             :         const scs_float * RESTRICT b,
     894             :         scs_float * RESTRICT x,
     895             :         scs_float tol,
     896             :         scs_int * RESTRICT maxiter,
     897             :         scs_float * RESTRICT workspace
     898             :         ) {
     899           3 :     const scs_int maxmn = m > n ? m : n;
     900           3 :     scs_float * r = workspace;
     901           3 :     scs_float * p = r + n;
     902           3 :     scs_float * t = p;
     903           3 :     scs_float * xi = p + maxmn;
     904           3 :     scs_float * phi = xi + n;
     905             :     scs_float r_norm_old;
     906             :     scs_float r_norm_new;
     907             :     scs_int k;
     908             : 
     909             : 
     910             :     /* t = b */
     911           3 :     memcpy(t, b, m * sizeof (*t));
     912             :     /* t = t - Ax */
     913           3 :     scs_matrix_multiply(m, 1, n, -1.0, A, 1.0, x, t);
     914             :     /* r = A' * t */
     915           3 :     scs_matrix_transpose_multiply(n, 1, m, 1.0, A, 0.0, t, r);
     916             :     /* p = r */
     917           3 :     memcpy(p, r, n * sizeof (*p));
     918             :     /* r_norm_old = norm(r)^2 */
     919           3 :     r_norm_old = scs_norm_squared(r, n);
     920             : 
     921          11 :     for (k = 0; k < *maxiter; ++k) {
     922             :         double alpha;
     923             :         /* phi = A * p */
     924          11 :         scs_matrix_multiply(m, 1, n, 1.0, A, 0.0, p, phi);
     925             :         /* xi = A' * phi */
     926          11 :         scs_matrix_transpose_multiply(n, 1, m, 1.0, A, 0.0, phi, xi);
     927             :         /* alpha = r_norm_old / (p'*xi) */
     928          11 :         alpha = r_norm_old / scs_inner_product(p, xi, n);
     929             :         /*  x = x + alpha * p */
     930          11 :         scs_axpy(x, x, p, 1.0, alpha, n);
     931             :         /* r = r - alpha * xi */
     932          11 :         scs_axpy(r, r, xi, 1.0, -alpha, n);
     933             :         /* r_norm_new = norm(r)^2 */
     934          11 :         r_norm_new = scs_norm_squared(r, n);
     935          11 :         if (sqrt(r_norm_new) < tol) {
     936             :             break;
     937             :         }
     938             :         /* p = beta * p + r*/
     939           8 :         scs_axpy(p, p, r, r_norm_new / r_norm_old, 1.0, n);
     940           8 :         r_norm_old = r_norm_new;
     941             :     }
     942             : 
     943           3 :     if (k == *maxiter) {
     944             :         return 1;
     945             :     }
     946             : 
     947           3 :     *maxiter = k + 1;
     948             : 
     949           3 :     return 0;
     950             : }
     951             : 
     952             : #ifdef LAPACK_LIB_FOUND
     953             : 
     954           1 : scs_int scs_qr_workspace_size(
     955             :         scs_int m,
     956             :         scs_int n
     957             :         ) {
     958           1 :     blasint lwork = -1;
     959             :     blasint status;
     960           1 :     blasint nrhs = 1;
     961           1 :     blasint lda = m;
     962           1 :     blasint ldb = m;
     963             :     scs_float wkopt;
     964           1 :     blasint m_ = m;
     965           1 :     blasint n_ = n;
     966           1 :     if (m <= 0 || n <= 0) {
     967             :         return 0;
     968             :     }
     969           1 :     scs_gels_((char *) "No transpose", &m_, &n_, &nrhs, 0, &lda, 0, &ldb, &wkopt, &lwork,
     970             :             &status);
     971           1 :     return (scs_int) wkopt;
     972             : }
     973             : 
     974           1 : scs_int scs_qrls(
     975             :         scs_int m,
     976             :         scs_int n,
     977             :         scs_float * RESTRICT A,
     978             :         scs_float * RESTRICT b,
     979             :         scs_float * RESTRICT wspace,
     980             :         scs_int wsize
     981             :         ) {
     982             :     blasint status;
     983           1 :     blasint nrhs = 1;
     984           1 :     blasint lda = m;
     985           1 :     blasint ldb = m;
     986           1 :     blasint m_ = m;
     987           1 :     blasint n_ = n;
     988           1 :     blasint wsize_ = wsize;
     989           1 :     scs_gels_("No transpose", &m_, &n_, &nrhs, A, &lda, b, &ldb, wspace, &wsize_, &status);
     990           1 :     return status;
     991             : }
     992             : 
     993           5 : scs_int scs_svd_workspace_size(
     994             :         scs_int m,
     995             :         scs_int n
     996             :         ) {
     997             :     blasint status;
     998           5 :     blasint nrhs = 1;
     999           5 :     scs_float rcond = 1.;
    1000             :     scs_float wkopt;
    1001             :     scs_float singular_values;
    1002             :     blasint rank;
    1003           5 :     blasint lwork = -1;
    1004           5 :     blasint m_ = m;
    1005           5 :     blasint n_ = n;
    1006             : 
    1007           5 :     if (m <= 0 || n <= 0) {
    1008             :         return 0;
    1009             :     }
    1010             : 
    1011           5 :     scs_dgelss_(&m_, &n_, &nrhs, 0, &m_, 0, &m_,
    1012             :             &singular_values, &rcond, &rank,
    1013             :             &wkopt, &lwork, &status);
    1014             : 
    1015           5 :     return (scs_int) wkopt;
    1016             : }
    1017             : 
    1018          43 : scs_int scs_svdls(
    1019             :         scs_int m,
    1020             :         scs_int n,
    1021             :         scs_float * RESTRICT A,
    1022             :         scs_float * RESTRICT b,
    1023             :         scs_float * RESTRICT wspace,
    1024             :         scs_int wsize,
    1025             :         scs_float rcond,
    1026             :         scs_float * RESTRICT singular_values,
    1027             :         scs_int * RESTRICT rank
    1028             :         ) {
    1029             : 
    1030             :     blasint status;
    1031          43 :     blasint nrhs = 1;
    1032          43 :     blasint m_ = m;
    1033          43 :     blasint n_ = n;
    1034          43 :     blasint wsize_ = wsize;
    1035          43 :     blasint rank_ = *rank;
    1036          43 :     scs_dgelss_(&m_, &n_, &nrhs, A, &m_, b, &m_,
    1037             :             singular_values, &rcond, &rank_,
    1038             :             wspace, &wsize_, &status);
    1039          43 :     *rank = rank_;
    1040          43 :     return (scs_int) status;
    1041             : }
    1042             : #endif /* #ifdef LAPACK_LIB_FOUND */

Generated by: LCOV version 1.10