RsBundle  Check-in [d7ed56f9b3]

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

Overview
Comment:Remove `DVector` from external API. The use of `[Real]` or `Vec<Real>` is sufficient in most cases.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d7ed56f9b311ddfc63436056e6830cab90b8293b
User & Date: fifr 2017-02-22 16:32:29.394
Context
2017-02-22
16:33
Update version to 0.3.0. check-in: 75fcbb74a4 user: fifr tags: trunk, v0.3.0
16:32
Remove `DVector` from external API. check-in: d7ed56f9b3 user: fifr tags: trunk
2017-02-14
05:27
Fix a clippy warning in quadratic example. check-in: e61d025a57 user: fifr tags: trunk, v0.2.2
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/firstorderproblem.rs.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Copyright (c) 2016 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/>
//

//! Problem description of a first-order convex optimization problem.

use {Real, Vector, DVector, Minorant};
use solver::UpdateState;

use std::error;
use std::vec::IntoIter;

/**
 * Trait for results of an evaluation.
|

















|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 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/>
//

//! Problem description of a first-order convex optimization problem.

use {Real, Minorant};
use solver::UpdateState;

use std::error;
use std::vec::IntoIter;

/**
 * Trait for results of an evaluation.
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    /**
     * 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<Vector> {
        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<Vector> {
        None
    }

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







|










|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    /**
     * 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
    }
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
     * true function value within $relprec \cdot (\\|f(y)\\| + 1.0)$,
     * otherwise the returned objective should be the maximum of all
     * linear minorants at $y$.
     *
     * Note that `nullstep_bound` and `relprec` are usually only
     * useful if there is only a `single` subproblem.
     */
    fn evaluate(&'a mut self, i: usize, y: &DVector, nullstep_bound: Real, relprec: Real) -> Result<Self::EvalResult, Self::Error>;

    /// Aggregate primal information.
    ///
    /// This function is called from the solver when minorants are
    /// aggregated. The problem can use this information to aggregate
    /// the corresponding primal information.
    ///







|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
     * true function value within $relprec \cdot (\\|f(y)\\| + 1.0)$,
     * otherwise the returned objective should be the maximum of all
     * linear minorants at $y$.
     *
     * Note that `nullstep_bound` and `relprec` are usually only
     * useful if there is only a `single` subproblem.
     */
    fn evaluate(&'a mut self, i: usize, y: &[Real], nullstep_bound: Real, relprec: Real) -> Result<Self::EvalResult, Self::Error>;

    /// Aggregate primal information.
    ///
    /// This function is called from the solver when minorants are
    /// aggregated. The problem can use this information to aggregate
    /// the corresponding primal information.
    ///
181
182
183
184
185
186
187
188
189
190
191
    ///
    /// The components are typically generated by some primal
    /// information. The corresponding primal is passed as a
    /// parameter.
    ///
    /// The default implementation fails because it should never be
    /// called.
    fn extend_subgradient(&mut self, _primal: &Self::Primal, _vars: &[usize]) -> Result<DVector, Self::Error> {
        unimplemented!()
    }
}







|



181
182
183
184
185
186
187
188
189
190
191
    ///
    /// The components are typically generated by some primal
    /// information. The corresponding primal is passed as a
    /// parameter.
    ///
    /// The default implementation fails because it should never be
    /// called.
    fn extend_subgradient(&mut self, _primal: &Self::Primal, _vars: &[usize]) -> Result<Vec<Real>, Self::Error> {
        unimplemented!()
    }
}
Changes to src/master/cpx.rs.
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
            updateinds: vec![],
            min2index: vec![],
            index2min: vec![],
            qterm: vec![],
            weight: 1.0,
            minorants: vec![],
            opt_mults: vec![],
            opt_minorant: Minorant::new(),
        })
    }

    fn num_subproblems(&self) -> usize {
        self.minorants.len()
    }








|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
            updateinds: vec![],
            min2index: vec![],
            index2min: vec![],
            qterm: vec![],
            weight: 1.0,
            minorants: vec![],
            opt_mults: vec![],
            opt_minorant: Minorant::default(),
        })
    }

    fn num_subproblems(&self) -> usize {
        self.minorants.len()
    }

308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
                for (idx_j, &j) in mins.iter().enumerate() {
                    aggr_qterm[i] += aggr_coeffs[idx_j] * self.qterm[i][j];
                }
            }
        }

        // aggregate the minorants
        let mut aggr = Minorant::new();
        {
            let mut aggr_mins = Vec::with_capacity(mins.len());

            for &i in mins {
                let (min_fidx, min_idx) = self.index2min[i];
                debug_assert!(min_fidx == fidx);








|







308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
                for (idx_j, &j) in mins.iter().enumerate() {
                    aggr_qterm[i] += aggr_coeffs[idx_j] * self.qterm[i][j];
                }
            }
        }

        // aggregate the minorants
        let mut aggr = Minorant::default();
        {
            let mut aggr_mins = Vec::with_capacity(mins.len());

            for &i in mins {
                let (min_fidx, min_idx) = self.index2min[i];
                debug_assert!(min_fidx == fidx);

Changes to src/master/minimal.rs.
1
2
3
4
5
6
7
8
// Copyright (c) 2016 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
|







1
2
3
4
5
6
7
8
// 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
Changes to src/mcf/problem.rs.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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 {Real, Vector, DVector, Minorant, FirstOrderProblem, SimpleEvaluation};
use mcf;

use std::fs::File;
use std::io::{self, Read};
use std::result;
use std::num::{ParseIntError, ParseFloatError};
use std::f64::INFINITY;







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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 {Real, DVector, Minorant, FirstOrderProblem, SimpleEvaluation};
use mcf;

use std::fs::File;
use std::io::{self, Read};
use std::result;
use std::num::{ParseIntError, ParseFloatError};
use std::f64::INFINITY;
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276

    type EvalResult = SimpleEvaluation<Vec<DVector>>;

    fn num_variables(&self) -> usize {
        self.lhs.len()
    }

    fn lower_bounds(&self) -> Option<Vector> {
        Some(Vector::new_sparse(self.lhs.len(), &[], &[]))
    }

    fn upper_bounds(&self) -> Option<Vector> {
        None
    }

    fn num_subproblems(&self) -> usize {
        if self.multimodel { self.nets.len() } else { 1 }
    }

    #[allow(unused_variables)]
    fn evaluate(&'a mut self, fidx: usize, y: &DVector, nullstep_bound: Real, relprec: Real) -> result::Result<Self::EvalResult, Self::Error> {
        // compute costs
        self.rhsval = 0.0;
        for i in 0..self.c.len() {
            self.c[i].clear();
            self.c[i].extend(self.cbase[i].iter());
        }

        for (i, &y) in y.iter().enumerate().filter(|&(i,&y)| y != 0.0) {
            self.rhsval += self.rhs[i] * y;
            for (fidx, c) in self.c.iter_mut().enumerate() {
                for elem in &self.lhs[i][fidx] {
                    c[elem.ind] += y * elem.val;
                }
            }
        }

        debug!("y={}", y);
        for i in 0..self.nets.len() {
            debug!("c[{}]={}", i, self.c[i]);
            try!(self.nets[i].set_objective(&self.c[i]));
        }

        // solve subproblems
        for (i, net) in self.nets.iter_mut().enumerate() {







|
|


|








|
















|







232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276

    type EvalResult = SimpleEvaluation<Vec<DVector>>;

    fn num_variables(&self) -> usize {
        self.lhs.len()
    }

    fn lower_bounds(&self) -> Option<Vec<Real>> {
        Some(vec![0.0; self.lhs.len()])
    }

    fn upper_bounds(&self) -> Option<Vec<Real>> {
        None
    }

    fn num_subproblems(&self) -> usize {
        if self.multimodel { self.nets.len() } else { 1 }
    }

    #[allow(unused_variables)]
    fn evaluate(&'a mut self, fidx: usize, y: &[Real], nullstep_bound: Real, relprec: Real) -> result::Result<Self::EvalResult, Self::Error> {
        // compute costs
        self.rhsval = 0.0;
        for i in 0..self.c.len() {
            self.c[i].clear();
            self.c[i].extend(self.cbase[i].iter());
        }

        for (i, &y) in y.iter().enumerate().filter(|&(i,&y)| y != 0.0) {
            self.rhsval += self.rhs[i] * y;
            for (fidx, c) in self.c.iter_mut().enumerate() {
                for elem in &self.lhs[i][fidx] {
                    c[elem.ind] += y * elem.val;
                }
            }
        }

        debug!("y={:?}", y);
        for i in 0..self.nets.len() {
            debug!("c[{}]={}", i, self.c[i]);
            try!(self.nets[i].set_objective(&self.c[i]));
        }

        // solve subproblems
        for (i, net) in self.nets.iter_mut().enumerate() {
Changes to src/minorant.rs.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59










60
61
62
63
64
65
66
 * \mathbb{R}$ is a linear function of the form
 *
 *   \\[ l \colon \mathbb{R}\^n \to \mathbb{R}, x \mapsto \langle g, x
 *   \rangle + c \\]
 *
 * such that $l(x) \le f(x)$ for all $x \in \mathbb{R}\^n$.
 */
#[derive(Clone, Debug, Default)]
pub struct Minorant {
    /// The constant term.
    pub constant: Real,

    /// The linear term.
    pub linear: DVector,
}



impl fmt::Display for Minorant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{} + y * {}", self.constant, self.linear));
        Ok(())
    }
}


impl Minorant {
    /// Return a new 0 minorant.
    pub fn new() -> Minorant {
        Minorant {
            constant: 0.0,
            linear: dvec![],
        }
    }











    /**
     * Evaluate minorant at some point.
     *
     * This function computes $c + \langle g, x \rangle$ for this minorant
     *   \\[\ell \colon \mathbb{R}\^n \to \mathbb{R}, x \mapsto c + \langle g, x \rangle\\]
     * and the given point $x \in \mathbb{R}\^n$.







|







>









<
|
<
|





>
>
>
>
>
>
>
>
>
>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

52

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
 * \mathbb{R}$ is a linear function of the form
 *
 *   \\[ l \colon \mathbb{R}\^n \to \mathbb{R}, x \mapsto \langle g, x
 *   \rangle + c \\]
 *
 * such that $l(x) \le f(x)$ for all $x \in \mathbb{R}\^n$.
 */
#[derive(Clone, Debug)]
pub struct Minorant {
    /// The constant term.
    pub constant: Real,

    /// The linear term.
    pub linear: DVector,
}



impl fmt::Display for Minorant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{} + y * {}", self.constant, self.linear));
        Ok(())
    }
}


impl Default for Minorant {

    fn default() -> Minorant {
        Minorant {
            constant: 0.0,
            linear: dvec![],
        }
    }
}

impl Minorant {
    /// Return a new 0 minorant.
    pub fn new(constant: Real, linear: Vec<Real>) -> Minorant {
        Minorant {
            constant: constant,
            linear: DVector(linear),
        }
    }

    /**
     * Evaluate minorant at some point.
     *
     * This function computes $c + \langle g, x \rangle$ for this minorant
     *   \\[\ell \colon \mathbb{R}\^n \to \mathbb{R}, x \mapsto c + \langle g, x \rangle\\]
     * and the given point $x \in \mathbb{R}\^n$.
Changes to src/solver.rs.
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
    pub fn init(&mut self) -> Result<()> {
        try!(self.params.check());
        if self.cur_y.len() != self.problem.num_variables() {
            self.cur_valid = false;
            self.cur_y.init0(self.problem.num_variables());
        }

        let lb = self.problem.lower_bounds().map(|x| x.to_dense());
        let ub = self.problem.upper_bounds().map(|x| x.to_dense());
        for i in 0..self.cur_y.len() {
            let lb_i = lb.as_ref().map(|x| x[i]).unwrap_or(NEG_INFINITY);
            let ub_i = ub.as_ref().map(|x| x[i]).unwrap_or(INFINITY);
            if lb_i > ub_i {
                return Err(Error::InvalidBounds(lb_i, ub_i));
            }
            if self.cur_y[i] < lb_i {







|
|







513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
    pub fn init(&mut self) -> Result<()> {
        try!(self.params.check());
        if self.cur_y.len() != self.problem.num_variables() {
            self.cur_valid = false;
            self.cur_y.init0(self.problem.num_variables());
        }

        let lb = self.problem.lower_bounds();
        let ub = self.problem.upper_bounds();
        for i in 0..self.cur_y.len() {
            let lb_i = lb.as_ref().map(|x| x[i]).unwrap_or(NEG_INFINITY);
            let ub_i = ub.as_ref().map(|x| x[i]).unwrap_or(INFINITY);
            if lb_i > ub_i {
                return Err(Error::InvalidBounds(lb_i, ub_i));
            }
            if self.cur_y[i] < lb_i {
623
624
625
626
627
628
629

630
631
632
633
634
635
636

        if !newvars.is_empty() {
            let mut problem = &mut self.problem;
            let minorants = &self.minorants;
            self.master.add_vars(&newvars,
                                 &mut move |fidx, minidx, vars| {
                                     problem.extend_subgradient(minorants[fidx][minidx].primal.as_ref().unwrap(), vars)

                                         .unwrap()
                                 });
            let newn = self.cur_y.len() + newvars.len();
            self.cur_y.resize(newn, 0.0);
            self.nxt_d.resize(newn, 0.0);
            self.nxt_y.resize(newn, 0.0);
            Ok(true)







>







623
624
625
626
627
628
629
630
631
632
633
634
635
636
637

        if !newvars.is_empty() {
            let mut problem = &mut self.problem;
            let minorants = &self.minorants;
            self.master.add_vars(&newvars,
                                 &mut move |fidx, minidx, vars| {
                                     problem.extend_subgradient(minorants[fidx][minidx].primal.as_ref().unwrap(), vars)
                                         .map(DVector)
                                         .unwrap()
                                 });
            let newn = self.cur_y.len() + newvars.len();
            self.cur_y.resize(newn, 0.0);
            self.nxt_d.resize(newn, 0.0);
            self.nxt_y.resize(newn, 0.0);
            Ok(true)
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
            debug!("Use minimal master problem");
            Box::new(BoxedMasterProblem::<MinimalMaster>::new().unwrap())
        } else {
            debug!("Use CPLEX master problem");
            Box::new(BoxedMasterProblem::<CplexMaster>::new().unwrap())
        };

        let lb = self.problem.lower_bounds().map(|v| v.to_dense());
        let ub = self.problem.upper_bounds().map(|v| v.to_dense());

        if let Some(ref x) = lb {
            if x.len() != self.problem.num_variables() {
                return Err(Error::Dimension("Dimension of lower bounds does not match number of \
                                             variables"));
            }
        }







|
|







691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
            debug!("Use minimal master problem");
            Box::new(BoxedMasterProblem::<MinimalMaster>::new().unwrap())
        } else {
            debug!("Use CPLEX master problem");
            Box::new(BoxedMasterProblem::<CplexMaster>::new().unwrap())
        };

        let lb = self.problem.lower_bounds().map(DVector);
        let ub = self.problem.upper_bounds().map(DVector);

        if let Some(ref x) = lb {
            if x.len() != self.problem.num_variables() {
                return Err(Error::Dimension("Dimension of lower bounds does not match number of \
                                             variables"));
            }
        }