frequency assignment problem
This commit is contained in:
123
examples/cpp/fap_model_printer.cc
Normal file
123
examples/cpp/fap_model_printer.cc
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright 2010-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 "cpp/fap_model_printer.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/concise_iterator.h"
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
FapModelPrinter::FapModelPrinter(const std::map<int, FapVariable>& variables,
|
||||
const std::vector<FapConstraint>& constraints,
|
||||
const string& objective,
|
||||
const std::vector<int>& values)
|
||||
: variables_(variables),
|
||||
constraints_(constraints),
|
||||
objective_(objective),
|
||||
values_(values) { }
|
||||
|
||||
FapModelPrinter::~FapModelPrinter() { }
|
||||
|
||||
void FapModelPrinter::PrintFapVariables() {
|
||||
int key;
|
||||
int domain_index;
|
||||
int initial_position;
|
||||
int mobility_index;
|
||||
int mobility_cost;
|
||||
|
||||
LOG(INFO) << "Variable File:";
|
||||
for (ConstIter<std::map<int, FapVariable> > it(variables_); !it.at_end(); ++it) {
|
||||
LOG(INFO) << "Variable ";
|
||||
|
||||
key = it->first;
|
||||
LOG(INFO) << StringPrintf("%3d: ", key);
|
||||
|
||||
domain_index = it->second.domain_index_;
|
||||
LOG(INFO) << StringPrintf("%3d", domain_index);
|
||||
|
||||
initial_position = it->second.initial_position_;
|
||||
LOG(INFO) << StringPrintf("%3d", initial_position);
|
||||
|
||||
mobility_index = it->second.mobility_index_;
|
||||
LOG(INFO) << StringPrintf("%3d", mobility_index);
|
||||
|
||||
mobility_cost = it->second.mobility_cost_;
|
||||
LOG(INFO) << StringPrintf("%8d", mobility_cost);
|
||||
|
||||
LOG(INFO) << StringPrintf(" { ");
|
||||
for (int i = 0; i < it->second.domain_.size(); ++i)
|
||||
LOG(INFO) << StringPrintf("%d ", it->second.domain_[i]);
|
||||
LOG(INFO) << "}";
|
||||
|
||||
LOG(INFO) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FapModelPrinter::PrintFapConstraints() {
|
||||
int variable1;
|
||||
int variable2;
|
||||
string type;
|
||||
string operation;
|
||||
int value;
|
||||
int weight_index;
|
||||
int weight_cost;
|
||||
|
||||
LOG(INFO) << "Constraint File:";
|
||||
for (ConstIter<std::vector<FapConstraint> > it(constraints_); !it.at_end(); ++it) {
|
||||
variable1 = it->variable1_;
|
||||
LOG(INFO) << StringPrintf("%3d ", variable1);
|
||||
|
||||
variable2 = it->variable2_;
|
||||
LOG(INFO) << StringPrintf("%3d ", variable2);
|
||||
|
||||
type = it->type_;
|
||||
LOG(INFO) << type;
|
||||
|
||||
operation = it->operator_;
|
||||
LOG(INFO) << operation;
|
||||
|
||||
value = it->value_;
|
||||
LOG(INFO) << StringPrintf("%3d", value);
|
||||
|
||||
weight_index = it->weight_index_;
|
||||
LOG(INFO) << StringPrintf("%3d", weight_index);
|
||||
|
||||
weight_cost = it->weight_cost_;
|
||||
LOG(INFO) << StringPrintf("%8d", weight_cost);
|
||||
|
||||
if (it->hard_) {
|
||||
LOG(INFO) << " hard";
|
||||
}
|
||||
|
||||
LOG(INFO) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void FapModelPrinter::PrintFapObjective() {
|
||||
LOG(INFO) << "Objective: " << objective_;
|
||||
}
|
||||
|
||||
void FapModelPrinter::PrintFapValues() {
|
||||
LOG(INFO) << StringPrintf("Values(%d): ", static_cast<int>(values_.size()));
|
||||
for (ConstIter<std::vector<int> > it(values_); !it.at_end(); ++it) {
|
||||
LOG(INFO) << *it;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
53
examples/cpp/fap_model_printer.h
Normal file
53
examples/cpp/fap_model_printer.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2010-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.
|
||||
//
|
||||
// Prints a model of Frequency Assignment Problem.
|
||||
// Format: http://www.inra.fr/mia/T/schiex/Doc/CELAR.shtml#synt
|
||||
//
|
||||
|
||||
#ifndef OR_TOOLS_EXAMPLES_FAP_MODEL_PRINTER_H_
|
||||
#define OR_TOOLS_EXAMPLES_FAP_MODEL_PRINTER_H_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "cpp/fap_parser.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
// Prints the instance of the Frequency Assignment Problem
|
||||
class FapModelPrinter {
|
||||
public:
|
||||
FapModelPrinter(const std::map<int, FapVariable>& variables,
|
||||
const std::vector<FapConstraint>& constraints,
|
||||
const string& objective,
|
||||
const std::vector<int>& values);
|
||||
~FapModelPrinter();
|
||||
|
||||
void PrintFapObjective();
|
||||
void PrintFapVariables();
|
||||
void PrintFapConstraints();
|
||||
void PrintFapValues();
|
||||
|
||||
private:
|
||||
const std::map<int, FapVariable> variables_;
|
||||
const std::vector<FapConstraint> constraints_;
|
||||
const string objective_;
|
||||
const std::vector<int> values_;
|
||||
DISALLOW_COPY_AND_ASSIGN(FapModelPrinter);
|
||||
};
|
||||
|
||||
} // namespace operations_research
|
||||
#endif // OR_TOOLS_EXAMPLES_FAP_MODEL_PRINTER_H_
|
||||
245
examples/cpp/fap_parser.cc
Normal file
245
examples/cpp/fap_parser.cc
Normal file
@@ -0,0 +1,245 @@
|
||||
// Copyright 2010-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 <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "base/file.h"
|
||||
#include "base/split.h"
|
||||
#include "base/concise_iterator.h"
|
||||
#include "base/map-util.h"
|
||||
|
||||
#include "cpp/fap_parser.h"
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
void ParseFileByLines(const string& filename, std::vector<string>* lines) {
|
||||
CHECK_NOTNULL(lines);
|
||||
File::Init();
|
||||
File* file = File::OpenOrDie(filename.c_str(), "r");
|
||||
|
||||
string result;
|
||||
const int64 kMaxInputFileSize = 1 << 30; // 1GB
|
||||
file->ReadToString(&result, kMaxInputFileSize);
|
||||
file->Close();
|
||||
|
||||
SplitStringUsing(result, "\n", lines);
|
||||
}
|
||||
|
||||
// VariableParser Implementation
|
||||
VariableParser::VariableParser(const string& data_directory)
|
||||
: filename_(data_directory + "/var.txt") { }
|
||||
|
||||
VariableParser::~VariableParser() { }
|
||||
|
||||
void VariableParser::Parse() {
|
||||
std::vector<string> lines;
|
||||
ParseFileByLines(filename_, &lines);
|
||||
for (ConstIter<std::vector<string> > it(lines); !it.at_end(); ++it) {
|
||||
std::vector<string> tokens;
|
||||
SplitStringUsing(*it, " ", &tokens);
|
||||
if (tokens.empty()) {
|
||||
continue;
|
||||
}
|
||||
CHECK_GE(tokens.size(), 2);
|
||||
|
||||
FapVariable variable;
|
||||
variable.domain_index_ = atoi32(tokens[1].c_str());
|
||||
if (tokens.size() > 3) {
|
||||
variable.initial_position_ = atoi32(tokens[2].c_str());
|
||||
variable.mobility_index_ = atoi32(tokens[3].c_str());
|
||||
}
|
||||
|
||||
InsertOrUpdate(&variables_, atoi32(tokens[0].c_str()), variable);
|
||||
}
|
||||
}
|
||||
|
||||
// DomainParser Implementation
|
||||
DomainParser::DomainParser(const string& data_directory)
|
||||
: filename_(data_directory + "/dom.txt") { }
|
||||
|
||||
DomainParser::~DomainParser() { }
|
||||
|
||||
void DomainParser::Parse() {
|
||||
std::vector<string> lines;
|
||||
ParseFileByLines(filename_, &lines);
|
||||
for (ConstIter<std::vector<string> > it(lines); !it.at_end(); ++it) {
|
||||
std::vector<string> tokens;
|
||||
SplitStringUsing(*it, " ", &tokens);
|
||||
if (tokens.empty()) {
|
||||
continue;
|
||||
}
|
||||
CHECK_GE(tokens.size(), 2);
|
||||
|
||||
const int key = atoi32(tokens[0].c_str());
|
||||
domain_cardinality_ = atoi32(tokens[1].c_str());
|
||||
|
||||
std::vector<int> domain;
|
||||
domain.clear();
|
||||
for (int i = 2; i < tokens.size(); ++i) {
|
||||
domain.push_back(atoi32(tokens[i].c_str()));
|
||||
}
|
||||
|
||||
if (!domain.empty()) {
|
||||
InsertOrUpdate(&domains_, key, domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ConstraintParser Implementation
|
||||
ConstraintParser::ConstraintParser(const string& data_directory)
|
||||
: filename_(data_directory + "/ctr.txt") { }
|
||||
|
||||
ConstraintParser::~ConstraintParser() { }
|
||||
|
||||
void ConstraintParser::Parse() {
|
||||
std::vector<string> lines;
|
||||
ParseFileByLines(filename_, &lines);
|
||||
for (ConstIter<std::vector<string> > it(lines); !it.at_end(); ++it) {
|
||||
std::vector<string> tokens;
|
||||
SplitStringUsing(*it, " ", &tokens);
|
||||
if (tokens.empty()) {
|
||||
continue;
|
||||
}
|
||||
CHECK_GE(tokens.size(), 5);
|
||||
|
||||
FapConstraint constraint;
|
||||
constraint.variable1_ = atoi32(tokens[0].c_str());
|
||||
constraint.variable2_ = atoi32(tokens[1].c_str());
|
||||
constraint.type_ = tokens[2];
|
||||
constraint.operator_ = tokens[3];
|
||||
constraint.value_ = atoi32(tokens[4].c_str());
|
||||
|
||||
if (tokens.size() > 5) {
|
||||
constraint.weight_index_ = atoi32(tokens[5].c_str());
|
||||
}
|
||||
|
||||
constraints_.push_back(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
// ParametersParser Implementation
|
||||
ParametersParser::ParametersParser(const string& data_directory)
|
||||
: filename_(data_directory + "/cst.txt") ,
|
||||
objective_(""),
|
||||
constraint_weights_(constraint_coefficient_no_, 0),
|
||||
variable_weights_(variable_coefficient_no_, 0) { }
|
||||
|
||||
ParametersParser::~ParametersParser() { }
|
||||
|
||||
void ParametersParser::Parse() {
|
||||
bool objective = true;
|
||||
bool largest_token = false;
|
||||
bool value_token = false;
|
||||
bool number_token = false;
|
||||
bool values_token = false;
|
||||
bool coefficient = false;
|
||||
std::vector<int> coefficients;
|
||||
std::vector<string> lines;
|
||||
|
||||
ParseFileByLines(filename_, &lines);
|
||||
for (ConstIter<std::vector<string> > it(lines); !it.at_end(); ++it) {
|
||||
if (objective) {
|
||||
largest_token = largest_token || (it->find("largest") != string::npos);
|
||||
value_token = value_token || (it->find("value") != string::npos);
|
||||
number_token = number_token || (it->find("number") != string::npos);
|
||||
values_token = values_token || (it->find("values") != string::npos);
|
||||
coefficient = coefficient || (it->find("coefficient") != string::npos);
|
||||
}
|
||||
|
||||
if (coefficient) {
|
||||
CHECK_EQ(coefficient_no_,
|
||||
constraint_coefficient_no_ + variable_coefficient_no_);
|
||||
objective = false;
|
||||
if (it->find("=") != string::npos) {
|
||||
std::vector<string> tokens;
|
||||
SplitStringUsing(*it, " ", &tokens);
|
||||
CHECK_GE(tokens.size(), 3);
|
||||
coefficients.push_back(atoi32(tokens[2].c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (coefficient) {
|
||||
CHECK_EQ(coefficient_no_, coefficients.size());
|
||||
for (int i = 0; i < coefficient_no_; i++) {
|
||||
if (i < constraint_coefficient_no_) {
|
||||
constraint_weights_[i] = coefficients[i];
|
||||
} else {
|
||||
variable_weights_[i - constraint_coefficient_no_] = coefficients[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (largest_token && value_token) {
|
||||
objective_ = "Minimize the largest assigned value.";
|
||||
} else if (number_token && values_token) {
|
||||
objective_ = "Minimize the number of assigned values.";
|
||||
} else {
|
||||
// Should not reach this point.
|
||||
LOG(WARNING) << "Cannot read the objective of the instance.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ParseInstance(const string& data_directory,
|
||||
std::map<int, FapVariable>* variables,
|
||||
std::vector<FapConstraint>* constraints, string* objective,
|
||||
std::vector<int>* frequencies) {
|
||||
CHECK_NOTNULL(variables);
|
||||
CHECK_NOTNULL(constraints);
|
||||
CHECK_NOTNULL(objective);
|
||||
|
||||
VariableParser var(data_directory);
|
||||
var.Parse();
|
||||
*variables = var.variables();
|
||||
|
||||
ConstraintParser ctr(data_directory);
|
||||
ctr.Parse();
|
||||
*constraints = ctr.constraints();
|
||||
|
||||
DomainParser dom(data_directory);
|
||||
dom.Parse();
|
||||
|
||||
ParametersParser cst(data_directory);
|
||||
cst.Parse();
|
||||
|
||||
for (MutableIter<std::map<int, FapVariable> > it(*variables); !it.at_end(); ++it) {
|
||||
it->second.domain_ = FindOrDie(dom.domains(), it->second.domain_index_);
|
||||
it->second.domain_size_ = dom.domain_cardinality();
|
||||
if ((it->second.mobility_index_ == -1) ||
|
||||
(it->second.mobility_index_ == 0)) {
|
||||
it->second.mobility_cost_ = -1;
|
||||
if (it->second.initial_position_ != -1) {
|
||||
it->second.hard_ = true;
|
||||
}
|
||||
} else {
|
||||
it->second.mobility_cost_ =
|
||||
(cst.variable_weights())[it->second.mobility_index_-1];
|
||||
}
|
||||
}
|
||||
*frequencies = FindOrDie(dom.domains(), 0);
|
||||
*objective = cst.objective();
|
||||
|
||||
for (MutableIter<std::vector<FapConstraint> > it(*constraints);
|
||||
!it.at_end(); ++it) {
|
||||
if ((it->weight_index_ == -1) || (it->weight_index_ == 0)) {
|
||||
it->weight_cost_ = -1;
|
||||
it->hard_ = true;
|
||||
} else {
|
||||
it->weight_cost_ = (cst.constraint_weights())[it->weight_index_-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
193
examples/cpp/fap_parser.h
Normal file
193
examples/cpp/fap_parser.h
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright 2010-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.
|
||||
//
|
||||
// Reading and parsing the data of Frequency Assignment Problem
|
||||
// Format: http://www.inra.fr/mia/T/schiex/Doc/CELAR.shtml#synt
|
||||
//
|
||||
|
||||
#ifndef OR_TOOLS_EXAMPLES_FAP_PARSER_H_
|
||||
#define OR_TOOLS_EXAMPLES_FAP_PARSER_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "base/logging.h"
|
||||
#include "base/strtoint.h"
|
||||
#include "base/split.h"
|
||||
#include "base/concise_iterator.h"
|
||||
#include "base/map-util.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
// Takes a filename and a buffer and fills the lines buffer
|
||||
// with the lines of the file corresponding to the filename.
|
||||
void ParseFileByLines(const string& filename, std::vector<string>* lines);
|
||||
|
||||
// The FapVariable struct represents a radio link of the
|
||||
// frequency assignment problem.
|
||||
// Each variable has the following fields:
|
||||
// - domain_: a finite set of frequencies that can be assigned to
|
||||
// this link
|
||||
// - domain_index_: the domain index
|
||||
// - domain_size_: the domain cardinality
|
||||
// - initial_position_: if positive, it means that the link has already
|
||||
// been assigned a frequency of that value
|
||||
// - mobility_cost_: cost of modification of a link's assigned value
|
||||
// - mobility_index_: the index of mobility cost
|
||||
// - hard_: if true, it means that the link's value cannot be modified
|
||||
struct FapVariable {
|
||||
FapVariable() : domain_index_(-1),
|
||||
initial_position_(-1),
|
||||
mobility_index_(-1),
|
||||
mobility_cost_(-1),
|
||||
hard_(false) { }
|
||||
~FapVariable() { }
|
||||
|
||||
int domain_index_;
|
||||
int domain_size_;
|
||||
std::vector<int> domain_;
|
||||
int initial_position_;
|
||||
int mobility_index_;
|
||||
int mobility_cost_;
|
||||
bool hard_;
|
||||
};
|
||||
|
||||
// The FapConstraint struct represents a constraint between two
|
||||
// radio links of the frequency assignment problem.
|
||||
// Each constraint has the following fields:
|
||||
// - variable1_: the index of the first variable involved in the constraint
|
||||
// - variable2_: the index of the second variable involved in the constraint
|
||||
// - type_: the constraint type (D (difference), C (viscosity), F (fixed),
|
||||
// P (prefix) or L (far fields)) which is not used in practice
|
||||
// - operator_: the operator used in the constraint ("=" or ">")
|
||||
// - value_: the constraint deviation
|
||||
// it defines the constant k12 mentioned in FAP description
|
||||
// - weight_cost_: cost of not satisfaction of the constraint
|
||||
// - weight_index_: the index of weight cost
|
||||
// - hard_: if true, it means that the constraint must be satisfied
|
||||
struct FapConstraint {
|
||||
FapConstraint() : variable1_(-1),
|
||||
variable2_(-1),
|
||||
type_(""),
|
||||
operator_(""),
|
||||
value_(-1),
|
||||
weight_index_(-1),
|
||||
weight_cost_(-1),
|
||||
hard_(false) { }
|
||||
~FapConstraint() { }
|
||||
|
||||
int variable1_;
|
||||
int variable2_;
|
||||
string type_;
|
||||
string operator_;
|
||||
int value_;
|
||||
int weight_index_;
|
||||
int weight_cost_;
|
||||
bool hard_;
|
||||
};
|
||||
|
||||
// Parser of the var.txt file.
|
||||
// This file describes all the variables in the instance.
|
||||
// Each line corresponds to one variable.
|
||||
class VariableParser {
|
||||
public:
|
||||
explicit VariableParser(const string& data_directory);
|
||||
~VariableParser();
|
||||
|
||||
const std::map<int, FapVariable>& variables() const { return variables_; }
|
||||
|
||||
void Parse();
|
||||
|
||||
private:
|
||||
const string filename_;
|
||||
std::map<int, FapVariable> variables_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(VariableParser);
|
||||
};
|
||||
|
||||
// Parser of the dom.txt file.
|
||||
// This file describes the domains used by the variables of the problem.
|
||||
// Each line describes one domain.
|
||||
class DomainParser {
|
||||
public:
|
||||
explicit DomainParser(const string& data_directory);
|
||||
~DomainParser();
|
||||
|
||||
int domain_cardinality() const { return domain_cardinality_; }
|
||||
const std::map<int, std::vector<int> >& domains() const { return domains_; }
|
||||
|
||||
void Parse();
|
||||
|
||||
private:
|
||||
const string filename_;
|
||||
int domain_cardinality_;
|
||||
std::map<int, std::vector<int> > domains_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DomainParser);
|
||||
};
|
||||
|
||||
// Parse ctr.txt file.
|
||||
// This file describes the constraints of the instance.
|
||||
// Each line defines a binary constraint.
|
||||
class ConstraintParser {
|
||||
public:
|
||||
explicit ConstraintParser(const string& data_directory);
|
||||
~ConstraintParser();
|
||||
|
||||
const std::vector<FapConstraint>& constraints() const { return constraints_; }
|
||||
|
||||
void Parse();
|
||||
|
||||
private:
|
||||
const string filename_;
|
||||
std::vector<FapConstraint> constraints_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ConstraintParser);
|
||||
};
|
||||
|
||||
// Parse cst.txt file.
|
||||
// This file defines the criterion on which the solution will be based.
|
||||
// It may also contain 8 coefficients: 4 for different constraint violation
|
||||
// costs and 4 for different variable mobility costs.
|
||||
class ParametersParser {
|
||||
public:
|
||||
explicit ParametersParser(const string& data_directory);
|
||||
~ParametersParser();
|
||||
|
||||
string objective() const { return objective_; }
|
||||
const std::vector<int>& constraint_weights() const { return constraint_weights_; }
|
||||
const std::vector<int>& variable_weights() const { return variable_weights_; }
|
||||
|
||||
void Parse();
|
||||
|
||||
private:
|
||||
const string filename_;
|
||||
static const int constraint_coefficient_no_ = 4;
|
||||
static const int variable_coefficient_no_ = 4;
|
||||
static const int coefficient_no_ = 8;
|
||||
string objective_;
|
||||
std::vector<int> constraint_weights_;
|
||||
std::vector<int> variable_weights_;
|
||||
};
|
||||
|
||||
// Function that parses an instance of frequency assignment problem.
|
||||
void ParseInstance(const string& data_directory,
|
||||
std::map<int, FapVariable>* variables,
|
||||
std::vector<FapConstraint>* constraints,
|
||||
string* objective,
|
||||
std::vector<int>* frequencies);
|
||||
|
||||
} // namespace operations_research
|
||||
#endif // OR_TOOLS_EXAMPLES_FAP_PARSER_H_
|
||||
202
examples/cpp/fap_utilities.cc
Normal file
202
examples/cpp/fap_utilities.cc
Normal file
@@ -0,0 +1,202 @@
|
||||
// Copyright 2010-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 "cpp/fap_utilities.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/concise_iterator.h"
|
||||
#include "base/map-util.h"
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
bool CheckConstraintSatisfaction(const std::vector<FapConstraint>& data_constraints,
|
||||
const std::vector<int>& variables,
|
||||
const std::map<int, int>& index_from_key) {
|
||||
bool status = true;
|
||||
for (ConstIter<std::vector<FapConstraint> > it(data_constraints);
|
||||
!it.at_end(); ++it) {
|
||||
const int index1 = FindOrDie(index_from_key, it->variable1_);
|
||||
const int index2 = FindOrDie(index_from_key, it->variable2_);
|
||||
CHECK_LT(index1, variables.size());
|
||||
CHECK_LT(index2, variables.size());
|
||||
const int var1 = variables[index1];
|
||||
const int var2 = variables[index2];
|
||||
const int absolute_difference = abs(var1 - var2);
|
||||
|
||||
if (it->hard_) {
|
||||
if ((it->operator_ == ">") && (absolute_difference <= it->value_)) {
|
||||
LOG(INFO) << StringPrintf(" Violation of contraint between variable %d"
|
||||
" and variable %d.\n",
|
||||
it->variable1_, it->variable2_);
|
||||
LOG(INFO) << StringPrintf(" Expected |%d - %d| (= %d) > %d.",
|
||||
var1, var2,
|
||||
absolute_difference, it->value_);
|
||||
status = false;
|
||||
} else if ((it->operator_ == "=") &&
|
||||
(absolute_difference != it->value_)) {
|
||||
LOG(INFO) << StringPrintf(" Violation of contraint between variable %d"
|
||||
" and variable %d.\n",
|
||||
it->variable1_, it->variable2_);
|
||||
LOG(INFO) << StringPrintf(" Expected |%d - %d| (= %d) == %d.",
|
||||
var1, var2,
|
||||
absolute_difference, it->value_);
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bool CheckVariablePosition(const std::map<int, FapVariable>& data_variables,
|
||||
const std::vector<int>& variables,
|
||||
const std::map<int, int>& index_from_key) {
|
||||
bool status = true;
|
||||
for (ConstIter<std::map<int, FapVariable> > it(data_variables);
|
||||
!it.at_end(); ++it) {
|
||||
const int index = FindOrDie(index_from_key, it->first);
|
||||
CHECK_LT(index, variables.size());
|
||||
const int var = variables[index];
|
||||
|
||||
if (it->second.hard_ &&
|
||||
(it->second.initial_position_ != -1) &&
|
||||
(var != it->second.initial_position_)) {
|
||||
LOG(INFO) << StringPrintf(" Change of position of hard variable %d.\n",
|
||||
it->first);
|
||||
LOG(INFO) << StringPrintf(" Expected %d instead of given %d.",
|
||||
it->second.initial_position_, var);
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int NumberOfAssignedValues(const std::vector<int>& variables) {
|
||||
std::set<int> assigned(variables.begin(), variables.end());
|
||||
return static_cast<int>(assigned.size());
|
||||
}
|
||||
|
||||
void PrintElapsedTime(const int64 time1, const int64 time2) {
|
||||
LOG(INFO) << "End of solving process.";
|
||||
LOG(INFO) << "The Solve method took " << (time2 - time1)/1000.0 <<
|
||||
" seconds.";
|
||||
}
|
||||
|
||||
void PrintResultsHard(SolutionCollector* const collector,
|
||||
const std::vector<IntVar*>& variables,
|
||||
IntVar* const objective_var,
|
||||
const std::map<int, FapVariable>& data_variables,
|
||||
const std::vector<FapConstraint>& data_constraints,
|
||||
const std::map<int, int>& index_from_key,
|
||||
const std::vector<int>& key_from_index) {
|
||||
LOG(INFO) << "Printing...";
|
||||
LOG(INFO) << "Number of Solutions: " << collector->solution_count();
|
||||
for (int solution_index = 0; solution_index < collector->solution_count();
|
||||
++solution_index) {
|
||||
Assignment* const solution = collector->solution(solution_index);
|
||||
std::vector<int> results(variables.size());
|
||||
LOG(INFO) << "------------------------------------------------------------";
|
||||
LOG(INFO) << "Solution " << solution_index + 1;
|
||||
for (int i = 0; i < variables.size(); ++i) {
|
||||
LOG(INFO) << StringPrintf(" Variable %2d: %3lld",
|
||||
key_from_index[i],
|
||||
solution->Value(variables[i]));
|
||||
results[i] = solution->Value(variables[i]);
|
||||
}
|
||||
if (CheckConstraintSatisfaction(data_constraints, results,
|
||||
index_from_key)) {
|
||||
LOG(INFO) << "All hard constraints satisfied.";
|
||||
} else {
|
||||
LOG(INFO) << "WARNING!!! Hard constraint violation detected!";
|
||||
}
|
||||
if (CheckVariablePosition(data_variables, results, index_from_key)) {
|
||||
LOG(INFO) << "All hard variables stayed unharmed.";
|
||||
} else {
|
||||
LOG(INFO) << "WARNING!!! Hard variable modification detected!";
|
||||
}
|
||||
|
||||
LOG(INFO) << "Values used: " << NumberOfAssignedValues(results);
|
||||
LOG(INFO) << "Maximum value used: " << *max_element(results.begin(),
|
||||
results.end());
|
||||
LOG(INFO) << " Objective: " << solution->Value(objective_var);
|
||||
LOG(INFO) << StringPrintf(" Failures: %3lld\n\n",
|
||||
collector->failures(solution_index));
|
||||
}
|
||||
|
||||
LOG(INFO) << " ============================================================";
|
||||
LOG(INFO) << " ============================================================";
|
||||
}
|
||||
|
||||
void PrintResultsSoft(SolutionCollector* const collector,
|
||||
const std::vector<IntVar*>& variables,
|
||||
IntVar* const total_cost,
|
||||
const std::map<int, FapVariable>& hard_variables,
|
||||
const std::vector<FapConstraint>& hard_constraints,
|
||||
const std::map<int, FapVariable>& soft_variables,
|
||||
const std::vector<FapConstraint>& soft_constraints,
|
||||
const std::map<int, int>& index_from_key,
|
||||
const std::vector<int>& key_from_index) {
|
||||
LOG(INFO) << "Printing...";
|
||||
LOG(INFO) << "Number of Solutions: " << collector->solution_count();
|
||||
for (int solution_index = 0; solution_index < collector->solution_count();
|
||||
++solution_index) {
|
||||
Assignment* const solution = collector->solution(solution_index);
|
||||
std::vector<int> results(variables.size());
|
||||
LOG(INFO) << "------------------------------------------------------------";
|
||||
LOG(INFO) << "Solution";
|
||||
for (int i = 0; i < variables.size(); ++i) {
|
||||
LOG(INFO) << StringPrintf(" Variable %2d: %3lld",
|
||||
key_from_index[i],
|
||||
solution->Value(variables[i]));
|
||||
results[i] = solution->Value(variables[i]);
|
||||
}
|
||||
if (CheckConstraintSatisfaction(hard_constraints, results,
|
||||
index_from_key)) {
|
||||
LOG(INFO) << "All hard constraints satisfied.";
|
||||
} else {
|
||||
LOG(INFO) << "WARNING!!! Hard constraint violation detected!";
|
||||
}
|
||||
if (CheckVariablePosition(hard_variables, results, index_from_key)) {
|
||||
LOG(INFO) << "All hard variables stayed unharmed.";
|
||||
} else {
|
||||
LOG(INFO) << "WARNING!!! Hard variable modification detected!";
|
||||
}
|
||||
|
||||
if (CheckConstraintSatisfaction(soft_constraints, results,
|
||||
index_from_key) &&
|
||||
CheckVariablePosition(soft_variables, results, index_from_key)) {
|
||||
LOG(INFO) << "Problem feasible: "
|
||||
"Soft constraints and soft variables satisfied.";
|
||||
LOG(INFO) << " Weighted Sum: " << solution->Value(total_cost);
|
||||
} else {
|
||||
LOG(INFO) << "Problem unfeasible. Optimized weighted sum of violations.";
|
||||
LOG(INFO) << " Weighted Sum: " << solution->Value(total_cost);
|
||||
}
|
||||
|
||||
LOG(INFO) << "Values used: " << NumberOfAssignedValues(results);
|
||||
LOG(INFO) << "Maximum value used: " <<
|
||||
*max_element(results.begin(), results.end());
|
||||
LOG(INFO) << StringPrintf(" Failures: %3lld\n\n",
|
||||
collector->failures(solution_index));
|
||||
}
|
||||
|
||||
LOG(INFO) << " ============================================================";
|
||||
LOG(INFO) << " ============================================================";
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
67
examples/cpp/fap_utilities.h
Normal file
67
examples/cpp/fap_utilities.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2010-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.
|
||||
//
|
||||
// Utilities used by frequency_assignment_problem.cc.
|
||||
//
|
||||
|
||||
#ifndef OR_TOOLS_EXAMPLES_FAP_UTILITIES_H_
|
||||
#define OR_TOOLS_EXAMPLES_FAP_UTILITIES_H_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "constraint_solver/constraint_solver.h"
|
||||
#include "cpp/fap_parser.h"
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
// Checks if the solution given from the Solver satisfies all
|
||||
// the hard binary constraints specified in the ctr.txt.
|
||||
bool CheckConstraintSatisfaction(const std::vector<FapConstraint>& data_constraints,
|
||||
const std::vector<int>& variables,
|
||||
const std::map<int, int>& index_from_key);
|
||||
|
||||
// Checks if the solution given from the Solver has not modified the values of
|
||||
// the variables that were initially assigned and denoted as hard in var.txt.
|
||||
bool CheckVariablePosition(const std::map<int, FapVariable>& data_variables,
|
||||
const std::vector<int>& variables,
|
||||
const std::map<int, int>& index_from_key);
|
||||
|
||||
// Counts the number of different values in the variable vector.
|
||||
int NumberOfAssignedValues(const std::vector<int>& variables);
|
||||
|
||||
// Prints the duration of the solving process.
|
||||
void PrintElapsedTime(const int64 time1, const int64 time2);
|
||||
|
||||
// Prints the solution found by the Hard Solver for feasible instances.
|
||||
void PrintResultsHard(SolutionCollector* const collector,
|
||||
const std::vector<IntVar*>& variables,
|
||||
IntVar* const objective_var,
|
||||
const std::map<int, FapVariable>& data_variables,
|
||||
const std::vector<FapConstraint>& data_constraints,
|
||||
const std::map<int, int>& index_from_key,
|
||||
const std::vector<int>& key_from_index);
|
||||
|
||||
// Prints the solution found by the Soft Solver for unfeasible instances.
|
||||
void PrintResultsSoft(SolutionCollector* const collector,
|
||||
const std::vector<IntVar*>& variables,
|
||||
IntVar* const total_cost,
|
||||
const std::map<int, FapVariable>& hard_variables,
|
||||
const std::vector<FapConstraint>& hard_constraints,
|
||||
const std::map<int, FapVariable>& soft_variables,
|
||||
const std::vector<FapConstraint>& soft_constraints,
|
||||
const std::map<int, int>& index_from_key,
|
||||
const std::vector<int>& key_from_index);
|
||||
|
||||
} // namespace operations_research
|
||||
#endif // OR_TOOLS_EXAMPLES_FAP_UTILITIES_H_
|
||||
541
examples/cpp/frequency_assignment_problem.cc
Normal file
541
examples/cpp/frequency_assignment_problem.cc
Normal file
@@ -0,0 +1,541 @@
|
||||
// Copyright 2010-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.
|
||||
//
|
||||
// Frequency Assignment Problem
|
||||
// The Radio Link Frequency Assignment Problem consists in assigning frequencies
|
||||
// to a set of radio links defined between pairs of sites in order to avoid
|
||||
// interferences. Each radio link is represented by a variable whose domain is
|
||||
// the set of all frequences that are available for this link.
|
||||
// The essential constraint involving two variables of the problem F1 and F2 is
|
||||
// |F1 - F2| > k12, where k12 is a predefined constant value.
|
||||
// The Frequency Assignment Problem is an NP-complete problem as proved by means
|
||||
// of reduction from k-Colorability problem for undirected graphs.
|
||||
// The solution of the problem can be based on various criteria:
|
||||
// - Simple satisfaction
|
||||
// - Minimizing the number of frequencies used
|
||||
// - Minimizing the maximum frequency used
|
||||
// - Minimizing a weighted sum of violated constraints if the problem is
|
||||
// inconsistent
|
||||
// More on the Frequency Assignment Problem and the data format of its instances
|
||||
// can be found at: http://www.inra.fr/mia/T/schiex/Doc/CELAR.shtml#synt
|
||||
//
|
||||
// Implementation
|
||||
// Two solvers are implemented: The FapSolverHard is dealing with finding the
|
||||
// solution to feasible instances of the problem with objective either the
|
||||
// minimization of the largest frequency assigned or the minimization of
|
||||
// the number of frequencies used to the solution.
|
||||
// The FapSolverSoft is dealing with the optimization of unfeasible instances
|
||||
// and aims to minimize the total cost of violated constraints.
|
||||
// If the latter solver is forced to solve a feasible instance, the main
|
||||
// function redirects to the former.
|
||||
//
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/concise_iterator.h"
|
||||
#include "base/map-util.h"
|
||||
#include "base/hash.h"
|
||||
#include "constraint_solver/constraint_solver.h"
|
||||
#include "cpp/fap_model_printer.h"
|
||||
#include "cpp/fap_parser.h"
|
||||
#include "cpp/fap_utilities.h"
|
||||
|
||||
DEFINE_string(directory, "", "Specifies the directory of the data.");
|
||||
DEFINE_string(evaluator, "",
|
||||
"Specifies if a value evaluator will be used by the "
|
||||
"decision builder.");
|
||||
DEFINE_int32(time_limit_in_ms, 0, "Time limit in ms, <= 0 means no limit.");
|
||||
DEFINE_int32(choose_next_variable_strategy, 1,
|
||||
"Selection strategy for variable: "
|
||||
"1 = CHOOSE_MIN_SIZE_LOWEST_MIN, "
|
||||
"2 = CHOOSE_MIN_SIZE_HIGHEST_MAX, "
|
||||
"3 = CHOOSE_FIRST_UNBOUND, "
|
||||
"4 = CHOOSE_RANDOM, ");
|
||||
DEFINE_int32(restart, -1, "Parameter for constant restart monitor.");
|
||||
DEFINE_bool(luby, false,
|
||||
"Use luby restart monitor instead of constant restart monitor.");
|
||||
DEFINE_bool(log_search, true,
|
||||
"Create a search log.");
|
||||
DEFINE_bool(soft, false,
|
||||
"Use soft solver instead of hard solver.");
|
||||
DEFINE_bool(display_time, true,
|
||||
"Print how much time the solving process took.");
|
||||
DEFINE_bool(display_results, true,
|
||||
"Print the results of the solving process.");
|
||||
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
int64 ValueEvaluator(hash_map<int64, std::pair<int64, int64> >* value_evaluator,
|
||||
int64 variable_index,
|
||||
int64 value) {
|
||||
CHECK_NOTNULL(value_evaluator);
|
||||
// Evaluate the choice. Smaller ranking denotes a better choice.
|
||||
int64 ranking = -1;
|
||||
for (ConstIter<hash_map<int64, pair<int64, int64> > > it(*value_evaluator);
|
||||
!it.at_end(); ++it) {
|
||||
if ((it->first != variable_index) && (it->second.first == value)) {
|
||||
ranking = -2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the history of assigned values and their rankings of each variable.
|
||||
hash_map<int64, pair<int64, int64> >::iterator it;
|
||||
int64 new_value = value;
|
||||
int64 new_ranking = ranking;
|
||||
if ((it = value_evaluator->find(variable_index)) != value_evaluator->end()) {
|
||||
pair<int64, int64> existing_value_ranking = it->second;
|
||||
// Replace only if the current choice for this variable has smaller
|
||||
// ranking or same ranking but smaller value of the existing choice.
|
||||
if (!(existing_value_ranking.second > ranking ||
|
||||
(existing_value_ranking.second == ranking &&
|
||||
existing_value_ranking.first > value))) {
|
||||
new_value = existing_value_ranking.first;
|
||||
new_ranking = existing_value_ranking.second;
|
||||
}
|
||||
}
|
||||
std::pair<int64, int64> new_value_ranking =
|
||||
std::make_pair(new_value, new_ranking);
|
||||
InsertOrUpdate(value_evaluator, variable_index, new_value_ranking);
|
||||
|
||||
return new_ranking;
|
||||
}
|
||||
|
||||
// Creates the variables of the solver from the parsed data.
|
||||
void CreateModelVariables(const std::map<int, FapVariable>& data_variables,
|
||||
Solver* solver,
|
||||
std::vector<IntVar*>* model_variables,
|
||||
std::map<int, int>* index_from_key,
|
||||
std::vector<int>* key_from_index) {
|
||||
CHECK_NOTNULL(solver);
|
||||
CHECK_NOTNULL(model_variables);
|
||||
CHECK_NOTNULL(index_from_key);
|
||||
CHECK_NOTNULL(key_from_index);
|
||||
|
||||
const int number_of_variables = static_cast<int>(data_variables.size());
|
||||
model_variables->resize(number_of_variables);
|
||||
key_from_index->resize(number_of_variables);
|
||||
|
||||
int index = 0;
|
||||
for (ConstIter<std::map<int, FapVariable> > it(data_variables);
|
||||
!it.at_end(); ++it) {
|
||||
CHECK_LT(index, model_variables->size());
|
||||
(*model_variables)[index] = solver->MakeIntVar(it->second.domain_);
|
||||
InsertOrUpdate(index_from_key, it->first, index);
|
||||
(*key_from_index)[index] = it->first;
|
||||
|
||||
if ((it->second.initial_position_ != -1) && (it->second.hard_)) {
|
||||
CHECK_LT(it->second.mobility_cost_, 0);
|
||||
solver->AddConstraint(solver->MakeEquality((*model_variables)[index],
|
||||
it->second.initial_position_));
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Creates the constraints of the instance from the parsed data.
|
||||
void CreateModelConstraints(const std::vector<FapConstraint>& data_constraints,
|
||||
const std::vector<IntVar*>& variables,
|
||||
const std::map<int, int>& index_from_key,
|
||||
Solver* solver) {
|
||||
CHECK_NOTNULL(solver);
|
||||
|
||||
for (ConstIter<std::vector<FapConstraint> > it(data_constraints);
|
||||
!it.at_end(); ++it) {
|
||||
const int index1 = FindOrDie(index_from_key, it->variable1_);
|
||||
const int index2 = FindOrDie(index_from_key, it->variable2_);
|
||||
CHECK_LT(index1, variables.size());
|
||||
CHECK_LT(index2, variables.size());
|
||||
IntVar* var1 = variables[index1];
|
||||
IntVar* var2 = variables[index2];
|
||||
IntVar* absolute_difference = solver->MakeAbs(solver->MakeDifference(var1,
|
||||
var2))
|
||||
->Var();
|
||||
if (it->operator_ == ">") {
|
||||
solver->AddConstraint(solver->MakeGreater(absolute_difference,
|
||||
it->value_));
|
||||
} else if (it->operator_ == "=") {
|
||||
solver->AddConstraint(solver->MakeEquality(absolute_difference,
|
||||
it->value_));
|
||||
} else {
|
||||
LOG(FATAL) << "Invalid operator detected.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// According to the value of a command line flag, chooses the strategy which
|
||||
// determines the selection of the variable to be assigned next.
|
||||
void ChooseVariableStrategy(Solver::IntVarStrategy* variable_strategy) {
|
||||
CHECK_NOTNULL(variable_strategy);
|
||||
|
||||
switch (FLAGS_choose_next_variable_strategy) {
|
||||
case 1: {
|
||||
*variable_strategy = Solver::CHOOSE_MIN_SIZE_LOWEST_MIN;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_LOWEST_MIN "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
*variable_strategy = Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
*variable_strategy = Solver::CHOOSE_FIRST_UNBOUND;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_FIRST_UNBOUND "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
*variable_strategy = Solver::CHOOSE_RANDOM;
|
||||
LOG(INFO) << "Using Solver::CHOOSE_RANDOM "
|
||||
"for variable selection strategy.";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG(FATAL) << "Should not be here";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// According to the values of some command line flags, adds some monitors
|
||||
// for the search of the Solver.
|
||||
void CreateAdditionalMonitors(OptimizeVar* const objective,
|
||||
Solver* solver,
|
||||
std::vector<SearchMonitor*>* monitors) {
|
||||
CHECK_NOTNULL(solver);
|
||||
CHECK_NOTNULL(monitors);
|
||||
|
||||
// Search Log
|
||||
if (FLAGS_log_search) {
|
||||
SearchMonitor* const log = solver->MakeSearchLog(100000, objective);
|
||||
monitors->push_back(log);
|
||||
}
|
||||
|
||||
// Time Limit
|
||||
if (FLAGS_time_limit_in_ms != 0) {
|
||||
LOG(INFO) << "Adding time limit of " << FLAGS_time_limit_in_ms << " ms.";
|
||||
SearchLimit* const limit = solver->MakeLimit(FLAGS_time_limit_in_ms,
|
||||
kint64max,
|
||||
kint64max,
|
||||
kint64max);
|
||||
monitors->push_back(limit);
|
||||
}
|
||||
|
||||
// Search Restart
|
||||
SearchMonitor* const restart = FLAGS_restart != -1?
|
||||
(FLAGS_luby?
|
||||
solver->MakeLubyRestart(FLAGS_restart):
|
||||
solver->MakeConstantRestart(FLAGS_restart)):
|
||||
NULL;
|
||||
if (restart) {
|
||||
monitors->push_back(restart);
|
||||
}
|
||||
}
|
||||
|
||||
// The Hard Solver is dealing with finding the solution to feasible
|
||||
// instances of the problem with objective either the minimization of
|
||||
// the largest frequency assigned or the minimization of the number
|
||||
// of frequencies used to the solution.
|
||||
void FapSolverHard(const std::map<int, FapVariable>& data_variables,
|
||||
const std::vector<FapConstraint>& data_constraints,
|
||||
const string& data_objective,
|
||||
const std::vector<int>& values) {
|
||||
Solver solver("FapSolverHard");
|
||||
std::vector<SearchMonitor*> monitors;
|
||||
|
||||
// Create Model Variables
|
||||
std::vector<IntVar*> variables;
|
||||
std::map<int, int> index_from_key;
|
||||
std::vector<int> key_from_index;
|
||||
CreateModelVariables(data_variables, &solver, &variables,
|
||||
&index_from_key, &key_from_index);
|
||||
|
||||
// Create Model Constraints
|
||||
CreateModelConstraints(data_constraints, variables, index_from_key, &solver);
|
||||
|
||||
// Objective:
|
||||
// Either minimize the largest assigned frequency or
|
||||
// minimize the number of different frequencies assigned
|
||||
IntVar* objective_var;
|
||||
OptimizeVar* objective;
|
||||
if (data_objective == "Minimize the largest assigned value.") {
|
||||
LOG(INFO) << "Minimize the largest assigned value.";
|
||||
// The objective_var is set to hold the maximum value assigned
|
||||
// in the variables vector.
|
||||
objective_var = solver.MakeMax(variables)->Var();
|
||||
objective = solver.MakeMinimize(objective_var, 1);
|
||||
} else if (data_objective == "Minimize the number of assigned values.") {
|
||||
LOG(INFO) << "Minimize the number of assigned values.";
|
||||
|
||||
std::vector<IntVar*> cardinality;
|
||||
solver.MakeIntVarArray(static_cast<int>(values.size()),
|
||||
0,
|
||||
static_cast<int>(variables.size()),
|
||||
&cardinality);
|
||||
solver.AddConstraint(solver.MakeDistribute(variables, values, cardinality));
|
||||
std::vector<IntVar*> value_not_assigned;
|
||||
for (int val = 0; val < values.size(); ++val) {
|
||||
value_not_assigned.push_back(solver.MakeIsEqualCstVar(cardinality[val],
|
||||
0));
|
||||
}
|
||||
CHECK(!value_not_assigned.empty());
|
||||
// The objective_var is set to maximize the number of values
|
||||
// that have not been assigned to a variable.
|
||||
objective_var = solver.MakeSum(value_not_assigned)->Var();
|
||||
objective = solver.MakeMaximize(objective_var, 1);
|
||||
} else {
|
||||
LOG(FATAL) << "No right objective specified.";
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Finished with objective specifier.";
|
||||
monitors.push_back(objective);
|
||||
|
||||
// Collector
|
||||
SolutionCollector* const collector = solver.MakeLastSolutionCollector();
|
||||
collector->Add(variables);
|
||||
collector->Add(objective_var);
|
||||
LOG(INFO) << "Made collector.";
|
||||
monitors.push_back(collector);
|
||||
|
||||
// Decision Builder Configuration
|
||||
// Choose the next variable selection strategy
|
||||
Solver::IntVarStrategy variable_strategy;
|
||||
ChooseVariableStrategy(&variable_strategy);
|
||||
// Choose the value selection strategy
|
||||
DecisionBuilder* db;
|
||||
hash_map<int64, pair<int64, int64> > history;
|
||||
if (FLAGS_evaluator == "evaluator") {
|
||||
LOG(INFO) << "Using ValueEvaluator for value selection strategy.";
|
||||
db = solver.MakePhase(variables,
|
||||
variable_strategy,
|
||||
NewPermanentCallback(&ValueEvaluator, &history));
|
||||
} else {
|
||||
LOG(INFO) << "Using Solver::ASSIGN_MIN_VALUE for value selection strategy.";
|
||||
db = solver.MakePhase(variables,
|
||||
variable_strategy,
|
||||
Solver::ASSIGN_MIN_VALUE);
|
||||
}
|
||||
|
||||
// Create Additional Monitors
|
||||
CreateAdditionalMonitors(objective, &solver, &monitors);
|
||||
|
||||
// Solve
|
||||
LOG(INFO) << "Solving...";
|
||||
const int64 time1 = solver.wall_time();
|
||||
solver.Solve(db, monitors);
|
||||
const int64 time2 = solver.wall_time();
|
||||
|
||||
// Display
|
||||
if (FLAGS_display_time) {
|
||||
PrintElapsedTime(time1, time2);
|
||||
}
|
||||
|
||||
if (FLAGS_display_results) {
|
||||
PrintResultsHard(collector, variables, objective_var,
|
||||
data_variables, data_constraints,
|
||||
index_from_key, key_from_index);
|
||||
}
|
||||
}
|
||||
|
||||
// The Soft Solver is dealing with the optimization of unfeasible instances
|
||||
// and aims to minimize the total cost of violated constraints. Returning value
|
||||
// equals to 0 denotes that the instance is feasible.
|
||||
int FapSolverSoft(const std::map<int, FapVariable>& data_variables,
|
||||
const std::vector<FapConstraint>& data_constraints,
|
||||
const string& data_objective, const std::vector<int>& values) {
|
||||
Solver solver("FapSolverSoft");
|
||||
std::vector<SearchMonitor*> monitors;
|
||||
|
||||
// Split variables to hard and soft
|
||||
std::map<int, FapVariable> hard_variables;
|
||||
std::map<int, FapVariable> soft_variables;
|
||||
for (ConstIter<std::map<int, FapVariable> > it(data_variables);
|
||||
!it.at_end(); ++it) {
|
||||
if (it->second.initial_position_ != -1) {
|
||||
if (it->second.hard_) {
|
||||
CHECK_LT(it->second.mobility_cost_, 0);
|
||||
InsertOrUpdate(&hard_variables, it->first, it->second);
|
||||
} else {
|
||||
CHECK_GE(it->second.mobility_cost_, 0);
|
||||
InsertOrUpdate(&soft_variables, it->first, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Split constraints to hard and soft
|
||||
std::vector<FapConstraint> hard_constraints;
|
||||
std::vector<FapConstraint> soft_constraints;
|
||||
for (ConstIter<std::vector<FapConstraint> > it(data_constraints);
|
||||
!it.at_end(); ++it) {
|
||||
if (it->hard_) {
|
||||
CHECK_LT(it->weight_cost_ , 0);
|
||||
hard_constraints.push_back(*it);
|
||||
} else {
|
||||
CHECK_GE(it->weight_cost_ , 0);
|
||||
soft_constraints.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// Create Model Variables
|
||||
std::vector<IntVar*> variables;
|
||||
std::map<int, int> index_from_key;
|
||||
std::vector<int> key_from_index;
|
||||
CreateModelVariables(data_variables, &solver, &variables,
|
||||
&index_from_key, &key_from_index);
|
||||
|
||||
// Create Model Constraints
|
||||
CreateModelConstraints(hard_constraints, variables, index_from_key, &solver);
|
||||
|
||||
// Objective:
|
||||
// Minimize the weighted sum of violated constraints
|
||||
IntVar* objective_var;
|
||||
OptimizeVar* objective;
|
||||
std::vector<IntVar*> cost;
|
||||
// Penalize the modification of the initial position of a soft variable
|
||||
for (ConstIter<std::map<int, FapVariable> > it(soft_variables);
|
||||
!it.at_end(); ++it) {
|
||||
const int index = index_from_key[it->first];
|
||||
CHECK_LT(index, variables.size());
|
||||
IntExpr* displaced =
|
||||
solver.MakeIsDifferentCstVar(variables[index],
|
||||
it->second.initial_position_);
|
||||
IntExpr* weight = solver.MakeProd(displaced, it->second.mobility_cost_);
|
||||
cost.push_back(weight->Var());
|
||||
}
|
||||
// Penalize the violation of a soft constraint
|
||||
for (ConstIter<std::vector<FapConstraint> > it(soft_constraints);
|
||||
!it.at_end(); ++it) {
|
||||
const int index1 = index_from_key[it->variable1_];
|
||||
const int index2 = index_from_key[it->variable2_];
|
||||
CHECK_LT(index1, variables.size());
|
||||
CHECK_LT(index2, variables.size());
|
||||
IntVar* absolute_difference =
|
||||
solver.MakeAbs(solver.MakeDifference(variables[index1],
|
||||
variables[index2]))
|
||||
->Var();
|
||||
IntExpr* violation;
|
||||
if (it->operator_ == ">") {
|
||||
violation = solver.MakeIsLessCstVar(absolute_difference,
|
||||
it->value_);
|
||||
} else if (it->operator_ == "=") {
|
||||
violation = solver.MakeIsDifferentCstVar(absolute_difference,
|
||||
it->value_);
|
||||
} else {
|
||||
LOG(FATAL) << "Invalid operator detected.";
|
||||
return -1;
|
||||
}
|
||||
IntExpr* weight = solver.MakeProd(violation, it->weight_cost_);
|
||||
cost.push_back(weight->Var());
|
||||
}
|
||||
objective_var = solver.MakeSum(cost)->Var();
|
||||
objective = solver.MakeMinimize(objective_var, 1);
|
||||
LOG(INFO) << "Finished with penalties.";
|
||||
monitors.push_back(objective);
|
||||
|
||||
// Collector
|
||||
SolutionCollector* const collector = solver.MakeLastSolutionCollector();
|
||||
collector->Add(variables);
|
||||
collector->Add(objective_var);
|
||||
LOG(INFO) << "Made collector.";
|
||||
monitors.push_back(collector);
|
||||
|
||||
// Decision Builder Configuration
|
||||
// Choose the next variable selection strategy
|
||||
Solver::IntVarStrategy variable_strategy;
|
||||
ChooseVariableStrategy(&variable_strategy);
|
||||
// Choose the value selection strategy
|
||||
LOG(INFO) << "Using Solver::ASSIGN_RANDOM_VALUE for value selection "
|
||||
"strategy.";
|
||||
DecisionBuilder* const db = solver.MakePhase(variables,
|
||||
variable_strategy,
|
||||
Solver::ASSIGN_RANDOM_VALUE);
|
||||
|
||||
// Create Additional Monitors
|
||||
CreateAdditionalMonitors(objective, &solver, &monitors);
|
||||
|
||||
// Solve
|
||||
LOG(INFO) << "Solving...";
|
||||
const int64 time1 = solver.wall_time();
|
||||
solver.Solve(db, monitors);
|
||||
const int64 time2 = solver.wall_time();
|
||||
|
||||
int result = collector->Value(collector->solution_count() - 1, objective_var);
|
||||
// Display Time //
|
||||
if (FLAGS_display_time) {
|
||||
PrintElapsedTime(time1, time2);
|
||||
}
|
||||
if (result != 0) {
|
||||
// Display Results //
|
||||
if (FLAGS_display_results) {
|
||||
PrintResultsSoft(collector, variables, objective_var,
|
||||
hard_variables, hard_constraints,
|
||||
soft_variables, soft_constraints,
|
||||
index_from_key, key_from_index);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
CHECK(!FLAGS_directory.empty()) << "Requires --directory=<directory name>";
|
||||
|
||||
// Parse!
|
||||
std::map<int, operations_research::FapVariable> variables;
|
||||
std::vector<operations_research::FapConstraint> constraints;
|
||||
string objective;
|
||||
std::vector<int> values;
|
||||
operations_research::ParseInstance(FLAGS_directory, &variables,
|
||||
&constraints, &objective, &values);
|
||||
// Print Instance!
|
||||
operations_research::FapModelPrinter model_printer(variables, constraints,
|
||||
objective, values);
|
||||
model_printer.PrintFapObjective();
|
||||
model_printer.PrintFapVariables();
|
||||
model_printer.PrintFapConstraints();
|
||||
model_printer.PrintFapValues();
|
||||
|
||||
// Create Model & Solve!
|
||||
if (!FLAGS_soft) {
|
||||
LOG(INFO) << "Running FapSolverHard on directory: " << FLAGS_directory;
|
||||
operations_research::FapSolverHard(variables, constraints,
|
||||
objective, values);
|
||||
} else {
|
||||
LOG(INFO) << "Running FapSolverSoft on directory: " << FLAGS_directory;
|
||||
int result = operations_research::FapSolverSoft(variables, constraints,
|
||||
objective, values);
|
||||
if (result == 0) {
|
||||
LOG(INFO) << "The instance is feasible. "
|
||||
"Now the FapSolverHard will be executed.";
|
||||
LOG(INFO) << "Running FapSolverHard on directory: " << FLAGS_directory;
|
||||
operations_research::FapSolverHard(variables, constraints,
|
||||
objective, values);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -27,6 +27,9 @@ DYNAMIC_FLATZINC_LIBS = \
|
||||
DYNAMIC_DIMACS_LIBS = \
|
||||
$(LIB_DIR)/$(LIBPREFIX)dimacs.$(DYNAMIC_LIB_SUFFIX)
|
||||
|
||||
DYNAMIC_FAP_LIBS = \
|
||||
$(LIB_DIR)/$(LIBPREFIX)fap.$(DYNAMIC_LIB_SUFFIX)
|
||||
|
||||
# Lib dependencies.
|
||||
DYNAMIC_BASE_DEPS = $(DYNAMIC_BASE_LIBS)
|
||||
|
||||
@@ -44,6 +47,8 @@ DYNAMIC_FLATZINC_DEPS = $(DYNAMIC_FLATZINC_LIBS) $(DYNAMIC_CP_LIBS) $(DYNAMIC_LP
|
||||
|
||||
DYNAMIC_DIMACS_DEPS = $(DYNAMIC_DIMACS_LIBS) $(DYNAMIC_GRAPH_LIBS) $(DYNAMIC_ALGORITHMS_LIBS) $(DYNAMIC_BASE_LIBS)
|
||||
|
||||
DYNAMIC_FAB_DEPS = $(DYNAMIC_FAP_LIBS) $(DYNAMIC_CP_LIBS) $(DYNAMIC_LP_LIBS) $(DYNAMIC_BASE_LIBS)
|
||||
|
||||
|
||||
# Create link commands.
|
||||
DYNAMIC_BASE_LNK = \
|
||||
@@ -84,6 +89,11 @@ DYNAMIC_DIMACS_LNK = \
|
||||
$(DYNAMIC_PRE_LIB)dimacs$(DYNAMIC_POST_LIB) \
|
||||
$(DYNAMIC_ALGORITHMS_LNK)
|
||||
|
||||
DYNAMIC_FAP_LNK = \
|
||||
$(DYNAMIC_PRE_LIB)fap$(DYNAMIC_POST_LIB) \
|
||||
$(DYNAMIC_CP_LNK)
|
||||
|
||||
|
||||
#### STATIC link and libs ####
|
||||
|
||||
# List libraries by module.
|
||||
@@ -248,6 +258,8 @@ graphlibs: $(DYNAMIC_GRAPH_DEPS) $(STATIC_GRAPH_DEPS)
|
||||
|
||||
dimacslibs: $(DYNAMIC_DIMACS_LIBS)
|
||||
|
||||
faplibs: $(DYNAMIC_FAP_LIBS)
|
||||
|
||||
# Constraint Solver Lib.
|
||||
|
||||
CONSTRAINT_SOLVER_LIB_OBJS = \
|
||||
@@ -690,6 +702,33 @@ $(OBJ_DIR)/print_dimacs_assignment.$O:$(EX_DIR)/cpp/print_dimacs_assignment.cc
|
||||
$(LIB_DIR)/$(LIBPREFIX)dimacs.$(DYNAMIC_LIB_SUFFIX): $(DIMACS_LIB_OBJS)
|
||||
$(DYNAMIC_LINK_CMD) $(DYNAMIC_LINK_PREFIX)$(LIB_DIR)$S$(LIBPREFIX)dimacs.$(DYNAMIC_LIB_SUFFIX) $(DIMACS_LIB_OBJS)
|
||||
|
||||
FLATZINC_LIB_OBJS=\
|
||||
$(OBJ_DIR)/flatzinc.$O\
|
||||
$(OBJ_DIR)/fz_search.$O\
|
||||
$(OBJ_DIR)/lexer.yy.$O\
|
||||
$(OBJ_DIR)/parser.tab.$O\
|
||||
$(OBJ_DIR)/parser.$O\
|
||||
$(OBJ_DIR)/registry.$O
|
||||
|
||||
# FAP challenge problem format library
|
||||
|
||||
FAP_LIB_OBJS=\
|
||||
$(OBJ_DIR)/fap_model_printer.$O\
|
||||
$(OBJ_DIR)/fap_parser.$O\
|
||||
$(OBJ_DIR)/fap_utilities.$O
|
||||
|
||||
$(OBJ_DIR)/fap_model_printer.$O:$(EX_DIR)/cpp/fap_model_printer.cc
|
||||
$(CCC) $(CFLAGS) -c $(EX_DIR)$Scpp/fap_model_printer.cc $(OBJ_OUT)fap_model_printer.$O
|
||||
$(OBJ_DIR)/fap_parser.$O:$(EX_DIR)/cpp/fap_parser.cc
|
||||
$(CCC) $(CFLAGS) -c $(EX_DIR)$Scpp/fap_parser.cc $(OBJ_OUT)fap_parser.$O
|
||||
$(OBJ_DIR)/fap_utilities.$O:$(EX_DIR)/cpp/fap_utilities.cc
|
||||
$(CCC) $(CFLAGS) -c $(EX_DIR)$Scpp/fap_utilities.cc $(OBJ_OUT)fap_utilities.$O
|
||||
|
||||
$(LIB_DIR)/$(LIBPREFIX)fap.$(DYNAMIC_LIB_SUFFIX): $(FAP_LIB_OBJS)
|
||||
$(DYNAMIC_LINK_CMD) $(DYNAMIC_LINK_PREFIX)$(LIB_DIR)$S$(LIBPREFIX)fap.$(DYNAMIC_LIB_SUFFIX) $(FAP_LIB_OBJS)
|
||||
|
||||
# Flatzinc Support
|
||||
|
||||
FLATZINC_LIB_OBJS=\
|
||||
$(OBJ_DIR)/flatzinc.$O\
|
||||
$(OBJ_DIR)/fz_search.$O\
|
||||
@@ -925,6 +964,14 @@ $(OBJ_DIR)/ls_api.$O:$(EX_DIR)/cpp/ls_api.cc $(SRC_DIR)/constraint_solver/constr
|
||||
$(BIN_DIR)/ls_api$E: $(DYNAMIC_CP_DEPS) $(OBJ_DIR)/ls_api.$O
|
||||
$(CCC) $(CFLAGS) $(OBJ_DIR)/ls_api.$O $(DYNAMIC_CP_LNK) $(DYNAMIC_LD_FLAGS) $(EXEOUT)ls_api$E
|
||||
|
||||
# Frequency Assignment Problem
|
||||
|
||||
$(OBJ_DIR)/frequency_assignment_problem.$O:$(EX_DIR)/cpp/frequency_assignment_problem.cc
|
||||
$(CCC) $(CFLAGS) -c $(EX_DIR)$Scpp/frequency_assignment_problem.cc $(OBJ_OUT)frequency_assignment_problem.$O
|
||||
|
||||
$(BIN_DIR)/frequency_assignment_problem$E: $(DYNAMIC_FAP_DEPS) $(OBJ_DIR)/frequency_assignment_problem.$O
|
||||
$(CCC) $(CFLAGS) $(OBJ_DIR)/frequency_assignment_problem.$O $(DYNAMIC_FAP_LNK) $(DYNAMIC_LD_FLAGS) $(EXEOUT)frequency_assignment_problem$E
|
||||
|
||||
# Linear Programming Examples
|
||||
|
||||
$(OBJ_DIR)/strawberry_fields_with_column_generation.$O: $(EX_DIR)/cpp/strawberry_fields_with_column_generation.cc $(SRC_DIR)/linear_solver/linear_solver.h
|
||||
|
||||
Reference in New Issue
Block a user