27 #ifndef SRC_METHODS_RING_IPP_    28 #define SRC_METHODS_RING_IPP_    33 template<
class UserNodeLabel, 
class UserEdgeLabel>
    34 Ring<UserNodeLabel, UserEdgeLabel>::
    37 template<
class UserNodeLabel, 
class UserEdgeLabel>
    38 Ring<UserNodeLabel, UserEdgeLabel>::
    39 Ring(
const GEDData<UserNodeLabel, UserEdgeLabel> & ged_data) :
    40 LSAPEBasedMethod<UserNodeLabel, UserEdgeLabel>(ged_data),
    42 led_method_{LSAPE_OPTIMAL},
    43 sort_method_{COUNTING},
    56 template<
class UserNodeLabel, 
class UserEdgeLabel>
    63 template<
class UserNodeLabel, 
class UserEdgeLabel>
    67     led_method_ = LSAPE_OPTIMAL;
    68     sort_method_ = COUNTING;
    74 template<
class UserNodeLabel, 
class UserEdgeLabel>
    78     if (load_config_file_()) {
    79         read_params_from_file_();
    83 template<
class UserNodeLabel, 
class UserEdgeLabel>
    87     if (not load_config_file_())  {
    89         for (std::size_t level{0}; level < num_layers_; level++) {
    90             lambda_.push_back(1.0 / static_cast<double>(num_layers_));
    92         for (std::size_t i{0}; i < 3; i++) {
    93             alpha_.push_back(1.0 / 3.0);
    98 template<
class UserNodeLabel, 
class UserEdgeLabel>
   104     if (load_config_file_()) {
   112     std::vector<NOMAD::Point> x0s;
   116     std::vector<NOMAD::Point> solutions;
   117     std::vector<NOMAD::Double> objectives;
   119     std::cout << 
"\rNOMAD: " << progress_bar << std::flush;
   124 #pragma omp parallel for if(this->num_threads_ > 1)   126     for (std::size_t i = 0; i < num_x0s_; i++) {
   127         NOMAD::Display out (std::cout);
   128         out.precision (NOMAD::DISPLAY_PRECISION_STD);
   131             NOMAD::begin(0, 
nullptr);
   132             NOMAD::Parameters p(out);
   133             std::vector<NOMAD::bb_output_type> bbot(3);
   134             bbot[0] = NOMAD::OBJ; 
   137             p.set_BB_OUTPUT_TYPE(bbot);
   138             p.set_DISPLAY_STATS (
"bbe ( sol ) obj");
   139             p.set_DIMENSION(3 + num_layers_);
   140             p.set_LOWER_BOUND(NOMAD::Point(3 + num_layers_, 0.0));
   141             p.set_UPPER_BOUND(NOMAD::Point(3 + num_layers_, 1.0));
   142             p.set_MAX_BB_EVAL(num_evals_);
   143             p.set_DISPLAY_DEGREE(
"NO_DISPLAY");
   148             Evaluator_ ev(p, 
this);
   149             NOMAD::Mads mads(p, &ev);
   157                 solutions.push_back(*mads.get_best_feasible());
   158                 objectives.push_back(mads.get_best_feasible()->get_f());
   161         catch (NOMAD::Exception & e) {
   162             throw Error(std::string(
"NOMAD error: ") + e.what());
   164         NOMAD::Slave::stop_slaves(out);
   171             std::cout << 
"\rNOMAD: " << progress_bar << std::flush;
   176     NOMAD::Double best_objective(objectives.at(0));
   177     std::size_t pos_best_solution{0};
   178     for (std::size_t pos{1}; pos < objectives.size(); pos++) {
   179         if (objectives.at(pos) < best_objective) {
   180             best_objective = objectives.at(pos);
   181             pos_best_solution = pos;
   184     NOMAD::Point best_solution(solutions.at(pos_best_solution));
   187     nomad_point_to_params_(best_solution, alpha_, lambda_);
   190     if (outfile_ != 
"") {
   191         write_params_to_file_();
   195 template<
class UserNodeLabel, 
class UserEdgeLabel>
   199     return "[--led-method <arg>] [--sort-method <arg>] [--load <arg>] [--save <arg>] [--init-evaluations <arg>] [--init-initial-solutions <arg>] [--init-mu <arg>]";
   202 template<
class UserNodeLabel, 
class UserEdgeLabel>
   206     if (option == 
"led-method") {
   207         if (arg == 
"LSAPE_OPTIMAL") {
   208             led_method_ = LSAPE_OPTIMAL;
   210         else if (arg  == 
"LSAPE_GREEDY") {
   211             led_method_ = LSAPE_GREEDY;
   213         else if (arg == 
"GAMMA") {
   217             throw Error(std::string(
"Invalid argument \"") + arg  + 
"\" for option led-method. Usage: options = \"[--led-method LSAPE_OPTIMAL|LSAPE_GREEDY|GAMMA] [...]\"");
   221     else if (option == 
"sort-method") {
   222         if (arg == 
"COUNTING") {
   223             sort_method_ = COUNTING;
   225         else if (arg  == 
"STD") {
   229             throw Error(std::string(
"Invalid argument \"") + arg  + 
"\" for option sort-method. Usage: options = \"[--sort-method COUNTING|STD] [...]\"");
   233     else if (option == 
"load") {
   237     else if (option == 
"save") {
   241     else if (option == 
"init-evaluations") {
   243             num_evals_ = std::stoi(arg);
   246             throw Error(std::string(
"Invalid argument \"") + arg  + 
"\" for option init-evaluations. Usage: options = \"[--init-evaluations <convertible to int greater 0>] [...]");
   248         if (num_evals_ <= 0) {
   249             throw Error(std::string(
"Invalid argument \"") + arg  + 
"\" for option init-evaluations. Usage: options = \"[--init-evaluations <convertible to int greater 0>] [...]");
   253     else if (option == 
"init-initial-solutions") {
   255             num_x0s_ = std::stoi(arg);
   258             throw Error(std::string(
"Invalid argument \"") + arg  + 
"\" for option init-initial-solutions. Usage: options = \"[--init-initial-solutions <convertible to int greater 0>] [...]");
   261             throw Error(std::string(
"Invalid argument \"") + arg  + 
"\" for option init-initial-solutions. Usage: options = \"[--init-initial-solutions <convertible to int greater 0>] [...]");
   265     else if (option == 
"init-mu") {
   267             mu_ = std::stod(arg);
   270             throw Error(std::string(
"Invalid argument \"") + arg  + 
"\" for option init-mu. Usage: options = \"[--init-mu <convertible to double between 0 and 1>] [...]");
   272         if (mu_ < 0 or mu_ > 1) {
   273             throw Error(std::string(
"Invalid argument \"") + arg  + 
"\" for option init-mu.  Usage: options = \"[--init-mu <convertible to double between 0 and 1>] [...]");
   280 template<
class UserNodeLabel, 
class UserEdgeLabel>
   284     const NodeRingMap_ & rings_g = rings_.at(g.
id());
   285     const NodeRingMap_ & rings_h = rings_.at(h.
id());
   288 #pragma omp parallel for if(this->num_threads_ > 1)   290     for (std::size_t row_in_master = 0; row_in_master < master_problem.
num_rows(); row_in_master++) {
   291         for (std::size_t col_in_master = 0; col_in_master < master_problem.
num_cols(); col_in_master++) {
   292             master_problem(row_in_master, col_in_master) = compute_ring_distance_(g, h, rings_g, rings_h, alpha_, lambda_, row_in_master, col_in_master);
   298 template<
class UserNodeLabel, 
class UserEdgeLabel>
   301 Layer_(std::size_t level) :
   305 outer_edge_labels() {}
   308 template<
class UserNodeLabel, 
class UserEdgeLabel>
   315 template<
class UserNodeLabel, 
class UserEdgeLabel>
   319 NOMAD::Evaluator(param),
   322 template<
class UserNodeLabel, 
class UserEdgeLabel>
   327 template<
class UserNodeLabel, 
class UserEdgeLabel>
   331 eval_x(NOMAD::Eval_Point & x, 
const NOMAD::Double & h_max, 
bool & count_eval)
 const {
   338 template<
class UserNodeLabel, 
class UserEdgeLabel>
   341 nomad_point_to_params_(
const NOMAD::Point & x, std::vector<double> & alpha, std::vector<double> & lambda)
 const {
   343     for (std::size_t i{0} ; i < 3; i++) {
   344         alpha.push_back(x.get_coord(i).value());
   346     std::size_t max_non_zero_level{0};
   347     for (std::size_t i{0} ; i < num_layers_; i++) {
   348         if (x.get_coord(i + 3).value() > 0) {
   349             max_non_zero_level = i;
   353     for (std::size_t i{0} ; i <= max_non_zero_level; i++) {
   354         lambda.push_back(x.get_coord(i + 3).value());
   358 template<
class UserNodeLabel, 
class UserEdgeLabel>
   362     double sum_alpha {0.0};
   363     for (
auto alpha = alpha_.begin(); alpha != alpha_.end(); alpha++) {
   366     for (
auto alpha = alpha_.begin(); alpha != alpha_.end(); alpha++) {
   369     double sum_lambda {0.0};
   370     for (
auto lambda = lambda_.begin(); lambda != lambda_.end(); lambda++) {
   371         sum_lambda += *lambda;
   373     for (
auto lambda = lambda_.begin(); lambda != lambda_.end(); lambda++) {
   374         *lambda /= sum_lambda;
   378 template<
class UserNodeLabel, 
class UserEdgeLabel>
   381 eval_x_(NOMAD::Eval_Point & x)
 const {
   382     std::vector<double> alpha;
   383     std::vector<double> lambda;
   384     nomad_point_to_params_(x, alpha, lambda);
   389         if (this->
ged_data_.is_shuffled_graph_copy(g->id())) {
   393             if (this->
ged_data_.is_shuffled_graph_copy(h->id())) {
   396             NodeMap matching(g->num_nodes(), h->num_nodes());
   397             DMatrix lsape_instance(g->num_nodes() + 1, h->num_nodes() + 1, 0.0);
   399             if (this->
ged_data_.shuffled_graph_copies_available() and (g->id() == h->id())) {
   401                 populate_instance_with_params_(*g, this->
ged_data_.graph(id_shuffled_graph_copy), alpha, lambda, lsape_instance);
   402                 lsape_solver.
solve();
   404                 this->
ged_data_.compute_induced_cost(*g, this->
ged_data_.graph(id_shuffled_graph_copy), matching);
   407                 populate_instance_with_params_(*g, *h, alpha, lambda, lsape_instance);
   408                 lsape_solver.
solve();
   410                 this->
ged_data_.compute_induced_cost(*g, *h, matching);
   412             val += matching.induced_cost();
   415     val /= 
static_cast<double>(this->
ged_data_.num_graphs() * this->
ged_data_.num_graphs());
   416     std::size_t supp_lambda{0};
   417     double sum_lambda{0.0};
   418     for (
auto lambda_l = lambda.begin(); lambda_l != lambda.end(); lambda_l++) {
   421             sum_lambda += *lambda_l;
   424     if (num_layers_ > 1 and mu_ < 1) {
   425         val *=  (mu_ + ((1 - mu_) * static_cast<double>(supp_lambda - 1)  / 
static_cast<double>(num_layers_ - 1)));
   427     double sum_alpha{0.0};
   428     for (
auto alpha_i = alpha.begin(); alpha_i != alpha.end(); alpha_i++) {
   429         sum_alpha += *alpha_i;
   431     double epsilon{0.00001};
   432     x.set_bb_output(0, val);
   433     x.set_bb_output(1, epsilon - sum_alpha);
   434     x.set_bb_output(2, epsilon - sum_lambda);
   437 template<
class UserNodeLabel, 
class UserEdgeLabel>
   441     rings_[graph.
id()] = NodeRingMap_();
   442     for (
auto node = graph.
nodes().first; node != graph.
nodes().second; node++) {
   443         build_ring_(graph, *node, rings_.at(graph.
id()));
   447 template<
class UserNodeLabel, 
class UserEdgeLabel>
   451     std::map<GEDGraph::NodeID, int> distance_to_root;
   452     for (
auto node = graph.
nodes().first; node != graph.
nodes().second; node++) {
   453         distance_to_root[*node] = -1;
   455     distance_to_root[root] = 0;
   457     std::map<GEDGraph::EdgeID, bool> discovered_edge;
   458     for (
auto edge = graph.
edges().first; edge != graph.
edges().second; edge++) {
   459         discovered_edge[*edge] = 
false;
   462     Layer_ current_layer(0);
   463     std::queue<GEDGraph::NodeID> queue;
   465     while (not queue.empty()) {
   468         if (static_cast<int>(current_layer.level) < distance_to_root.at(current_node)) {
   469             if (sort_method_ == COUNTING) {
   471                 util::counting_sort(current_layer.inner_edge_labels.begin(), current_layer.inner_edge_labels.end());
   472                 util::counting_sort(current_layer.outer_edge_labels.begin(), current_layer.outer_edge_labels.end());
   475                 std::sort(current_layer.node_labels.begin(), current_layer.node_labels.end());
   476                 std::sort(current_layer.inner_edge_labels.begin(), current_layer.inner_edge_labels.end());
   477                 std::sort(current_layer.outer_edge_labels.begin(), current_layer.outer_edge_labels.end());
   479             rings[root].layers.push_back(current_layer);
   480             current_layer = Layer_(current_layer.level + 1);
   482         current_layer.node_labels.push_back(graph.
get_node_label(current_node));
   485             if (distance_to_root.at(next_node) == -1) {
   486                 distance_to_root[next_node] = current_layer.level + 1;
   487                 if (current_layer.level < num_layers_) {
   488                     queue.push(next_node);
   491             if (not discovered_edge.at(*edge)) {
   492                 discovered_edge[*edge] = 
true;
   493                 if (distance_to_root.at(current_node) == distance_to_root.at(next_node)) {
   494                     current_layer.inner_edge_labels.push_back(graph.
get_edge_label(*edge));
   496                 else if (distance_to_root.at(current_node) < distance_to_root.at(next_node)) {
   497                     current_layer.outer_edge_labels.push_back(graph.
get_edge_label(*edge));
   500                     throw Error(std::string(
"Error when building ring rooted at ") + std::to_string(root) +
   501                             " for graph " + std::to_string(graph.
id()) + 
": dist(" +
   502                             std::to_string(current_node) +
") = " + std::to_string(distance_to_root.at(current_node)) +
   503                             " > dist(" + std::to_string(next_node) +
") = " + std::to_string(distance_to_root.at(next_node)));
   508     if (led_method_ == GAMMA) {
   509         if (sort_method_ == COUNTING) {
   511             util::counting_sort(current_layer.inner_edge_labels.begin(), current_layer.inner_edge_labels.end());
   512             util::counting_sort(current_layer.outer_edge_labels.begin(), current_layer.outer_edge_labels.end());
   515             std::sort(current_layer.node_labels.begin(), current_layer.node_labels.end());
   516             std::sort(current_layer.inner_edge_labels.begin(), current_layer.inner_edge_labels.end());
   517             std::sort(current_layer.outer_edge_labels.begin(), current_layer.outer_edge_labels.end());
   520     rings[root].layers.push_back(current_layer);
   523 template<
class UserNodeLabel, 
class UserEdgeLabel>
   527     std::size_t max_num_layers{0};
   528     for (
auto graph_rings_pair = rings_.begin(); graph_rings_pair != rings_.end(); graph_rings_pair++) {
   529         for (
auto ring = graph_rings_pair->second.begin(); ring != graph_rings_pair->second.end(); ring++) {
   530             max_num_layers = std::max(max_num_layers, ring->second.layers.size());
   533     num_layers_ = std::min(num_layers_, max_num_layers);
   536 template<
class UserNodeLabel, 
class UserEdgeLabel>
   540     return (infile_ != 
"");
   543 template<
class UserNodeLabel, 
class UserEdgeLabel>
   546 init_x0s_(std::vector<NOMAD::Point> & x0s)
 const {
   547     std::random_device rd;
   548     std::mt19937 rng(rd());
   549     std::uniform_real_distribution<double> uni(0.0, 1.0);
   551     NOMAD::Point x0(3 + num_layers_, 0.0);
   552     bool found_new_x0{
true};
   553     std::vector<double> alpha_gen;
   554     std::vector<double> lambda_gen;
   555     while(x0s.size() < num_x0s_) {
   557         alpha_gen.push_back(0.0);
   558         alpha_gen.push_back(1.0);
   559         for (std::size_t i{0}; i < 2; i++) {
   560             alpha_gen.push_back(uni(rng));
   562         std::sort(alpha_gen.begin(), alpha_gen.end());
   563         for (std::size_t i{0}; i < 3; i++) {
   564             x0[i] = alpha_gen.at(i+1) - alpha_gen.at(i);
   567         lambda_gen.push_back(0.0);
   568         lambda_gen.push_back(1.0);
   569         for (std::size_t level{0}; level < num_layers_ - 1; level++) {
   570             lambda_gen.push_back(uni(rng));
   572         std::sort(lambda_gen.begin(), lambda_gen.end());
   573         for (std::size_t level{0}; level < num_layers_; level++) {
   574             x0[level + 3] = lambda_gen.at(level + 1) - lambda_gen.at(level);
   576         for (
auto old_x0 = x0s.begin(); old_x0 != x0s.end(); old_x0++) {
   578                 found_new_x0 = 
false;
   589 template<
class UserNodeLabel, 
class UserEdgeLabel>
   593         const std::vector<double> & alpha, 
const std::vector<double> & lambda, std::size_t row_in_master, std::size_t col_in_master)
 const {
   596         const Ring_ & ring_i = rings_g.at(row_in_master);
   597         const Ring_ & ring_k = rings_h.at(col_in_master);
   598         for (std::size_t level{0}; level < lambda.size(); level++) {
   599             red += lambda.at(level) * compute_substitution_cost_(ring_i, ring_k, alpha, level);
   602     else if (row_in_master < g.
num_nodes()) { 
   603         const Ring_ & ring_i = rings_g.at(row_in_master);
   604         for (std::size_t level{0}; level < lambda.size(); level++) {
   605             red += lambda.at(level) * compute_deletion_cost_(ring_i, alpha, level);
   608     else if (col_in_master < h.
num_nodes()) { 
   609         const Ring_ & ring_k = rings_h.at(col_in_master);
   610         for (std::size_t level{0}; level < lambda.size(); level++) {
   611             red += lambda.at(level) * compute_insertion_cost_(ring_k, alpha, level);
   617 template<
class UserNodeLabel, 
class UserEdgeLabel>
   620 compute_substitution_cost_(
const Ring_ & ring_i, 
const Ring_ & ring_k, 
const std::vector<double> & alpha, std::size_t level)
 const {
   621     if ((ring_i.layers.size() > level) and (ring_k.layers.size() > level)) {
   622         return compute_layer_distance_(ring_i.layers.at(level), ring_k.layers.at(level), alpha);
   624     if (ring_i.layers.size() > level) {
   625         return compute_layer_distance_(ring_i.layers.at(level), Layer_(0), alpha);
   627     if (ring_k.layers.size() > level) {
   628         return compute_layer_distance_(Layer_(0), ring_k.layers.at(level), alpha);
   633 template<
class UserNodeLabel, 
class UserEdgeLabel>
   637     if (ring.layers.size() > level) {
   638         return compute_layer_distance_(ring.layers.at(level), Layer_(0), alpha);
   643 template<
class UserNodeLabel, 
class UserEdgeLabel>
   647     if (ring.layers.size() > level) {
   648         return compute_layer_distance_(Layer_(0), ring.layers.at(level), alpha);
   653 template<
class UserNodeLabel, 
class UserEdgeLabel>
   657     double node_cost{0.0};
   658     double inner_edge_cost{0.0};
   659     double outer_edge_cost{0.0};
   661     switch (led_method_) {
   663         node_cost = gamma_multiset_cost_(lhs.node_labels, rhs.node_labels, 
true);
   664         inner_edge_cost = gamma_multiset_cost_(lhs.inner_edge_labels, rhs.inner_edge_labels, 
false);
   665         outer_edge_cost = gamma_multiset_cost_(lhs.outer_edge_labels, rhs.outer_edge_labels, 
false);
   668         node_cost = lsape_multiset_cost_(lhs.node_labels, rhs.node_labels, 
true);
   669         inner_edge_cost = lsape_multiset_cost_(lhs.inner_edge_labels, rhs.inner_edge_labels, 
false);
   670         outer_edge_cost = lsape_multiset_cost_(lhs.outer_edge_labels, rhs.outer_edge_labels, 
false);
   674     std::size_t max_num_node_labels{std::max(lhs.node_labels.size(), rhs.node_labels.size())};
   675     if (max_num_node_labels > 0) {
   676         node_cost /= 
static_cast<double>(max_num_node_labels);
   678     std::size_t max_num_inner_edge_labels{std::max(lhs.inner_edge_labels.size(), rhs.inner_edge_labels.size())};
   679     if (max_num_inner_edge_labels > 0) {
   680         inner_edge_cost /= 
static_cast<double>(max_num_inner_edge_labels);
   682     std::size_t max_num_outer_edge_labels{std::max(lhs.outer_edge_labels.size(), rhs.outer_edge_labels.size())};
   683     if (max_num_outer_edge_labels > 0) {
   684         outer_edge_cost /= 
static_cast<double>(max_num_outer_edge_labels);
   687     return alpha.at(0) * node_cost + alpha.at(1) * inner_edge_cost + alpha.at(2) * outer_edge_cost;
   690 template<
class UserNodeLabel, 
class UserEdgeLabel>
   693 lsape_multiset_cost_(
const std::vector<LabelID> & lhs, 
const std::vector<LabelID> & rhs, 
bool node_labels)
 const {
   695     if ((lhs.size() == 0) and (rhs.size() == 0)) {
   699     if ((lhs.size() > 0) and (rhs.size() == 0)) {
   701         for (std::size_t row{0}; row < lhs.size(); row++) {
   712     if ((lhs.size() == 0) and (rhs.size() > 0)) {
   714         for (std::size_t col{0}; col < rhs.size(); col++) {
   726     DMatrix problem(lhs.size() + 1, rhs.size() + 1, 0.0);
   728     for (std::size_t row{0}; row < lhs.size(); row++) {
   738     for (std::size_t col{0}; col < rhs.size(); col++) {
   748     for (std::size_t row{0}; row < lhs.size(); row++) {
   749         for (std::size_t col{0}; col < rhs.size(); col++) {
   751                 problem(row, col) = this->
ged_data_.node_cost(lhs.at(row), rhs.at(col));
   754                 problem(row, col) = this->
ged_data_.edge_cost(lhs.at(row), rhs.at(col));
   760     if (led_method_ == LSAPE_OPTIMAL) {
   766     problem_solver.
solve();
   771 template<
class UserNodeLabel, 
class UserEdgeLabel>
   774 gamma_multiset_cost_(
const std::vector<LabelID> & lhs, 
const std::vector<LabelID> & rhs, 
bool node_labels)
 const {
   778     if (lhs.size() < rhs.size()) {
   779         double avg_ins_cost{0.0};
   780         for (
auto label_rhs = rhs.begin(); label_rhs != rhs.end(); label_rhs++) {
   788         avg_ins_cost /= 
static_cast<double>(rhs.size());
   789         cost += 
static_cast<double>(rhs.size() - lhs.size()) * avg_ins_cost;
   793     if (lhs.size() > rhs.size()) {
   794         double avg_del_cost{0.0};
   795         for (
auto label_lhs = lhs.begin(); label_lhs != lhs.end(); label_lhs++) {
   803         avg_del_cost /= 
static_cast<double>(lhs.size());
   804         cost += 
static_cast<double>(lhs.size() - rhs.size()) * avg_del_cost;
   808     double avg_rel_cost{0.0};
   809     std::size_t count_diff_labels{0};
   810     for (
auto label_lhs = lhs.begin(); label_lhs != lhs.end(); label_lhs++) {
   811         for (
auto label_rhs = rhs.begin(); label_rhs != rhs.end(); label_rhs++) {
   812             if (*label_lhs != *label_rhs) {
   815                     avg_rel_cost += this->
ged_data_.node_cost(*label_lhs, *label_rhs);
   818                     avg_rel_cost += this->
ged_data_.edge_cost(*label_lhs, *label_rhs);
   823     avg_rel_cost /= 
static_cast<double>(count_diff_labels);
   826     std::size_t intersection_size{0};
   827     auto label_lhs = lhs.begin();
   828     auto label_rhs = rhs.begin();
   829     while ((label_lhs != lhs.end()) and (label_rhs != rhs.end())) {
   830         if (*label_lhs == *label_rhs) {
   835         else if (*label_lhs < *label_rhs) {
   843     std::size_t gamma(std::min(lhs.size(), rhs.size()) - intersection_size);
   845         cost += 
static_cast<double>(gamma) * avg_rel_cost;
   851 template<
class UserNodeLabel, 
class UserEdgeLabel>
   855     const NodeRingMap_ & rings_g = rings_.at(g.
id());
   856     const NodeRingMap_ & rings_h = rings_.at(h.
id());
   858     for (std::size_t row_in_master = 0; row_in_master < lsape_instance.
num_rows(); row_in_master++) {
   859         for (std::size_t col_in_master = 0; col_in_master < lsape_instance.
num_cols(); col_in_master++) {
   860             lsape_instance(row_in_master, col_in_master) = compute_ring_distance_(g, h, rings_g, rings_h, alpha, lambda, row_in_master, col_in_master);
   865 template<
class UserNodeLabel, 
class UserEdgeLabel>
   869     std::map<std::string, std::string> options;
   870     options[
"num_layers"] = std::to_string(lambda_.size());
   871     for (std::size_t i{0}; i < alpha_.size(); i++) {
   872         double val{alpha_.at(i)};
   873         options[
"alpha_" + std::to_string(i)] = std::to_string(val);
   875     for (std::size_t i{0}; i <lambda_.size(); i++) {
   876         double val{lambda_.at(i)};
   877         options[
"lambda_" + std::to_string(i)] = std::to_string(val);
   882 template<
class UserNodeLabel, 
class UserEdgeLabel>
   886     std::map<std::string, std::string> options;
   888     num_layers_ = std::stoul(options.at(
"num_layers"));
   890     for (std::size_t i{0}; i < 3; i++) {
   891         alpha_.push_back(std::stod(options.at(
"alpha_" + std::to_string(i))));
   894     for (std::size_t i{0}; i < num_layers_; i++) {
   895         lambda_.push_back(std::stod(options.at(
"lambda_" + std::to_string(i))));
 void set_model(const Model &model)
Makes the solver use a specific model for optimal solving. 
virtual void lsape_init_() final
Initializes the method after initializing the global variables for the graphs. 
std::size_t num_nodes() const
Returns the number of nodes. 
std::size_t num_threads_
The number of threads to be used. 
virtual void lsape_pre_graph_init_(bool called_at_runtime) final
Initializes the method at runtime or during initialization before initializing the global variables f...
This class solves LSAPE instances by calling the library lsape available at https://bougleux.users.greyc.fr/lsape/. 
virtual bool lsape_parse_option_(const std::string &option, const std::string &arg) final
Parses one option that is not among the ones shared by all derived classes of ged::LSAPEBasedMethod. 
std::vector< GEDGraph >::size_type GraphID
Type of internally used graph IDs. 
const GEDData< UserNodeLabel, UserEdgeLabel > & ged_data_
The data on which the method is run. 
NodeID head(EdgeID edge) const
Returns the head of an edge. 
void solve(int num_solutions=1)
Solves the LSAPE problem instance. 
virtual void lsape_set_default_options_() final
Sets all options that are not among the ones shared by all derived classes of ged::LSAPEBasedMethod t...
std::size_t num_cols() const
Returns the number of columns. 
virtual std::string lsape_valid_options_string_() const final
Returns string of all valid options that are not among the ones shared by all derived classes of ged:...
void counting_sort(std::vector< LabelID >::iterator first, std::vector< LabelID >::iterator last)
Implementation of counting sort. 
LabelID get_node_label(NodeID node) const
Returns the label of a given node. 
void parse_config_file(const std::string &filename, std::map< std::string, std::string > &options)
Parses a configuration file. 
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. 
LabelID get_edge_label(EdgeID edge) const
Returns the label of a given edge. 
std::pair< incident_edge_iterator, incident_edge_iterator > incident_edges(NodeID node) const
Provides access to all incident edges of a node. 
double minimal_cost() const
Returns the cost of the computed solutions. 
std::pair< node_iterator, node_iterator > nodes() const
Provides access to all nodes in the graph. 
The normalized input graphs used by GEDLIB. All labels are integers. 
virtual void lsape_default_post_graph_init_() final
Default initializes the method at runtime after initializing the global variables for the graphs...
constexpr LabelID dummy_label()
Returns a dummy label. 
constexpr std::size_t undefined()
Returns undefined size. 
Global namespace for GEDLIB. 
void increment()
Increments the number of solved tasks. 
virtual void lsape_init_graph_(const GEDGraph &graph) final
Initializes global variables for one graph. 
void save_as_config_file(const std::string &filename, const std::map< std::string, std::string > &options)
Saves a string map as a configuration file as expected by parse_config_file(). 
Computes an upper bound for general edit costs. 
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...
void set_problem(const DMatrix *cost_matrix)
Sets the LSAPE problem instance. 
LSAPESolver::GreedyMethod greedy_method_
Specifies method for greedy LSAPE solver. 
std::size_t NodeID
Internally used vertex ID type. 
void set_greedy_method(const GreedyMethod &greedy_method)
Makes the solver use a greedy method. 
GraphID id() const
Returns the ID of the graph. 
virtual void lsape_populate_instance_(const GEDGraph &g, const GEDGraph &h, DMatrix &master_problem) final
Populates the LSAPE instance. 
std::pair< edge_iterator, edge_iterator > edges() const
Provides access to all edge in the graph. 
std::size_t num_rows() const
Returns the number of rows.