4
4
#include "scs_blas.h" /* contains BLAS(X) macros and type info */
5
5
#include "util.h"
6
6
7
- #define CONE_TOL (1e-9)
8
- #define CONE_THRESH (1e-8)
9
- #define EXP_CONE_MAX_ITERS (100)
10
7
#define BOX_CONE_MAX_ITERS (25)
8
+ #define POW_CONE_TOL (1e-9)
11
9
#define POW_CONE_MAX_ITERS (20)
12
10
13
11
/* Box cone limits (+ or -) taken to be INF */
@@ -35,6 +33,11 @@ void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
35
33
36
34
#endif
37
35
36
+ /* Forward declare exponential cone projection routine.
37
+ * Implemented in exp_cone.c.
38
+ */
39
+ scs_float SCS (proj_pd_exp_cone )(scs_float * v0 , scs_int primal );
40
+
38
41
void SCS (free_cone )(ScsCone * k ) {
39
42
if (k ) {
40
43
if (k -> bu )
@@ -325,118 +328,6 @@ char *SCS(get_cone_header)(const ScsCone *k) {
325
328
return tmp ;
326
329
}
327
330
328
- static scs_float exp_newton_one_d (scs_float rho , scs_float y_hat ,
329
- scs_float z_hat , scs_float w ) {
330
- scs_float t_prev , t = MAX (w - z_hat , MAX (- z_hat , 1e-9 ));
331
- scs_float f = 1. , fp = 1. ;
332
- scs_int i ;
333
- for (i = 0 ; i < EXP_CONE_MAX_ITERS ; ++ i ) {
334
- t_prev = t ;
335
- f = t * (t + z_hat ) / rho / rho - y_hat / rho + log (t / rho ) + 1 ;
336
- fp = (2 * t + z_hat ) / rho / rho + 1 / t ;
337
-
338
- t = t - f / fp ;
339
-
340
- if (t <= - z_hat ) {
341
- t = - z_hat ;
342
- break ;
343
- } else if (t <= 0 ) {
344
- t = 0 ;
345
- break ;
346
- } else if (ABS (t - t_prev ) < CONE_TOL ) {
347
- break ;
348
- } else if (SQRTF (f * f / fp ) < CONE_TOL ) {
349
- break ;
350
- }
351
- }
352
- if (i == EXP_CONE_MAX_ITERS ) {
353
- scs_printf ("warning: exp cone newton step hit maximum %i iters\n" , (int )i );
354
- scs_printf ("rho=%1.5e; y_hat=%1.5e; z_hat=%1.5e; w=%1.5e; f=%1.5e, "
355
- "fp=%1.5e, t=%1.5e, t_prev= %1.5e\n" ,
356
- rho , y_hat , z_hat , w , f , fp , t , t_prev );
357
- }
358
- return t + z_hat ;
359
- }
360
-
361
- static void exp_solve_for_x_with_rho (const scs_float * v , scs_float * x ,
362
- scs_float rho , scs_float w ) {
363
- x [2 ] = exp_newton_one_d (rho , v [1 ], v [2 ], w );
364
- x [1 ] = (x [2 ] - v [2 ]) * x [2 ] / rho ;
365
- x [0 ] = v [0 ] - rho ;
366
- }
367
-
368
- static scs_float exp_calc_grad (const scs_float * v , scs_float * x , scs_float rho ,
369
- scs_float w ) {
370
- exp_solve_for_x_with_rho (v , x , rho , w );
371
- if (x [1 ] <= 1e-12 ) {
372
- return x [0 ];
373
- }
374
- return x [0 ] + x [1 ] * log (x [1 ] / x [2 ]);
375
- }
376
-
377
- static void exp_get_rho_ub (const scs_float * v , scs_float * x , scs_float * ub ,
378
- scs_float * lb ) {
379
- * lb = 0 ;
380
- * ub = 0.125 ;
381
- while (exp_calc_grad (v , x , * ub , v [1 ]) > 0 ) {
382
- * lb = * ub ;
383
- (* ub ) *= 2 ;
384
- }
385
- }
386
-
387
- /* project onto the exponential cone, v has dimension *exactly* 3 */
388
- static scs_int proj_exp_cone (scs_float * v ) {
389
- scs_int i ;
390
- scs_float ub , lb , rho , g , x [3 ];
391
- scs_float r = v [0 ], s = v [1 ], t = v [2 ];
392
-
393
- /* v in cl(Kexp) */
394
- if ((s * exp (r / s ) - t <= CONE_THRESH && s > 0 ) ||
395
- (r <= 0 && s == 0 && t >= 0 )) {
396
- return 0 ;
397
- }
398
-
399
- /* -v in Kexp^* */
400
- if ((r > 0 && r * exp (s / r ) + exp (1 ) * t <= CONE_THRESH ) ||
401
- (r == 0 && s <= 0 && t <= 0 )) {
402
- memset (v , 0 , 3 * sizeof (scs_float ));
403
- return 0 ;
404
- }
405
-
406
- /* special case with analytical solution */
407
- if (r < 0 && s < 0 ) {
408
- v [1 ] = 0.0 ;
409
- v [2 ] = MAX (v [2 ], 0 );
410
- return 0 ;
411
- }
412
-
413
- /* iterative procedure to find projection, bisects on dual variable: */
414
- exp_get_rho_ub (v , x , & ub , & lb ); /* get starting upper and lower bounds */
415
- for (i = 0 ; i < EXP_CONE_MAX_ITERS ; ++ i ) {
416
- rho = (ub + lb ) / 2 ; /* halfway between upper and lower bounds */
417
- g = exp_calc_grad (v , x , rho , x [1 ]); /* calculates gradient wrt dual var */
418
- if (g > 0 ) {
419
- lb = rho ;
420
- } else {
421
- ub = rho ;
422
- }
423
- if (ub - lb < CONE_TOL ) {
424
- break ;
425
- }
426
- }
427
- #if VERBOSITY > 10
428
- scs_printf ("exponential cone proj iters %i\n" , (int )i );
429
- #endif
430
- if (i == EXP_CONE_MAX_ITERS ) {
431
- scs_printf ("warning: exp cone outer step hit maximum %i iters\n" , (int )i );
432
- scs_printf ("r=%1.5e; s=%1.5e; t=%1.5e\n" , r , s , t );
433
- }
434
- v [0 ] = x [0 ];
435
- v [1 ] = x [1 ];
436
- v [2 ] = x [2 ];
437
- return 0 ;
438
- }
439
-
440
331
static scs_int set_up_sd_cone_work_space (ScsConeWork * c , const ScsCone * k ) {
441
332
scs_int i ;
442
333
#ifdef USE_LAPACK
@@ -741,13 +632,13 @@ static void proj_power_cone(scs_float *v, scs_float a) {
741
632
scs_int i ;
742
633
/* v in K_a */
743
634
if (xh >= 0 && yh >= 0 &&
744
- CONE_THRESH + POWF (xh , a ) * POWF (yh , (1 - a )) >= rh ) {
635
+ POW_CONE_TOL + POWF (xh , a ) * POWF (yh , (1 - a )) >= rh ) {
745
636
return ;
746
637
}
747
638
748
639
/* -v in K_a^* */
749
640
if (xh <= 0 && yh <= 0 &&
750
- CONE_THRESH + POWF (- xh , a ) * POWF (- yh , 1 - a ) >=
641
+ POW_CONE_TOL + POWF (- xh , a ) * POWF (- yh , 1 - a ) >=
751
642
rh * POWF (a , a ) * POWF (1 - a , 1 - a )) {
752
643
v [0 ] = v [1 ] = v [2 ] = 0 ;
753
644
return ;
@@ -760,7 +651,7 @@ static void proj_power_cone(scs_float *v, scs_float a) {
760
651
y = pow_calc_x (r , yh , rh , 1 - a );
761
652
762
653
f = pow_calc_f (x , y , r , a );
763
- if (ABS (f ) < CONE_TOL ) {
654
+ if (ABS (f ) < POW_CONE_TOL ) {
764
655
break ;
765
656
}
766
657
@@ -829,51 +720,16 @@ static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
829
720
}
830
721
}
831
722
832
- if (k -> ep ) { /* doesn't use r_y */
833
- /*
834
- * exponential cone is not self dual, if s \in K
835
- * then y \in K^* and so if K is the primal cone
836
- * here we project onto K^*, via Moreau
837
- * \Pi_C^*(y) = y + \Pi_C(-y)
838
- */
723
+ if (k -> ep || k -> ed ) { /* doesn't use r_y */
839
724
#ifdef _OPENMP
840
725
#pragma omp parallel for
841
726
#endif
842
- for (i = 0 ; i < k -> ep ; ++ i ) {
843
- proj_exp_cone (& (x [count + 3 * i ]));
727
+ for (i = 0 ; i < k -> ep + k -> ed ; ++ i ) {
728
+ /* provided in exp_cone.c */
729
+ SCS (proj_pd_exp_cone )(& (x [count + 3 * i ]), i < k -> ep );
844
730
}
845
- count += 3 * k -> ep ;
731
+ count += 3 * ( k -> ep + k -> ed ) ;
846
732
}
847
-
848
- /* dual exponential cone */
849
- if (k -> ed ) { /* doesn't use r_y */
850
- /*
851
- * exponential cone is not self dual, if s \in K
852
- * then y \in K^* and so if K is the primal cone
853
- * here we project onto K^*, via Moreau
854
- * \Pi_C^*(y) = y + \Pi_C(-y)
855
- */
856
- scs_int idx ;
857
- scs_float r , s , t ;
858
- SCS (scale_array )(& (x [count ]), -1 , 3 * k -> ed ); /* x = -x; */
859
- #ifdef _OPENMP
860
- #pragma omp parallel for private(r, s, t, idx)
861
- #endif
862
- for (i = 0 ; i < k -> ed ; ++ i ) {
863
- idx = count + 3 * i ;
864
- r = x [idx ];
865
- s = x [idx + 1 ];
866
- t = x [idx + 2 ];
867
-
868
- proj_exp_cone (& (x [idx ]));
869
-
870
- x [idx ] -= r ;
871
- x [idx + 1 ] -= s ;
872
- x [idx + 2 ] -= t ;
873
- }
874
- count += 3 * k -> ed ;
875
- }
876
-
877
733
if (k -> psize && k -> p ) { /* doesn't use r_y */
878
734
scs_float v [3 ];
879
735
scs_int idx ;
0 commit comments