Index: examples/cflp.rs ================================================================== --- examples/cflp.rs +++ examples/cflp.rs @@ -236,14 +236,10 @@ } } fn main() -> Result<(), Box> { better_panic::install(); - // env_logger::builder() - // .default_format_timestamp(false) - // .default_format_module_path(false) - // .init(); env_logger::builder() .format(|buf, record| { let mut style = buf.style(); let color = match record.level() { Level::Error | Level::Warn => Color::Red, @@ -260,12 +256,14 @@ style.value("]"), style.value(record.args()) ) }) .init(); + { let mut slv = DefaultSolver::new(CFLProblem::new())?; + slv.params.max_bundle_size = 5; slv.terminator.termination_precision = 1e-9; slv.solve()?; for i in 0..Ncus { let x = slv.aggregated_primals(Nfac + i); @@ -293,10 +291,11 @@ } { let mut slv = ParallelSolver::<_>::new(CFLProblem::new()); slv.terminator.termination_precision = 1e-9; + slv.master_builder.max_bundle_size = 5; slv.solve()?; } Ok(()) } Index: src/master/boxed.rs ================================================================== --- src/master/boxed.rs +++ src/master/boxed.rs @@ -380,5 +380,19 @@ fn build(&mut self) -> Result::Err> { self.0.build().map(BoxedMasterProblem::with_master) } } + +impl std::ops::Deref for Builder { + type Target = B; + + fn deref(&self) -> &B { + &self.0 + } +} + +impl std::ops::DerefMut for Builder { + fn deref_mut(&mut self) -> &mut B { + &mut self.0 + } +} Index: src/master/cpx.rs ================================================================== --- src/master/cpx.rs +++ src/master/cpx.rs @@ -99,10 +99,13 @@ minorants: Vec>, /// Optimal multipliers for each subproblem in the model. opt_mults: Vec, /// Optimal aggregated minorant. opt_minorant: Minorant, + + /// Maximal bundle size. + pub max_bundle_size: usize, } unsafe impl Send for CplexMaster {} impl Drop for CplexMaster { @@ -137,10 +140,11 @@ qterm: vec![], weight: 1.0, minorants: vec![], opt_mults: vec![], opt_minorant: Minorant::default(), + max_bundle_size: 50, }) } fn num_subproblems(&self) -> usize { self.minorants.len() @@ -176,11 +180,25 @@ fn num_minorants(&self, fidx: usize) -> usize { self.minorants[fidx].len() } fn compress(&mut self) -> Result<()> { - unimplemented!() + assert!(self.max_bundle_size >= 2, "Maximal bundle size must be >= 2"); + for i in 0..self.num_subproblems() { + let n = self.num_minorants(i); + if n >= self.max_bundle_size { + // aggregate minorants with smallest coefficients + let mut inds = (0..n).collect::>(); + inds.sort_by_key(|&j| -((1e6 * self.opt_mults[i][j]) as isize)); + let inds = inds[self.max_bundle_size - 2..] + .iter() + .map(|&j| self.min2index[i][j]) + .collect::>(); + self.aggregate(i, &inds)?; + } + } + Ok(()) } fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result { debug!("Add minorant"); debug!(" fidx={} index={}: {}", fidx, self.minorants[fidx].len(), minorant); @@ -549,14 +567,27 @@ Ok(()) } } #[derive(Default)] -pub struct Builder; +pub struct Builder { + /// The maximal bundle size used in the master problem. + pub max_bundle_size: usize, +} impl unconstrained::Builder for Builder { type MasterProblem = CplexMaster; fn build(&mut self) -> Result { - CplexMaster::new() + let mut cpx = CplexMaster::new()?; + cpx.max_bundle_size = self.max_bundle_size; + Ok(cpx) + } +} + +impl Builder { + pub fn max_bundle_size(&mut self, s: usize) -> &mut Self { + assert!(s >= 2, "The maximal bundle size must be >= 2"); + self.max_bundle_size = s; + self } } Index: src/parallel/masterprocess.rs ================================================================== --- src/parallel/masterprocess.rs +++ src/parallel/masterprocess.rs @@ -209,11 +209,11 @@ debug!("master: move center"); master.move_center(alpha, &d); } MasterTask::Compress => { debug!("Compress bundle"); - warn!("Bundle compression not yet implemented"); + master.compress()?; } MasterTask::Solve { center_value } => { debug!("master: solve with center_value {}", center_value); master.solve(center_value)?; let master_response = MasterResponse { Index: src/parallel/solver.rs ================================================================== --- src/parallel/solver.rs +++ src/parallel/solver.rs @@ -207,20 +207,20 @@ /// Weighter heuristic. pub weighter: W, /// The threadpool of the solver. pub threadpool: ThreadPool, + + /// The master problem builder. + pub master_builder: M, /// The first order problem. problem: P, /// The algorithm data. data: SolverData, - /// The master problem builder. - master_builder: M, - /// The master problem process. master: Option>, /// The channel to receive the evaluation results from subproblems. client_tx: Option>,