RsBundle  Artifact [acd821c22b]

Artifact acd821c22b9a85a7c7763e2e1b6dbe0a685bab92:

  • File src/master/base.rs — part of check-in [58f8ffe7a1] at 2018-06-26 21:39:59 on branch error-handling — Implement `MasterProblemError` as more specific enum (user: fifr size: 5274) [more...]

// Copyright (c) 2016, 2017 Frank Fischer <frank-fischer@shadow-soft.de>
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// 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 {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;

    /// Set the number of subproblems.
    fn set_num_subproblems(&mut self, n: usize) -> Result<()>;

    /// Set the lower and upper bounds of the variables.
    fn set_vars(&mut self, nvars: usize, lb: Option<DVector>, ub: Option<DVector>) -> Result<()>;

    /// Return the current number of minorants of subproblem `fidx`.
    fn num_minorants(&self, fidx: usize) -> usize;

    /// Return the current weight of the quadratic term.
    fn weight(&self) -> Real;

    /// Set the weight of the quadratic term, must be > 0.
    fn set_weight(&mut self, weight: Real) -> Result<()>;

    /// Set the maximal number of inner iterations.
    fn set_max_updates(&mut self, max_updates: usize) -> Result<()>;

    /// Return the current number of inner iterations.
    fn cnt_updates(&self) -> usize;

    /// 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.
    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<Self::MinorantIndex>;

    /// Solve the master problem.
    fn solve(&mut self, cur_value: Real) -> Result<()>;

    /// Aggregate the given minorants according to the current
    /// solution.
    ///
    /// The (indices of the) minorants to be aggregated get invalid
    /// after this operation. The function returns the index of the
    /// aggregated minorant along with the coefficients of the convex
    /// combination. The index of the new aggregated minorant might or
    /// might not be one of indices of the original minorants.
    ///
    /// # Error The indices of the minorants `mins` must belong to
    /// subproblem `fidx`.
    fn aggregate(&mut self, fidx: usize, mins: &[usize]) -> Result<(Self::MinorantIndex, DVector)>;

    /// Return the (primal) optimal solution $\\|d\^*\\|$.
    fn get_primopt(&self) -> DVector;

    /// Return the value of the linear model in the optimal solution.
    ///
    /// This is the term $\langle g\^*, d\^* \rangle$ where $g^\*$ is
    /// the optimal aggregated subgradient of the current
    /// cutting-plane model and $d\^*$ is the (primal) optimal solution.
    fn get_primoptval(&self) -> Real;

    /// Return $\\|g^\*\\|_2\^2$.
    ///
    /// $g\^*$ is the optimal aggregated subgradient.
    fn get_dualoptnorm2(&self) -> Real;

    /// Return the multiplier associated with a minorant.
    fn multiplier(&self, min: Self::MinorantIndex) -> Real;

    /// Move the center of the master problem to $\alpha \cdot d$.
    fn move_center(&mut self, alpha: Real, d: &DVector);
}