RsBundle  Diff

Differences From Artifact [f2405d0d0b]:

  • File src/solver.rs — part of check-in [6186a4f7ed] at 2019-07-17 14:41:42 on branch async — solver: make master problem a type argument (user: fifr size: 36835)

To Artifact [57470ce51a]:

  • File src/solver.rs — part of check-in [b6b5c1ec21] at 2019-07-17 15:38:30 on branch async — Simplify error handling (again) by using boxed errors (user: fifr size: 36759)

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#[derive(Debug)]
pub enum SolverError<E> {
    /// An error occurred during oracle evaluation.
    Evaluation(E),
    /// An error occurred during oracle update.
    Update(E),
    /// An error has been raised by the master problem.
    Master(MasterProblemError<E>),
    /// The oracle did not return a minorant.
    NoMinorant,
    /// The dimension of some data is wrong.
    Dimension,
    /// Some parameter has an invalid value.
    Parameter(ParameterError),
    /// The lower bound of a variable is larger than the upper bound.







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#[derive(Debug)]
pub enum SolverError<E> {
    /// An error occurred during oracle evaluation.
    Evaluation(E),
    /// An error occurred during oracle update.
    Update(E),
    /// An error has been raised by the master problem.
    Master(MasterProblemError),
    /// The oracle did not return a minorant.
    NoMinorant,
    /// The dimension of some data is wrong.
    Dimension,
    /// Some parameter has an invalid value.
    Parameter(ParameterError),
    /// The lower bound of a variable is larger than the upper bound.
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
                write!(fmt, "Variable index out of bounds, got:{} must be < {}", index, nvars)
            }
            IterationLimit { limit } => write!(fmt, "The iteration limit of {} has been reached.", limit),
        }
    }
}

impl<E: Error> Error for SolverError<E>
where
    E: 'static,
{
    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> {
        SolverError::Parameter(err)
    }
}

impl<E> From<MasterProblemError<E>> for SolverError<E> {
    fn from(err: MasterProblemError<E>) -> SolverError<E> {
        SolverError::Master(err)
    }
}

/**
 * The current state of the bundle method.
 *







|
<
<
<
|















|
|







78
79
80
81
82
83
84
85



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
                write!(fmt, "Variable index out of bounds, got:{} must be < {}", index, nvars)
            }
            IterationLimit { limit } => write!(fmt, "The iteration limit of {} has been reached.", limit),
        }
    }
}

impl<E: Error + 'static> Error for SolverError<E> {



    fn source(&self) -> Option<&(dyn Error + 'static)> {
        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> {
        SolverError::Parameter(err)
    }
}

impl<E> From<MasterProblemError> for SolverError<E> {
    fn from(err: MasterProblemError) -> SolverError<E> {
        SolverError::Master(err)
    }
}

/**
 * The current state of the bundle method.
 *
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
    /// This is the last primal generated by the oracle.
    pub fn last_primal(&self, fidx: usize) -> Option<&Pr> {
        self.minorants[fidx].last().and_then(|m| m.primal.as_ref())
    }
}

/// The default bundle solver with general master problem.
pub type DefaultSolver<P> = Solver<P, BoxedMasterProblem<CplexMaster<<P as FirstOrderProblem>::Err>>>;

/// A bundle solver with a minimal cutting plane model.
pub type NoBundleSolver<P> = Solver<P, BoxedMasterProblem<MinimalMaster<<P as FirstOrderProblem>::Err>>>;

/**
 * Implementation of a bundle method.
 */
pub struct Solver<P, M = BoxedMasterProblem<CplexMaster<<P as FirstOrderProblem>::Err>>>
where
    P: FirstOrderProblem,
{
    /// The first order problem description.
    problem: P,

    /// The solver parameter.







|


|




|







379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
    /// This is the last primal generated by the oracle.
    pub fn last_primal(&self, fidx: usize) -> Option<&Pr> {
        self.minorants[fidx].last().and_then(|m| m.primal.as_ref())
    }
}

/// The default bundle solver with general master problem.
pub type DefaultSolver<P> = Solver<P, BoxedMasterProblem<CplexMaster>>;

/// A bundle solver with a minimal cutting plane model.
pub type NoBundleSolver<P> = Solver<P, BoxedMasterProblem<MinimalMaster>>;

/**
 * Implementation of a bundle method.
 */
pub struct Solver<P, M = BoxedMasterProblem<CplexMaster>>
where
    P: FirstOrderProblem,
{
    /// The first order problem description.
    problem: P,

    /// The solver parameter.
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
    /// Accumulated information about the last iteration.
    iterinfos: Vec<IterationInfo>,
}

impl<P, M> Solver<P, M>
where
    P: FirstOrderProblem,
    P::Err: Into<Box<dyn Error + Send + Sync>> + 'static,
    M: MasterProblem<MinorantIndex = usize, SubgradientExtensionErr = P::Err>,
{
    /**
     * Create a new solver for the given problem.
     *
     * Note that the solver owns the problem, so you cannot use the
     * same problem description elsewhere as long as it is assigned to
     * the solver. However, it is possible to get a reference to the







|
|







482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
    /// Accumulated information about the last iteration.
    iterinfos: Vec<IterationInfo>,
}

impl<P, M> Solver<P, M>
where
    P: FirstOrderProblem,
    P::Err: Into<Box<std::error::Error + Send + Sync + 'static>>,
    M: MasterProblem<MinorantIndex = usize>,
{
    /**
     * Create a new solver for the given problem.
     *
     * Note that the solver owns the problem, so you cannot use the
     * same problem description elsewhere as long as it is assigned to
     * the solver. However, it is possible to get a reference to the
719
720
721
722
723
724
725

726
727
728
729
730
731
732
            let minorants = &self.minorants;
            self.master.add_vars(
                &newvars.iter().map(|v| (v.0, v.1, v.2)).collect::<Vec<_>>(),
                &mut |fidx, minidx, vars| {
                    problem
                        .extend_subgradient(minorants[fidx][minidx].primal.as_ref().unwrap(), vars)
                        .map(DVector)

                },
            )?;
            // modify moved variables
            for (index, val) in newvars.iter().filter_map(|v| v.0.map(|i| (i, v.3))) {
                self.cur_y[index] = val;
                self.nxt_y[index] = val;
                self.nxt_d[index] = 0.0;







>







716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
            let minorants = &self.minorants;
            self.master.add_vars(
                &newvars.iter().map(|v| (v.0, v.1, v.2)).collect::<Vec<_>>(),
                &mut |fidx, minidx, vars| {
                    problem
                        .extend_subgradient(minorants[fidx][minidx].primal.as_ref().unwrap(), vars)
                        .map(DVector)
                        .map_err(|e| e.into())
                },
            )?;
            // modify moved variables
            for (index, val) in newvars.iter().filter_map(|v| v.0.map(|i| (i, v.3))) {
                self.cur_y[index] = val;
                self.nxt_y[index] = val;
                self.nxt_d[index] = 0.0;