RsBundle  Check-in [f5557bc6af]

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

Overview
Comment:Remove unused parameters from `SolverParam`
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | async
Files: files | file ages | folders
SHA1: f5557bc6afdbd0bfad51536d180a98ea90d7792c
User & Date: fifr 2019-07-20 14:17:40.921
Context
2019-07-21
17:28
Move master process code to `masterprocess` check-in: a7b5649186 user: fifr tags: async
2019-07-20
14:17
Remove unused parameters from `SolverParam` check-in: f5557bc6af user: fifr tags: async
13:58
Merge terminator check-in: 071e757395 user: fifr tags: async
Changes
Unified Diff Ignore Whitespace Patch
Changes to examples/mmcf.rs.
20
21
22
23
24
25
26
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
use log::info;

use bundle::mcf;
use bundle::{DefaultSolver, FirstOrderProblem, SolverParams};

use std::env;

fn main() {
    env_logger::init();

    let mut args = env::args();
    let program = args.next().unwrap();

    if let Some(filename) = args.next() {
        info!("Reading instance: {}", filename);
        let mut mmcf = mcf::MMCFProblem::read_mnetgen(&filename).unwrap();
        mmcf.multimodel = false;

        let mut solver = DefaultSolver::new_params(
            mmcf,
            SolverParams {
                max_bundle_size: 25,
                min_weight: 1e-3,
                max_weight: 100.0,
                ..Default::default()
            },
        )
        .unwrap();

        solver.terminator.termination_precision = 1e-6;
        solver.solve().unwrap();

        let costs: f64 = (0..solver.problem().num_subproblems())
            .map(|i| {
                let aggr_primals = solver.aggregated_primals(i);
                solver.problem().get_primal_costs(i, &aggr_primals)
            })
            .sum();
        info!("Primal costs: {}", costs);
    } else {
        panic!("Usage: {} FILENAME", program);
    }


}







|



|



|






<
<


|
<
>

|











>
>

20
21
22
23
24
25
26
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
use log::info;

use bundle::mcf;
use bundle::{DefaultSolver, FirstOrderProblem, SolverParams};

use std::env;

fn main() -> std::result::Result<(), Box<std::error::Error>> {
    env_logger::init();

    let mut args = env::args();
    let program = args.next().ok_or_else(|| "Missing filename".to_string())?;

    if let Some(filename) = args.next() {
        info!("Reading instance: {}", filename);
        let mut mmcf = mcf::MMCFProblem::read_mnetgen(&filename)?;
        mmcf.multimodel = false;

        let mut solver = DefaultSolver::new_params(
            mmcf,
            SolverParams {
                max_bundle_size: 25,


                ..Default::default()
            },
        )?;

        solver.weighter.set_weight_bounds(1e-3, 100.0);
        solver.terminator.termination_precision = 1e-6;
        solver.solve()?;

        let costs: f64 = (0..solver.problem().num_subproblems())
            .map(|i| {
                let aggr_primals = solver.aggregated_primals(i);
                solver.problem().get_primal_costs(i, &aggr_primals)
            })
            .sum();
        info!("Primal costs: {}", costs);
    } else {
        panic!("Usage: {} FILENAME", program);
    }

    Ok(())
}
Changes to examples/quadratic.rs.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

use std::error::Error;

use bundle::{self, dvec};
use env_logger;
use log::debug;

use bundle::{DVector, DefaultSolver, FirstOrderProblem, Minorant, Real, SimpleEvaluation, SolverParams};

struct QuadraticProblem {
    a: [[Real; 2]; 2],
    b: [Real; 2],
    c: Real,
}








|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

use std::error::Error;

use bundle::{self, dvec};
use env_logger;
use log::debug;

use bundle::{DVector, DefaultSolver, FirstOrderProblem, Minorant, Real, SimpleEvaluation};

struct QuadraticProblem {
    a: [[Real; 2]; 2],
    b: [Real; 2],
    c: Real,
}

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
                },
                (),
            )],
        })
    }
}

fn main() {
    env_logger::init();

    let f = QuadraticProblem::new();
    let mut solver = DefaultSolver::new_params(
        f,
        SolverParams {
            min_weight: 1.0,
            max_weight: 1.0,
            ..Default::default()
        },

    )
    .unwrap();
    solver.solve().unwrap();
}







|



|
<
<
|
<
<
<
>
|
|
<

79
80
81
82
83
84
85
86
87
88
89
90


91



92
93
94

95
                },
                (),
            )],
        })
    }
}

fn main() -> Result<(), Box<Error>> {
    env_logger::init();

    let f = QuadraticProblem::new();
    let mut solver = DefaultSolver::new(f).map_err(|e| format!("{}", e))?;


    solver.weighter.set_weight_bounds(1.0, 1.0);



    solver.solve().map_err(|e| format!("{}", e))?;

    Ok(())

}
Changes to src/master/boxed.rs.
26
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
76
77
78
79
80
81
82
83
84
 * Turn unconstrained master problem into box-constrained one.
 *
 * This master problem adds box constraints to an unconstrainted
 * master problem implementation. The box constraints are enforced by
 * an additional outer optimization loop.
 */
pub struct BoxedMasterProblem<M> {







    lb: DVector,


    ub: DVector,


    eta: DVector,

    /// Primal optimal solution.
    primopt: DVector,

    /// Primal optimal solution value.
    primoptval: Real,

    /// Square of norm of dual optimal solution.
    dualoptnorm2: Real,

    /// Model precision.
    model_eps: Real,

    need_new_candidate: bool,

    /// Maximal number of updates of box multipliers.
    max_updates: usize,

    /// Current number of updates.
    cnt_updates: usize,

    /// The unconstrained master problem solver.
    master: M,
}

impl<M> BoxedMasterProblem<M>
where
    M: UnconstrainedMasterProblem,
{
    pub fn with_master(master: M) -> BoxedMasterProblem<M> {
        BoxedMasterProblem {


            lb: dvec![],
            ub: dvec![],
            eta: dvec![],
            primopt: dvec![],
            primoptval: 0.0,
            dualoptnorm2: 0.0,
            model_eps: 0.6,
            max_updates: 100,
            cnt_updates: 0,
            need_new_candidate: true,
            master,
        }
    }

    pub fn set_max_updates(&mut self, max_updates: usize) -> Result<(), M::Err> {
        assert!(max_updates > 0);
        self.max_updates = max_updates;
        Ok(())







>
>
>
>
>
>
>

>
>

>
>
















<
<
<


<
<
<








>
>







<


<







26
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
76
77
78
79
80

81
82

83
84
85
86
87
88
89
 * Turn unconstrained master problem into box-constrained one.
 *
 * This master problem adds box constraints to an unconstrainted
 * master problem implementation. The box constraints are enforced by
 * an additional outer optimization loop.
 */
pub struct BoxedMasterProblem<M> {
    /// The unconstrained master problem solver.
    pub master: M,

    /// Maximal number of updates of box multipliers.
    pub max_updates: usize,

    /// Variable lower bounds.
    lb: DVector,

    /// Variable upper bounds.
    ub: DVector,

    /// Multipliers for box constraints.
    eta: DVector,

    /// Primal optimal solution.
    primopt: DVector,

    /// Primal optimal solution value.
    primoptval: Real,

    /// Square of norm of dual optimal solution.
    dualoptnorm2: Real,

    /// Model precision.
    model_eps: Real,

    need_new_candidate: bool,




    /// Current number of updates.
    cnt_updates: usize,



}

impl<M> BoxedMasterProblem<M>
where
    M: UnconstrainedMasterProblem,
{
    pub fn with_master(master: M) -> BoxedMasterProblem<M> {
        BoxedMasterProblem {
            master,
            max_updates: 50,
            lb: dvec![],
            ub: dvec![],
            eta: dvec![],
            primopt: dvec![],
            primoptval: 0.0,
            dualoptnorm2: 0.0,
            model_eps: 0.6,

            cnt_updates: 0,
            need_new_candidate: true,

        }
    }

    pub fn set_max_updates(&mut self, max_updates: usize) -> Result<(), M::Err> {
        assert!(max_updates > 0);
        self.max_updates = max_updates;
        Ok(())
Changes to src/parallel/solver.rs.
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    num_subproblems: usize,
    /// The number of variables.
    num_vars: usize,
    /// The lower bounds on the variables.
    lower_bounds: Option<DVector>,
    /// The lower bounds on the variables.
    upper_bounds: Option<DVector>,
    /// The maximal number of inner updates.
    max_updates: usize,
}

/// A task for the master problem.
enum MasterTask<Pr> {
    /// Add a new minorant for a subfunction to the master problem.
    AddMinorant(usize, Minorant, Pr),








<
<







104
105
106
107
108
109
110


111
112
113
114
115
116
117
    num_subproblems: usize,
    /// The number of variables.
    num_vars: usize,
    /// The lower bounds on the variables.
    lower_bounds: Option<DVector>,
    /// The lower bounds on the variables.
    upper_bounds: Option<DVector>,


}

/// A task for the master problem.
enum MasterTask<Pr> {
    /// Add a new minorant for a subfunction to the master problem.
    AddMinorant(usize, Minorant, Pr),

353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
        self.master_rx = Some(rev_rx);

        let master_config = MasterConfig {
            num_subproblems: m,
            num_vars: n,
            lower_bounds: self.problem.lower_bounds().map(DVector),
            upper_bounds: self.problem.upper_bounds().map(DVector),
            max_updates: self.params.max_updates,
        };

        if master_config
            .lower_bounds
            .as_ref()
            .map(|lb| lb.len() != n)
            .unwrap_or(false)







<







351
352
353
354
355
356
357

358
359
360
361
362
363
364
        self.master_rx = Some(rev_rx);

        let master_config = MasterConfig {
            num_subproblems: m,
            num_vars: n,
            lower_bounds: self.problem.lower_bounds().map(DVector),
            upper_bounds: self.problem.upper_bounds().map(DVector),

        };

        if master_config
            .lower_bounds
            .as_ref()
            .map(|lb| lb.len() != n)
            .unwrap_or(false)
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
        // Initialize the master problem.
        master.set_num_subproblems(master_config.num_subproblems)?;
        master.set_vars(
            master_config.num_vars,
            master_config.lower_bounds,
            master_config.upper_bounds,
        )?;
        master.set_max_updates(master_config.max_updates)?;

        // The main iteration: wait for new tasks.
        for m in rx {
            match m {
                MasterTask::AddMinorant(i, m, primal) => {
                    debug!("master: add minorant to subproblem {}", i);
                    let index = master.add_minorant(i, m)?;







<







459
460
461
462
463
464
465

466
467
468
469
470
471
472
        // Initialize the master problem.
        master.set_num_subproblems(master_config.num_subproblems)?;
        master.set_vars(
            master_config.num_vars,
            master_config.lower_bounds,
            master_config.upper_bounds,
        )?;


        // The main iteration: wait for new tasks.
        for m in rx {
            match m {
                MasterTask::AddMinorant(i, m, primal) => {
                    debug!("master: add minorant to subproblem {}", i);
                    let index = master.add_minorant(i, m)?;
Changes to src/solver.rs.
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
     * step. If the function is evaluated by some iterative method that ensures
     * an objective value that is at least as large as this bound, the
     * oracle can stop returning an appropriate $\varepsilon$-subgradient.
     *
     * Must be in (0, acceptance_factor).
     */
    pub nullstep_factor: Real,

    /// Minimal allowed bundle weight. Must be > 0 and < max_weight.
    pub min_weight: Real,

    /// Maximal allowed bundle weight. Must be > min_weight,
    pub max_weight: Real,

    /**
     * Maximal number of updates of box multipliers.
     *
     * This is the maximal number of iterations for updating the box
     * multipliers when solving the master problem with box
     * constraints. This is a technical parameter that should probably
     * never be changed. If you experience an unexpectedly high number
     * of inner iterations, consider removing/fixing the corresponding
     * variables.
     */
    pub max_updates: usize,
}

impl SolverParams {
    /// Verify that all parameters are valid.
    fn check(&self) -> Result<(), ParameterError> {
        if self.max_bundle_size < 2 {
            Err(ParameterError(format!(
                "max_bundle_size must be >= 2 (got: {})",
                self.max_bundle_size
            )))
        } else if self.acceptance_factor <= 0.0 || self.acceptance_factor >= 1.0 {
            Err(ParameterError(format!(
                "acceptance_factor must be in (0,1) (got: {})",
                self.acceptance_factor
            )))
        } else if self.nullstep_factor <= 0.0 || self.nullstep_factor > self.acceptance_factor {
            Err(ParameterError(format!(
                "nullstep_factor must be in (0,acceptance_factor] (got: {}, acceptance_factor:{})",
                self.nullstep_factor, self.acceptance_factor
            )))
        } else if self.min_weight <= 0.0 {
            Err(ParameterError(format!(
                "min_weight must be in > 0 (got: {})",
                self.min_weight
            )))
        } else if self.max_weight < self.min_weight {
            Err(ParameterError(format!(
                "max_weight must be in >= min_weight (got: {}, min_weight: {})",
                self.max_weight, self.min_weight
            )))
        } else if self.max_updates == 0 {
            Err(ParameterError(format!(
                "max_updates must be in > 0 (got: {})",
                self.max_updates
            )))
        } else {
            Ok(())
        }
    }
}

impl Default for SolverParams {
    fn default() -> SolverParams {
        SolverParams {
            max_bundle_size: 50,

            nullstep_factor: 0.1,
            acceptance_factor: 0.1,

            min_weight: 0.01,
            max_weight: 1000.0,

            max_updates: 50,
        }
    }
}

/// The step type that has been performed.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Step {







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<













<
<
<
<
<







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
277
278
279
280
281
282
283





284
285
286
287
288
289
290
     * step. If the function is evaluated by some iterative method that ensures
     * an objective value that is at least as large as this bound, the
     * oracle can stop returning an appropriate $\varepsilon$-subgradient.
     *
     * Must be in (0, acceptance_factor).
     */
    pub nullstep_factor: Real,


















}

impl SolverParams {
    /// Verify that all parameters are valid.
    fn check(&self) -> Result<(), ParameterError> {
        if self.max_bundle_size < 2 {
            Err(ParameterError(format!(
                "max_bundle_size must be >= 2 (got: {})",
                self.max_bundle_size
            )))
        } else if self.acceptance_factor <= 0.0 || self.acceptance_factor >= 1.0 {
            Err(ParameterError(format!(
                "acceptance_factor must be in (0,1) (got: {})",
                self.acceptance_factor
            )))
        } else if self.nullstep_factor <= 0.0 || self.nullstep_factor > self.acceptance_factor {
            Err(ParameterError(format!(
                "nullstep_factor must be in (0,acceptance_factor] (got: {}, acceptance_factor:{})",
                self.nullstep_factor, self.acceptance_factor
            )))















        } else {
            Ok(())
        }
    }
}

impl Default for SolverParams {
    fn default() -> SolverParams {
        SolverParams {
            max_bundle_size: 50,

            nullstep_factor: 0.1,
            acceptance_factor: 0.1,





        }
    }
}

/// The step type that has been performed.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Step {
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
            .unwrap_or(false)
        {
            return Err(SolverError::Dimension);
        }

        self.master.set_num_subproblems(m)?;
        self.master.set_vars(self.problem.num_variables(), lb, ub)?;
        self.master.set_max_updates(self.params.max_updates)?;

        self.minorants = (0..m).map(|_| vec![]).collect();

        self.cur_val = 0.0;
        for i in 0..m {
            let result = self
                .problem







<







778
779
780
781
782
783
784

785
786
787
788
789
790
791
            .unwrap_or(false)
        {
            return Err(SolverError::Dimension);
        }

        self.master.set_num_subproblems(m)?;
        self.master.set_vars(self.problem.num_variables(), lb, ub)?;


        self.minorants = (0..m).map(|_| vec![]).collect();

        self.cur_val = 0.0;
        for i in 0..m {
            let result = self
                .problem