27 #ifndef SRC_METHODS_MIP_BASED_METHOD_IPP_ 28 #define SRC_METHODS_MIP_BASED_METHOD_IPP_ 33 template<
class UserNodeLabel,
class UserEdgeLabel>
37 template<
class UserNodeLabel,
class UserEdgeLabel>
40 GEDMethod<UserNodeLabel, UserEdgeLabel>(ged_data),
44 time_limit_in_sec_{0},
46 tune_time_limit_in_sec_{0},
48 project_to_node_map_{
true} {}
51 template<
class UserNodeLabel,
class UserEdgeLabel>
58 template<
class UserNodeLabel,
class UserEdgeLabel>
64 GRBEnv env = GRBEnv();
65 env.set(GRB_IntParam_OutputFlag, 0);
66 env.set(GRB_IntParam_Threads, num_threads_);
67 if (time_limit_in_sec_ > 0) {
68 env.set(GRB_DoubleParam_TimeLimit, time_limit_in_sec_);
70 if (tune_ and (tune_time_limit_in_sec_ > 0)) {
71 env.set(GRB_DoubleParam_TuneTimeLimit, tune_time_limit_in_sec_);
75 GRBModel model = GRBModel(env);
77 if (model.get(GRB_IntAttr_IsMIP) and
relax_) {
78 throw Error(
"Relaxed model contains integral variables.");
88 int model_status{model.get(GRB_IntAttr_Status)};
89 if (model_status == GRB_INF_OR_UNBD) {
90 throw Error(
"The model is infeasible or unbounded.");
92 else if (model_status == GRB_UNBOUNDED) {
93 throw Error(
"The model is unbounded.");
95 else if (model_status == GRB_INFEASIBLE) {
97 model.write(
"infeasible_model.lp");
98 model.write(
"infeasible_model.ilp");
99 throw Error(
"The model for the graphs with IDs " + std::to_string(g.
id()) +
" and " + std::to_string(h.
id()) +
" is infeasible. For more information, investigate files 'infeasible_model.lp' and 'infeasible_model.ilp'.");
101 else if ((model_status == GRB_OPTIMAL) or (model_status == GRB_SUBOPTIMAL) or (model_status == GRB_TIME_LIMIT)) {
102 if (model_status == GRB_OPTIMAL) {
109 throw Error(
"Root constrained model does not map root to root.");
112 else if (project_to_node_map_) {
117 lsape_solver.
solve();
125 throw Error(
"Unexpected model status " + std::to_string(model_status) +
".");
128 catch (
const GRBException & e) {
129 throw Error(
"Optimization failed with GRBException. Error code: " + std::to_string(e.getErrorCode()) +
". Error message: " + e.getMessage() +
".");
133 template<
class UserNodeLabel,
class UserEdgeLabel>
137 bool is_valid_option{
false};
138 if (option ==
"relax") {
142 else if (arg !=
"FALSE") {
143 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option relax. Usage: options = \"[--relax TRUE|FALSE] [...]\"");
145 is_valid_option =
true;
147 else if (option ==
"project-to-node-map") {
148 if (arg ==
"FALSE") {
149 project_to_node_map_ =
false;
151 else if (arg !=
"TRUE") {
152 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option project-to-node-map. Usage: options = \"[--project-to-node-map TRUE|FALSE] [...]\"");
154 is_valid_option =
true;
156 else if (option ==
"lsape-model") {
160 else if (arg ==
"FLWC") {
163 else if (arg ==
"FLCC") {
166 else if (arg ==
"FBP") {
169 else if (arg ==
"SFBP") {
172 else if (arg ==
"FBP0") {
175 else if (arg !=
"ECBP") {
176 throw ged::Error(std::string(
"Invalid argument ") + arg +
" for option lsape-model. Usage: options = \"[--lsape-model ECBP|EBP|FLWC|FLCC|FBP|SFBP|FBP0] [...]\"");
178 is_valid_option =
true;
180 else if (option ==
"map-root-to-root") {
184 else if (arg !=
"FALSE") {
185 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option map-root-to-root. Usage: options = \"[--map-root-to-root TRUE|FALSE] [...]\"");
187 is_valid_option =
true;
189 else if (option ==
"tune") {
193 else if (arg !=
"FALSE") {
194 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option tune. Usage: options = \"[--tune TRUE|FALSE] [...]\"");
196 is_valid_option =
true;
198 else if (option ==
"threads") {
200 num_threads_ = std::stoul(arg);
203 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option threads. Usage: options = \"[--threads <convertible to int greater 0>]\"");
205 if (num_threads_ <= 0) {
206 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option threads. Usage: options = \"[--threads <convertible to int greater 0>]\"");
208 is_valid_option =
true;
210 else if (option ==
"time-limit") {
212 time_limit_in_sec_ = std::stod(arg);
215 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option time-limit. Usage: options = \"[--time-limit <convertible to double>] [...]");
217 is_valid_option =
true;
219 else if (option ==
"tune-time-limit") {
221 tune_time_limit_in_sec_ = std::stod(arg);
224 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option tune-time-limit. Usage: options = \"[--tune-time-limit <convertible to double>] [...]");
226 is_valid_option =
true;
229 return is_valid_option;
232 template<
class UserNodeLabel,
class UserEdgeLabel>
237 return "[--relax <arg>] [--map-root-to-root <arg>] [--tune <arg>] [--threads <arg>] [--time-limit <arg>] [--tune-time-limit <arg>] [--lsape-model <arg>]";
239 return mip_valid_options_string_() +
" [--relax <arg>] [--project-to-node-map <arg>] [--map-root-to-root <arg>] [--tune <arg>] [--threads <arg>] [--time-limit <arg>] [--tune-time-limit <arg>] [--lsape-model <arg>]";
242 template<
class UserNodeLabel,
class UserEdgeLabel>
247 project_to_node_map_ =
true;
251 time_limit_in_sec_ = 0;
252 tune_time_limit_in_sec_ = 0;
259 template<
class UserNodeLabel,
class UserEdgeLabel>
264 template<
class UserNodeLabel,
class UserEdgeLabel>
269 template<
class UserNodeLabel,
class UserEdgeLabel>
276 template<
class UserNodeLabel,
class UserEdgeLabel>
281 template<
class UserNodeLabel,
class UserEdgeLabel>
288 template<
class UserNodeLabel,
class UserEdgeLabel>
295 template<
class UserNodeLabel,
class UserEdgeLabel>
virtual void mip_init_()
Initializes the method.
virtual void ged_init_() final
Initializes the method.
void set_model(const Model &model)
Makes the solver use a specific model for optimal solving.
virtual bool mip_parse_option_(const std::string &option, const std::string &arg)
Parses one option that is not among the ones shared by all derived classes of ged::MIPBasedMethod.
virtual void mip_set_default_options_()
Sets all options that are not among the ones shared by all derived classes of ged::MIPBasedMethod to ...
bool relax_
If true, the model populated by mip_populate_model_() must be continuous.
Reduction to compact LSAP instance for quasimetric costs.
Reduction to compact LSAP instance for quasimetric costs.
virtual std::string mip_valid_options_string_() const
Returns string of all valid options that are not among the ones shared by all derived classes of ged:...
std::size_t num_nodes() const
Returns the number of nodes.
Contains the standardized input data along with basic functionality.
This class solves LSAPE instances by calling the library lsape available at https://bougleux.users.greyc.fr/lsape/.
Reduction to compact LSAP instance without cost constraints.
const GEDData< UserNodeLabel, UserEdgeLabel > & ged_data_
The data on which the method is run.
void set_lower_bound(double lower_bound)
Sets the lower bound for GED.
virtual void mip_populate_model_(const GEDGraph &g, const GEDGraph &h, GRBModel &model)
Runs the local search from an initial node map.
virtual std::string ged_valid_options_string_() const final
Returns string of all valid options.
MIPBasedMethod(const GEDData< UserNodeLabel, UserEdgeLabel > &ged_data)
Constructor.
void solve(int num_solutions=1)
Solves the LSAPE problem instance.
A wrapper structure for the result of calls to ged::GEDMethod::run_as_util() and ged::GEDMethod::ged_...
virtual void ged_set_default_options_() final
Sets all options to default values.
Abstract class for the (suboptimal) computation of the graph edit distance.
Reduction to extended LSAP instance without cost constraints.
std::size_t add_node_map(std::size_t num_nodes_g, std::size_t num_nodes_h)
Adds an empty node map to the result.
virtual ~MIPBasedMethod()=0
Pure virtual destructor.
Adaption of Hungarian Algorithm to LSAPE.
virtual void ged_run_(const GEDGraph &g, const GEDGraph &h, Result &result) final
Runs the method with options specified by set_options().
The normalized input graphs used by GEDLIB. All labels are integers.
Reduction to compact LSAP instance for quasimetric costs.
Global namespace for GEDLIB.
virtual void mip_model_to_node_map_(const GEDGraph &g, const GEDGraph &h, GRBModel &model, NodeMap &node_map)
Given a, possibly sub-optimally, solved unrelaxed model, this method constructs a node map and sets i...
GEDGraph::NodeID image(GEDGraph::NodeID node) const
Returns image of a node.
NodeMap & node_map(std::size_t index_node_map)
Provides access to a node map.
void construct_node_map_from_solver(const Solver &solver, NodeMap &node_map, std::size_t solution_id=0)
Constructs a node map from a solution to LSAPE or LSAPE stored in a ged::LSAPESolver or a ged::LSAPSo...
Reduction to compact LSAP instance for quasimetric costs.
virtual bool mip_model_to_lsape_projection_problem_(const GEDGraph &g, const GEDGraph &h, GRBModel &model, DMatrix &lsape_instance)
Given a, possibly sub-optimally, solved model, this method constructs an LSAPE instance for projectin...
virtual bool ged_parse_option_(const std::string &option, const std::string &arg) final
Parses one option.
GraphID id() const
Returns the ID of the graph.
bool map_root_to_root_
If true, the model populated by mip_populate_model_() must enforce that the nodes with ID 0 are mappe...