408 lines
11 KiB
C++
408 lines
11 KiB
C++
// Copyright 2011-2012 Google
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "absl/flags/parse.h"
|
|
#include "ortools/base/logging.h"
|
|
#include "ortools/base/hash.h"
|
|
#include "ortools/base/map_util.h"
|
|
#include "ortools/base/stl_util.h"
|
|
#include "ortools/constraint_solver/constraint_solver.h"
|
|
#include "ortools/constraint_solver/constraint_solveri.h"
|
|
#include "ortools/util/string_array.h"
|
|
|
|
namespace operations_research {
|
|
|
|
class NullDemon : public Demon {
|
|
virtual void Run(Solver* const s) {}
|
|
};
|
|
|
|
// ----- Min Array Test -----
|
|
|
|
class MinArrayCtTestSetToMin : public DecisionBuilder {
|
|
public:
|
|
MinArrayCtTestSetToMin(IntExpr* const min, const std::vector<IntVar*>& vars)
|
|
: min_(min), vars_(vars) {}
|
|
virtual ~MinArrayCtTestSetToMin() {}
|
|
|
|
virtual Decision* Next(Solver* const s) {
|
|
min_->SetMax(0);
|
|
CHECK(vars_[0]->Bound()) << "var not bound";
|
|
CHECK_EQ(0, vars_[0]->Min()) << "var not bound to the correct value";
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
IntExpr* const min_;
|
|
const std::vector<IntVar*>& vars_;
|
|
};
|
|
|
|
class MinArrayCtTestSetToMax : public DecisionBuilder {
|
|
public:
|
|
MinArrayCtTestSetToMax(IntExpr* const min, const std::vector<IntVar*>& vars)
|
|
: min_(min), vars_(vars) {}
|
|
virtual ~MinArrayCtTestSetToMax() {}
|
|
|
|
virtual Decision* Next(Solver* const s) {
|
|
min_->SetMin(5);
|
|
CHECK(vars_[0]->Bound()) << "var not bound";
|
|
CHECK_EQ(5, vars_[0]->Min()) << "var not bound to the correct value";
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
IntExpr* const min_;
|
|
const std::vector<IntVar*>& vars_;
|
|
};
|
|
|
|
class MinArrayCtTestSetOneVar : public DecisionBuilder {
|
|
public:
|
|
MinArrayCtTestSetOneVar(IntExpr* const min, const std::vector<IntVar*>& vars)
|
|
: min_(min), vars_(vars) {}
|
|
virtual ~MinArrayCtTestSetOneVar() {}
|
|
|
|
virtual Decision* Next(Solver* const s) {
|
|
vars_[0]->SetValue(5);
|
|
CHECK_EQ(1, min_->Min()) << "bad computed min in min_array";
|
|
CHECK_EQ(5, min_->Max()) << "bad computed max in min_array";
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
IntExpr* const min_;
|
|
const std::vector<IntVar*>& vars_;
|
|
};
|
|
|
|
class MinArrayCtTest {
|
|
public:
|
|
void SetUp() {
|
|
solver_.reset(new Solver("MinConstraintTest"));
|
|
vars_.clear();
|
|
vars_.resize(10);
|
|
for (int i = 0; i < 10; ++i) {
|
|
vars_[i] = solver_->MakeIntVar(i, 2 * i + 5);
|
|
}
|
|
min_ = solver_->MakeMin(vars_)->Var();
|
|
}
|
|
|
|
std::unique_ptr<Solver> solver_;
|
|
std::vector<IntVar*> vars_;
|
|
IntExpr* min_;
|
|
|
|
void TestAlternateCtor() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
for (int i = 0; i < 4; ++i) {
|
|
vars.push_back(solver_->MakeIntVar(i, 2 * i));
|
|
}
|
|
IntExpr* emin = solver_->MakeMin(vars);
|
|
CHECK(!emin->DebugString().empty());
|
|
}
|
|
|
|
void TestBounds() {
|
|
SetUp();
|
|
CHECK_EQ(0LL, min_->Min()) << "bad computed min in min_array";
|
|
CHECK_EQ(5, min_->Max()) << "bad computed min in min_array";
|
|
}
|
|
|
|
void TestSetToMin() {
|
|
SetUp();
|
|
solver_->Solve(solver_->RevAlloc(new MinArrayCtTestSetToMin(min_, vars_)));
|
|
}
|
|
|
|
void TestSetToMax() {
|
|
SetUp();
|
|
solver_->Solve(solver_->RevAlloc(new MinArrayCtTestSetToMax(min_, vars_)));
|
|
}
|
|
|
|
void TestSetOneVar() {
|
|
SetUp();
|
|
solver_->Solve(solver_->RevAlloc(new MinArrayCtTestSetOneVar(min_, vars_)));
|
|
}
|
|
|
|
void TestWhen() {
|
|
SetUp();
|
|
Demon* const d = solver_->RevAlloc(new NullDemon());
|
|
min_->WhenRange(d);
|
|
}
|
|
|
|
void TestBigMinVector() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
for (int i = 0; i < 1001; ++i) {
|
|
vars.push_back(
|
|
solver_->MakeIntVar(i, 3000 - i, absl::StrFormat("x%d", i)));
|
|
}
|
|
IntExpr* expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(2000, expr->Max());
|
|
CHECK_EQ(0, expr->Min());
|
|
}
|
|
|
|
void TestBigMinArray() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
vars.reserve(1001);
|
|
for (int i = 0; i < 1001; ++i) {
|
|
vars.push_back(
|
|
solver_->MakeIntVar(i, 3000 - i, absl::StrFormat("x%d", i)));
|
|
}
|
|
IntExpr* expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(2000, expr->Max());
|
|
CHECK_EQ(0, expr->Min());
|
|
}
|
|
|
|
void TestSmallMinVector() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
IntExpr* expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(kint64max, expr->Min());
|
|
CHECK_EQ(kint64max, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(1, 10, "x0"));
|
|
expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(1, expr->Min());
|
|
CHECK_EQ(10, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(2, 9, "x1"));
|
|
expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(1, expr->Min());
|
|
CHECK_EQ(9, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(3, 8, "x2"));
|
|
expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(1, expr->Min());
|
|
CHECK_EQ(8, expr->Max());
|
|
}
|
|
|
|
void TestSmallMinArray() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
vars.reserve(3);
|
|
IntExpr* expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(kint64max, expr->Min());
|
|
CHECK_EQ(kint64max, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(1, 10, absl::StrFormat("x%d", 0)));
|
|
expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(1, expr->Min());
|
|
CHECK_EQ(10, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(1, 9, absl::StrFormat("x%d", 1)));
|
|
expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(1, expr->Min());
|
|
CHECK_EQ(9, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(1, 8, absl::StrFormat("x%d", 2)));
|
|
expr = solver_->MakeMin(vars);
|
|
CHECK_EQ(1, expr->Min());
|
|
CHECK_EQ(8, expr->Max());
|
|
}
|
|
};
|
|
|
|
// ----- Max Array Test -----
|
|
|
|
class MaxArrayCtTestSetToMin : public DecisionBuilder {
|
|
public:
|
|
MaxArrayCtTestSetToMin(IntExpr* const max, const std::vector<IntVar*>& vars)
|
|
: max_(max), vars_(vars) {}
|
|
virtual ~MaxArrayCtTestSetToMin() {}
|
|
|
|
virtual Decision* Next(Solver* const s) {
|
|
max_->SetMin(23);
|
|
CHECK(vars_[9]->Bound()) << "var not bound";
|
|
CHECK_EQ(23, vars_[9]->Min()) << "var not bound to the correct value";
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
IntExpr* const max_;
|
|
const std::vector<IntVar*>& vars_;
|
|
};
|
|
|
|
class MaxArrayCtTestSetToMax : public DecisionBuilder {
|
|
public:
|
|
MaxArrayCtTestSetToMax(IntExpr* const max, const std::vector<IntVar*>& vars)
|
|
: max_(max), vars_(vars) {}
|
|
virtual ~MaxArrayCtTestSetToMax() {}
|
|
|
|
virtual Decision* Next(Solver* const s) {
|
|
max_->SetMax(9);
|
|
CHECK(vars_[9]->Bound()) << "var not bound";
|
|
CHECK_EQ(9, vars_[9]->Min()) << "var not bound to the correct value";
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
IntExpr* const max_;
|
|
const std::vector<IntVar*>& vars_;
|
|
};
|
|
|
|
class MaxArrayCtTestSetOneVar : public DecisionBuilder {
|
|
public:
|
|
MaxArrayCtTestSetOneVar(IntExpr* const max, const std::vector<IntVar*>& vars)
|
|
: max_(max), vars_(vars) {}
|
|
virtual ~MaxArrayCtTestSetOneVar() {}
|
|
|
|
virtual Decision* Next(Solver* const s) {
|
|
vars_[9]->SetValue(18);
|
|
CHECK_EQ(18, max_->Min()) << "bad computed min in max_array";
|
|
CHECK_EQ(21, max_->Max()) << "bad computed max in max_array";
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
IntExpr* const max_;
|
|
const std::vector<IntVar*>& vars_;
|
|
};
|
|
|
|
class MaxArrayCtTest {
|
|
public:
|
|
void SetUp() {
|
|
solver_.reset(new Solver("MaxArrayCtTest"));
|
|
vars_.resize(10);
|
|
for (int i = 0; i < 10; ++i) {
|
|
vars_[i] = solver_->MakeIntVar(i, 2 * i + 5);
|
|
}
|
|
max_ = solver_->MakeMax(vars_)->Var();
|
|
}
|
|
|
|
std::unique_ptr<Solver> solver_;
|
|
std::vector<IntVar*> vars_;
|
|
IntExpr* max_;
|
|
|
|
void TestAlternateCtor() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
for (int i = 0; i < 4; ++i) {
|
|
vars.push_back(solver_->MakeIntVar(i, 2 * i));
|
|
}
|
|
IntExpr* emax = solver_->MakeMax(vars);
|
|
CHECK(!emax->DebugString().empty());
|
|
}
|
|
|
|
void TestBounds() {
|
|
SetUp();
|
|
CHECK_EQ(9, max_->Min()) << "bad computed min in max_array";
|
|
CHECK_EQ(23, max_->Max()) << "bad computed min in max_array";
|
|
}
|
|
|
|
void TestSetToMin() {
|
|
SetUp();
|
|
solver_->Solve(solver_->RevAlloc(new MaxArrayCtTestSetToMin(max_, vars_)));
|
|
}
|
|
|
|
void TestSetToMax() {
|
|
SetUp();
|
|
solver_->Solve(solver_->RevAlloc(new MaxArrayCtTestSetToMax(max_, vars_)));
|
|
}
|
|
|
|
void TestSetOneVar() {
|
|
SetUp();
|
|
solver_->Solve(solver_->RevAlloc(new MaxArrayCtTestSetOneVar(max_, vars_)));
|
|
}
|
|
|
|
void TestWhen() {
|
|
SetUp();
|
|
Demon* d = solver_->RevAlloc(new NullDemon());
|
|
max_->WhenRange(d);
|
|
}
|
|
|
|
void TestBigMaxVector() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
vars.reserve(1001);
|
|
for (int i = 0; i < 1001; ++i) {
|
|
vars.push_back(
|
|
solver_->MakeIntVar(i, 3000 - i, absl::StrFormat("x%d", i)));
|
|
}
|
|
IntExpr* expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(3000, expr->Max());
|
|
CHECK_EQ(1000, expr->Min());
|
|
}
|
|
|
|
void TestBigMaxArray() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
for (int i = 0; i < 1001; ++i) {
|
|
vars.push_back(
|
|
solver_->MakeIntVar(i, 3000 - i, absl::StrFormat("x%d", i)));
|
|
}
|
|
IntExpr* expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(3000, expr->Max());
|
|
CHECK_EQ(1000, expr->Min());
|
|
}
|
|
|
|
void TestSmallMaxVector() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
IntExpr* expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(kint64min, expr->Min());
|
|
CHECK_EQ(kint64min, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(1, 10, "x0"));
|
|
expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(1, expr->Min());
|
|
CHECK_EQ(10, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(2, 9, "x1"));
|
|
expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(2, expr->Min());
|
|
CHECK_EQ(10, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(3, 8, "x2"));
|
|
expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(3, expr->Min());
|
|
CHECK_EQ(10, expr->Max());
|
|
}
|
|
|
|
void TestSmallMaxArray() {
|
|
SetUp();
|
|
std::vector<IntVar*> vars;
|
|
IntExpr* expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(kint64min, expr->Min());
|
|
CHECK_EQ(kint64min, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(1, 10, absl::StrFormat("x%d", 0)));
|
|
expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(1, expr->Min());
|
|
CHECK_EQ(10, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(2, 10, absl::StrFormat("x%d", 1)));
|
|
expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(2, expr->Min());
|
|
CHECK_EQ(10, expr->Max());
|
|
vars.push_back(solver_->MakeIntVar(3, 10, absl::StrFormat("x%d", 2)));
|
|
expr = solver_->MakeMax(vars);
|
|
CHECK_EQ(3, expr->Min());
|
|
CHECK_EQ(10, expr->Max());
|
|
}
|
|
};
|
|
} // namespace operations_research
|
|
|
|
int main(int argc, char** argv) {
|
|
absl::ParseCommandLine(argc, argv);
|
|
operations_research::MinArrayCtTest min_test;
|
|
min_test.TestAlternateCtor();
|
|
min_test.TestBounds();
|
|
min_test.TestSetToMin();
|
|
min_test.TestSetToMax();
|
|
min_test.TestSetOneVar();
|
|
min_test.TestWhen();
|
|
min_test.TestBigMinVector();
|
|
min_test.TestBigMinArray();
|
|
min_test.TestSmallMinVector();
|
|
min_test.TestSmallMinArray();
|
|
|
|
operations_research::MaxArrayCtTest max_test;
|
|
max_test.TestAlternateCtor();
|
|
max_test.TestBounds();
|
|
max_test.TestSetToMin();
|
|
max_test.TestSetToMax();
|
|
max_test.TestSetOneVar();
|
|
max_test.TestWhen();
|
|
max_test.TestBigMaxVector();
|
|
max_test.TestBigMaxArray();
|
|
max_test.TestSmallMaxVector();
|
|
max_test.TestSmallMaxArray();
|
|
|
|
return 0;
|
|
}
|