Skip to content

Commit

Permalink
Merge pull request #3 from hedtke/make-upper-and-lower-bounds-optional
Browse files Browse the repository at this point in the history
Make upper and lower bounds in addVar(s) optional
  • Loading branch information
hedtke authored Aug 9, 2023
2 parents 6da1dd9 + 8c176f7 commit c78e798
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 14 deletions.
21 changes: 11 additions & 10 deletions include/scippp/model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <algorithm>
#include <array>
#include <functional>
#include <optional>
#include <scip/scip.h>
#include <string>
#include <type_traits>
Expand Down Expand Up @@ -86,16 +87,16 @@ class Model {
* @param name of the variable when the model is written.
* @param coeff Coefficient in the objective function.
* @param varType variable type.
* @param lb lower bound.
* @param ub upper bound.
* @param lb lower bound. \c std::nullopt is interpreted as -infinity.
* @param ub upper bound. \c std::nullopt is interpreted as infinity.
* @return Reference to the newly created variable.
*/
Var& addVar(
const std::string& name,
SCIP_Real coeff = 0.0,
VarType varType = VarType::CONTINUOUS,
SCIP_Real lb = 0.0,
SCIP_Real ub = 1.0);
std::optional<SCIP_Real> lb = 0.0,
std::optional<SCIP_Real> ub = 1.0);

/**
* Adds multiple variables to the model.
Expand All @@ -106,8 +107,8 @@ class Model {
* @param numVars number of variables to create.
* @param coeffs Object holding the coefficients for the objective function.
* @param varType variable type.
* @param lb lower bound.
* @param ub upper bound.
* @param lb lower bound. \c std::nullopt is interpreted as -infinity.
* @param ub upper bound. \c std::nullopt is interpreted as infinity.
* @return Vector of variables.
*/
template <typename CoeffType = ConstantCoefficient>
Expand All @@ -116,8 +117,8 @@ class Model {
size_t numVars,
const CoeffType& coeffs = COEFF_ZERO,
VarType varType = VarType::CONTINUOUS,
SCIP_Real lb = 0.0,
SCIP_Real ub = 1.0)
std::optional<SCIP_Real> lb = 0.0,
std::optional<SCIP_Real> ub = 1.0)
{
std::vector<Var> result;
result.reserve(numVars);
Expand Down Expand Up @@ -149,8 +150,8 @@ class Model {
const std::string& prefix,
const CoeffType& coeffs = COEFF_ZERO,
VarType varType = VarType::CONTINUOUS,
SCIP_Real lb = 0.0,
SCIP_Real ub = 1.0)
std::optional<SCIP_Real> lb = 0.0,
std::optional<SCIP_Real> ub = 1.0)
{
std::array<Var, NumVars> result;
auto vec { addVars(prefix, NumVars, coeffs, varType, lb, ub) };
Expand Down
11 changes: 8 additions & 3 deletions source/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@

namespace scippp {

Var& Model::addVar(const std::string& name, SCIP_Real coeff, VarType varType, SCIP_Real lb, SCIP_Real ub)
Var& Model::addVar(
const std::string& name,
SCIP_Real coeff,
VarType varType,
std::optional<SCIP_Real> lb,
std::optional<SCIP_Real> ub)
{
SCIP_VAR* var { nullptr };
m_scipCallWrapper(SCIPcreateVarBasic(
m_scip, /* SCIP environment */
&var, /* reference to the variable */
name.c_str(), /* name of the variable */
lb, /* lower bound of the variable */
ub, /* upper bound of the variable */
lb != std::nullopt ? lb.value() : -SCIPinfinity(m_scip), /* lower bound of the variable */
ub != std::nullopt ? ub.value() : SCIPinfinity(m_scip), /* upper bound of the variable */
coeff, /* obj. coefficient. */
static_cast<SCIP_Vartype>(varType) /* variable is binary */
));
Expand Down
78 changes: 78 additions & 0 deletions test/test_add_var.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <boost/test/unit_test.hpp>

#include "scippp/model.hpp"

using namespace scippp;
using namespace std;

BOOST_AUTO_TEST_SUITE(AddVar)

// lb nullopt ub value lNuD
// lb nullopt ub nullopt lNuN
// lb value ub value GetSolVal
// lb value ub nullopt lDuN

const SCIP_Real LB_DEFAULT { 0.0 };
const SCIP_Real UB_DEFAULT { 1.0 };

BOOST_AUTO_TEST_CASE(lDuN, *boost::unit_test::tolerance(1e-3))
{
Model m1("Simple");
auto x1 = m1.addVar("x_1", 1, VarType::CONTINUOUS, LB_DEFAULT, nullopt);
auto x2 = m1.addVar("x_2", 1);
m1.addConstr(x1 + x2 <= 1, "line");
m1.setObjsense(Sense::MINIMIZE);
m1.solve();
BOOST_REQUIRE(m1.getNSols() > 0);
BOOST_TEST(m1.getPrimalbound() == 0);

Model m2("Simple");
x1 = m2.addVar("x_1", 1, VarType::CONTINUOUS, LB_DEFAULT, nullopt);
x2 = m2.addVar("x_2", 1);
m2.addConstr(x1 + x2 >= 1, "line");
m2.setObjsense(Sense::MAXIMIZE);
m2.solve();
BOOST_TEST(m2.getStatus() == SCIP_STATUS_UNBOUNDED);
}

BOOST_AUTO_TEST_CASE(lNuD, *boost::unit_test::tolerance(1e-3))
{
Model m1("Simple");
auto x1 = m1.addVar("x_1", 1, VarType::CONTINUOUS, nullopt, UB_DEFAULT);
auto x2 = m1.addVar("x_2", 1);
m1.addConstr(x1 + x2 <= 1, "line");
m1.setObjsense(Sense::MINIMIZE);
m1.solve();
BOOST_TEST(m1.getStatus() == SCIP_STATUS_UNBOUNDED);

Model m2("Simple");
x1 = m2.addVar("x_1", 1, VarType::CONTINUOUS, nullopt, UB_DEFAULT);
x2 = m2.addVar("x_2", 1);
m2.addConstr(x1 + x2 <= 1, "line");
m2.setObjsense(Sense::MAXIMIZE);
m2.solve();
BOOST_REQUIRE(m2.getNSols() > 0);
BOOST_TEST(m2.getPrimalbound() == 1);
}

BOOST_AUTO_TEST_CASE(lNuN, *boost::unit_test::tolerance(1e-3))
{
Model m1("Simple");
auto x1 = m1.addVar("x_1", 1, VarType::CONTINUOUS, nullopt, nullopt);
auto x2 = m1.addVar("x_2", 1);
m1.addConstr(x1 + x2 <= 1, "line");
m1.setObjsense(Sense::MINIMIZE);
m1.solve();
BOOST_TEST(m1.getStatus() == SCIP_STATUS_UNBOUNDED);

Model m2("Simple");
x1 = m2.addVar("x_1", 1, VarType::CONTINUOUS, nullopt, nullopt);
x2 = m2.addVar("x_2", 1);
m2.addConstr(x1 + x2 <= 1, "line");
m2.setObjsense(Sense::MAXIMIZE);
m2.solve();
BOOST_REQUIRE(m2.getNSols() > 0);
BOOST_TEST(m2.getPrimalbound() == 1);
}

BOOST_AUTO_TEST_SUITE_END()
1 change: 0 additions & 1 deletion test/test_var.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include <boost/test/unit_test.hpp>

#include "scippp/model.hpp"
#include "scippp/parameters.hpp"

using namespace scippp;
using namespace std;
Expand Down

0 comments on commit c78e798

Please sign in to comment.