RsBundle  Check-in [32372fda04]

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

Overview
Comment:Replace `extern crate` with `use`
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 32372fda04e9dcc1c7f87e33f0954d023842e9ec
User & Date: fifr 2018-12-12 15:38:03.747
Context
2018-12-12
15:38
Update version to 0.5.1 check-in: 393791e563 user: fifr tags: trunk, v0.5.1
15:38
Replace `extern crate` with `use` check-in: 32372fda04 user: fifr tags: trunk
15:30
Update to 2018 edition check-in: 80cbe311ac user: fifr tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to Cargo.toml.
1
2
3

4
5
6
7
8
9
10
[package]
name = "bundle"
version = "0.5.0"

authors = ["Frank Fischer <frank-fischer@shadow-soft.de>"]

[dependencies]
itertools = "^0.7.2"
libc = "^0.2.6"
log = "^0.4"
c_str_macro = "^1.0"



>







1
2
3
4
5
6
7
8
9
10
11
[package]
name = "bundle"
version = "0.5.0"
edition = "2018"
authors = ["Frank Fischer <frank-fischer@shadow-soft.de>"]

[dependencies]
itertools = "^0.7.2"
libc = "^0.2.6"
log = "^0.4"
c_str_macro = "^1.0"
Changes to examples/mmcf.rs.
11
12
13
14
15
16
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
 * 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/>
 */

extern crate bundle;
extern crate env_logger;
#[macro_use]
extern crate log;

use bundle::mcf;
use bundle::{FirstOrderProblem, Solver, SolverParams, StandardTerminator};

use std::env;

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

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







|
|
<
|



>







11
12
13
14
15
16
17
18
19

20
21
22
23
24
25
26
27
28
29
30
31
 * 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 bundle;
use env_logger;

use log::info;

use bundle::mcf;
use bundle::{FirstOrderProblem, Solver, SolverParams, StandardTerminator};

use std::env;

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

    let mut args = env::args();
    let program = args.next().unwrap();
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54
55
56

57
58
59
60
61
62
            mmcf,
            SolverParams {
                max_bundle_size: 25,
                min_weight: 1e-3,
                max_weight: 100.0,
                ..Default::default()
            },

        ).unwrap();
        solver.terminator = Box::new(StandardTerminator {
            termination_precision: 1e-6,
        });
        solver.solve().unwrap();

        let costs: f64 = (0..solver.problem().num_subproblems())
            .map(|i| {
                let primals = solver.aggregated_primals(i);
                let aggr_primals = solver.problem().aggregate_primals_ref(&primals);
                solver.problem().get_primal_costs(i, &aggr_primals)

            }).sum();
        info!("Primal costs: {}", costs);
    } else {
        panic!("Usage: {} FILENAME", program);
    }
}







>
|










>
|





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
            mmcf,
            SolverParams {
                max_bundle_size: 25,
                min_weight: 1e-3,
                max_weight: 100.0,
                ..Default::default()
            },
        )
        .unwrap();
        solver.terminator = Box::new(StandardTerminator {
            termination_precision: 1e-6,
        });
        solver.solve().unwrap();

        let costs: f64 = (0..solver.problem().num_subproblems())
            .map(|i| {
                let primals = solver.aggregated_primals(i);
                let aggr_primals = solver.problem().aggregate_primals_ref(&primals);
                solver.problem().get_primal_costs(i, &aggr_primals)
            })
            .sum();
        info!("Primal costs: {}", costs);
    } else {
        panic!("Usage: {} FILENAME", program);
    }
}
Changes to examples/quadratic.rs.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 *
 * 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 std::error::Error;

#[macro_use]
extern crate bundle;
extern crate env_logger;
#[macro_use]
extern crate log;

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

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







<
|
|
<
|







13
14
15
16
17
18
19

20
21

22
23
24
25
26
27
28
29
 *
 * 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 std::error::Error;


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

use log::debug;

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

struct QuadraticProblem {
    a: [[Real; 2]; 2],
    b: [Real; 2],
    c: Real,
92
93
94
95
96
97
98

99
100
101
    let mut solver = Solver::new_params(
        f,
        SolverParams {
            min_weight: 1.0,
            max_weight: 1.0,
            ..Default::default()
        },

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







>
|


90
91
92
93
94
95
96
97
98
99
100
    let mut solver = Solver::new_params(
        f,
        SolverParams {
            min_weight: 1.0,
            max_weight: 1.0,
            ..Default::default()
        },
    )
    .unwrap();
    solver.solve().unwrap();
}
Changes to src/hkweighter.rs.
20
21
22
23
24
25
26


27
28
29
30
31
32
33
//!
//! > Helmberg, C. and Kiwiel, K.C. (2002): A spectral bundle method
//! > with bounds, Math. Programming A 93, 173--194
//!

use crate::Real;
use crate::{BundleState, SolverParams, Step, Weighter};



use std::cmp::{max, min};
use std::f64::NEG_INFINITY;

const FACTOR: Real = 2.0;

/**







>
>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//!
//! > Helmberg, C. and Kiwiel, K.C. (2002): A spectral bundle method
//! > with bounds, Math. Programming A 93, 173--194
//!

use crate::Real;
use crate::{BundleState, SolverParams, Step, Weighter};

use log::debug;

use std::cmp::{max, min};
use std::f64::NEG_INFINITY;

const FACTOR: Real = 2.0;

/**
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
        if state.step == Step::Term {
            self.eps_weight = 1e30;
            self.iter = 0;
            return if state.cur_y.len() == 0 || state.sgnorm < state.cur_y.len() as Real * 1e-10 {
                1.0
            } else {
                state.sgnorm.max(1e-4)

            }.max(params.min_weight)
            .min(params.max_weight);
        }

        let cur_nxt = state.cur_val - state.nxt_val;
        let cur_mod = state.cur_val - state.nxt_mod;
        let w = 2.0 * state.weight * (1.0 - cur_nxt / cur_mod);

        debug!("  cur_nxt={} cur_mod={} w={}", cur_nxt, cur_mod, w);

        if state.step == Step::Null {
            let sgnorm = state.sgnorm;
            let lin_err = state.cur_val - state.new_cutval;
            self.eps_weight = self.eps_weight.min(sgnorm + cur_mod - sgnorm * sgnorm / state.weight);
            let new_weight = if self.iter < -3 && lin_err > self.eps_weight.max(FACTOR * cur_mod) {
                w
            } else {
                state.weight

            }.min(FACTOR * state.weight)
            .min(params.max_weight);
            if new_weight > state.weight {
                self.iter = -1
            } else {
                self.iter = min(self.iter - 1, -1);
            }








>
|

















>
|







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
114
115
        if state.step == Step::Term {
            self.eps_weight = 1e30;
            self.iter = 0;
            return if state.cur_y.len() == 0 || state.sgnorm < state.cur_y.len() as Real * 1e-10 {
                1.0
            } else {
                state.sgnorm.max(1e-4)
            }
            .max(params.min_weight)
            .min(params.max_weight);
        }

        let cur_nxt = state.cur_val - state.nxt_val;
        let cur_mod = state.cur_val - state.nxt_mod;
        let w = 2.0 * state.weight * (1.0 - cur_nxt / cur_mod);

        debug!("  cur_nxt={} cur_mod={} w={}", cur_nxt, cur_mod, w);

        if state.step == Step::Null {
            let sgnorm = state.sgnorm;
            let lin_err = state.cur_val - state.new_cutval;
            self.eps_weight = self.eps_weight.min(sgnorm + cur_mod - sgnorm * sgnorm / state.weight);
            let new_weight = if self.iter < -3 && lin_err > self.eps_weight.max(FACTOR * cur_mod) {
                w
            } else {
                state.weight
            }
            .min(FACTOR * state.weight)
            .min(params.max_weight);
            if new_weight > state.weight {
                self.iter = -1
            } else {
                self.iter = min(self.iter - 1, -1);
            }

120
121
122
123
124
125
126

127
128
129
130
131
132
133
134
            self.model_max = self.model_max.max(state.nxt_mod);
            let new_weight = if self.iter > 0 && cur_nxt > self.m_r * cur_mod {
                w
            } else if self.iter > 3 || state.nxt_val < self.model_max {
                state.weight / 2.0
            } else {
                state.weight

            }.max(state.weight / FACTOR)
            .max(params.min_weight);
            self.eps_weight = self.eps_weight.max(2.0 * cur_mod);
            if new_weight < state.weight {
                self.iter = 1;
                self.model_max = NEG_INFINITY;
            } else {
                self.iter = max(self.iter + 1, 1);







>
|







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
            self.model_max = self.model_max.max(state.nxt_mod);
            let new_weight = if self.iter > 0 && cur_nxt > self.m_r * cur_mod {
                w
            } else if self.iter > 3 || state.nxt_val < self.model_max {
                state.weight / 2.0
            } else {
                state.weight
            }
            .max(state.weight / FACTOR)
            .max(params.min_weight);
            self.eps_weight = self.eps_weight.max(2.0 * cur_mod);
            if new_weight < state.weight {
                self.iter = 1;
                self.model_max = NEG_INFINITY;
            } else {
                self.iter = max(self.iter + 1, 1);
Changes to src/lib.rs.
12
13
14
15
16
17
18
19
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
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see  <http://www.gnu.org/licenses/>
//

//! Proximal bundle method implementation.

#[macro_use]
extern crate c_str_macro;
extern crate itertools;

#[macro_use]
extern crate log;

/// Type used for real numbers throughout the library.
pub type Real = f64;

#[macro_export]
macro_rules! dvec {
    ( $ elem : expr ; $ n : expr ) => { DVector(vec![$elem; $n]) };
    ( $ ( $ x : expr ) , * ) => { DVector(vec![$($x),*]) };
    ( $ ( $ x : expr , ) * ) => { DVector(vec![$($x,)*]) };
}

#[macro_use]
extern crate cplex_sys;

pub mod vector;
pub use crate::vector::{DVector, Vector};

pub mod minorant;
pub use crate::minorant::Minorant;

pub mod firstorderproblem;







<
<
<
<
<
<
<










<
<
<







12
13
14
15
16
17
18







19
20
21
22
23
24
25
26
27
28



29
30
31
32
33
34
35
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see  <http://www.gnu.org/licenses/>
//

//! Proximal bundle method implementation.








/// Type used for real numbers throughout the library.
pub type Real = f64;

#[macro_export]
macro_rules! dvec {
    ( $ elem : expr ; $ n : expr ) => { DVector(vec![$elem; $n]) };
    ( $ ( $ x : expr ) , * ) => { DVector(vec![$($x),*]) };
    ( $ ( $ x : expr , ) * ) => { DVector(vec![$($x,)*]) };
}




pub mod vector;
pub use crate::vector::{DVector, Vector};

pub mod minorant;
pub use crate::minorant::Minorant;

pub mod firstorderproblem;
Changes to src/master/boxed.rs.
15
16
17
18
19
20
21

22

23
24
25
26
27
28
29
//

use crate::master::MasterProblem;
use crate::master::UnconstrainedMasterProblem;
use crate::{DVector, Minorant, Real};

use super::Result;

use itertools::multizip;

use std::error::Error;
use std::f64::{EPSILON, INFINITY, NEG_INFINITY};
use std::result;

/**
 * Turn unconstrained master problem into box-constrained one.
 *







>

>







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

use crate::master::MasterProblem;
use crate::master::UnconstrainedMasterProblem;
use crate::{DVector, Minorant, Real};

use super::Result;

use itertools::multizip;
use log::debug;
use std::error::Error;
use std::f64::{EPSILON, INFINITY, NEG_INFINITY};
use std::result;

/**
 * Turn unconstrained master problem into box-constrained one.
 *
157
158
159
160
161
162
163

164
165
166
167
168
169
170
171
                        0.0
                    }
                } else if ub < INFINITY {
                    ub * eta
                } else {
                    0.0
                }

            }).sum()
    }

    /**
     * Return $\\|G \alpha - \eta\\|_2\^2$.
     *
     * This is the norm-square of the dual optimal solution including
     * the current box-multipliers $\eta$.







>
|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
                        0.0
                    }
                } else if ub < INFINITY {
                    ub * eta
                } else {
                    0.0
                }
            })
            .sum()
    }

    /**
     * Return $\\|G \alpha - \eta\\|_2\^2$.
     *
     * This is the norm-square of the dual optimal solution including
     * the current box-multipliers $\eta$.
Changes to src/master/cpx.rs.
17
18
19
20
21
22
23



24


25
26
27
28
29
30
31
32
33
//! Master problem implementation using CPLEX.

#![allow(unused_unsafe)]

use crate::master::{Error as MasterProblemError, UnconstrainedMasterProblem};
use crate::{DVector, Minorant, Real};




use cplex_sys as cpx;



use super::Result;
use std;
use std::error::Error;
use std::f64::{self, NEG_INFINITY};
use std::os::raw::{c_char, c_int};
use std::ptr;
use std::result;








>
>
>

>
>

<







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

31
32
33
34
35
36
37
//! Master problem implementation using CPLEX.

#![allow(unused_unsafe)]

use crate::master::{Error as MasterProblemError, UnconstrainedMasterProblem};
use crate::{DVector, Minorant, Real};

use super::Result;

use c_str_macro::c_str;
use cplex_sys as cpx;
use cplex_sys::trycpx;
use log::debug;


use std;
use std::error::Error;
use std::f64::{self, NEG_INFINITY};
use std::os::raw::{c_char, c_int};
use std::ptr;
use std::result;

Changes to src/master/minimal.rs.
14
15
16
17
18
19
20



21
22
23
24
25
26
27
// along with this program.  If not, see  <http://www.gnu.org/licenses/>
//

use crate::master::{Error as MasterProblemError, UnconstrainedMasterProblem};
use crate::{DVector, Minorant, Real};

use super::Result;



use std::error::Error;
use std::f64::NEG_INFINITY;
use std::fmt;
use std::result;

/// Minimal master problem error.
#[derive(Debug)]







>
>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// along with this program.  If not, see  <http://www.gnu.org/licenses/>
//

use crate::master::{Error as MasterProblemError, UnconstrainedMasterProblem};
use crate::{DVector, Minorant, Real};

use super::Result;

use log::debug;

use std::error::Error;
use std::f64::NEG_INFINITY;
use std::fmt;
use std::result;

/// Minimal master problem error.
#[derive(Debug)]
Changes to src/mcf/problem.rs.
12
13
14
15
16
17
18


19
20
21
22
23
24
25
//
// 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 crate::mcf;
use crate::{DVector, FirstOrderProblem, Minorant, Real, SimpleEvaluation};



use std::error::Error;
use std::f64::INFINITY;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::result;







>
>







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

use log::debug;

use std::error::Error;
use std::f64::INFINITY;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::result;
Changes to src/mcf/solver.rs.
14
15
16
17
18
19
20

21

22
23
24
25
26
27
28
// along with this program.  If not, see  <http://www.gnu.org/licenses/>
//

#![allow(unused_unsafe)]

use crate::{DVector, Real};


use cplex_sys as cpx;


use std;
use std::error::Error;
use std::ffi::CString;
use std::ptr;
use std::result;








>

>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// along with this program.  If not, see  <http://www.gnu.org/licenses/>
//

#![allow(unused_unsafe)]

use crate::{DVector, Real};

use c_str_macro::c_str;
use cplex_sys as cpx;
use cplex_sys::trycpx;

use std;
use std::error::Error;
use std::ffi::CString;
use std::ptr;
use std::result;

73
74
75
76
77
78
79

80
81
82
83
84
85
86
87
            if status != 0 {
                let msg = CString::new(vec![0; cpx::MESSAGE_BUF_SIZE]).unwrap().into_raw();
                cpx::geterrorstring(cpx::env(), status, msg);
                cpx::NETfreeprob(cpx::env(), &mut net);
                return Err(cpx::CplexError {
                    code: status,
                    msg: CString::from_raw(msg).to_string_lossy().into_owned(),

                }.into());
            }
        }

        Ok(Solver { net })
    }

    pub fn num_nodes(&self) -> usize {







>
|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
            if status != 0 {
                let msg = CString::new(vec![0; cpx::MESSAGE_BUF_SIZE]).unwrap().into_raw();
                cpx::geterrorstring(cpx::env(), status, msg);
                cpx::NETfreeprob(cpx::env(), &mut net);
                return Err(cpx::CplexError {
                    code: status,
                    msg: CString::from_raw(msg).to_string_lossy().into_owned(),
                }
                .into());
            }
        }

        Ok(Solver { net })
    }

    pub fn num_nodes(&self) -> usize {
Changes to src/solver.rs.
18
19
20
21
22
23
24


25
26
27
28
29
30
31

use crate::{DVector, Real};
use crate::{Evaluation, FirstOrderProblem, HKWeighter, Update};

use crate::master::{BoxedMasterProblem, Error as MasterProblemError, MasterProblem, UnconstrainedMasterProblem};
use crate::master::{CplexMaster, MinimalMaster};



use std::error::Error;
use std::f64::{INFINITY, NEG_INFINITY};
use std::fmt;
use std::mem::swap;
use std::result::Result;
use std::time::Instant;








>
>







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

use crate::{DVector, Real};
use crate::{Evaluation, FirstOrderProblem, HKWeighter, Update};

use crate::master::{BoxedMasterProblem, Error as MasterProblemError, MasterProblem, UnconstrainedMasterProblem};
use crate::master::{CplexMaster, MinimalMaster};

use log::{debug, info, warn};

use std::error::Error;
use std::f64::{INFINITY, NEG_INFINITY};
use std::fmt;
use std::mem::swap;
use std::result::Result;
use std::time::Instant;

690
691
692
693
694
695
696

697
698
699
700
701
702
703
704
                    &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())
                    },

                ).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;
                self.nxt_d[index] = 0.0;
            }
            // add new variables







>
|







692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
                    &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())
                    },
                )
                .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;
                self.nxt_d[index] = 0.0;
            }
            // add new variables