LCOV - code coverage report
Current view: top level - src - directions.c (source / functions) Hit Total Coverage
Test: SuperSCS Unit Tests Lines: 71 73 97.3 %
Date: 2018-05-30 Functions: 4 4 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             :  *
       8             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       9             :  * of this software and associated documentation files (the "Software"), to deal
      10             :  * in the Software without restriction, including without limitation the rights
      11             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12             :  * copies of the Software, and to permit persons to whom the Software is
      13             :  * furnished to do so, subject to the following conditions:
      14             :  *
      15             :  * The above copyright notice and this permission notice shall be included in all
      16             :  * copies or substantial portions of the Software.
      17             :  *
      18             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24             :  * SOFTWARE.
      25             :  * 
      26             :  */
      27             : #include "directions.h"
      28             : 
      29             : 
      30             : /*TODO Allocate this variable within work */
      31             : static scs_float * HY; /* Vector H*Y of length l */
      32             : 
      33        3620 : scs_int scs_reset_direction_cache(ScsDirectionCache * cache) {
      34        3620 :     cache->mem_cursor = 0; /* set active memory to 0 */
      35        3620 :     cache->current_mem = 0;
      36        3620 :     return SCS_DIRECTION_CACHE_RESET;
      37             : }
      38             : 
      39          41 : scs_int scs_compute_dir_anderson(ScsWork *work) {
      40             :     /* --- DECLARATIONS --- */
      41             :     ScsDirectionCache * cache; /* the SU cache (pointer) */
      42          41 :     const scs_int l = work->l; /* size of vectors */
      43             :     scs_float * s_current;
      44             :     scs_float * y_current;
      45             :     scs_float * s_minus_y_current;
      46             :     scs_int colsY;
      47             : 
      48             : #ifdef SVD_ACTIVATED
      49          41 :     scs_float rcond = 1e-8;
      50             :     scs_int rank;
      51             :     scs_float * singular_values;
      52             : #endif
      53             :     
      54             :     scs_float * copy_cache_Y;
      55             :     
      56          41 :     cache = work->direction_cache;
      57             : 
      58             : #ifdef SVD_ACTIVATED    
      59          41 :     singular_values = cache->ls_wspace + cache->ls_wspace_length;
      60          41 :     copy_cache_Y = singular_values + cache->mem;
      61             : #else
      62             :     copy_cache_Y = cache->ls_wspace + cache->ls_wspace_length;
      63             : #endif
      64             : 
      65             : 
      66             : 
      67             :     /* d [work->dir] = -R [work->R] */
      68          41 :     scs_set_as_scaled_array(work->dir, work->R, -1.0, l);
      69             : 
      70          41 :     s_current = cache->S + (cache->mem_cursor * l);
      71          41 :     y_current = cache->U + (cache->mem_cursor * l);
      72          41 :     s_minus_y_current = cache->S_minus_Y + (cache->mem_cursor * l);
      73             : 
      74          41 :     memcpy(s_current, work->Sk, l * sizeof (scs_float));
      75          41 :     memcpy(y_current, work->Yk, l * sizeof (scs_float));
      76             : 
      77          41 :     cache->current_mem++; /* increment the current memory */
      78          41 :     if (cache->current_mem > cache->mem)
      79          18 :         cache->current_mem = cache->mem;
      80             : 
      81          41 :     colsY = cache->current_mem;
      82             : 
      83             :     /* Construct matrix S-Y by subtracting one pair of vecs at a time */
      84          41 :     scs_axpy(s_minus_y_current, s_current, y_current, 1.0, -1.0, l);
      85             : 
      86             :     /* Solve Yt = R with SVD (we need to copy Y into a different memory positions
      87             :      * because svdls modifies it (see the documentation of svdls). */
      88          41 :     memcpy(cache->t, work->R, l * sizeof (scs_float));
      89          41 :     memcpy(copy_cache_Y, cache->U, l * colsY * sizeof (scs_float));
      90             : 
      91             : #ifdef SVD_ACTIVATED
      92             :     /* Solve LS with SVD */
      93          41 :     scs_svdls(l, colsY,
      94             :             copy_cache_Y,
      95             :             cache->t,
      96             :             cache->ls_wspace,
      97             :             cache->ls_wspace_length,
      98             :             rcond,
      99             :             singular_values,
     100             :             &rank);
     101             : #else   
     102             :     /* Solve LS with QR */
     103             :     scs_qrls(l, colsY,
     104             :             copy_cache_Y,
     105             :             cache->t,
     106             :             cache->ls_wspace,
     107             :             cache->ls_wspace_length);
     108             : #endif
     109             : 
     110             :     /* dir = dir - S_minus_Y * t */
     111          82 :     scs_matrix_multiply(l, 1, colsY, -1.0,
     112          41 :             cache->S_minus_Y, 1.0, cache->t, work->dir);
     113             : 
     114          41 :     cache->mem_cursor++; /* move the cursor */
     115          41 :     if (cache->mem_cursor >= cache->mem)
     116           7 :         cache->mem_cursor = 0;
     117             : 
     118          41 :     return SCS_DIRECTION_SUCCESS;
     119             : }
     120             : 
     121       34499 : scs_int scs_compute_dir_restarted_broyden(ScsWork *work) {
     122             :     /* --- DECLARATIONS --- */
     123             :     ScsDirectionCache * cache; /* the SU cache (pointer) */
     124             :     scs_int i; /* index */
     125             :     scs_float * s_tilde_current; /* s_tilde (which is updated) */
     126             :     scs_float * u_new; /* new value of u */
     127             :     scs_float ip; /* temporary float to store inner products */
     128             :     scs_float s_norm_sq; /* scalar gamma as in (6.5e) */
     129       34499 :     scs_float theta = 0; /* theta */
     130       34499 :     const scs_int l = work->l; /* size of vectors */
     131       34499 :     const scs_float theta_bar = work->stgs->thetabar; /* parameter in Powell's trick */
     132             : 
     133       34499 :     cache = work->direction_cache; /* cache of Sk and Uk */
     134             : 
     135             :     /* d [work->dir] = -R [work->R] */
     136       34499 :     scs_set_as_scaled_array(work->dir, work->R, -1.0, l);
     137             : 
     138             :     /* s_tilde_current = y [work->Yk]                                           */
     139             :     /* use the end of the cache to store s_tilde_current                        */
     140             :     /* later we use the same position of the S-buffer to store the current Sk   */
     141       34499 :     s_tilde_current = cache->S + (cache->mem_cursor * l);
     142       34499 :     memcpy(s_tilde_current, work->Yk, l * sizeof (scs_float));
     143             : 
     144             :     /* update s and d */
     145      188240 :     for (i = 0; i < cache->mem_cursor; ++i) {
     146             :         scs_float * s_i; /* pointer to the current value of s_i */
     147             :         scs_float * u_i; /* pointer to the current value of u_i */
     148      153741 :         s_i = cache->S + i * l; /* retrieve s_i from the cache */
     149      153741 :         u_i = cache->U + i * l; /* retrieve u_i from the cache */
     150      153741 :         ip = scs_inner_product(s_i, s_tilde_current, l);
     151      153741 :         scs_add_scaled_array(s_tilde_current, u_i, l, ip); /* update s_tilde */
     152      153741 :         ip = scs_inner_product(s_i, work->dir, l);
     153      153741 :         scs_add_scaled_array(work->dir, u_i, l, ip); /* update direction */
     154             :     }
     155             : 
     156             :     /* compute theta */
     157       34499 :     ip = scs_inner_product(s_tilde_current, work->Sk, l);
     158       34499 :     s_norm_sq = scs_norm_squared(work->Sk, l);
     159             : 
     160       34499 :     if (ABS(ip) >= theta_bar * s_norm_sq) {
     161             :         theta = 1;
     162             :     } else {
     163        3113 :         theta = s_norm_sq * (1 - SGN(ip) * theta_bar) / (s_norm_sq - ip);
     164             :         /* s_tilde_current = (1-theta)*s + theta*s_tilde_current */
     165        3113 :         scs_axpy(s_tilde_current, s_tilde_current, work->Sk, theta, 1 - theta, l);
     166             :     }
     167             : 
     168             :     /* FINALISE */
     169             : 
     170             :     /* update u_new (at the end of the buffer) */
     171       34499 :     u_new = cache->U + (cache->mem_cursor * l);
     172       34499 :     ip = (1 - theta) * s_norm_sq + theta * ip;
     173      377589 :     for (i = 0; i < l; ++i) {
     174      343090 :         u_new[i] = (work->Sk[i] - s_tilde_current[i]) / ip;
     175             :     }
     176             :     /* update direction */
     177       34499 :     ip = scs_inner_product(work->Sk, work->dir, l); /* s'd */
     178       34499 :     scs_add_scaled_array(work->dir, u_new, l, ip);
     179             : 
     180             :     /* push s into the buffer */
     181       34499 :     memcpy(s_tilde_current, work->Sk, l * sizeof (scs_float));
     182             : 
     183       34499 :     cache->mem_cursor++; /* move the cursor */
     184             : 
     185             :     /* if the cursor has exceeded the last position, reset the cache */
     186       34499 :     if (cache->mem_cursor >= cache->mem) {
     187        3295 :         return scs_reset_direction_cache(cache); /* returns SCS_DIRECTION_CACHE_RESET */
     188             :     }
     189             : 
     190             :     return SCS_DIRECTION_CACHE_INCREMENT;
     191             : }
     192             : 
     193             : /* LCOV_EXCL_START */
     194             : scs_int scs_compute_dir_full_broyden(ScsWork *work, scs_int i) {
     195             :     scs_float ip = 0;
     196             :     scs_float tmp = 0;
     197             : 
     198             :     if (i == 0 || HY == SCS_NULL) {
     199             :         /* HY is allocated the first time this function is called (that is, for i==0) */
     200             :         HY = malloc(work->l * sizeof (*HY));
     201             :         if (HY == SCS_NULL) {
     202             :             scs_printf("ERROR: allocating `HY` in `scs_compute_dir_full_broyden` failure\n");
     203             :             return SCS_DIRECTION_ERROR;
     204             :         }
     205             :     }
     206             : 
     207             :     if ((work->stgs->broyden_init_scaling && i == 1)
     208             :             || (work->stgs->tRule == 1 || work->stgs->tRule == 2)) {
     209             :         ip = scs_inner_product(work->Yk, work->Sk, work->l);
     210             :     }
     211             : 
     212             :     if (work->stgs->broyden_init_scaling && i == 1) {
     213             :         scs_int i;
     214             :         tmp = ip / scs_norm(work->Yk, work->l);
     215             :         for (i = 0; i < work->l; ++i) {
     216             :             work->H[i * (work->l + 1)] = tmp;
     217             :         }
     218             :     }
     219             : 
     220             :     return SCS_DIRECTION_SUCCESS;
     221             : }
     222             : 
     223             : /* LCOV_EXCL_STOP */
     224             : 
     225       29120 : scs_int scs_compute_direction(ScsWork *work, scs_int i) {
     226       29120 :     scs_int status = SCS_DIRECTION_SUCCESS;
     227             : 
     228       29120 :     switch (work->stgs->direction) {
     229             :         case fixed_point_residual:
     230          89 :             scs_set_as_scaled_array(work->dir, work->R, -1.0, work->l); /* dir = -R */
     231          89 :             status = SCS_DIRECTION_SUCCESS;
     232          89 :             break;
     233             :         case restarted_broyden:
     234       28990 :             status = scs_compute_dir_restarted_broyden(work);
     235       28990 :             break;
     236             :         case anderson_acceleration:
     237          41 :             status = scs_compute_dir_anderson(work);
     238          41 :             break;
     239             :         case full_broyden:
     240           0 :             status = scs_compute_dir_full_broyden(work, i);
     241           0 :             break;
     242             :         default:
     243             :             /* Not implemented yet */
     244             :             status = SCS_DIRECTION_ERROR;
     245             :     }
     246             : 
     247       29120 :     return status;
     248             : }
     249             : 
     250             : /* LCOV_EXCL_START */
     251             : void scs_free_full_broyden() {
     252             :     if (HY != SCS_NULL) {
     253             :         scs_free(HY);
     254             :     }
     255             : }
     256             : /* LCOV_EXCL_STOP */

Generated by: LCOV version 1.10