| ︙ | | |
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
|
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
|
-
+
-
-
-
+
+
+
-
+
-
+
|
Descent,
/// No step but the algorithm has been terminated.
Term,
}
/// Information about a minorant.
#[derive(Debug, Clone)]
struct MinorantInfo<Pr> {
struct MinorantInfo {
/// The minorant's index in the master problem
index: usize,
/// Current multiplier.
multiplier: Real,
/// Primal associated with this minorant.
primal: Option<Pr>,
}
/// Information about the last iteration.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum IterationInfo {
NewMinorantTooHigh { new: Real, old: Real },
UpperBoundNullStep,
ShallowCut,
}
/// State information for the update callback.
pub struct UpdateState<'a, Pr: 'a> {
/// Current model minorants.
minorants: &'a [Vec<MinorantInfo<Pr>>],
minorants: &'a [Vec<MinorantInfo>],
/// The primals.
primals: &'a Vec<Option<Pr>>,
/// The last step type.
pub step: Step,
/// Iteration information.
pub iteration_info: &'a [IterationInfo],
/// The current candidate. If the step was a descent step, this is
/// the new center.
pub nxt_y: &'a DVector,
/// The center. IF the step was a descent step, this is the old
/// center.
pub cur_y: &'a DVector,
}
impl<'a, Pr: 'a> UpdateState<'a, Pr> {
pub fn aggregated_primals(&self, subproblem: usize) -> Vec<(Real, &Pr)> {
self.minorants[subproblem]
.iter()
.map(|m| (m.multiplier, m.primal.as_ref().unwrap()))
.map(|m| (m.multiplier, self.primals[m.index].as_ref().unwrap()))
.collect()
}
/// Return the last primal for a given subproblem.
///
/// This is the last primal generated by the oracle.
pub fn last_primal(&self, fidx: usize) -> Option<&Pr> {
self.minorants[fidx].last().and_then(|m| m.primal.as_ref())
self.minorants[fidx].last().and_then(|m| self.primals[m.index].as_ref())
}
}
/// The default builder.
pub type FullMasterBuilder = master::boxed::Builder<master::cpx::Builder>;
/**
|
| ︙ | | |
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
|
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
|
-
+
+
+
+
|
*/
start_time: Instant,
/// The master problem.
master: M::MasterProblem,
/// The active minorant indices for each subproblem.
minorants: Vec<Vec<MinorantInfo<P::Primal>>>,
minorants: Vec<Vec<MinorantInfo>>,
/// The primals associated with each global minorant index.
primals: Vec<Option<P::Primal>>,
/// Accumulated information about the last iteration.
iterinfos: Vec<IterationInfo>,
}
pub type Result<T, P, M> = std::result::Result<
T,
|
| ︙ | | |
494
495
496
497
498
499
500
501
502
503
504
505
506
507
|
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
|
+
|
sgnorm: 0.0,
expected_progress: 0.0,
cnt_descent: 0,
cnt_null: 0,
start_time: Instant::now(),
master: M::default().build().map_err(|e| SolverError::BuildMaster(e.into()))?,
minorants: vec![],
primals: vec![],
iterinfos: vec![],
})
}
/// A new solver with default parameter.
#[allow(clippy::type_complexity)]
pub fn new(problem: P) -> Result<Solver<P, T, W, M>, P, M> {
|
| ︙ | | |
617
618
619
620
621
622
623
624
625
626
627
628
629
630
|
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
|
+
|
///
/// Calling this function typically triggers the problem to
/// separate new constraints depending on the current solution.
fn update_problem(&mut self, term: Step) -> Result<bool, P, M> {
let updates = {
let state = UpdateState {
minorants: &self.minorants,
primals: &self.primals,
step: term,
iteration_info: &self.iterinfos,
// this is a dirty trick: when updating the center, we
// simply swapped the `cur_*` fields with the `nxt_*`
// fields
cur_y: if term == Step::Descent {
&self.nxt_y
|
| ︙ | | |
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
|
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
|
-
+
-
+
|
newvars.push((Some(index), lower - value, upper - value, value));
}
}
}
if !newvars.is_empty() {
let problem = &mut self.problem;
let minorants = &self.minorants;
let primals = &self.primals;
self.master.add_vars(
&newvars.iter().map(|v| (v.0, v.1, v.2)).collect::<Vec<_>>(),
&mut |fidx, minidx, vars| {
problem
.extend_subgradient(fidx, minorants[fidx][minidx].primal.as_ref().unwrap(), vars)
.extend_subgradient(fidx, primals[minidx].as_ref().unwrap(), vars)
.map(DVector)
.map_err(|e| e.into())
},
)?;
// modify moved variables
for (index, val) in newvars.iter().filter_map(|v| v.0.map(|i| (i, v.3))) {
self.cur_y[index] = val;
|
| ︙ | | |
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
|
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
|
-
+
|
/// with their coefficients $\alpha_i$. The aggregated primal can
/// be computed by combining the minorants $\bar{x} =
/// \sum_{i=1}\^m \alpha_i x_i$.
pub fn aggregated_primals(&self, subproblem: usize) -> P::Primal {
Aggregatable::combine(
self.minorants[subproblem]
.iter()
.map(|m| (m.multiplier, m.primal.as_ref().unwrap())),
.map(|m| (m.multiplier, self.primals[m.index].as_ref().unwrap())),
)
}
fn show_info(&self, step: Step) {
let time = self.start_time.elapsed();
info!(
"{} {:0>2}:{:0>2}:{:0>2}.{:0>2} {:4} {:4} {:4}{:1} {:9.4} {:9.4} \
|
| ︙ | | |
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
|
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
|
+
-
+
-
+
+
+
+
|
self.cur_vals[i] = result.objective();
self.cur_val += self.cur_vals[i];
let mut minorants = result.into_iter();
if let Some((minorant, primal)) = minorants.next() {
self.cur_mods[i] = minorant.constant;
self.cur_mod += self.cur_mods[i];
let minidx = self.master.add_minorant(i, minorant)?;
self.minorants[i].push(MinorantInfo {
index: self.master.add_minorant(i, minorant)?,
index: minidx,
multiplier: 0.0,
primal: Some(primal),
});
if minidx >= self.primals.len() {
self.primals.resize_with(minidx + 1, || None);
}
self.primals[minidx] = Some(primal);
} else {
return Err(SolverError::NoMinorant);
}
}
self.cur_valid = true;
|
| ︙ | | |
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
|
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
|
-
-
+
+
+
+
-
+
|
for i in 0..self.problem.num_subproblems() {
let n = self.master.num_minorants(i);
if n >= self.params.max_bundle_size {
// aggregate minorants with smallest coefficients
self.minorants[i].sort_by_key(|m| -((1e6 * m.multiplier) as isize));
let aggr = self.minorants[i].split_off(self.params.max_bundle_size - 2);
let aggr_sum = aggr.iter().map(|m| m.multiplier).sum();
let (aggr_mins, aggr_primals): (Vec<_>, Vec<_>) =
aggr.into_iter().map(|m| (m.index, m.primal.unwrap())).unzip();
let (aggr_mins, aggr_primals): (Vec<_>, Vec<_>) = aggr
.into_iter()
.map(|m| (m.index, self.primals[m.index].take().unwrap()))
.unzip();
let (aggr_min, aggr_coeffs) = self.master.aggregate(i, &aggr_mins)?;
// append aggregated minorant
self.minorants[i].push(MinorantInfo {
index: aggr_min,
multiplier: aggr_sum,
primal: Some(Aggregatable::combine(aggr_coeffs.into_iter().zip(&aggr_primals))),
});
self.primals[aggr_min] = Some(Aggregatable::combine(aggr_coeffs.into_iter().zip(&aggr_primals)));
}
}
Ok(())
}
/// Perform a descent step.
fn descent_step(&mut self) -> Result<(), P, M> {
|
| ︙ | | |
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
|
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
|
+
-
+
-
+
+
+
+
|
nxt_lb += fun_lb;
nxt_ub += fun_ub;
self.nxt_vals[fidx] = fun_ub;
// move center of minorant to cur_y
nxt_minorant.move_center(-1.0, &self.nxt_d);
self.new_cutval += nxt_minorant.constant;
let minidx = self.master.add_minorant(fidx, nxt_minorant)?;
self.minorants[fidx].push(MinorantInfo {
index: self.master.add_minorant(fidx, nxt_minorant)?,
index: minidx,
multiplier: 0.0,
primal: Some(nxt_primal),
});
if minidx >= self.primals.len() {
self.primals.resize_with(minidx + 1, || None);
}
self.primals[minidx] = Some(nxt_primal);
}
if self.new_cutval > self.cur_val + 1e-3 {
warn!(
"New minorant has higher value in center new:{} old:{}",
self.new_cutval, self.cur_val
);
|
| ︙ | | |