RsBundle  Check-in [29f93aefac]

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

Overview
Comment:Add `MinorantIndex` as reference to minorants to master problem.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 29f93aefacb2fab43bf52adba5a25dad39150a79
User & Date: fifr 2016-09-28 15:52:38.696
Context
2016-09-28
16:00
master::cpx: Return error when solving an empty model. check-in: 487d3d7ad8 user: fifr tags: trunk
15:52
Add `MinorantIndex` as reference to minorants to master problem. check-in: 29f93aefac user: fifr tags: trunk
15:15
solver: Use `CplexMaster` as default for large master problems. check-in: cc9ce5ef15 user: fifr tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/master/boxed.rs.
178
179
180
181
182
183
184


185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
        }
        return norm2;
    }
}


impl<M : UnconstrainedMasterProblem> MasterProblem for BoxedMasterProblem<M> {


    fn set_num_subproblems(&mut self, n : usize) -> Result<()> {
        self.master.set_num_subproblems(n).map_err(|err| Error::Solver(Box::new(err)))
    }

    fn set_vars(&mut self, n: usize, lb : Option<DVector>, ub: Option<DVector>) {
        assert!(lb.as_ref().map(|x| x.len()).unwrap_or(n) == n);
        assert!(ub.as_ref().map(|x| x.len()).unwrap_or(n) == n);
        self.lb = lb.unwrap_or_else(|| dvec![NEG_INFINITY; n]);
        self.ub = ub.unwrap_or_else(|| dvec![INFINITY; n]);
    }

    fn num_minorants(&self, fidx: usize) -> usize { self.master.num_minorants(fidx) }

    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<()> {
        self.master.add_minorant(fidx, minorant).map_err(|err| Error::Solver(Box::new(err)))
    }

    fn weight(&self) -> Real {
        self.master.weight()
    }








>
>













|







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
        }
        return norm2;
    }
}


impl<M : UnconstrainedMasterProblem> MasterProblem for BoxedMasterProblem<M> {
    type MinorantIndex = M::MinorantIndex;

    fn set_num_subproblems(&mut self, n : usize) -> Result<()> {
        self.master.set_num_subproblems(n).map_err(|err| Error::Solver(Box::new(err)))
    }

    fn set_vars(&mut self, n: usize, lb : Option<DVector>, ub: Option<DVector>) {
        assert!(lb.as_ref().map(|x| x.len()).unwrap_or(n) == n);
        assert!(ub.as_ref().map(|x| x.len()).unwrap_or(n) == n);
        self.lb = lb.unwrap_or_else(|| dvec![NEG_INFINITY; n]);
        self.ub = ub.unwrap_or_else(|| dvec![INFINITY; n]);
    }

    fn num_minorants(&self, fidx: usize) -> usize { self.master.num_minorants(fidx) }

    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<Self::MinorantIndex> {
        self.master.add_minorant(fidx, minorant).map_err(|err| Error::Solver(Box::new(err)))
    }

    fn weight(&self) -> Real {
        self.master.weight()
    }

278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
        debug!("  dualopt={}", self.master.dualopt());
        debug!("  etaopt={}", self.eta);
        debug!("  primoptval={}", self.primoptval);

        Ok(())
    }

    fn aggregate(&mut self, fidx: usize, mins: &[usize]) {
        self.master.aggregate(fidx, mins)
    }

    fn get_primopt(&self) -> DVector { self.primopt.clone() }

    fn get_primoptval(&self) -> Real { self.primoptval }

    fn get_dualoptnorm2(&self) -> Real { self.dualoptnorm2 }







|
|







280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
        debug!("  dualopt={}", self.master.dualopt());
        debug!("  etaopt={}", self.eta);
        debug!("  primoptval={}", self.primoptval);

        Ok(())
    }

    fn aggregate(&mut self, fidx: usize, mins: &[usize]) -> Result<Self::MinorantIndex> {
        self.master.aggregate(fidx, mins).map_err(|err| Error::Solver(Box::new(err)))
    }

    fn get_primopt(&self) -> DVector { self.primopt.clone() }

    fn get_primoptval(&self) -> Real { self.primoptval }

    fn get_dualoptnorm2(&self) -> Real { self.dualoptnorm2 }
Changes to src/master/cpx.rs.
84
85
86
87
88
89
90


91
92
93
94
95
96
97
        unsafe { CPXfreeprob(env(), &mut self.lp) };
    }
}


impl UnconstrainedMasterProblem for CplexMaster {
    type Error = Error;



    fn new() -> Result<CplexMaster> {
        Ok(CplexMaster {
            lp: ptr::null_mut(),
            force_update: true,
            freeinds: vec![],
            min2index: vec![],







>
>







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
        unsafe { CPXfreeprob(env(), &mut self.lp) };
    }
}


impl UnconstrainedMasterProblem for CplexMaster {
    type Error = Error;

    type MinorantIndex = usize;

    fn new() -> Result<CplexMaster> {
        Ok(CplexMaster {
            lp: ptr::null_mut(),
            force_update: true,
            freeinds: vec![],
            min2index: vec![],
130
131
132
133
134
135
136
137
138
139
140
141
142
143


144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
        self.weight = weight;
    }

    fn num_minorants(&self, fidx : usize) -> usize {
        self.minorants[fidx].len()
    }

    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<()> {
        debug!("Add minorant");
        debug!("  fidx={} index={}: {}", fidx, self.minorants[fidx].len()-1, minorant);

        let min_idx = self.minorants[fidx].len();
        self.minorants[fidx].push(minorant);
        self.opt_mults[fidx].push(0.0);



        if let Some(idx) = self.freeinds.pop() {
            self.min2index[fidx].push(idx);
            self.index2min[idx] = (fidx, min_idx)

        } else {
            let idx = self.index2min.len();
            self.min2index[fidx].push(idx);
            self.index2min.push((fidx, min_idx));
        }

        self.force_update = true;

        Ok(())
    }

    #[allow(unused_variables)]
    fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> Result<()> {
        if self.force_update { try!(self.init_qp()) }

        let nvars = unsafe { CPXgetnumcols(env(), self.lp) as usize };







|






>
>



|
>




<
|
<
|
<







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

157

158

159
160
161
162
163
164
165
        self.weight = weight;
    }

    fn num_minorants(&self, fidx : usize) -> usize {
        self.minorants[fidx].len()
    }

    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<usize> {
        debug!("Add minorant");
        debug!("  fidx={} index={}: {}", fidx, self.minorants[fidx].len()-1, minorant);

        let min_idx = self.minorants[fidx].len();
        self.minorants[fidx].push(minorant);
        self.opt_mults[fidx].push(0.0);

        self.force_update = true;

        if let Some(idx) = self.freeinds.pop() {
            self.min2index[fidx].push(idx);
            self.index2min[idx] = (fidx, min_idx);
            Ok(idx)
        } else {
            let idx = self.index2min.len();
            self.min2index[fidx].push(idx);
            self.index2min.push((fidx, min_idx));

            Ok(idx)

        }

    }

    #[allow(unused_variables)]
    fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> Result<()> {
        if self.force_update { try!(self.init_qp()) }

        let nvars = unsafe { CPXgetnumcols(env(), self.lp) as usize };
211
212
213
214
215
216
217
218




219
220
221
222
223
224
225
                this_val = this_val.max(m.eval(y));
            }
            result += this_val;
        }
        result
    }

    fn aggregate(&mut self, fidx: usize, mins: &[usize]) {




        let mut sum_coeffs = 0.0;
        let mut aggr = Minorant::new();
        {
            let mut aggr_mins = Vec::with_capacity(mins.len());
            let mut aggr_coeffs = Vec::with_capacity(mins.len());

            for &i in mins {







|
>
>
>
>







213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
                this_val = this_val.max(m.eval(y));
            }
            result += this_val;
        }
        result
    }

    fn aggregate(&mut self, fidx: usize, mins: &[usize]) -> Result<usize> {
        assert!(mins.len() > 0, "No minorants specified to be aggregated");

        if mins.len() == 1 { return Ok(mins[0]) }

        let mut sum_coeffs = 0.0;
        let mut aggr = Minorant::new();
        {
            let mut aggr_mins = Vec::with_capacity(mins.len());
            let mut aggr_coeffs = Vec::with_capacity(mins.len());

            for &i in mins {
250
251
252
253
254
255
256


257
258
259
260
261
262
263
        let aggr_idx = self.freeinds.pop().unwrap();
        self.minorants[fidx].push(aggr);
        self.opt_mults[fidx].push(sum_coeffs);
        self.min2index[fidx].push(aggr_idx);
        self.index2min[aggr_idx] = (fidx, self.minorants[fidx].len()-1);

        self.force_update = true;


    }

    fn move_center(&mut self, alpha: Real, d: &DVector) {
        for mins in self.minorants.iter_mut() {
            for m in mins.iter_mut() {
                m.move_center(alpha, d);
            }







>
>







256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
        let aggr_idx = self.freeinds.pop().unwrap();
        self.minorants[fidx].push(aggr);
        self.opt_mults[fidx].push(sum_coeffs);
        self.min2index[fidx].push(aggr_idx);
        self.index2min[aggr_idx] = (fidx, self.minorants[fidx].len()-1);

        self.force_update = true;

        Ok(aggr_idx)
    }

    fn move_center(&mut self, alpha: Real, d: &DVector) {
        for mins in self.minorants.iter_mut() {
            for m in mins.iter_mut() {
                m.move_center(alpha, d);
            }
Changes to src/master/master.rs.
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
}


/// Result type for master problems.
pub type Result<T> = result::Result<T, Error>;

pub trait MasterProblem {



    /// Set the number of subproblems.
    fn set_num_subproblems(&mut self, n : usize) -> Result<()>;

    /// Set the lower and upper bounds of the variables.
    fn set_vars(&mut self, nvars: usize, lb : Option<DVector>, ub: Option<DVector>);

    /// Return the current number of minorants of subproblem `fidx`.
    fn num_minorants(&self, fidx : usize) -> usize;

    /// Add a new minorant to the model.




    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<()>;

    /// 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);

    /// Solve the master problem.
    fn solve(&mut self, cur_value: Real) -> Result<()>;

    /// Aggregate the given minorants according to the current solution.








    fn aggregate(&mut self, fidx: usize, mins: &[usize]);

    /// Return the primal optimal solution.
    fn get_primopt(&self) -> DVector;

    /// Return the primal optimal solution value.
    fn get_primoptval(&self) -> Real;








>
>
>










>
>
>
>
|











>
>
>
>
>
>
>
>
|







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
76
77
78
79
80
81
82
83
84
}


/// Result type for master problems.
pub type Result<T> = result::Result<T, Error>;

pub trait MasterProblem {
    /// Unique index for a minorant.
    type MinorantIndex : Copy + Eq;

    /// Set the number of subproblems.
    fn set_num_subproblems(&mut self, n : usize) -> Result<()>;

    /// Set the lower and upper bounds of the variables.
    fn set_vars(&mut self, nvars: usize, lb : Option<DVector>, ub: Option<DVector>);

    /// Return the current number of minorants of subproblem `fidx`.
    fn num_minorants(&self, fidx : usize) -> usize;

    /// 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>;

    /// 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);

    /// Solve the master problem.
    fn solve(&mut self, cur_value: Real) -> Result<()>;

    /// Aggregate the given minorants according to the current solution.
    ///
    /// The (indices of the) minorants to be aggregated get invalid
    /// after this operation. The index of the new aggregated minorant
    /// is returned and 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>;

    /// Return the primal optimal solution.
    fn get_primopt(&self) -> DVector;

    /// Return the primal optimal solution value.
    fn get_primoptval(&self) -> Real;

Changes to src/master/minimal.rs.
68
69
70
71
72
73
74


75
76
77
78
79
80
81
    /// Optimal aggregated minorant.
    opt_minorant: Minorant,
}


impl UnconstrainedMasterProblem for MinimalMaster {
    type Error = Error;



    fn new() -> Result<MinimalMaster> {
        Ok(MinimalMaster {
            weight: 1.0,
            minorants: vec![],
            opt_mult: dvec![],
            opt_minorant: Minorant::default(),







>
>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    /// Optimal aggregated minorant.
    opt_minorant: Minorant,
}


impl UnconstrainedMasterProblem for MinimalMaster {
    type Error = Error;

    type MinorantIndex = usize;

    fn new() -> Result<MinimalMaster> {
        Ok(MinimalMaster {
            weight: 1.0,
            minorants: vec![],
            opt_mult: dvec![],
            opt_minorant: Minorant::default(),
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
    }

    fn num_minorants(&self, fidx: usize) -> usize {
        assert!(fidx == 0);
        self.minorants.len()
    }

    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<()>{
        assert!(fidx == 0);
        if self.minorants.len() >= 2 {
            return Err(Error::MaxMinorants)
        }
        self.minorants.push(minorant);
        self.opt_mult.push(0.0);
        Ok(())
    }

    #[allow(unused_variables)]
    fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> Result<()> {
        for (i, m) in self.minorants.iter().enumerate() {
            debug!("  {}:min[{},{}] = {}",  i, 0, 0, m);
        }







|






|







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
    }

    fn num_minorants(&self, fidx: usize) -> usize {
        assert!(fidx == 0);
        self.minorants.len()
    }

    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> Result<usize>{
        assert!(fidx == 0);
        if self.minorants.len() >= 2 {
            return Err(Error::MaxMinorants)
        }
        self.minorants.push(minorant);
        self.opt_mult.push(0.0);
        Ok(self.minorants.len()-1)
    }

    #[allow(unused_variables)]
    fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> Result<()> {
        for (i, m) in self.minorants.iter().enumerate() {
            debug!("  {}:min[{},{}] = {}",  i, 0, 0, m);
        }
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
        let mut result = NEG_INFINITY;
        for m in &self.minorants {
            result = result.max(m.eval(y));
        }
        return result;
    }

    fn aggregate(&mut self, fidx: usize, mins: &[usize]) {
        assert!(fidx == 0);
        if mins.len() == 2 {
            debug!("Aggregate");
            debug!("  {} * {}", self.opt_mult[0], self.minorants[0]);
            debug!("  {} * {}", self.opt_mult[1], self.minorants[1]);
            self.minorants[0] = self.minorants[0].combine(self.opt_mult[0], self.opt_mult[1], &self.minorants[1]);
            self.minorants.truncate(1);
            self.opt_mult.truncate(1);
            self.opt_mult[0] = 1.0;
            debug!("  {}", self.minorants[0]);





        }
    }

    fn move_center(&mut self, alpha: Real, d: &DVector) {
        for m in self.minorants.iter_mut() {
            m.move_center(alpha, d);
        }
    }
}







|










>
>
>
>
>









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
192
193
194
195
196
197
198
        let mut result = NEG_INFINITY;
        for m in &self.minorants {
            result = result.max(m.eval(y));
        }
        return result;
    }

    fn aggregate(&mut self, fidx: usize, mins: &[usize]) -> Result<usize> {
        assert!(fidx == 0);
        if mins.len() == 2 {
            debug!("Aggregate");
            debug!("  {} * {}", self.opt_mult[0], self.minorants[0]);
            debug!("  {} * {}", self.opt_mult[1], self.minorants[1]);
            self.minorants[0] = self.minorants[0].combine(self.opt_mult[0], self.opt_mult[1], &self.minorants[1]);
            self.minorants.truncate(1);
            self.opt_mult.truncate(1);
            self.opt_mult[0] = 1.0;
            debug!("  {}", self.minorants[0]);
            Ok(0)
        } else if mins.len() == 1 {
            Ok(mins[0])
        } else {
            panic!("No minorants specified to be aggregated");
        }
    }

    fn move_center(&mut self, alpha: Real, d: &DVector) {
        for m in self.minorants.iter_mut() {
            m.move_center(alpha, d);
        }
    }
}
Changes to src/master/unconstrained.rs.
38
39
40
41
42
43
44



45
46
47
48
49
50
51
 * optimal coefficients $\bar{\alpha}$ for the dual problem
 *
 * \\[ \max_{\alpha \in \Delta} \min_{d \in \mathbb{R}\^n} \sum_{i=1}\^k \alpha_i \ell_i(d) + \frac{u}{2} \\| d \\|\^2. \\]
 */
pub trait UnconstrainedMasterProblem {
    /// Error type.
    type Error : error::Error + 'static;




    /// Return a new instance of the unconstrained master problem.
    fn new() -> result::Result<Self, Self::Error>
        where Self: Sized;

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







>
>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
 * optimal coefficients $\bar{\alpha}$ for the dual problem
 *
 * \\[ \max_{\alpha \in \Delta} \min_{d \in \mathbb{R}\^n} \sum_{i=1}\^k \alpha_i \ell_i(d) + \frac{u}{2} \\| d \\|\^2. \\]
 */
pub trait UnconstrainedMasterProblem {
    /// Error type.
    type Error : error::Error + 'static;

    /// Unique index for a minorant.
    type MinorantIndex : Copy + Eq;

    /// Return a new instance of the unconstrained master problem.
    fn new() -> result::Result<Self, Self::Error>
        where Self: Sized;

    /// Return the number of subproblems.
    fn num_subproblems(&self) -> usize;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80








81
82
83
84
85
    /// Set the weight of the quadratic term, must be > 0.
    fn set_weight(&mut self, weight: Real);

    /// Return the number of minorants of subproblem `fidx`.
    fn num_minorants(&self, fidx: usize) -> usize;

    /// Add a new minorant to the model.
    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> result::Result<(), Self::Error>;

    /// Solve the master problem.
    fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> result::Result<(), Self::Error>;

    /// Return the current dual optimal solution.
    fn dualopt(&self) -> &DVector;

    /// Return the current dual optimal solution value.
    fn dualopt_cutval(&self) -> Real;

    /// Return the value of the current model at the given point.
    fn eval_model(&self, y: &DVector) -> Real;

    /// Aggregate the given minorants according to the current solution.








    fn aggregate(&mut self, fidx: usize, mins: &[usize]);

    /// Move the center of the master problem along $\alpha \cdot d$.
    fn move_center(&mut self, alpha: Real, d: &DVector);
}







|














>
>
>
>
>
>
>
>
|




62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
    /// Set the weight of the quadratic term, must be > 0.
    fn set_weight(&mut self, weight: Real);

    /// Return the number of minorants of subproblem `fidx`.
    fn num_minorants(&self, fidx: usize) -> usize;

    /// Add a new minorant to the model.
    fn add_minorant(&mut self, fidx: usize, minorant: Minorant) -> result::Result<Self::MinorantIndex, Self::Error>;

    /// Solve the master problem.
    fn solve(&mut self, eta: &DVector, fbound: Real, augbound: Real, relprec: Real) -> result::Result<(), Self::Error>;

    /// Return the current dual optimal solution.
    fn dualopt(&self) -> &DVector;

    /// Return the current dual optimal solution value.
    fn dualopt_cutval(&self) -> Real;

    /// Return the value of the current model at the given point.
    fn eval_model(&self, y: &DVector) -> Real;

    /// Aggregate the given minorants according to the current solution.
    ///
    /// The (indices of the) minorants to be aggregated get invalid
    /// after this operation. The index of the new aggregated minorant
    /// is returned and 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, Self::Error>;

    /// Move the center of the master problem along $\alpha \cdot d$.
    fn move_center(&mut self, alpha: Real, d: &DVector);
}
Changes to src/solver.rs.
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
     * Time when the solution process started.
     *
     * This is actually the time of the last call to `Solver::init`.
     */
    start_time : Instant,

    /// The master problem.
    master: Box<MasterProblem>,
}


impl<P> Solver<P>
    where P : for <'a> FirstOrderProblem<'a>
{
    /**







|







361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
     * Time when the solution process started.
     *
     * This is actually the time of the last call to `Solver::init`.
     */
    start_time : Instant,

    /// The master problem.
    master: Box<MasterProblem<MinorantIndex=usize>>,
}


impl<P> Solver<P>
    where P : for <'a> FirstOrderProblem<'a>
{
    /**