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...