27 #ifndef SRC_METHODS_LSAPE_BASED_METHOD_IPP_ 28 #define SRC_METHODS_LSAPE_BASED_METHOD_IPP_ 33 template<
class UserNodeLabel,
class UserEdgeLabel>
37 template<
class UserNodeLabel,
class UserEdgeLabel>
40 GEDMethod<UserNodeLabel, UserEdgeLabel>(ged_data),
46 centrality_method_{NONE},
47 centrality_weight_{0.7},
49 max_num_solutions_{1} {}
53 template<
class UserNodeLabel,
class UserEdgeLabel>
68 template<
class UserNodeLabel,
class UserEdgeLabel>
84 lsape_solver.
solve(max_num_solutions_);
91 for (std::size_t solution_id{0}; solution_id < lsape_solver.
num_solutions(); solution_id++) {
98 if (centrality_weight_ > 0.0 and centrality_method_ != NONE) {
99 add_centralities_(g, h, lsape_instance);
100 lsape_solver.
solve(max_num_solutions_);
101 for (std::size_t solution_id{0}; solution_id < lsape_solver.
num_solutions(); solution_id++) {
113 template<
class UserNodeLabel,
class UserEdgeLabel>
124 template<
class UserNodeLabel,
class UserEdgeLabel>
132 template<
class UserNodeLabel,
class UserEdgeLabel>
136 bool is_valid_option{
false};
137 if (option ==
"threads") {
142 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option threads. Usage: options = \"[--threads <convertible to int greater 0>] [...]");
145 throw Error(std::string(
"Invalid argument \"") + arg +
"\" for option threads. Usage: options = \"[--threads <convertible to int greater 0>] [...]");
147 is_valid_option =
true;
149 else if (option ==
"lsape-model") {
153 else if (arg ==
"FLWC") {
156 else if (arg ==
"FLCC") {
159 else if (arg ==
"FBP") {
162 else if (arg ==
"SFBP") {
165 else if (arg ==
"FBP0") {
168 else if (arg ==
"ECBP") {
172 throw ged::Error(std::string(
"Invalid argument ") + arg +
" for option lsape-model. Usage: options = \"[--lsape-model ECBP|EBP|FLWC|FLCC|FBP|SFBP|FBP0] [...]\"");
174 is_valid_option =
true;
176 else if (option ==
"greedy-method") {
177 if (arg ==
"BASIC") {
180 else if (arg ==
"REFINED") {
183 else if (arg ==
"LOSS") {
186 else if (arg ==
"BASIC_SORT") {
189 else if (arg ==
"INT_BASIC_SORT") {
193 throw ged::Error(std::string(
"Invalid argument ") + arg +
" for option greedy-method. Usage: options = \"[--greedy-method BASIC|REFINED|LOSS|BASIC_SORT|INT_BASIC_SORT] [...]\"");
195 is_valid_option =
true;
197 else if (option ==
"optimal") {
201 else if (arg ==
"FALSE") {
205 throw ged::Error(std::string(
"Invalid argument ") + arg +
" for option optimal. Usage: options = \"[--optimal TRUE|FALSE] [...]\"");
207 is_valid_option =
true;
209 else if (option ==
"centrality-method") {
211 centrality_method_ = NONE;
213 else if (arg ==
"DEGREE") {
214 centrality_method_ = DEGREE;
216 else if (arg ==
"EIGENVECTOR") {
217 centrality_method_ = EIGENVECTOR;
219 else if (arg ==
"PAGERANK") {
220 centrality_method_ = PAGERANK;
223 throw ged::Error(std::string(
"Invalid argument ") + arg +
" for option centrality-method. Usage: options = \"[--centrality-method NONE|DEGREE|EIGENVECTOR|PAGERANK] [...]\"");
225 is_valid_option =
true;
227 else if (option ==
"centrality-weight") {
229 centrality_weight_ = std::stod(arg);
232 throw Error(std::string(
"Invalid argument ") + arg +
" for option centrality-weight. Usage: options = \"[--centrality-weight <convertible to double between 0 and 1>] [...]");
234 if (centrality_weight_ < 0.0 or centrality_weight_ > 1.0) {
235 throw Error(std::string(
"Invalid argument ") + arg +
" for option centrality-weight. Usage: options = \"[--centrality-weight <convertible to double between 0 and 1>] [...]");
237 is_valid_option =
true;
239 else if (option ==
"max-num-solutions") {
241 max_num_solutions_ = -1;
245 max_num_solutions_ = std::stoi(arg);
248 throw Error(std::string(
"Invalid argument ") + arg +
" for option max-num-solutions. Usage: options = \"[--max-num-solutions ALL|<convertible to int greater 0>] [...]");
250 if (max_num_solutions_ < 1) {
251 throw Error(std::string(
"Invalid argument ") + arg +
" for option max-num-solutions. Usage: options = \"[--max-num-solutions ALL|<convertible to int greater 0>] [...]");
254 is_valid_option =
true;
257 return is_valid_option;
260 template<
class UserNodeLabel,
class UserEdgeLabel>
265 return "[--lsape-model <arg>] [--threads <arg>] [--greedy-method <arg>] [--optimal <arg>] [--centrality-method <arg>] [--centrality-weight <arg>] [--max-num-solutions <arg>]";
267 return lsape_valid_options_string_() +
" [--lsape-model <arg>] [--greedy-method <arg>] [--optimal <arg>] [--centrality-method <arg>] [--centrality-weight <arg>] [--max-num-solutions <arg>]";
270 template<
class UserNodeLabel,
class UserEdgeLabel>
277 centrality_method_ = NONE;
278 centrality_weight_ = 0.7;
279 max_num_solutions_ = 1;
285 template<
class UserNodeLabel,
class UserEdgeLabel>
289 if (centrality_method_ != NONE) {
290 init_centralities_(graph);
295 template<
class UserNodeLabel,
class UserEdgeLabel>
299 centralities_[graph.
id()] = std::vector<double>(graph.
num_nodes(), 0.0);
300 if (centrality_method_ == DEGREE) {
301 for (std::size_t row{0}; row < graph.
num_nodes(); row++) {
302 centralities_.at(graph.
id())[row] = static_cast<double>(graph.
degree(row));
309 std::vector<double> eigenvector;
310 compute_eigenvector_with_largest_eigenvalue_(adj_matrix, eigenvector, eigenvalue);
311 for (std::size_t row{0}; row < adj_matrix.num_rows(); row++) {
312 for (std::size_t col{0}; col < adj_matrix.num_cols(); col++) {
313 double summand{adj_matrix(row, col) * eigenvector.at(col)};
314 if (centrality_method_ == PAGERANK) {
315 summand /= std::max(1.0, static_cast<double>(graph.
degree(col)));
318 centralities_.at(graph.
id())[row] += summand;
320 if (centrality_method_ == PAGERANK) {
321 centralities_.at(graph.
id())[row] *= 0.85;
324 centralities_.at(graph.
id())[row] /= eigenvalue;
329 template<
class UserNodeLabel,
class UserEdgeLabel>
334 master_problem *= (1 - centrality_weight_);
337 #pragma omp parallel for if(this->num_threads_ > 1) 339 for (std::size_t row = 0; row < master_problem.
num_rows(); row++) {
340 for (std::size_t col = 0; col < master_problem.
num_cols(); col++) {
342 master_problem(row, col) += centrality_weight_ * std::fabs(static_cast<double>(centralities_.at(g.
id()).at(row) - centralities_.at(h.
id()).at(col)));
345 master_problem(row, h.
num_nodes()) += centrality_weight_ * centralities_.at(g.
id()).at(row);
348 master_problem(g.
num_nodes(), col) += centrality_weight_ * centralities_.at(h.
id()).at(col);
354 template<
class UserNodeLabel,
class UserEdgeLabel>
361 Eigen::EigenSolver<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> eigen_solver(symmetric_matrix.
matrix());
362 Eigen::VectorXd eigen_values = eigen_solver.eigenvalues().real();
364 eigenvalue = eigen_values.maxCoeff(&pos);
365 Eigen::VectorXd eigen_vector = eigen_solver.eigenvectors().col(pos).real();
366 eigenvector.resize(eigen_vector.rows());
367 for (std::size_t row{0}; row < static_cast<std::size_t>(eigen_vector.rows()); row++) {
368 eigenvector[row] = eigen_vector(row);
373 template<
class UserNodeLabel,
class UserEdgeLabel>
378 template<
class UserNodeLabel,
class UserEdgeLabel>
385 template<
class UserNodeLabel,
class UserEdgeLabel>
392 template<
class UserNodeLabel,
class UserEdgeLabel>
397 template<
class UserNodeLabel,
class UserEdgeLabel>
402 template<
class UserNodeLabel,
class UserEdgeLabel>
407 template<
class UserNodeLabel,
class UserEdgeLabel>
412 template<
class UserNodeLabel,
class UserEdgeLabel>
417 template<
class UserNodeLabel,
class UserEdgeLabel>
void set_model(const Model &model)
Makes the solver use a specific model for optimal solving.
void populate_instance_and_run_as_util(const GEDGraph &g, const GEDGraph &h, Result &result, DMatrix &lsape_instance)
Runs the method with options specified by set_options() and provides access to constructed LSAPE inst...
virtual bool lsape_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::LSAPEBasedMethod.
Reduction to compact LSAP instance for quasimetric costs.
virtual void lsape_set_default_options_()
Sets all options that are not among the ones shared by all derived classes of ged::LSAPEBasedMethod t...
Reduction to compact LSAP instance for quasimetric costs.
std::size_t num_nodes() const
Returns the number of nodes.
Contains the standardized input data along with basic functionality.
virtual ~LSAPEBasedMethod()=0
Pure virtual destructor.
std::size_t num_threads_
The number of threads to be used.
This class solves LSAPE instances by calling the library lsape available at https://bougleux.users.greyc.fr/lsape/.
virtual std::string lsape_valid_options_string_() const
Returns string of all valid options that are not among the ones shared by all derived classes of ged:...
Reduction to compact LSAP instance without cost constraints.
void resize(std::size_t num_rows, std::size_t num_cols)
Resizes the matrix.
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.
void solve(int num_solutions=1)
Solves the LSAPE problem instance.
std::size_t degree(NodeID node) const
Returns node degree.
virtual double lsape_lower_bound_scaling_factor_(const GEDGraph &g, const GEDGraph &h)
Returns scaling factor for lower bound.
A wrapper structure for the result of calls to ged::GEDMethod::run_as_util() and ged::GEDMethod::ged_...
Abstract class for the (suboptimal) computation of the graph edit distance.
void sort_node_maps_and_set_upper_bound(std::size_t num_node_maps=std::numeric_limits< std::size_t >::max())
Sorts the vector of node maps w.r.t non-decreasing induced cost and possibly discards expensive node ...
Reduction to extended LSAP instance without cost constraints.
virtual void ged_set_default_options_() final
Sets all options to default values.
virtual void lsape_default_post_graph_init_()
Default initializes the method at runtime after initializing the global variables for the graphs...
std::size_t num_cols() const
Returns the number of columns.
bool solve_optimally_
Flag that equals true if an optimal LSAPE solver is used and false if a greedy method is employed...
virtual void ged_init_() final
Initializes the method.
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.
Adaption of Hungarian Algorithm to LSAPE.
bool compute_lower_bound_
Flag that should be set to true if and only if the method computes a lower bound. ...
LSAPESolver::Model lsape_model_
Specifies model for optimal LSAPE solver.
See https://doi.org/10.1007/978-3-319-18224-7_1.
Eigen::Matrix< ScalarT, Eigen::Dynamic, Eigen::Dynamic > & matrix()
Returns reference to the internal Eigen matrix.
Abstract class for methods that use lossy transformations to LSAPE for approximating the graph edit d...
double minimal_cost() const
Returns the cost of the computed solutions.
void populate_instance(const GEDGraph &g, const GEDGraph &h, DMatrix &lsape_instance)
Populates the LSAPE instance.
bool initialized_
A flag that equals true if init() has been called and false otherwise.
The normalized input graphs used by GEDLIB. All labels are integers.
virtual void lsape_init_graph_(const GEDGraph &graph)
Initializes global variables for one graph.
Reduction to compact LSAP instance for quasimetric costs.
Global namespace for GEDLIB.
virtual void lsape_populate_instance_(const GEDGraph &g, const GEDGraph &h, DMatrix &lsape_instance)
Populates the LSAPE instance.
virtual void lsape_pre_graph_init_(bool called_at_runtime)
Initializes the method at runtime or during initialization before initializing the global variables f...
NodeMap & node_map(std::size_t index_node_map)
Provides access to a node map.
See https://doi.org/10.1007/978-3-319-18224-7_1.
See https://doi.org/10.1007/978-3-319-18224-7_1.
virtual std::string ged_valid_options_string_() const final
Returns string of all valid options.
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...
virtual void ged_run_(const GEDGraph &g, const GEDGraph &h, Result &result) final
Runs the method with options specified by set_options().
LSAPESolver::GreedyMethod greedy_method_
Specifies method for greedy LSAPE solver.
Reduction to compact LSAP instance for quasimetric costs.
std::size_t num_solutions() const
Returns the number of solutions.
void init_adj_matrix(const GEDGraph &graph, DMatrix &adj_matrix)
Initalizes the adjacency matrix of a graph.
virtual void lsape_init_()
Initializes the method after initializing the global variables for the graphs.
See https://doi.org/10.1007/978-3-319-18224-7_1.
void set_greedy_method(const GreedyMethod &greedy_method)
Makes the solver use a greedy method.
GraphID id() const
Returns the ID of the graph.
LSAPEBasedMethod(const GEDData< UserNodeLabel, UserEdgeLabel > &ged_data)
Constructor.
virtual bool ged_parse_option_(const std::string &option, const std::string &arg) final
Parses one option.
std::size_t num_rows() const
Returns the number of rows.
See https://doi.org/10.1007/978-3-319-18224-7_1.