RsBundle  Check-in [b318be645a]

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

Overview
Comment:Use `cplex-sys` crate for interfacing with cplex.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b318be645a81709d708350fc47d9b27068ed0da5
User & Date: fifr 2017-03-16 14:57:33.443
Context
2017-03-16
15:06
Remove build script. check-in: 8a75c0bcc8 user: fifr tags: trunk
14:57
Use `cplex-sys` crate for interfacing with cplex. check-in: b318be645a user: fifr tags: trunk
14:04
Satisfy some clippy warnings. check-in: 4adb6c3b41 user: fifr tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to Cargo.toml.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
[package]
name = "bundle"
version = "0.3.0"
authors = ["Frank Fischer <frank-fischer@shadow-soft.de>"]

build = "build.rs"

[dependencies]
libc = "^0.2.6"
quick-error = "^1.1.0"
log = "^0.3.6"


[dev-dependencies]
env_logger = "^0.4.1"





|





>



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

#build = "build.rs"

[dependencies]
libc = "^0.2.6"
quick-error = "^1.1.0"
log = "^0.3.6"
cplex-sys = { version = "^0.1", path = "../cplex-sys" }

[dev-dependencies]
env_logger = "^0.4.1"
Changes to examples/mmcf.rs.
1
2
3
4
5
6
7
8
9
/*
 * 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
9
/*
 * 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
Deleted src/cplex.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
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
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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
164
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
192
193
194
195
196
197
198
199
200
201
202
// 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/>
//

//! Low-level CPLEX interface.
//!
//! This module contains plain, unsafe functions to the CPLEX
//! C-interface.
//!
//! Most CPLEX functions require an environment pointer as first
//! argument. This environment corresponds to available licenses, so
//! you must be careful to not exhaust them by opening too many
//! environment. The helper function `cplex::env` can be used to
//! return a single global environment to be reused for different
//! models.
//!
//! CPLEX error handling depends on returned status codes. The helper
//! macro `trycpx!` wraps the call to a low-level CPLEX function with
//! status return code by additional error checking code. This
//! error-checking code returns either `Ok(())` or a
//! `Err(CplexError(...))`.
//!
//! ```rust,ignore
//! fn myfunc(net : *mut CPXnet) -> Result<()> {
//!   trycpx!(CPXNETchgobj(cplex::env(), net, CPX_MAX))
//! }
//! ```

#![allow(dead_code)]

use libc::{c_int, c_double, c_char};
use std::fmt;
use std::error;

pub use std::result::Result as cplex_std_Result;
pub use std::convert::From as cplex_std_From;

pub const CPXMSGBUFSIZE: usize = 1024;
#[allow(dead_code)]
pub const CPX_MAX: c_int = -1;
pub const CPX_MIN: c_int = 1;

pub enum CPXenv {}
pub enum CPXnet {}
pub enum CPXlp {}
pub enum CPXfile {}

pub type CPXINT = i32;


pub const CPX_PARAM_QPMETHOD: c_int = 1063;
pub const CPX_PARAM_THREADS: c_int = 1067;
pub const CPX_PARAM_BAREPCOMP: c_int = 3002;

pub const CPX_ALG_AUTOMATIC: CPXINT = 0;
pub const CPX_ALG_PRIMAL: CPXINT = 1;
pub const CPX_ALG_DUAL: CPXINT = 2;
pub const CPX_ALG_NET: CPXINT = 3;
pub const CPX_ALG_BARRIER: CPXINT = 4;

/// Globally unique environment.
static mut ENV: *mut CPXenv = 0 as *mut CPXenv;

pub unsafe fn env() -> *mut CPXenv {
    if ENV.is_null() {
        let mut status: c_int = 0;
        ENV = CPXopenCPLEX(&mut status);
        if status != 0 {
            panic!("Can't open CPLEX environment");
        }
    }
    ENV
}

#[allow(dead_code)]
extern "C" {
    pub fn CPXopenCPLEX(status: *mut c_int) -> *mut CPXenv;
    pub fn CPXcloseCPLEX(env: *mut *mut CPXenv) -> c_int;
    pub fn CPXgeterrorstring(env: *const CPXenv, errcode: c_int, buffer_str: *mut c_char) -> *const c_char;
    pub fn CPXfopen(filename: *const c_char, mode: *const c_char) -> *mut CPXfile;
    pub fn CPXfclose(file: *mut CPXfile) -> c_int;
    pub fn CPXsetlogfile(env: *mut CPXenv, file: *mut CPXfile) -> c_int;
    pub fn CPXsetintparam(env: *mut CPXenv, whichparam: c_int, newvalue: CPXINT) -> c_int;
    pub fn CPXsetdblparam(env: *mut CPXenv, whichparam: c_int, newvalue: c_double) -> c_int;

    pub fn CPXcreateprob(env: *mut CPXenv, status: *mut c_int, name: *const c_char) -> *mut CPXlp;
    pub fn CPXfreeprob(env: *mut CPXenv, net: *mut *mut CPXlp) -> c_int;
    pub fn CPXgetnumrows(env: *const CPXenv, lp: *const CPXlp) -> c_int;
    pub fn CPXgetnumcols(env: *const CPXenv, lp: *const CPXlp) -> c_int;
    pub fn CPXchgobj(env: *const CPXenv, lp: *mut CPXlp, cnt: c_int, indices: *const c_int, values: *const c_double) -> c_int;
    pub fn CPXaddrows(env: *const CPXenv,
                      lp: *mut CPXlp,
                      ccnt: c_int,
                      rcnt: c_int,
                      nzcnt: c_int,
                      rhs: *const c_double,
                      sense: *const c_char,
                      rmatbeg: *const c_int,
                      rmatind: *const c_int,
                      rmatval: *const c_double,
                      colname: *const *const c_char,
                      rowname: *const *const c_char)
                      -> c_int;
    pub fn CPXchgqpcoef(env: *const CPXenv, lp: *mut CPXlp, i: c_int, j: c_int, x: c_double) -> c_int;
    pub fn CPXqpopt(env: *const CPXenv, lp: *mut CPXlp) -> c_int;
    pub fn CPXgetx(env: *const CPXenv, lp: *const CPXlp, x: *mut c_double, begin: c_int, end: c_int) -> c_int;

    pub fn CPXNETcreateprob(env: *mut CPXenv, status: *mut c_int, name: *const c_char) -> *mut CPXnet;
    pub fn CPXNETfreeprob(env: *mut CPXenv, net: *mut *mut CPXnet) -> c_int;
    pub fn CPXNETgetnumnodes(env: *const CPXenv, net: *const CPXnet) -> c_int;
    pub fn CPXNETgetnumarcs(env: *const CPXenv, net: *const CPXnet) -> c_int;
    pub fn CPXNETaddnodes(env: *const CPXenv, net: *mut CPXnet, nnodes: c_int, supply: *const c_double, names: *const *const c_char) -> c_int;
    pub fn CPXNETaddarcs(env: *const CPXenv,
                         net: *mut CPXnet,
                         narcs: c_int,
                         fromnode: *const c_int,
                         tonode: *const c_int,
                         low: *const c_double,
                         up: *const c_double,
                         obj: *const c_double,
                         names: *const *const c_char)
                         -> c_int;
    pub fn CPXNETchgobjsen(env: *const CPXenv, net: *mut CPXnet, maxormin: c_int) -> c_int;
    pub fn CPXNETchgsupply(env: *const CPXenv, net: *mut CPXnet, cnt: c_int, indices: *const c_int, supply: *const c_double) -> c_int;
    pub fn CPXNETchgobj(env: *const CPXenv, net: *mut CPXnet, cnt: c_int, indices: *const c_int, obj: *const c_double) -> c_int;

    pub fn CPXNETprimopt(env: *const CPXenv, net: *mut CPXnet) -> c_int;
    pub fn CPXNETgetobjval(env: *const CPXenv, net: *const CPXnet, objval: *mut c_double) -> c_int;
    pub fn CPXNETsolution(env: *const CPXenv, net: *const CPXnet, netstat: *mut c_int, objval: *mut c_double, x: *mut c_double, pi: *mut c_double, slack: *mut c_double, dj: *mut c_double) -> c_int;
    pub fn CPXNETwriteprob(env: *const CPXenv, net: *const CPXnet, filename: *const c_char, format: *const c_char) -> c_int;
}


/// Error descriping a CPLEX status code.
///
/// This is a wrapper around CPLEX status code as returned by most
/// CPLEX low-level functions. The error struct contains the status
/// code itself along with the error message string returned by
/// `CPXgeterrorstring`.
#[derive(Debug)]
pub struct CplexError {
    /// The CPLEX error status code.
    pub code: c_int,
    /// The CPLEX error message associated with the status code.
    pub msg: String,
}

impl error::Error for CplexError {
    fn description(&self) -> &str {
        "CPLEX Error"
    }
}

impl fmt::Display for CplexError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CPLEX Error {}: {}", self.code, self.msg)
    }
}

/// Wrapper around CPLEX low-level functions returning status code.
///
/// This macro is analogous to `try!` but expects as argument a CPLEX
/// low-level function that returns a `c_int` status code.
///
/// # Examples
///
/// ```rust,ignore
/// fn myfunc(net : *mut CPXnet) -> Result<()> {
///   trycpx!(CPXNETchgobj(cplex::env(), net, CPX_MAX))
/// }
/// ```
#[macro_export]
macro_rules! trycpx {
    ($e:expr) => {
        unsafe {
            let status = $e;
            if status != 0 {
                let msg = CString::from_vec_unchecked(vec![0; CPXMSGBUFSIZE]).into_raw();
                $crate::cplex::CPXgeterrorstring(cplex::env(), status, msg);
                let err = $crate::cplex::CplexError {
                    code: status,
                    msg: CString::from_raw(msg).to_string_lossy().into_owned(),
                };
                return $crate::cplex::cplex_std_Result::Err($crate::cplex::cplex_std_From::from(err))
            } else {
                ()
            }
        }
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































































































































































Changes to src/lib.rs.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
macro_rules! dvec {
    ( $ elem : expr ; $ n : expr ) => { DVector(vec![$elem; $n]) };
    ( $ ( $ x : expr ) , * ) => { DVector(vec![$($x),*]) };
    ( $ ( $ x : expr , ) * ) => { DVector(vec![$($x,)*]) };
}

#[macro_use]
mod cplex;

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

pub mod minorant;
pub use minorant::Minorant;








|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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 vector::{DVector, Vector};

pub mod minorant;
pub use minorant::Minorant;

Changes to src/master/cpx.rs.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//

//! Master problem implementation using CPLEX.

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

use cplex;
use cplex::*;

use std::result;
use std::ffi::CString;
use std::ptr;
use libc::{c_char, c_int};
use std::f64::NEG_INFINITY;
use std::f64;







<
|







15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
//

//! Master problem implementation using CPLEX.

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


use cplex_sys::*;

use std::result;
use std::ffi::CString;
use std::ptr;
use libc::{c_char, c_int};
use std::f64::NEG_INFINITY;
use std::f64;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

pub struct CplexMaster {
    lp: *mut CPXlp,

    /// True if the QP must be updated.
    force_update: bool,

    /// List of free minorant indices.
    freeinds: Vec<usize>,








|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

pub struct CplexMaster {
    lp: *mut CPXLp,

    /// True if the QP must be updated.
    force_update: bool,

    /// List of free minorant indices.
    freeinds: Vec<usize>,

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
    }

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

    fn set_num_subproblems(&mut self, n: usize) -> Result<()> {
        trycpx!(CPXsetintparam(env(), CPX_PARAM_QPMETHOD, CPX_ALG_BARRIER));
        trycpx!(CPXsetdblparam(env(), CPX_PARAM_BAREPCOMP, 1e-12));

        self.min2index = vec![vec![]; n];
        self.index2min.clear();
        self.freeinds.clear();
        self.minorants = vec![vec![]; n];
        self.opt_mults = vec![dvec![]; n];








|
|







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
    }

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

    fn set_num_subproblems(&mut self, n: usize) -> Result<()> {
        trycpx!(CPXsetintparam(env(), Param::Qpmethod.to_c(), Alg::Barrier.to_c()));
        trycpx!(CPXsetdblparam(env(), Param::Barepcomp.to_c(), 1e-12));

        self.min2index = vec![vec![]; n];
        self.index2min.clear();
        self.freeinds.clear();
        self.minorants = vec![vec![]; n];
        self.opt_mults = vec![dvec![]; n];

Changes to src/mcf/solver.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
46
47
48
49
50
51
52
53
54
55
56
57
58
//
// 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};

use cplex;
use cplex::*;

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

use libc::{c_char, c_int, c_double};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Cplex(err: CplexError) {
            cause(err)
                description(err.description())
                display("{}", err)
                from()
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

pub struct Solver {
    net: *mut CPXnet,
    logfile: *mut CPXfile,
}


impl Drop for Solver {
    fn drop(&mut self) {
        unsafe {
            CPXNETfreeprob(cplex::env(), &mut self.net);
            CPXfclose(self.logfile);
        }
    }
}

fn clit(s: &'static str) -> *const c_char {
    s.as_ptr() as *const c_char







<
|





|
















|
|






|







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
46
47
48
49
50
51
52
53
54
55
56
57
//
// 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};


use cplex_sys::*;

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

use libc::{c_char, c_int, c_double, FILE};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Cplex(err: CplexError) {
            cause(err)
                description(err.description())
                display("{}", err)
                from()
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

pub struct Solver {
    net: *mut CPXNet,
    logfile: *mut FILE,
}


impl Drop for Solver {
    fn drop(&mut self) {
        unsafe {
            CPXNETfreeprob(env(), &mut self.net);
            CPXfclose(self.logfile);
        }
    }
}

fn clit(s: &'static str) -> *const c_char {
    s.as_ptr() as *const c_char
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
                if status != 0 {
                    break;
                }
                status = CPXNETaddnodes(env(), net, nnodes as c_int, ptr::null(), ptr::null());
                if status != 0 {
                    break;
                }
                status = CPXNETchgobjsen(env(), net, CPX_MIN);
                if status != 0 {
                    break;
                }
                break;
            }

            if status != 0 {
                let msg = CString::new(vec![0; CPXMSGBUFSIZE]).unwrap().into_raw();
                CPXgeterrorstring(env(), status, msg);
                CPXNETfreeprob(env(), &mut net);
                CPXfclose(logfile);
                return Err(Error::Cplex(CplexError {
                    code: status,
                    msg: CString::from_raw(msg).to_string_lossy().into_owned(),
                }));







|







|







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
                if status != 0 {
                    break;
                }
                status = CPXNETaddnodes(env(), net, nnodes as c_int, ptr::null(), ptr::null());
                if status != 0 {
                    break;
                }
                status = CPXNETchgobjsen(env(), net, ObjectiveSense::Minimize.to_c());
                if status != 0 {
                    break;
                }
                break;
            }

            if status != 0 {
                let msg = CString::new(vec![0; MESSAGE_BUF_SIZE]).unwrap().into_raw();
                CPXgeterrorstring(env(), status, msg);
                CPXNETfreeprob(env(), &mut net);
                CPXfclose(logfile);
                return Err(Error::Cplex(CplexError {
                    code: status,
                    msg: CString::from_raw(msg).to_string_lossy().into_owned(),
                }));