1use crate::conv_check::opt_error::OptErrorConvCheck;
24use crate::eq_mult::least_square::LeastSquareMults;
25use crate::hess::exact::ExactHessianUpdater;
26use crate::hess::lim_mem_quasi_newton::{LimMemQuasiNewtonUpdater, UpdateType};
27use crate::init::default::DefaultIterateInitializer;
28use crate::init::warm_start::WarmStartIterateInitializer;
29use crate::kkt::aug_system_solver::AugSystemSolver;
30use crate::kkt::low_rank_aug_system_solver::LowRankAugSystemSolver;
31use crate::kkt::pd_full_space_solver::PdFullSpaceSolver;
32use crate::kkt::pd_search_dir_calc::PdSearchDirCalc;
33use crate::kkt::perturbation_handler::PdPerturbationHandler;
34use crate::kkt::std_aug_system_solver::StdAugSystemSolver;
35use crate::line_search::backtracking::BacktrackingLineSearch;
36use crate::line_search::filter_acceptor::FilterLsAcceptor;
37use crate::line_search::ls_acceptor::BacktrackingLsAcceptor;
38use crate::line_search::penalty_acceptor::PenaltyLsAcceptor;
39use crate::mu::adaptive::{AdaptiveMuUpdate, MuOracleKind};
40use crate::mu::monotone::MonotoneMuUpdate;
41use crate::output::orig::OrigIterationOutput;
42use pounce_common::types::{Index, Number};
43use pounce_linsol::{SparseSymLinearSolverInterface, TSymLinearSolver};
44use std::cell::RefCell;
45use std::rc::Rc;
46
47pub type LinearBackendFactory =
53 Box<dyn FnMut(LinearSolverChoice) -> Box<dyn SparseSymLinearSolverInterface>>;
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
61pub enum AlgorithmChoice {
62 #[default]
63 InteriorPoint,
64 ActiveSetSqp,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum LinearSolverChoice {
69 Ma57,
70 Feral,
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
85pub enum LinearSystemScalingChoice {
86 #[default]
87 None,
88 Ruiz,
89 Mc19,
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub enum MuStrategyChoice {
94 Monotone,
95 Adaptive,
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
99pub enum HessianApproxChoice {
100 Exact,
101 LimitedMemory,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum LineSearchChoice {
106 Filter,
107 CgPenalty,
108 Penalty,
109}
110
111pub struct AlgorithmBundle {
114 pub mu_update: Box<dyn crate::mu::r#trait::MuUpdate>,
115 pub conv_check: Box<dyn crate::conv_check::r#trait::ConvCheck>,
116 pub init: Box<dyn crate::init::r#trait::IterateInitializer>,
117 pub eq_mult: Box<dyn crate::eq_mult::r#trait::EqMultCalculator>,
118 pub hess: Box<dyn crate::hess::r#trait::HessianUpdater>,
119 pub line_search: BacktrackingLineSearch,
120 pub iter_output: Box<dyn crate::output::r#trait::IterationOutput>,
121 pub search_dir: Option<PdSearchDirCalc>,
125}
126
127#[derive(Debug, Clone)]
131pub struct ConvCheckOptions {
132 pub tol: Number,
133 pub dual_inf_tol: Number,
134 pub constr_viol_tol: Number,
135 pub compl_inf_tol: Number,
136 pub acceptable_tol: Number,
137 pub acceptable_dual_inf_tol: Number,
138 pub acceptable_constr_viol_tol: Number,
139 pub acceptable_compl_inf_tol: Number,
140 pub acceptable_obj_change_tol: Number,
141 pub acceptable_iter: Index,
142 pub max_iter: Index,
143 pub max_cpu_time: Number,
144 pub max_wall_time: Number,
145 pub infeas_stationarity_tol: Number,
146 pub infeas_viol_kappa: Number,
147 pub infeas_max_streak: Index,
148}
149
150impl Default for ConvCheckOptions {
151 fn default() -> Self {
152 Self {
153 tol: 1e-8,
154 dual_inf_tol: 1.0,
155 constr_viol_tol: 1e-4,
156 compl_inf_tol: 1e-4,
157 acceptable_tol: 1e-6,
158 acceptable_dual_inf_tol: 1e10,
159 acceptable_constr_viol_tol: 1e-2,
160 acceptable_compl_inf_tol: 1e-2,
161 acceptable_obj_change_tol: 1e20,
162 acceptable_iter: 15,
163 max_iter: 3000,
164 max_cpu_time: 1e6,
165 max_wall_time: 1e6,
166 infeas_stationarity_tol: 1e-8,
167 infeas_viol_kappa: 1e2,
168 infeas_max_streak: 5,
169 }
170 }
171}
172
173#[derive(Debug, Clone)]
174pub struct AlgorithmBuilder {
175 pub algorithm: AlgorithmChoice,
183 pub linear_solver: LinearSolverChoice,
184 pub linear_system_scaling: LinearSystemScalingChoice,
188 pub linear_scaling_on_demand: bool,
195 pub mu_strategy: MuStrategyChoice,
196 pub mu_oracle: MuOracleKind,
200 pub hessian_approximation: HessianApproxChoice,
201 pub limited_memory_update_type: UpdateType,
202 pub limited_memory_max_history: i32,
205 pub line_search_method: LineSearchChoice,
206 pub warm_start_init_point: bool,
207 pub mehrotra_algorithm: bool,
216 pub conv_check: ConvCheckOptions,
217 pub mu: MuOptions,
218 pub line_search: LineSearchOptions,
219 pub output: OutputOptions,
220 pub warm: WarmStartOptions,
221 pub sqp: crate::sqp::SqpOptions,
224 pub sqp_qp: pounce_qp::QpOptions,
230 pub init: InitOptions,
231}
232
233#[derive(Debug, Clone)]
240pub struct InitOptions {
241 pub bound_push: Number,
242 pub bound_frac: Number,
243 pub slack_bound_push: Number,
244 pub slack_bound_frac: Number,
245 pub constr_mult_init_max: Number,
246 pub bound_mult_init_val: Number,
247 pub bound_mult_init_method: String,
250 pub least_square_init_primal: bool,
256}
257
258impl Default for InitOptions {
259 fn default() -> Self {
260 Self {
261 bound_push: 1e-2,
262 bound_frac: 1e-2,
263 slack_bound_push: 1e-2,
264 slack_bound_frac: 1e-2,
265 constr_mult_init_max: 1e3,
266 bound_mult_init_val: 1.0,
267 bound_mult_init_method: "constant".into(),
268 least_square_init_primal: false,
269 }
270 }
271}
272
273#[derive(Debug, Clone)]
286pub struct WarmStartOptions {
287 pub bound_push: Number,
288 pub bound_frac: Number,
289 pub slack_bound_push: Number,
290 pub slack_bound_frac: Number,
291 pub mult_bound_push: Number,
292 pub mult_init_max: Number,
293 pub target_mu: Number,
294 pub entire_iterate: bool,
295 pub same_structure: bool,
296}
297
298impl Default for WarmStartOptions {
299 fn default() -> Self {
300 Self {
301 bound_push: 1e-3,
302 bound_frac: 1e-3,
303 slack_bound_push: 1e-3,
304 slack_bound_frac: 1e-3,
305 mult_bound_push: 1e-3,
306 mult_init_max: 1e6,
307 target_mu: 0.0,
308 entire_iterate: false,
309 same_structure: false,
310 }
311 }
312}
313
314#[derive(Debug, Clone)]
321pub struct MuOptions {
322 pub mu_init: Number,
323 pub mu_max: Number,
324 pub mu_max_fact: Number,
325 pub mu_min: Number,
326 pub mu_target: Number,
327 pub mu_linear_decrease_factor: Number,
328 pub mu_superlinear_decrease_power: Number,
329 pub mu_allow_fast_monotone_decrease: bool,
330 pub barrier_tol_factor: Number,
331 pub sigma_max: Number,
336 pub sigma_min: Number,
337 pub adaptive_mu_globalization: crate::mu::adaptive::AdaptiveMuGlobalization,
343 pub quality_function_norm_type: crate::mu::oracle::quality_function::NormType,
347 pub quality_function_centrality: crate::mu::oracle::quality_function::CentralityType,
350 pub quality_function_balancing_term: crate::mu::oracle::quality_function::BalancingTermType,
354 pub quality_function_max_section_steps: i32,
357 pub quality_function_section_sigma_tol: Number,
360 pub quality_function_section_qf_tol: Number,
363 pub adaptive_mu_safeguard_factor: Number,
366 pub adaptive_mu_monotone_init_factor: Number,
370 pub adaptive_mu_restore_previous_iterate: bool,
374 pub adaptive_mu_kkterror_red_iters: usize,
377 pub adaptive_mu_kkterror_red_fact: Number,
380 pub adaptive_mu_kkt_norm_type: crate::mu::adaptive::AdaptiveMuKktNorm,
383 pub probing_iterate_quality_factor: Number,
394}
395
396impl Default for MuOptions {
397 fn default() -> Self {
398 Self {
399 mu_init: 0.1,
400 mu_max: -1.0,
401 mu_max_fact: 1e3,
402 mu_min: 1e-11,
403 mu_target: 0.0,
404 mu_linear_decrease_factor: 0.2,
405 mu_superlinear_decrease_power: 1.5,
406 mu_allow_fast_monotone_decrease: true,
407 barrier_tol_factor: 10.0,
408 sigma_max: 1e2,
409 sigma_min: 1e-6,
410 adaptive_mu_globalization:
411 crate::mu::adaptive::AdaptiveMuGlobalization::ObjConstrFilter,
412 quality_function_norm_type:
413 crate::mu::oracle::quality_function::NormType::TwoNormSquared,
414 quality_function_centrality: crate::mu::oracle::quality_function::CentralityType::None,
415 quality_function_balancing_term:
416 crate::mu::oracle::quality_function::BalancingTermType::None,
417 quality_function_max_section_steps: 8,
418 quality_function_section_sigma_tol: 1e-2,
419 quality_function_section_qf_tol: 0.0,
420 adaptive_mu_safeguard_factor: 0.0,
421 adaptive_mu_monotone_init_factor: 0.8,
422 adaptive_mu_restore_previous_iterate: false,
423 adaptive_mu_kkterror_red_iters: 4,
424 adaptive_mu_kkterror_red_fact: 0.9999,
425 adaptive_mu_kkt_norm_type: crate::mu::adaptive::AdaptiveMuKktNorm::TwoNormSquared,
426 probing_iterate_quality_factor: 1e4,
427 }
428 }
429}
430
431#[derive(Debug, Clone)]
434pub struct LineSearchOptions {
435 pub watchdog_shortened_iter_trigger: Index,
436 pub watchdog_trial_iter_max: Index,
437 pub soft_resto_pderror_reduction_factor: Number,
441 pub max_soft_resto_iters: Index,
444 pub accept_every_trial_step: bool,
452 pub alpha_for_y: crate::line_search::backtracking::AlphaForY,
456}
457
458impl Default for LineSearchOptions {
459 fn default() -> Self {
460 Self {
461 watchdog_shortened_iter_trigger: 10,
462 watchdog_trial_iter_max: 3,
463 soft_resto_pderror_reduction_factor: 1.0 - 1e-4,
464 max_soft_resto_iters: 10,
465 accept_every_trial_step: false,
466 alpha_for_y: crate::line_search::backtracking::AlphaForY::Primal,
467 }
468 }
469}
470
471#[derive(Debug, Clone)]
475pub struct OutputOptions {
476 pub print_frequency_iter: Index,
477 pub print_frequency_time: Number,
478 pub print_info_string: bool,
482 pub inf_pr_output_internal: bool,
487}
488
489impl Default for OutputOptions {
490 fn default() -> Self {
491 Self {
492 print_frequency_iter: 1,
493 print_frequency_time: 0.0,
494 print_info_string: false,
495 inf_pr_output_internal: false,
496 }
497 }
498}
499
500impl Default for AlgorithmBuilder {
501 fn default() -> Self {
502 Self {
503 algorithm: AlgorithmChoice::default(),
504 linear_solver: LinearSolverChoice::Feral,
505 linear_system_scaling: LinearSystemScalingChoice::None,
506 linear_scaling_on_demand: true,
507 mu_strategy: MuStrategyChoice::Monotone,
508 mu_oracle: MuOracleKind::QualityFunction,
509 hessian_approximation: HessianApproxChoice::Exact,
510 limited_memory_update_type: UpdateType::Bfgs,
511 limited_memory_max_history: 6,
512 line_search_method: LineSearchChoice::Filter,
513 warm_start_init_point: false,
514 mehrotra_algorithm: false,
515 conv_check: ConvCheckOptions::default(),
516 mu: MuOptions::default(),
517 line_search: LineSearchOptions::default(),
518 output: OutputOptions::default(),
519 warm: WarmStartOptions::default(),
520 sqp: crate::sqp::SqpOptions::default(),
521 sqp_qp: pounce_qp::QpOptions::default(),
522 init: InitOptions::default(),
523 }
524 }
525}
526
527impl AlgorithmBuilder {
528 pub fn new() -> Self {
529 Self::default()
530 }
531
532 pub fn build(&self) -> AlgorithmBundle {
536 self.build_inner(None)
537 }
538
539 pub fn build_with_backend(&self, mut factory: LinearBackendFactory) -> AlgorithmBundle {
543 let backend = factory(self.linear_solver);
544 let scaling: Option<Box<dyn pounce_linsol::TSymScalingMethod>> =
545 match self.linear_system_scaling {
546 LinearSystemScalingChoice::None => None,
547 LinearSystemScalingChoice::Ruiz => {
548 Some(Box::new(pounce_linsol::RuizTSymScalingMethod::new()))
549 }
550 LinearSystemScalingChoice::Mc19 => {
551 tracing::warn!(target: "pounce::algorithm",
552 "pounce: linear_system_scaling=mc19 not yet implemented; using no scaling"
553 );
554 None
555 }
556 };
557 let linsol = TSymLinearSolver::new(backend, scaling, self.linear_scaling_on_demand);
558 let inner_aug = StdAugSystemSolver::new(linsol);
559 let aug_solver: Box<dyn AugSystemSolver> = if matches!(
565 self.hessian_approximation,
566 HessianApproxChoice::LimitedMemory
567 ) {
568 Box::new(LowRankAugSystemSolver::new(Box::new(inner_aug)))
569 } else {
570 Box::new(inner_aug)
571 };
572 let perturb = Rc::new(RefCell::new(PdPerturbationHandler::new()));
573 let pd_solver = PdFullSpaceSolver::new(aug_solver, perturb);
574 let mut search_dir = PdSearchDirCalc::new(pd_solver);
575 search_dir.mehrotra_algorithm = self.mehrotra_algorithm;
576 self.build_inner(Some(search_dir))
577 }
578
579 pub fn build_sqp_with_backend(
589 &self,
590 mut factory: LinearBackendFactory,
591 ) -> Option<crate::sqp::SqpAlgorithm> {
592 if !matches!(self.algorithm, AlgorithmChoice::ActiveSetSqp) {
593 return None;
594 }
595 let backend = factory(self.linear_solver);
596 let qp_solver = pounce_qp::ParametricActiveSetSolver::new(backend);
597 Some(
598 crate::sqp::SqpAlgorithm::new(qp_solver, self.sqp.clone())
599 .with_qp_options(self.sqp_qp.clone()),
600 )
601 }
602
603 fn build_inner(&self, search_dir: Option<PdSearchDirCalc>) -> AlgorithmBundle {
604 let mu_update: Box<dyn crate::mu::r#trait::MuUpdate> = match self.mu_strategy {
605 MuStrategyChoice::Monotone => {
606 let mut m = MonotoneMuUpdate::new();
607 m.mu_init = self.mu.mu_init;
608 if self.mu.mu_max > 0.0 {
611 m.mu_max = self.mu.mu_max;
612 }
613 m.mu_min = self.mu.mu_min;
614 m.mu_target = self.mu.mu_target;
615 m.mu_linear_decrease_factor = self.mu.mu_linear_decrease_factor;
616 m.mu_superlinear_decrease_power = self.mu.mu_superlinear_decrease_power;
617 m.mu_allow_fast_monotone_decrease = self.mu.mu_allow_fast_monotone_decrease;
618 m.barrier_tol_factor = self.mu.barrier_tol_factor;
619 m.compl_inf_tol = self.conv_check.compl_inf_tol;
620 Box::new(m)
621 }
622 MuStrategyChoice::Adaptive => {
623 let mut adaptive = AdaptiveMuUpdate::new();
624 adaptive.mu_oracle = self.mu_oracle;
625 adaptive.mu_init = self.mu.mu_init;
626 adaptive.mu_max = self.mu.mu_max;
630 adaptive.mu_max_fact = self.mu.mu_max_fact;
631 adaptive.mu_min = self.mu.mu_min;
632 adaptive.mu_linear_decrease_factor = self.mu.mu_linear_decrease_factor;
633 adaptive.mu_superlinear_decrease_power = self.mu.mu_superlinear_decrease_power;
634 adaptive.barrier_tol_factor = self.mu.barrier_tol_factor;
635 adaptive.sigma_min = self.mu.sigma_min;
636 adaptive.sigma_max = self.mu.sigma_max;
637 adaptive.adaptive_mu_globalization = self.mu.adaptive_mu_globalization;
638 adaptive.qf_norm_type = self.mu.quality_function_norm_type;
639 adaptive.qf_centrality_type = self.mu.quality_function_centrality;
640 adaptive.qf_balancing_term = self.mu.quality_function_balancing_term;
641 adaptive.qf_max_section_steps = self.mu.quality_function_max_section_steps;
642 adaptive.qf_section_sigma_tol = self.mu.quality_function_section_sigma_tol;
643 adaptive.qf_section_qf_tol = self.mu.quality_function_section_qf_tol;
644 adaptive.probing_iterate_quality_factor = self.mu.probing_iterate_quality_factor;
645 adaptive.adaptive_mu_safeguard_factor = self.mu.adaptive_mu_safeguard_factor;
646 adaptive.adaptive_mu_monotone_init_factor =
647 self.mu.adaptive_mu_monotone_init_factor;
648 adaptive.restore_accepted_iterate = self.mu.adaptive_mu_restore_previous_iterate;
649 adaptive.adaptive_mu_kkterror_red_iters = self.mu.adaptive_mu_kkterror_red_iters;
650 adaptive.adaptive_mu_kkterror_red_fact = self.mu.adaptive_mu_kkterror_red_fact;
651 adaptive.adaptive_mu_kkt_norm = self.mu.adaptive_mu_kkt_norm_type;
652 Box::new(adaptive)
653 }
654 };
655
656 let acceptor: Box<dyn BacktrackingLsAcceptor> = match self.line_search_method {
657 LineSearchChoice::Filter => Box::new(FilterLsAcceptor::default()),
658 LineSearchChoice::Penalty => Box::new(PenaltyLsAcceptor::default()),
659 LineSearchChoice::CgPenalty => Box::new(PenaltyLsAcceptor::default()),
663 };
664 let mut line_search = BacktrackingLineSearch::new(acceptor);
665 line_search.watchdog_shortened_iter_trigger =
666 self.line_search.watchdog_shortened_iter_trigger;
667 line_search.watchdog_trial_iter_max = self.line_search.watchdog_trial_iter_max;
668 line_search.soft_resto_pderror_reduction_factor =
669 self.line_search.soft_resto_pderror_reduction_factor;
670 line_search.max_soft_resto_iters = self.line_search.max_soft_resto_iters;
671 line_search.accept_every_trial_step = self.line_search.accept_every_trial_step;
672 line_search.alpha_for_y = self.line_search.alpha_for_y;
673
674 let conv_check: Box<dyn crate::conv_check::r#trait::ConvCheck> =
675 Box::new(OptErrorConvCheck {
676 tol: self.conv_check.tol,
677 dual_inf_tol: self.conv_check.dual_inf_tol,
678 constr_viol_tol: self.conv_check.constr_viol_tol,
679 compl_inf_tol: self.conv_check.compl_inf_tol,
680 acceptable_tol: self.conv_check.acceptable_tol,
681 acceptable_dual_inf_tol: self.conv_check.acceptable_dual_inf_tol,
682 acceptable_constr_viol_tol: self.conv_check.acceptable_constr_viol_tol,
683 acceptable_compl_inf_tol: self.conv_check.acceptable_compl_inf_tol,
684 acceptable_obj_change_tol: self.conv_check.acceptable_obj_change_tol,
685 acceptable_iter: self.conv_check.acceptable_iter,
686 max_iter: self.conv_check.max_iter,
687 max_cpu_time: self.conv_check.max_cpu_time,
688 max_wall_time: self.conv_check.max_wall_time,
689 acceptable_count: 0,
690 last_acceptable_obj: None,
691 infeas_stationarity_tol: self.conv_check.infeas_stationarity_tol,
692 infeas_viol_kappa: self.conv_check.infeas_viol_kappa,
693 infeas_max_streak: self.conv_check.infeas_max_streak,
694 infeas_streak: 0,
695 });
696
697 let init: Box<dyn crate::init::r#trait::IterateInitializer> = if self.warm_start_init_point
698 {
699 Box::new(WarmStartIterateInitializer::with_options(self.warm.clone()))
700 } else {
701 let mut d = DefaultIterateInitializer::with_eq_mult_calculator(Box::new(
702 LeastSquareMults::new(),
703 ));
704 d.bound_push = self.init.bound_push;
705 d.bound_frac = self.init.bound_frac;
706 d.slack_bound_push = self.init.slack_bound_push;
707 d.slack_bound_frac = self.init.slack_bound_frac;
708 d.constr_mult_init_max = self.init.constr_mult_init_max;
709 d.bound_mult_init_val = self.init.bound_mult_init_val;
710 d.bound_mult_init_method = self.init.bound_mult_init_method.clone();
711 d.least_square_init_primal = self.init.least_square_init_primal;
712 Box::new(d)
713 };
714
715 let eq_mult: Box<dyn crate::eq_mult::r#trait::EqMultCalculator> =
716 Box::new(LeastSquareMults::new());
717
718 let hess: Box<dyn crate::hess::r#trait::HessianUpdater> = match self.hessian_approximation {
719 HessianApproxChoice::Exact => Box::new(ExactHessianUpdater::new()),
720 HessianApproxChoice::LimitedMemory => Box::new(LimMemQuasiNewtonUpdater {
721 update_type: self.limited_memory_update_type,
722 max_history: self.limited_memory_max_history,
723 ..LimMemQuasiNewtonUpdater::default()
724 }),
725 };
726
727 let iter_output: Box<dyn crate::output::r#trait::IterationOutput> = {
728 use crate::output::orig::{InfPrTag, PrintInfoString};
729 let mut o = OrigIterationOutput::new();
730 o.print_frequency_iter = self.output.print_frequency_iter;
731 o.print_frequency_time = self.output.print_frequency_time;
732 o.print_info_string = if self.output.print_info_string {
733 PrintInfoString::Yes
734 } else {
735 PrintInfoString::No
736 };
737 o.inf_pr_output = if self.output.inf_pr_output_internal {
738 InfPrTag::Internal
739 } else {
740 InfPrTag::Original
741 };
742 Box::new(o)
743 };
744
745 AlgorithmBundle {
746 mu_update,
747 conv_check,
748 init,
749 eq_mult,
750 hess,
751 line_search,
752 iter_output,
753 search_dir,
754 }
755 }
756}
757
758#[cfg(test)]
759mod tests {
760 use super::*;
761
762 #[test]
763 fn default_builder_assembles() {
764 let bundle = AlgorithmBuilder::new().build();
765 let _ = bundle.line_search.acceptor();
768 assert!(bundle.search_dir.is_none());
769 }
770
771 #[test]
772 fn build_with_backend_assembles_search_dir_chain() {
773 let factory: LinearBackendFactory = Box::new(|_| {
776 Box::new(pounce_feral::FeralSolverInterface::new())
777 as Box<dyn SparseSymLinearSolverInterface>
778 });
779 let bundle = AlgorithmBuilder::new().build_with_backend(factory);
780 assert!(bundle.search_dir.is_some());
781 }
782
783 #[test]
784 fn limited_memory_sr1_propagates() {
785 let b = AlgorithmBuilder {
786 hessian_approximation: HessianApproxChoice::LimitedMemory,
787 limited_memory_update_type: UpdateType::Sr1,
788 ..AlgorithmBuilder::default()
789 };
790 let _bundle = b.build();
791 }
792
793 #[test]
794 fn every_strategy_combination_assembles_without_panic() {
795 let solvers = [LinearSolverChoice::Ma57, LinearSolverChoice::Feral];
796 let mu = [MuStrategyChoice::Monotone, MuStrategyChoice::Adaptive];
797 let hess = [
798 HessianApproxChoice::Exact,
799 HessianApproxChoice::LimitedMemory,
800 ];
801 let ls = [
802 LineSearchChoice::Filter,
803 LineSearchChoice::CgPenalty,
804 LineSearchChoice::Penalty,
805 ];
806 for &linear_solver in &solvers {
807 for &mu_strategy in &mu {
808 for &hessian_approximation in &hess {
809 for &line_search_method in &ls {
810 let _ = AlgorithmBuilder {
811 algorithm: AlgorithmChoice::default(),
812 linear_solver,
813 linear_system_scaling: LinearSystemScalingChoice::None,
814 linear_scaling_on_demand: true,
815 mu_strategy,
816 mu_oracle: MuOracleKind::QualityFunction,
817 hessian_approximation,
818 limited_memory_update_type: UpdateType::Bfgs,
819 limited_memory_max_history: 6,
820 line_search_method,
821 warm_start_init_point: false,
822 mehrotra_algorithm: false,
823 conv_check: ConvCheckOptions::default(),
824 mu: MuOptions::default(),
825 line_search: LineSearchOptions::default(),
826 output: OutputOptions::default(),
827 warm: WarmStartOptions::default(),
828 sqp: crate::sqp::SqpOptions::default(),
829 sqp_qp: pounce_qp::QpOptions::default(),
830 init: InitOptions::default(),
831 }
832 .build();
833 }
834 }
835 }
836 }
837 }
838}