RsBundle  Artifact [826b5a4c7c]

Artifact 826b5a4c7cca521f8c7c3d946cb88402a215ae92:

  • File src/parallel/problem.rs — part of check-in [b6db39804c] at 2019-07-22 09:48:01 on branch async — parallel: require `Primal` to be sendable (user: fifr size: 4121)

/*
 * Copyright (c) 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/>
 */

//! An asynchronous first-order oracle.

use crate::{Aggregatable, DVector, Minorant, Real};
use crossbeam::channel::Sender;
use std::sync::Arc;

/// Evaluation result.
///
/// The result of an evaluation is new information to be made
/// available to the solver and the master problem. There are
/// essentially two types of information:
///
///    1. The (exact) function value of a sub-function at some point.
///    2. A minorant of some sub-function.
#[derive(Debug)]
pub enum EvalResult<I, P> {
    /// The objective value at some point.
    ObjectiveValue { index: I, value: Real },
    /// A minorant with an associated primal.
    Minorant { index: I, minorant: Minorant, primal: P },
}

pub type ResultSender<I, P, E> = Sender<Result<EvalResult<I, P>, E>>;

/// Trait for implementing a first-order problem description.
///
/// All computations made by an implementation are supposed to
/// be asynchronous. Hence, the interface is slightly different
/// compared with [`crate::FirstOrderProblem`].
pub trait FirstOrderProblem {
    /// Error raised by this oracle.
    type Err: Send + 'static;

    /// The primal information associated with a minorant.
    type Primal: Aggregatable + Send + 'static;

    /// Return the number of variables.
    fn num_variables(&self) -> usize;

    /// Return the lower bounds on the variables.
    ///
    /// If no lower bounds a specified, $-\infty$ is assumed.
    ///
    /// The lower bounds must be less then or equal the upper bounds.
    fn lower_bounds(&self) -> Option<Vec<Real>> {
        None
    }

    /**
     * Return the upper bounds on the variables.
     *
     * If no lower bounds a specified, $+\infty$ is assumed.
     *
     * The upper bounds must be greater than or equal the upper bounds.
     */
    fn upper_bounds(&self) -> Option<Vec<Real>> {
        None
    }

    /// Return the number of subproblems.
    fn num_subproblems(&self) -> usize {
        1
    }

    /// Start background processes.
    ///
    /// This method is called right before the solver starts the solution process.
    /// It can be used to setup any background tasks required for the evaluation
    /// of the subfunctions.
    ///
    /// Remember that background processes should be cleanup when the problem
    /// is deleted (e.g. by implementing the [`Drop`] trait).
    ///
    /// The default implementation does nothing.
    fn start(&mut self) {}

    /// Stop background processes.
    ///
    /// This method is called right after the solver stops the solution process.
    /// It can be used to stop any background tasks required for the evaluation
    /// of the subfunctions.
    ///
    /// A correct implementation of should cleanup all processes from the [`Drop`]
    /// thread.
    ///
    /// The default implementation does nothing.
    fn stop(&mut self) {}

    /// Start the evaluation of the i^th subproblem at the given point.
    ///
    /// The results of the evaluation should be passed to the provided channel.
    /// In order to work correctly, the results must contain (an upper bound on)
    /// the objective value at $y$ as well as at least one subgradient centered
    /// at $y$ eventually.
    fn evaluate<I: Send + Copy + 'static>(
        &mut self,
        i: usize,
        y: Arc<DVector>,
        index: I,
        tx: ResultSender<I, Self::Primal, Self::Err>,
    ) -> Result<(), Self::Err>;
}