@@ -674,7 +674,7 @@ where
674674 . for_each ( |( ( y_plus_i, y_i) , w_alm_aux_i) | * y_plus_i = * w_alm_aux_i + * y_i / c) ;
675675
676676 // Step #3: y_plus := Proj_C(y_plus)
677- alm_set_c. project ( y_plus) ;
677+ alm_set_c. project ( y_plus) ? ;
678678
679679 // Step #4
680680 y_plus
@@ -691,7 +691,7 @@ where
691691 }
692692
693693 /// Project y on set Y
694- fn project_on_set_y ( & mut self ) {
694+ fn project_on_set_y ( & mut self ) -> FunctionCallResult {
695695 let problem = & self . alm_problem ;
696696 if let Some ( y_set) = & problem. alm_set_y {
697697 // NOTE: as_mut() converts from &mut Option<T> to Option<&mut T>
@@ -700,9 +700,10 @@ where
700700 // * which can be treated as Option<&mut [T]>
701701 // * y_vec is &mut [T]
702702 if let Some ( xi_vec) = self . alm_cache . xi . as_mut ( ) {
703- y_set. project ( & mut xi_vec[ 1 ..] ) ;
703+ y_set. project ( & mut xi_vec[ 1 ..] ) ? ;
704704 }
705705 }
706+ Ok ( ( ) )
706707 }
707708
708709 /// Solve inner problem
@@ -764,7 +765,7 @@ where
764765 inner_solver. solve ( u)
765766 }
766767
767- fn is_exit_criterion_satisfied ( & self ) -> bool {
768+ fn is_exit_criterion_satisfied ( & self ) -> Result < bool , SolverError > {
768769 let cache = & self . alm_cache ;
769770 let problem = & self . alm_problem ;
770771 // Criterion 1: ||Delta y|| <= c * delta
@@ -787,9 +788,14 @@ where
787788 // This function will panic is there is no akkt_tolerance
788789 // This should never happen because we set the AKKT tolerance
789790 // in the constructor and can never become `None` again
790- let criterion_3 =
791- cache. panoc_cache . akkt_tolerance . unwrap ( ) <= self . epsilon_tolerance + T :: epsilon ( ) ;
792- criterion_1 && criterion_2 && criterion_3
791+ let criterion_3 = cache
792+ . panoc_cache
793+ . akkt_tolerance
794+ . ok_or ( SolverError :: InvalidProblemState (
795+ "missing inner AKKT tolerance while checking the exit criterion" ,
796+ ) ) ?
797+ <= self . epsilon_tolerance + T :: epsilon ( ) ;
798+ Ok ( criterion_1 && criterion_2 && criterion_3)
793799 }
794800
795801 /// Whether the penalty parameter should not be updated
@@ -826,17 +832,23 @@ where
826832 }
827833 }
828834
829- fn update_inner_akkt_tolerance ( & mut self ) {
835+ fn update_inner_akkt_tolerance ( & mut self ) -> FunctionCallResult {
830836 let cache = & mut self . alm_cache ;
831837 // epsilon_{nu+1} := max(epsilon, beta*epsilon_nu)
832- let next_tolerance = cache. panoc_cache . akkt_tolerance . unwrap ( ) * self . epsilon_update_factor ;
833- cache
834- . panoc_cache
835- . set_akkt_tolerance ( if next_tolerance > self . epsilon_tolerance {
836- next_tolerance
837- } else {
838- self . epsilon_tolerance
839- } ) ;
838+ let akkt_tolerance =
839+ cache
840+ . panoc_cache
841+ . akkt_tolerance
842+ . ok_or ( SolverError :: InvalidProblemState (
843+ "missing inner AKKT tolerance while updating it" ,
844+ ) ) ?;
845+ let next_tolerance = akkt_tolerance * self . epsilon_update_factor ;
846+ cache. panoc_cache . set_akkt_tolerance ( if next_tolerance > self . epsilon_tolerance {
847+ next_tolerance
848+ } else {
849+ self . epsilon_tolerance
850+ } ) ;
851+ Ok ( ( ) )
840852 }
841853
842854 fn final_cache_update ( & mut self ) {
@@ -871,7 +883,7 @@ where
871883 let mut inner_exit_status: ExitStatus = ExitStatus :: Converged ;
872884
873885 // Project y on Y
874- self . project_on_set_y ( ) ;
886+ self . project_on_set_y ( ) ? ;
875887
876888 // If the inner problem fails miserably, the failure should be propagated
877889 // upstream (using `?`). If the inner problem has not converged, that is fine,
@@ -895,7 +907,7 @@ where
895907 self . compute_alm_infeasibility ( ) ?; // ALM: ||y_plus - y||
896908
897909 // Check exit criterion
898- if self . is_exit_criterion_satisfied ( ) {
910+ if self . is_exit_criterion_satisfied ( ) ? {
899911 // Do not continue the outer iteration
900912 // An (epsilon, delta)-AKKT point has been found
901913 return Ok ( InnerProblemStatus :: new ( false , inner_exit_status) ) ;
@@ -904,7 +916,7 @@ where
904916 }
905917
906918 // Update inner problem tolerance
907- self . update_inner_akkt_tolerance ( ) ;
919+ self . update_inner_akkt_tolerance ( ) ? ;
908920
909921 // conclusive step: updated iteration count, resets PANOC cache,
910922 // sets f2_norm = f2_norm_plus etc
@@ -1010,12 +1022,11 @@ where
10101022 . with_penalty ( c)
10111023 . with_cost ( cost) ;
10121024 if self . alm_problem . n1 > 0 {
1013- let status = status. with_lagrange_multipliers (
1014- self . alm_cache
1015- . y_plus
1016- . as_ref ( )
1017- . expect ( "Although n1 > 0, there is no vector y (Lagrange multipliers)" ) ,
1018- ) ;
1025+ let status = status. with_lagrange_multipliers ( self . alm_cache . y_plus . as_ref ( ) . ok_or (
1026+ SolverError :: InvalidProblemState (
1027+ "missing Lagrange multipliers at the ALM solution" ,
1028+ ) ,
1029+ ) ?) ;
10191030 Ok ( status)
10201031 } else {
10211032 Ok ( status)
@@ -1163,7 +1174,7 @@ mod tests {
11631174 . with_initial_penalty ( 25.0 )
11641175 . with_initial_lagrange_multipliers ( & [ 2. , 3. , 4. , 10. ] ) ;
11651176
1166- alm_optimizer. project_on_set_y ( ) ;
1177+ alm_optimizer. project_on_set_y ( ) . unwrap ( ) ;
11671178 if let Some ( xi_after_proj) = & alm_optimizer. alm_cache . xi {
11681179 println ! ( "xi = {:#?}" , xi_after_proj) ;
11691180 let y_projected_correct = [
@@ -1316,7 +1327,7 @@ mod tests {
13161327 . with_initial_inner_tolerance ( 1e-1 )
13171328 . with_inner_tolerance_update_factor ( 0.2 ) ;
13181329
1319- alm_optimizer. update_inner_akkt_tolerance ( ) ;
1330+ alm_optimizer. update_inner_akkt_tolerance ( ) . unwrap ( ) ;
13201331
13211332 unit_test_utils:: assert_nearly_equal (
13221333 0.1 ,
@@ -1339,7 +1350,7 @@ mod tests {
13391350 ) ;
13401351
13411352 for _i in 1 ..=5 {
1342- alm_optimizer. update_inner_akkt_tolerance ( ) ;
1353+ alm_optimizer. update_inner_akkt_tolerance ( ) . unwrap ( ) ;
13431354 }
13441355 unit_test_utils:: assert_nearly_equal (
13451356 2e-5 ,
@@ -1445,20 +1456,20 @@ mod tests {
14451456
14461457 // should not exit yet...
14471458 assert ! (
1448- !alm_optimizer. is_exit_criterion_satisfied( ) ,
1459+ !alm_optimizer. is_exit_criterion_satisfied( ) . unwrap ( ) ,
14491460 "exists right away"
14501461 ) ;
14511462
14521463 let alm_optimizer = alm_optimizer
14531464 . with_initial_inner_tolerance ( 1e-3 )
14541465 . with_epsilon_tolerance ( 1e-3 ) ;
1455- assert ! ( !alm_optimizer. is_exit_criterion_satisfied( ) ) ;
1466+ assert ! ( !alm_optimizer. is_exit_criterion_satisfied( ) . unwrap ( ) ) ;
14561467
14571468 alm_optimizer. alm_cache . delta_y_norm_plus = 1e-3 ;
1458- assert ! ( !alm_optimizer. is_exit_criterion_satisfied( ) ) ;
1469+ assert ! ( !alm_optimizer. is_exit_criterion_satisfied( ) . unwrap ( ) ) ;
14591470
14601471 alm_optimizer. alm_cache . f2_norm_plus = 1e-3 ;
1461- assert ! ( alm_optimizer. is_exit_criterion_satisfied( ) ) ;
1472+ assert ! ( alm_optimizer. is_exit_criterion_satisfied( ) . unwrap ( ) ) ;
14621473 }
14631474
14641475 #[ test]
0 commit comments