RsBundle  Check-in [cd30b6f272]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:master: Subgradient extension callback may return an error. This callback eventually calls a method of the oracle and may fail with some user error. This error is now returned to the master problem and finally back to the solver.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | error-handling
Files: files | file ages | folders
SHA1: cd30b6f27247dbfbda5d1378e135328cccc7158f
User & Date: fifr 2018-06-26 21:17:34.348
Context
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
16:00
Update version to 0.5.0 check-in: c62a27d815 user: fifr tags: error-handling, v0.5.0
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/master/base.rs.
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    /// 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]) -> DVector,
    ) -> 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.







|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    /// 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<DVector>,
    ) -> 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.
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    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]) -> DVector,
    ) -> 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));







|







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    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<DVector>,
    ) -> 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.
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
        }
    }

    fn add_vars(
        &mut self,
        nnew: usize,
        changed: &[usize],
        extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> DVector,
    ) -> 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);
                    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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
        }
    }

    fn add_vars(
        &mut self,
        nnew: usize,
        changed: &[usize],
        extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> Result<DVector>,
    ) -> 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)?;
                    for (&j, &g) in changed.iter().zip(new_subg.iter()) {
                        m.linear[j] = g;
                    }
                    m.linear.extend_from_slice(&new_subg[changed.len()..]);
                }
            }
        }
Changes to src/master/minimal.rs.
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
        Ok(self.minorants.len() - 1)
    }

    fn add_vars(
        &mut self,
        nnew: usize,
        changed: &[usize],
        extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> DVector,
    ) -> 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);
                for (&j, &g) in changed.iter().zip(new_subg.iter()) {
                    m.linear[j] = g;
                }
                m.linear.extend_from_slice(&new_subg[changed.len()..]);
            }
        }








|







|







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
        Ok(self.minorants.len() - 1)
    }

    fn add_vars(
        &mut self,
        nnew: usize,
        changed: &[usize],
        extend_subgradient: &mut FnMut(usize, Self::MinorantIndex, &[usize]) -> Result<DVector>,
    ) -> 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)?;
                for (&j, &g) in changed.iter().zip(new_subg.iter()) {
                    m.linear[j] = g;
                }
                m.linear.extend_from_slice(&new_subg[changed.len()..]);
            }
        }

Changes to src/master/unconstrained.rs.
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    /// 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]) -> DVector,
    ) -> 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;







|







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    /// 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<DVector>,
    ) -> 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.
460
461
462
463
464
465
466
467



468
469
470
471
472
473
474
    /// The active minorant indices for each subproblem.
    minorants: Vec<Vec<MinorantInfo<P::Primal>>>,

    /// Accumulated information about the last iteration.
    iterinfos: Vec<IterationInfo>,
}

impl<P: FirstOrderProblem> Solver<P> {



    /**
     * 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
     * internally stored problem using `Solver::problem()`.







|
>
>
>







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
    /// The active minorant indices for each subproblem.
    minorants: Vec<Vec<MinorantInfo<P::Primal>>>,

    /// Accumulated information about the last iteration.
    iterinfos: Vec<IterationInfo>,
}

impl<P: FirstOrderProblem> Solver<P>
where
    P::Err: Into<Box<dyn Error>>,
{
    /**
     * 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
     * internally stored problem using `Solver::problem()`.
681
682
683
684
685
686
687
688

689
690
691
692
693
694
695
696
697
698
699
700

        if !newvars.is_empty() {
            let mut problem = &mut self.problem;
            let minorants = &self.minorants;
            self.master
                .add_vars(
                    &newvars.iter().map(|v| (v.0, v.1, v.2)).collect::<Vec<_>>(),
                    &mut move |fidx, minidx, vars| match problem

                        .extend_subgradient(minorants[fidx][minidx].primal.as_ref().unwrap(), vars)
                        .map(DVector)
                    {
                        Ok(g) => g,
                        Err(_) => unreachable!(),
                    },
                )
                .map_err(SolverError::Master)?;
            // 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;







|
>
|
|
<
<
|







684
685
686
687
688
689
690
691
692
693
694


695
696
697
698
699
700
701
702

        if !newvars.is_empty() {
            let mut problem = &mut self.problem;
            let minorants = &self.minorants;
            self.master
                .add_vars(
                    &newvars.iter().map(|v| (v.0, v.1, v.2)).collect::<Vec<_>>(),
                    &mut move |fidx, minidx, vars| {
                        problem
                            .extend_subgradient(minorants[fidx][minidx].primal.as_ref().unwrap(), vars)
                            .map(DVector)


                            .map_err(|e| e.into())
                    },
                )
                .map_err(SolverError::Master)?;
            // 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;