Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Implement `MasterProblemError` as more specific enum |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | error-handling |
| Files: | files | file ages | folders |
| SHA1: |
58f8ffe7a128b455f398130f00639f91 |
| User & Date: | fifr 2018-06-26 21:39:59.184 |
Context
|
2018-06-27
| ||
| 07:05 | solver: remove unnecessary `move` from extend subgradient closure check-in: f410ce94ba user: fifr tags: error-handling | |
|
2018-06-26
| ||
| 21:39 | Implement `MasterProblemError` as more specific enum check-in: 58f8ffe7a1 user: fifr tags: error-handling | |
| 21:17 | master: Subgradient extension callback may return an error. check-in: cd30b6f272 user: fifr tags: error-handling | |
Changes
Changes to src/master/base.rs.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 |
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>
//
use {DVector, Minorant, Real};
use std::error::Error;
use std::result;
/// Error type for master problems.
| > > > > > > > > > > > > | > > > > > > > > > > > | | > > > > > > > > | 13 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 55 56 57 58 59 60 61 62 63 |
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>
//
use {DVector, Minorant, Real};
use std::error::Error;
use std::fmt;
use std::result;
/// Error type for master problems.
#[derive(Debug)]
pub enum MasterProblemError {
/// Extension of the subgradient failed with some user error.
SubgradientExtension(Box<dyn Error>),
/// No minorants available when solving the master problem
NoMinorants,
/// An error in the solver backend occurred.
Solver(Box<dyn Error>),
/// A custom error (specific to the master problem solver) occurred.
Custom(Box<dyn Error>),
}
impl fmt::Display for MasterProblemError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
use self::MasterProblemError::*;
match self {
SubgradientExtension(err) => write!(fmt, "Subgradient extension failed: {}", err),
NoMinorants => write!(fmt, "No minorants when solving the master problem"),
Solver(err) => write!(fmt, "Solver error: {}", err),
Custom(err) => err.fmt(fmt),
}
}
}
impl Error for MasterProblemError {
fn cause(&self) -> Option<&Error> {
use self::MasterProblemError::*;
match self {
SubgradientExtension(err) | Solver(err) | Custom(err) => Some(err.as_ref()),
NoMinorants => None,
}
}
}
/// Result type of master problems.
pub type Result<T> = result::Result<T, MasterProblemError>;
pub trait MasterProblem {
/// Unique index for a minorant.
type MinorantIndex: Copy + Eq;
|
| ︙ | ︙ | |||
55 56 57 58 59 60 61 |
/// Add or movesome variables with bounds.
///
/// If an index is specified, existing variables are moved,
/// otherwise new variables are generated.
fn add_vars(
&mut self,
bounds: &[(Option<usize>, Real, Real)],
| | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/// Add or movesome variables with bounds.
///
/// If an index is specified, existing variables are moved,
/// otherwise new variables are generated.
fn add_vars(
&mut self,
bounds: &[(Option<usize>, Real, Real)],
extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> result::Result<DVector, Box<dyn Error>>,
) -> Result<()>;
/// 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.
|
| ︙ | ︙ |
Changes to src/master/boxed.rs.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
use master::MasterProblem;
use master::UnconstrainedMasterProblem;
use {DVector, Minorant, Real};
use super::Result;
use itertools::multizip;
use std::f64::{EPSILON, INFINITY, NEG_INFINITY};
/**
* Turn unconstrained master problem into box-constrained one.
*
* This master problem adds box constraints to an unconstrainted
* master problem implementation. The box constraints are enforced by
* an additional outer optimization loop.
| > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
use master::MasterProblem;
use master::UnconstrainedMasterProblem;
use {DVector, Minorant, Real};
use super::Result;
use itertools::multizip;
use std::error::Error;
use std::f64::{EPSILON, INFINITY, NEG_INFINITY};
use std::result;
/**
* Turn unconstrained master problem into box-constrained one.
*
* This master problem adds box constraints to an unconstrainted
* master problem implementation. The box constraints are enforced by
* an additional outer optimization loop.
|
| ︙ | ︙ | |||
205 206 207 208 209 210 211 |
fn set_weight(&mut self, weight: Real) -> Result<()> {
self.master.set_weight(weight)
}
fn add_vars(
&mut self,
bounds: &[(Option<usize>, Real, Real)],
| | | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
fn set_weight(&mut self, weight: Real) -> Result<()> {
self.master.set_weight(weight)
}
fn add_vars(
&mut self,
bounds: &[(Option<usize>, Real, Real)],
extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> result::Result<DVector, Box<dyn Error>>,
) -> Result<()> {
if !bounds.is_empty() {
for (index, l, u) in bounds.iter().filter_map(|v| v.0.map(|i| (i, v.1, v.2))) {
self.lb[index] = l;
self.ub[index] = u;
}
self.lb.extend(bounds.iter().filter(|v| v.0.is_none()).map(|x| x.1));
|
| ︙ | ︙ |
Changes to src/master/cpx.rs.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | // along with this program. If not, see <http://www.gnu.org/licenses/> // //! Master problem implementation using CPLEX. #![allow(unused_unsafe)] | | < < < | < < | < < | < < | | < < < | 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 |
// along with this program. If not, see <http://www.gnu.org/licenses/>
//
//! Master problem implementation using CPLEX.
#![allow(unused_unsafe)]
use master::{Error as MasterProblemError, UnconstrainedMasterProblem};
use {DVector, Minorant, Real};
use cplex_sys as cpx;
use super::Result;
use std;
use std::error::Error;
use std::f64::{self, NEG_INFINITY};
use std::os::raw::{c_char, c_int};
use std::ptr;
use std::result;
impl From<cpx::CplexError> for MasterProblemError {
fn from(err: cpx::CplexError) -> MasterProblemError {
MasterProblemError::Solver(err.into())
}
}
pub struct CplexMaster {
lp: *mut cpx::Lp,
/// True if the QP must be updated.
force_update: bool,
|
| ︙ | ︙ | |||
165 166 167 168 169 170 171 |
}
}
fn add_vars(
&mut self,
nnew: usize,
changed: &[usize],
| | | > | 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 179 180 |
}
}
fn add_vars(
&mut self,
nnew: usize,
changed: &[usize],
extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> result::Result<DVector, Box<dyn Error>>,
) -> Result<()> {
debug_assert!(!self.minorants[0].is_empty());
let noldvars = self.minorants[0][0].linear.len();
let nnewvars = noldvars + nnew;
let mut changedvars = vec![];
changedvars.extend_from_slice(changed);
changedvars.extend(noldvars..nnewvars);
for (fidx, mins) in self.minorants.iter_mut().enumerate() {
if !mins.is_empty() {
for (i, m) in mins.iter_mut().enumerate() {
let new_subg =
extend_subgradient(fidx, i, &changedvars).map_err(MasterProblemError::SubgradientExtension)?;
for (&j, &g) in changed.iter().zip(new_subg.iter()) {
m.linear[j] = g;
}
m.linear.extend_from_slice(&new_subg[changed.len()..]);
}
}
}
|
| ︙ | ︙ | |||
219 220 221 222 223 224 225 |
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());
}
let nvars = unsafe { cpx::getnumcols(cpx::env(), self.lp) as usize };
if nvars == 0 {
| | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
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());
}
let nvars = unsafe { cpx::getnumcols(cpx::env(), self.lp) as usize };
if nvars == 0 {
return Err(MasterProblemError::NoMinorants);
}
// update linear costs
{
let mut c = Vec::with_capacity(nvars);
let mut inds = Vec::with_capacity(nvars);
for mins in &self.minorants {
for m in mins {
|
| ︙ | ︙ |
Changes to src/master/minimal.rs.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/> // | | < < > > > > > > | 10 11 12 13 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 55 56 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>
//
use master::{Error as MasterProblemError, UnconstrainedMasterProblem};
use {DVector, Minorant, Real};
use super::Result;
use std::error::Error;
use std::f64::NEG_INFINITY;
use std::fmt;
use std::result;
/// Minimal master problem error.
#[derive(Debug)]
pub enum MinimalMasterError {
NumSubproblems { nsubs: usize },
MaxMinorants,
}
impl fmt::Display for MinimalMasterError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
use self::MinimalMasterError::*;
match self {
NumSubproblems { nsubs } => write!(fmt, "Too many subproblems (got: {} must be <= 2)", nsubs),
MaxMinorants => write!(fmt, "The minimal master problem allows at most two minorants"),
}
}
}
impl Error for MinimalMasterError {}
impl Into<MasterProblemError> for MinimalMasterError {
fn into(self) -> MasterProblemError {
MasterProblemError::Custom(self.into())
}
}
/**
* A minimal master problem with only two minorants.
*
* This is the simplest possible master problem for bundle methods. It
* has only two minorants and only one function model. The advantage
* is that this model can be solved explicitely and very quickly, but
|
| ︙ | ︙ | |||
117 118 119 120 121 122 123 |
Ok(self.minorants.len() - 1)
}
fn add_vars(
&mut self,
nnew: usize,
changed: &[usize],
| | | > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
Ok(self.minorants.len() - 1)
}
fn add_vars(
&mut self,
nnew: usize,
changed: &[usize],
extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> result::Result<DVector, Box<dyn Error>>,
) -> Result<()> {
if !self.minorants.is_empty() {
let noldvars = self.minorants[0].linear.len();
let mut changedvars = vec![];
changedvars.extend_from_slice(changed);
changedvars.extend(noldvars..noldvars + nnew);
for (i, m) in self.minorants.iter_mut().enumerate() {
let new_subg =
extend_subgradient(0, i, &changedvars).map_err(MasterProblemError::SubgradientExtension)?;
for (&j, &g) in changed.iter().zip(new_subg.iter()) {
m.linear[j] = g;
}
m.linear.extend_from_slice(&new_subg[changed.len()..]);
}
}
|
| ︙ | ︙ | |||
165 166 167 168 169 170 171 |
self.opt_mult[1] = alpha2;
self.opt_minorant = self.minorants[0].combine(1.0 - alpha2, alpha2, &self.minorants[1]);
} else if self.minorants.len() == 1 {
self.opt_minorant = self.minorants[0].clone();
self.opt_mult.resize(1, 1.0);
self.opt_mult[0] = 1.0;
} else {
| | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
self.opt_mult[1] = alpha2;
self.opt_minorant = self.minorants[0].combine(1.0 - alpha2, alpha2, &self.minorants[1]);
} else if self.minorants.len() == 1 {
self.opt_minorant = self.minorants[0].clone();
self.opt_mult.resize(1, 1.0);
self.opt_mult[0] = 1.0;
} else {
return Err(MasterProblemError::NoMinorants);
}
debug!("Unrestricted");
debug!(" opt_minorant={}", self.opt_minorant);
if self.opt_mult.len() == 2 {
debug!(" opt_mult={}", self.opt_mult);
}
|
| ︙ | ︙ |
Changes to src/master/unconstrained.rs.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// along with this program. If not, see <http://www.gnu.org/licenses/>
//
use {DVector, Minorant, Real};
use super::Result;
/**
* Trait for master problems without box constraints.
*
* Implementors of this trait are supposed to solve quadratic
* optimization problems of the form
*
* \\[ \min \left\\{ \hat{f}(d) + \frac{u}{2} \\| d \\|\^2 \colon
| > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// along with this program. If not, see <http://www.gnu.org/licenses/>
//
use {DVector, Minorant, Real};
use super::Result;
use std::error::Error;
use std::result;
/**
* Trait for master problems without box constraints.
*
* Implementors of this trait are supposed to solve quadratic
* optimization problems of the form
*
* \\[ \min \left\\{ \hat{f}(d) + \frac{u}{2} \\| d \\|\^2 \colon
|
| ︙ | ︙ | |||
74 75 76 77 78 79 80 |
/// The variables in `changed` have been changed, so the subgradient
/// information must be updated. Furthermore, `nnew` new variables
/// are added.
fn add_vars(
&mut self,
nnew: usize,
changed: &[usize],
| | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
/// The variables in `changed` have been changed, so the subgradient
/// information must be updated. Furthermore, `nnew` new variables
/// are added.
fn add_vars(
&mut self,
nnew: usize,
changed: &[usize],
extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> result::Result<DVector, Box<dyn Error>>,
) -> Result<()>;
/// Solve the master problem.
fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> Result<()>;
/// Return the current dual optimal solution.
fn dualopt(&self) -> &DVector;
|
| ︙ | ︙ |
Changes to src/solver.rs.
| ︙ | ︙ | |||
79 80 81 82 83 84 85 |
}
impl<E: Error> Error for SolverError<E> {
fn cause(&self) -> Option<&Error> {
match self {
SolverError::Evaluation(err) => Some(err),
SolverError::Update(err) => Some(err),
| | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
}
impl<E: Error> Error for SolverError<E> {
fn cause(&self) -> Option<&Error> {
match self {
SolverError::Evaluation(err) => Some(err),
SolverError::Update(err) => Some(err),
SolverError::Master(err) => Some(err),
_ => None,
}
}
}
impl<E> From<ParameterError> for SolverError<E> {
fn from(err: ParameterError) -> SolverError<E> {
|
| ︙ | ︙ |