// Copyright (c) 2016, 2017, 2019 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 crate::{DVector, Minorant, Real};
use std::error::Error;
use std::result;
/// Callback for subgradient extensions.
pub type SubgradientExtension<'a, I> =
FnMut(usize, I, &[usize]) -> result::Result<DVector, Box<dyn Error + Send + Sync + 'static>> + 'a;
pub trait MasterProblem {
/// Unique index for a minorant.
type MinorantIndex: Copy + Eq;
/// The error returned by the master problem.
type Err;
/// Create a new master problem.
fn new() -> Result<Self, Self::Err>
where
Self: Sized;
/// Set the number of subproblems.
fn set_num_subproblems(&mut self, n: usize) -> Result<(), Self::Err>;
/// Return the current number of subproblems.
fn num_subproblems(&self) -> usize;
/// Set the lower and upper bounds of the variables.
fn set_vars(&mut self, nvars: usize, lb: Option<DVector>, ub: Option<DVector>) -> Result<(), Self::Err>;
/// 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<(), Self::Err>;
/// Set the maximal number of inner iterations.
fn set_max_updates(&mut self, max_updates: usize) -> Result<(), Self::Err>;
/// Return the current number of inner iterations.
fn cnt_updates(&self) -> usize;
/// Add or move some 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 SubgradientExtension<Self::MinorantIndex>,
) -> Result<(), Self::Err>;
/// 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, Self::Err>;
/// Solve the master problem.
fn solve(&mut self, cur_value: Real) -> Result<(), Self::Err>;
/// 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), Self::Err>;
/// 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);
}