Skip to content

Commit

Permalink
Merge pull request #31 from scipopt/issue-30-initial-solution
Browse files Browse the repository at this point in the history
InitialSolution
  • Loading branch information
hedtke authored Jan 10, 2025
2 parents 84690e4 + a156c4f commit d9061e8
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 10 deletions.
47 changes: 37 additions & 10 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ on:

jobs:
coverage:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
env:
CC: gcc-11
CXX: g++-11
steps:
- uses: actions/checkout@v3
- uses: turtlebrowser/get-conan@main
Expand Down Expand Up @@ -55,7 +58,10 @@ jobs:
- name: Run Tests
run: ./build/test/Release/tests.exe
test_without_conan:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
env:
CC: gcc-11
CXX: g++-11
steps:
- uses: actions/checkout@v3
- name: Install parallelism library for C++
Expand All @@ -74,11 +80,29 @@ jobs:
make -j tests
- name: Run tests
run: ./test/tests
test_release_inx:
strategy:
matrix:
os: [ ubuntu-latest, macos-13 ]
runs-on: ${{ matrix.os }}
test_release_mac:
runs-on: macos-13
steps:
- uses: actions/checkout@v3
- uses: turtlebrowser/get-conan@main
- name: Run Conan Install
run: |
conan profile detect
pushd ~/.conan2/profiles
sed -i'' -e 's/gnu17/17/g' *
popd
conan install -of . -o with_tests=True --build=missing .
- name: Run CMake
run: cmake --preset conan-release .
- name: Compile
run: cmake --build build/Release --target tests
- name: Run Tests
run: ./build/Release/test/tests
test_release_linux:
runs-on: ubuntu-22.04
env:
CC: gcc-11
CXX: g++-11
steps:
- uses: actions/checkout@v3
- uses: turtlebrowser/get-conan@main
Expand All @@ -96,7 +120,10 @@ jobs:
- name: Run Tests
run: ./build/Release/test/tests
clang_tidy:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
env:
CC: gcc-11
CXX: g++-11
steps:
- uses: actions/checkout@v3
- uses: turtlebrowser/get-conan@main
Expand All @@ -112,7 +139,7 @@ jobs:
- name: Run Clang-Tidy
run: clang-tidy-14 -p build/Release source/*.cpp include/**/*.hpp
clang_format:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: DoozyX/[email protected]
Expand All @@ -121,7 +148,7 @@ jobs:
extensions: 'hpp,cpp'
clangFormatVersion: 17
doxygen:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: ssciwr/doxygen-install@v1
Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Added

- [PR31](https://github.com/scipopt/SCIPpp/pull/31) Add `InitialSolution` and `Model::addSolution`.
- [PR28](https://github.com/scipopt/SCIPpp/pull/28) Add `Var::getVar`.

## [1.2.0] - 2024-05-21
Expand Down
42 changes: 42 additions & 0 deletions include/scippp/initial_solution.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <map>

namespace scippp {

// forward declare
class Var;

/**
* A primal solution to be added to %SCIP's solution pool.
*
* @since 1.3.0
*/
class InitialSolution {
friend class Model;
//! Variable assignment in the initial solution.
std::map<const Var*, double> m_values {};

public:
/**
* Sets the value for a variable in the solution.
*
* @since 1.3.0
* @param var Variable to assign a value to.
* @param value to assign to the variable.
*/
void setValue(const Var& var, double value);

/**
* Access the mutable value assigned to the variable.
*
* Initializes the assigned value to 0 if no value was assigned to the variable so far.
*
* @since 1.3.0
* @param var Variable to manipulate the value in the solution for.
* @return Mutable value assigned to the variable.
*/
double& operator()(const Var& var);
};

}
21 changes: 21 additions & 0 deletions include/scippp/model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <vector>

#include "scippp/constant_coefficient.hpp"
#include "scippp/initial_solution.hpp"
#include "scippp/lin_expr.hpp"
#include "scippp/lin_ineq.hpp"
#include "scippp/param.hpp"
Expand Down Expand Up @@ -326,5 +327,25 @@ class Model {
That is only required for use-cases not supported by SCIP++.
Consider adding the feature you are using to SCIP++!)")]] [[nodiscard]] Scip*
scip() const;

/**
* Adds a solution to %SCIP's solution pool.
*
* @since 1.3.0
* @param initialSolution to add to the solution pool.
* @param printReason Should all reasons of violations be printed?
* @param completely Should all violations be checked if \p printReason is true?
* @param checkBounds Should the bounds of the variables be checked?
* @param checkIntegrality Should integrality be checked?
* @param checkLpRows Do constraints represented by rows in the current LP have to be checked?
* @return \c true iff the solution was feasible and stored in the solution storage (i.e, good enough to keep).
*/
bool addSolution(
const InitialSolution& initialSolution,
bool printReason = true,
bool completely = true,
bool checkBounds = true,
bool checkIntegrality = true,
bool checkLpRows = true);
};
}
15 changes: 15 additions & 0 deletions source/initial_solution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "scippp/initial_solution.hpp"

namespace scippp {

void InitialSolution::setValue(const Var& var, double value)
{
m_values[&var] = value;
}

double& InitialSolution::operator()(const Var& var)
{
return m_values[&var];
}

}
25 changes: 25 additions & 0 deletions source/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,29 @@ double Model::getPrimalbound() const
return SCIPgetPrimalbound(m_scip);
}

bool Model::addSolution(
const InitialSolution& initialSolution,
bool printReason,
bool completely,
bool checkBounds,
bool checkIntegrality,
bool checkLpRows)
{
SCIP_Sol* sol { nullptr };
m_scipCallWrapper(SCIPcreateSol(m_scip, &sol, nullptr));
for (const auto& [var, value] : initialSolution.m_values) {
m_scipCallWrapper(SCIPsetSolVal(m_scip, sol, var->getVar(), value));
}
SCIP_Bool isFeasible { false };
m_scipCallWrapper(SCIPcheckSol(
m_scip, sol, printReason, completely, checkBounds, checkIntegrality, checkLpRows, &isFeasible));
SCIP_Bool isStored { false };
if (isFeasible) {
m_scipCallWrapper(SCIPaddSolFree(m_scip, &sol, &isStored));
} else {
m_scipCallWrapper(SCIPfreeSol(m_scip, &sol));
}
return isStored;
}

}
57 changes: 57 additions & 0 deletions test/test_initial_solution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <boost/test/unit_test.hpp>

#include <boost/test/data/test_case.hpp>

#include "scippp/model.hpp"

using namespace scippp;
using namespace std;
namespace bdata = boost::unit_test::data;

BOOST_AUTO_TEST_SUITE(InitSolution)

BOOST_DATA_TEST_CASE(InitialSolutionStored, bdata::make({ 1, 2, 3 }), indexSetToOne)
{
Model model("Simple");
auto x1 = model.addVar("x_1", 1, VarType::BINARY);
auto x2 = model.addVar("x_2", 1, VarType::BINARY);
auto x3 = model.addVar("x_3", 1, VarType::BINARY);
model.addConstr(x1 + x2 + x3 <= 1, "upperBound");
model.setObjsense(Sense::MAXIMIZE);

InitialSolution is;
is.setValue(x1, indexSetToOne == 1 ? 1 : 0);
is.setValue(x2, indexSetToOne == 2 ? 1 : 0);
is.setValue(x3, indexSetToOne == 3 ? 1 : 0);
BOOST_TEST(model.addSolution(is));

BOOST_REQUIRE(model.getNSols() > 0);
auto sol = model.getBestSol();
BOOST_TEST(x1.getSolValAsInt(sol) == (indexSetToOne == 1 ? 1 : 0));
BOOST_TEST(x2.getSolValAsInt(sol) == (indexSetToOne == 2 ? 1 : 0));
BOOST_TEST(x3.getSolValAsInt(sol) == (indexSetToOne == 3 ? 1 : 0));
}

BOOST_AUTO_TEST_CASE(Infeasible)
{
Model model("Simple");
auto x1 = model.addVar("x_1", 1, VarType::BINARY);
model.setObjsense(Sense::MAXIMIZE);
InitialSolution is;
is.setValue(x1, 2);
BOOST_TEST(!model.addSolution(is));
}

BOOST_AUTO_TEST_CASE(UpdateSolution)
{
Model model("Simple");
const auto& [x1, x2] = model.addVars<2>("x_");
InitialSolution is;
is(x1) = 4;
is(x1) += 38;
is(x2) += 42;
BOOST_TEST(is(x1) == 42);
BOOST_TEST(is(x2) == 42);
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit d9061e8

Please sign in to comment.