Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Add problem update callback. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
814bd7230ac1b38a4e4f195023ed63cb |
| User & Date: | fifr 2016-10-05 16:54:25.606 |
Context
|
2016-10-05
| ||
| 20:11 | solver: Do not terminate of problem has been changed. check-in: 3248967d1a user: fifr tags: trunk | |
| 16:54 | Add problem update callback. check-in: 814bd7230a user: fifr tags: trunk | |
| 12:58 | solver: Update multipliers from master in `solve_model`. check-in: 106f4bb24e user: fifr tags: trunk | |
Changes
Changes to src/firstorderproblem.rs.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
//! Problem description of a first-order convex optimization problem.
use {Real, Vector, DVector, Minorant};
use std::error;
use std::vec::IntoIter;
/**
* Trait for results of an evaluation.
*
| > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
//! Problem description of a first-order convex optimization problem.
use {Real, Vector, DVector, Minorant};
use solver::UpdateState;
use std::error;
use std::vec::IntoIter;
/**
* Trait for results of an evaluation.
*
|
| ︙ | ︙ | |||
58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
}
impl<P> Evaluation<P> for SimpleEvaluation<P> {
fn objective(&self) -> Real {
self.objective
}
}
/**
* Trait for implementing a first-order problem description.
*
*/
pub trait FirstOrderProblem<'a> {
/// Custom error type for evaluating this oracle.
| > > > > > > > > > > | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
}
impl<P> Evaluation<P> for SimpleEvaluation<P> {
fn objective(&self) -> Real {
self.objective
}
}
/// Problem update information.
///
/// The solver calls the `update` method of the problem regularly.
/// This method can modify the problem by adding (or removing)
/// variables. The possible updates are encoded in this type.
#[derive(Debug, Clone, Copy)]
pub enum Update {
AddVariable{lower: Real, upper: Real},
}
/**
* Trait for implementing a first-order problem description.
*
*/
pub trait FirstOrderProblem<'a> {
/// Custom error type for evaluating this oracle.
|
| ︙ | ︙ | |||
141 142 143 144 145 146 147 |
/// last primal. This should work if the implementing problem does
/// not provide primal information, e.g. if `Self::Primal = ()`.
#[allow(unused_variables)]
fn aggregate_primals(&mut self, coeffs: &[Real], primals: Vec<Self::Primal>) -> Self::Primal {
let mut primals = primals;
primals.pop().unwrap()
}
| | > > > > > > > > > > > > > > > > > > > | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
/// last primal. This should work if the implementing problem does
/// not provide primal information, e.g. if `Self::Primal = ()`.
#[allow(unused_variables)]
fn aggregate_primals(&mut self, coeffs: &[Real], primals: Vec<Self::Primal>) -> Self::Primal {
let mut primals = primals;
primals.pop().unwrap()
}
/// Return updates of the problem.
///
/// The default implementation returns no updates.
fn update(&mut self, _state: &UpdateState<Self::Primal>) -> Result<Vec<Update>, Self::Error> {
Ok(vec![])
}
/// Return new components for a subgradient.
///
/// The components are typically generated by some primal
/// information. The corresponding primal is passed as a
/// parameter.
///
/// The default implementation fails because it should never be
/// called.
fn extend_subgradient(&mut self, _primal: &Self::Primal, _vars: &[usize]) -> Result<DVector, Self::Error> {
unimplemented!()
}
}
|
Changes to src/lib.rs.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 |
pub mod vector;
pub use vector::{DVector, Vector};
pub mod minorant;
pub use minorant::Minorant;
pub mod firstorderproblem;
| | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
pub mod vector;
pub use vector::{DVector, Vector};
pub mod minorant;
pub use minorant::Minorant;
pub mod firstorderproblem;
pub use firstorderproblem::{Evaluation, SimpleEvaluation, Update, FirstOrderProblem};
pub mod solver;
pub use solver::{Solver, SolverParams, BundleState, Terminator, StandardTerminator, Weighter, Step, UpdateState};
mod hkweighter;
pub use hkweighter::HKWeighter;
mod master;
pub mod mcf;
|
Changes to src/master/boxed.rs.
| ︙ | ︙ | |||
204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
fn weight(&self) -> Real {
self.master.weight()
}
fn set_weight(&mut self, weight: Real) {
self.master.set_weight(weight);
}
fn solve(&mut self, center_value: Real) -> Result<()> {
debug!("Solve Master");
debug!(" lb ={}", self.lb);
debug!(" ub ={}", self.ub);
if self.need_new_candidate {
| > > > > > > | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
fn weight(&self) -> Real {
self.master.weight()
}
fn set_weight(&mut self, weight: Real) {
self.master.set_weight(weight);
}
fn add_vars(&mut self, bounds: &[(Real,Real)], extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> DVector) {
self.lb.extend(bounds.iter().map(|x| x.0));
self.ub.extend(bounds.iter().map(|x| x.1));
self.master.add_vars(bounds.len(), extend_subgradient)
}
fn solve(&mut self, center_value: Real) -> Result<()> {
debug!("Solve Master");
debug!(" lb ={}", self.lb);
debug!(" ub ={}", self.ub);
if self.need_new_candidate {
|
| ︙ | ︙ |
Changes to src/master/cpx.rs.
| ︙ | ︙ | |||
159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
let idx = self.index2min.len();
self.min2index[fidx].push(idx);
self.index2min.push((fidx, min_idx));
self.updateinds.push(idx);
Ok(idx)
}
}
#[allow(unused_variables)]
fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> Result<()> {
if self.force_update || !self.updateinds.is_empty() {
try!(self.init_qp());
}
| > > > > | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
let idx = self.index2min.len();
self.min2index[fidx].push(idx);
self.index2min.push((fidx, min_idx));
self.updateinds.push(idx);
Ok(idx)
}
}
fn add_vars(&mut self, nvars: usize, extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> DVector) {
unimplemented!()
}
#[allow(unused_variables)]
fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> Result<()> {
if self.force_update || !self.updateinds.is_empty() {
try!(self.init_qp());
}
|
| ︙ | ︙ |
Changes to src/master/master.rs.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
/// Set the maximal number of inner iterations.
fn set_max_updates(&mut self, max_updates: usize);
/// Return the current number of inner iterations.
fn cnt_updates(&self) -> usize;
/// Add a new minorant to the model.
///
/// The function returns a unique (among all minorants of all
/// subproblems) index of the minorant. This index must remain
/// valid until the minorant is aggregated.
fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<Self::MinorantIndex>;
| > > > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
/// Set the maximal number of inner iterations.
fn set_max_updates(&mut self, max_updates: usize);
/// Return the current number of inner iterations.
fn cnt_updates(&self) -> usize;
/// Add some variables with bounds.
fn add_vars(&mut self, bounds: &[(Real,Real)], extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> DVector);
/// Add a new minorant to the model.
///
/// The function returns a unique (among all minorants of all
/// subproblems) index of the minorant. This index must remain
/// valid until the minorant is aggregated.
fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<Self::MinorantIndex>;
|
| ︙ | ︙ |
Changes to src/master/minimal.rs.
| ︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
if self.minorants.len() >= 2 {
return Err(Error::MaxMinorants)
}
self.minorants.push(minorant);
self.opt_mult.push(0.0);
Ok(self.minorants.len()-1)
}
#[allow(unused_variables)]
fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> Result<()> {
for (i, m) in self.minorants.iter().enumerate() {
debug!(" {}:min[{},{}] = {}", i, 0, 0, m);
}
| > > > > > > > > > > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
if self.minorants.len() >= 2 {
return Err(Error::MaxMinorants)
}
self.minorants.push(minorant);
self.opt_mult.push(0.0);
Ok(self.minorants.len()-1)
}
fn add_vars(&mut self, nvars: usize, extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> DVector) {
if !self.minorants.is_empty() {
let noldvars = self.minorants[0].linear.len();
let newvars = (noldvars .. noldvars + nvars).collect::<Vec<_>>();
for (i,m) in self.minorants.iter_mut().enumerate() {
let new_subg = extend_subgradient(0, i, &newvars);
m.linear.extend_from_slice(&new_subg);
}
}
}
#[allow(unused_variables)]
fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> Result<()> {
for (i, m) in self.minorants.iter().enumerate() {
debug!(" {}:min[{},{}] = {}", i, 0, 0, m);
}
|
| ︙ | ︙ |
Changes to src/master/unconstrained.rs.
| ︙ | ︙ | |||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
/// Return the number of minorants of subproblem `fidx`.
fn num_minorants(&self, fidx: usize) -> usize;
/// Add a new minorant to the model.
fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> result::Result<Self::MinorantIndex, Self::Error>;
/// Solve the master problem.
fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> result::Result<(), Self::Error>;
/// Return the current dual optimal solution.
fn dualopt(&self) -> &DVector;
/// Return the current dual optimal solution value.
| > > > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
/// Return the number of minorants of subproblem `fidx`.
fn num_minorants(&self, fidx: usize) -> usize;
/// Add a new minorant to the model.
fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> result::Result<Self::MinorantIndex, Self::Error>;
/// Add a number of variables.
fn add_vars(&mut self, nvars: usize, extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> DVector);
/// Solve the master problem.
fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> result::Result<(), Self::Error>;
/// Return the current dual optimal solution.
fn dualopt(&self) -> &DVector;
/// Return the current dual optimal solution value.
|
| ︙ | ︙ |
Changes to src/solver.rs.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
//! The main bundle method solver.
use {Real, DVector};
| | > > > > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
//! The main bundle method solver.
use {Real, DVector};
use {FirstOrderProblem, Update, Evaluation, HKWeighter};
use master::{self, MasterProblem, BoxedMasterProblem, MinimalMaster, CplexMaster};
use std::result;
use std::error;
use std::mem::swap;
use std::f64::{INFINITY, NEG_INFINITY};
use std::time::Instant;
quick_error! {
/// A solver error.
#[derive(Debug)]
pub enum Error {
/// An error occurred during evaluation of the oracle.
Eval(err: Box<error::Error>) {
cause(&**err)
description(err.description())
display("Evaluation error: {}", err)
}
/// An error occurred during update of the oracle.
Update(err: Box<error::Error>) {
cause(&**err)
description(err.description())
display("Update error: {}", err)
}
/// Error solving the master problem.
Master(err: Box<error::Error>) {
cause(&**err)
description(err.description())
display("Master problem error: {}", err)
from(err: master::Error) -> (Box::new(err))
|
| ︙ | ︙ | |||
281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
/// The minorant's index in the master problem
index: usize,
/// Current multiplier.
multiplier: Real,
/// Primal associated with this minorant.
primal: Option<Pr>,
}
/**
* Implementation of a bundle method.
*/
pub struct Solver<P, Pr, E>
where P : for <'a> FirstOrderProblem<'a,Primal=Pr,EvalResult=E>,
E : Evaluation<Pr>,
| > > > > > > > > > > > > > > > > | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
/// The minorant's index in the master problem
index: usize,
/// Current multiplier.
multiplier: Real,
/// Primal associated with this minorant.
primal: Option<Pr>,
}
/// State information for the update callback.
pub struct UpdateState<'a, Pr:'a> {
/// Current model minorants.
minorants: &'a [Vec<MinorantInfo<Pr>>],
/// The last step type.
pub step: Step,
}
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())
}).collect()
}
}
/**
* Implementation of a bundle method.
*/
pub struct Solver<P, Pr, E>
where P : for <'a> FirstOrderProblem<'a,Primal=Pr,EvalResult=E>,
E : Evaluation<Pr>,
|
| ︙ | ︙ | |||
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
}
/// Solve the problem.
pub fn solve(&mut self) -> Result<()> {
try!(self.init());
for _ in 0..100000 {
let term = try!(self.step());
self.show_info(term);
if term == Step::Term {
break;
}
}
Ok(())
}
/// Return the current aggregated primal information for a subproblem.
///
/// This function returns all currently used minorants $x_i$ along
/// with their coefficients $\alpha_i$. The aggregated primal can
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 |
}
/// Solve the problem.
pub fn solve(&mut self) -> Result<()> {
try!(self.init());
for _ in 0..100000 {
let term = try!(self.step());
try!(self.update_problem(term));
self.show_info(term);
if term == Step::Term {
break;
}
}
Ok(())
}
/// Called to update the problem.
///
/// Calling this function typically triggers the problem to
/// separate new constraints depending on the current solution.
fn update_problem(&mut self, term: Step) -> Result<()> {
let state = UpdateState {minorants: &self.minorants, step: term};
let updates = match self.problem.update(&state) {
Ok(updates) => updates,
Err(err) => return Err(Error::Update(Box::new(err))),
};
let mut newvars = Vec::with_capacity(updates.len());
for u in updates {
match u {
Update::AddVariable{lower, upper} => {
newvars.push((lower, upper));
},
}
}
if !newvars.is_empty() {
let mut problem = &mut self.problem;
let minorants = &self.minorants;
self.master.add_vars(&newvars, &mut move |fidx, minidx, vars| {
problem.extend_subgradient(minorants[fidx][minidx].primal.as_ref().unwrap(), vars).unwrap()
});
}
Ok(())
}
/// Return the current aggregated primal information for a subproblem.
///
/// This function returns all currently used minorants $x_i$ along
/// with their coefficients $\alpha_i$. The aggregated primal can
|
| ︙ | ︙ |