Skip to content

Commit

Permalink
Merge pull request #182 from scipopt/cuts-test
Browse files Browse the repository at this point in the history
Add method to add cuts
  • Loading branch information
mmghannam authored Jan 9, 2025
2 parents edbaf49 + 6d10daa commit 01b9d2a
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 6 deletions.
16 changes: 15 additions & 1 deletion src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::scip::ScipPtr;
use crate::solution::{SolError, Solution};
use crate::status::Status;
use crate::variable::{VarId, VarType, Variable};
use crate::{ffi, Separator};
use crate::{ffi, Row, Separator};
use crate::{BranchRule, HeurTiming, Heuristic, Pricer};

/// Represents an optimization model.
Expand Down Expand Up @@ -470,6 +470,20 @@ impl Model<Solving> {
})
}
}

/// Adds a new cut (row) to the model.
///
/// # Arguments
/// * `row` - The row to add.
/// * `force_cut` - If true, the cut (row) is forced to be selected.
///
/// # Returns
/// A boolean indicating whether the row is infeasible from the local bounds.
pub fn add_cut(&mut self, cut: Row, force_cut: bool) -> bool {
self.scip()
.add_row(cut, force_cut)
.expect("Failed to add row in state ProblemCreated")
}
}

impl Model<Solved> {
Expand Down
7 changes: 6 additions & 1 deletion src/row.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::scip::ScipPtr;
use crate::{ffi, Constraint};
use crate::{ffi, Constraint, Variable};
use std::ffi::c_int;
use std::rc::Rc;

Expand Down Expand Up @@ -162,6 +162,11 @@ impl Row {
pub fn set_rank(&self, rank: usize) {
unsafe { ffi::SCIProwChgRank(self.raw, rank as c_int) };
}

/// Sets the coefficient of a variable in the row.
pub fn set_coeff(&self, var: &Variable, coeff: f64) {
unsafe { ffi::SCIPaddVarToRow(self.scip.raw, self.raw, var.raw, coeff) };
}
}

impl PartialEq for Row {
Expand Down
15 changes: 13 additions & 2 deletions src/scip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::branchrule::{BranchRule, BranchingCandidate};
use crate::pricer::{Pricer, PricerResultState};
use crate::{
ffi, scip_call_panic, BranchingResult, Constraint, Event, Eventhdlr, HeurResult, Model, Node,
ObjSense, ParamSetting, Retcode, SCIPEventhdlr, SCIPPricer, SCIPSeparator, Separator, Solution,
Solving, Status, VarType, Variable,
ObjSense, ParamSetting, Retcode, Row, SCIPEventhdlr, SCIPPricer, SCIPSeparator, Separator,
Solution, Solving, Status, VarType, Variable,
};
use crate::{scip_call, HeurTiming, Heuristic};
use core::panic;
Expand Down Expand Up @@ -1145,6 +1145,17 @@ impl ScipPtr {
scip_call!(ffi::SCIPfreeTransform(self.raw));
Ok(())
}

pub(crate) fn add_row(&self, row: Row, force_cut: bool) -> Result<bool, Retcode> {
let mut infeasible = 0;
scip_call!(ffi::SCIPaddRow(
self.raw,
row.raw,
force_cut.into(),
&mut infeasible
));
Ok(infeasible != 0)
}
}

impl Drop for ScipPtr {
Expand Down
54 changes: 52 additions & 2 deletions src/separator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl SCIPSeparator {
/// Creates an empty LP row.
pub fn create_empty_row(
&self,
model: Model<Solving>,
model: &Model<Solving>,
name: &str,
lhs: f64,
rhs: f64,
Expand Down Expand Up @@ -238,7 +238,7 @@ mod tests {
assert_eq!(sep.maxbounddist(), 1.0);
assert!(!sep.is_delayed());
let row = sep
.create_empty_row(model, "test", 0.0, 1.0, true, false, false)
.create_empty_row(&model, "test", 0.0, 1.0, true, false, false)
.unwrap();
assert_eq!(row.name(), "test");
assert_eq!(row.lhs(), 0.0);
Expand Down Expand Up @@ -277,4 +277,54 @@ mod tests {
)
.solve();
}

struct CutsAddingSeparator;

impl Separator for CutsAddingSeparator {
fn execute_lp(
&mut self,
mut model: Model<Solving>,
sepa: SCIPSeparator,
) -> SeparationResult {
// adds a row representing the sum of all variables == 5, causing infeasibility
let row = sepa
.create_empty_row(&model, "test", 5.0, 5.0, true, false, false)
.unwrap();
for var in model.vars() {
row.set_coeff(&var, 1.0);
}
model.add_cut(row, true);

SeparationResult::Separated
}
}

#[test]
fn cuts_adding() {
let mut model = minimal_model()
.hide_output()
.set_obj_sense(ObjSense::Maximize);

let x = model.add_var(0.0, 1.0, 1.0, "x", VarType::Binary);
let y = model.add_var(0.0, 1.0, 1.0, "y", VarType::Binary);

model.add_cons(vec![x, y], &[1.0, 1.0], 1.0, 1.0, "cons1");

let sep = CutsAddingSeparator {};

let solved = model
.include_separator(
"CutsAddingSeparator",
"",
1000000,
1,
1.0,
false,
false,
Box::new(sep),
)
.solve();

assert_eq!(solved.status(), crate::Status::Infeasible);
}
}

0 comments on commit 01b9d2a

Please sign in to comment.