27 #ifndef SRC_METHODS_BIPARTITE_ML_IPP_ 28 #define SRC_METHODS_BIPARTITE_ML_IPP_ 32 template<
class UserNodeLabel,
class UserEdgeLabel>
33 BipartiteML<UserNodeLabel, UserEdgeLabel>::
38 template<
class UserNodeLabel,
class UserEdgeLabel>
39 BipartiteML<UserNodeLabel, UserEdgeLabel>::
40 BipartiteML(
const GEDData<UserNodeLabel, UserEdgeLabel> & ged_data) :
41 MLBasedMethod<UserNodeLabel, UserEdgeLabel>(ged_data),
42 lsape_method_{
new Bipartite<UserNodeLabel, UserEdgeLabel>(this->
ged_data_)},
43 lsape_method_options_(
""),
50 template<
class UserNodeLabel,
class UserEdgeLabel>
54 lsape_method_->init();
57 template<
class UserNodeLabel,
class UserEdgeLabel>
63 lsape_method_options_ = std::string(
"");
66 template<
class UserNodeLabel,
class UserEdgeLabel>
70 return "[--lsape-method <arg>] [--lsape-options <arg>]";
73 template<
class UserNodeLabel,
class UserEdgeLabel>
77 bool is_valid_option{
false};
78 if (option ==
"lsape-method") {
79 if (arg ==
"BRANCH_FAST") {
82 else if (arg ==
"BRANCH_UNIFORM") {
85 else if (arg ==
"BRANCH") {
88 else if (arg ==
"NODE") {
91 else if (arg ==
"RING") {
94 else if (arg ==
"SUBGRAPH") {
97 else if (arg ==
"WALKS") {
100 else if (arg !=
"BIPARTITE") {
101 throw Error(
"Invalid argument \"" + arg +
"\" for option lsape-method. Usage: options = \"[--lsape-method BIPARTITE|BRANCH_FAST|BRANCH_UNIFORM|BRANCH|NODE|RING|SUBGRAPH|WALKS] [...]");
103 is_valid_option =
true;
105 else if (option ==
"lsape-options") {
106 lsape_method_options_ = arg;
107 std::size_t bad_option_start{lsape_method_options_.find(
"--threads")};
108 std::size_t next_option_start;
109 if (bad_option_start != std::string::npos) {
110 next_option_start = lsape_method_options_.find(
"--", bad_option_start + 1);
111 if (next_option_start != std::string::npos) {
112 lsape_method_options_ = lsape_method_options_.substr(0, bad_option_start) + lsape_method_options_.substr(next_option_start);
115 lsape_method_options_ = lsape_method_options_.substr(0, bad_option_start);
118 is_valid_option =
true;
120 if (lsape_method_options_ !=
"") {
121 lsape_method_->set_options(lsape_method_options_ +
" --threads " + std::to_string(this->
num_threads_));
124 lsape_method_->set_options(std::string(
"--threads ") + std::to_string(this->
num_threads_));
126 return is_valid_option;
129 template<
class UserNodeLabel,
class UserEdgeLabel>
133 populate_lsape_instance_(g, h, num_threads);
134 Eigen::ArrayXXd substitution_matrix(lsape_instance_.topLeftCorner(g.
num_nodes(), h.
num_nodes()));
135 compute_global_features_(substitution_matrix);
136 row_features_.init(substitution_matrix);
137 col_features_.init(substitution_matrix);
140 template<
class UserNodeLabel,
class UserEdgeLabel>
146 feature_vector.clear();
147 add_global_features_(feature_vector);
149 row_features_.add_features_(lsape_instance_, row, col, feature_vector);
150 col_features_.add_features_(lsape_instance_, row, col, feature_vector);
153 template<
class UserNodeLabel,
class UserEdgeLabel>
158 std::size_t col{
static_cast<std::size_t
>(lsape_instance_.cols() - 1)};
159 feature_vector.clear();
160 add_global_features_(feature_vector);
162 row_features_.add_features_(lsape_instance_, row, col, feature_vector);
163 col_features_.add_features_(lsape_instance_, row, col, feature_vector);
166 template<
class UserNodeLabel,
class UserEdgeLabel>
170 std::size_t row{
static_cast<std::size_t
>(lsape_instance_.rows() - 1)};
172 feature_vector.clear();
173 add_global_features_(feature_vector);
175 row_features_.add_features_(lsape_instance_, row, col, feature_vector);
176 col_features_.add_features_(lsape_instance_, row, col, feature_vector);
179 template<
class UserNodeLabel,
class UserEdgeLabel>
187 template<
class UserNodeLabel,
class UserEdgeLabel>
198 template<
class UserNodeLabel,
class UserEdgeLabel>
202 init(
const Eigen::ArrayXXd & substitution_matrix) {
205 maxima_ = substitution_matrix.rowwise().maxCoeff();
208 minima_.resize(substitution_matrix.rows());
209 std::vector<RowVector_::Index> col_min(substitution_matrix.rows());
210 for (
auto row = 0; row < substitution_matrix.rows(); row++) {
211 minima_(row) = substitution_matrix.row(row).minCoeff(&col_min[row]);
215 means_ = substitution_matrix.rowwise().mean();
218 if (substitution_matrix.rows() <= 1) {
219 deviations_.resize(substitution_matrix.rows());
220 for (
auto row = 0; row < substitution_matrix.rows(); row++) {
221 deviations_(row) = 0.0;
225 deviations_ = ((substitution_matrix.colwise() - substitution_matrix.rowwise().mean()).square().rowwise().sum() / (substitution_matrix.rows() - 1)).sqrt();
229 RowVector_ second_minima(substitution_matrix.rows());
230 if (substitution_matrix.rows() == 1) {
231 second_minima = minima_;
234 for (
auto row = 0; row < substitution_matrix.rows(); row++) {
235 second_minima(row) = maxima_(row);
236 for (
auto col = 0; col < substitution_matrix.cols(); col++) {
237 if ((col != col_min.at(row)) and (substitution_matrix(row, col) < second_minima(row))) {
238 second_minima(row) = substitution_matrix(row, col);
243 leaders_ = (minima_ - second_minima);
244 for (
auto row = 0; row < substitution_matrix.rows(); row++) {
245 if (second_minima(row) != 0) {
246 leaders_(row) /= second_minima(row);
251 intervals_ = maxima_ - minima_;
252 if (intervals_.mean() > 0) {
253 intervals_ /= intervals_.mean();
257 template<
class UserNodeLabel,
class UserEdgeLabel>
261 add_features_(
const Eigen::ArrayXXd & matrix, std::size_t row, std::size_t col, std::vector<double> & feature_vector)
const {
264 if (row == static_cast<std::size_t>(matrix.rows() - 1)) {
265 for (
unsigned short counter{0}; counter < 9; counter++) {
266 feature_vector.push_back(0.0);
272 feature_vector.push_back(maxima_(row));
275 feature_vector.push_back(minima_(row));
278 feature_vector.push_back(means_(row));
281 feature_vector.push_back(deviations_(row));
284 double uniqueness{(matrix.row(row) - matrix(row, col)).abs().maxCoeff()};
285 feature_vector.push_back(uniqueness);
288 double divergence{(matrix.row(row) - matrix(row, col)).abs().sum()};
289 if (((matrix.cols() - 1) * (matrix(row, col) - means_(row))) != 0) {
290 divergence /= ((matrix.cols() - 1) * (matrix(row, col) - means_(row)));
292 feature_vector.push_back(divergence);
295 feature_vector.push_back(leaders_(row));
298 feature_vector.push_back(intervals_(row));
301 double outlierness{matrix(row, col)};
302 if (means_(row) != deviations_(row)) {
303 outlierness /= (means_(row) - deviations_(row));
305 feature_vector.push_back(outlierness);
309 template<
class UserNodeLabel,
class UserEdgeLabel>
320 template<
class UserNodeLabel,
class UserEdgeLabel>
324 init(
const Eigen::ArrayXXd & substitution_matrix) {
327 maxima_ = substitution_matrix.colwise().maxCoeff();
330 minima_.resize(substitution_matrix.cols());
331 std::vector<ColumnVector_::Index> row_min(substitution_matrix.cols());
332 for (
auto col = 0; col < substitution_matrix.cols(); col++) {
333 minima_(col) = substitution_matrix.col(col).minCoeff(&row_min[col]);
337 means_ = substitution_matrix.colwise().mean();
340 if (substitution_matrix.cols() <= 1) {
341 deviations_.resize(substitution_matrix.cols());
342 for (
auto col = 0; col < substitution_matrix.cols(); col++) {
343 deviations_(col) = 0.0;
347 deviations_ = ((substitution_matrix.rowwise() - substitution_matrix.colwise().mean()).square().colwise().sum() / (substitution_matrix.cols() - 1)).sqrt();
351 ColumnVector_ second_minima(substitution_matrix.cols());
352 if (substitution_matrix.cols() == 1) {
353 second_minima = minima_;
356 for (
auto col = 0; col < substitution_matrix.cols(); col++) {
357 second_minima(col) = maxima_(col);
358 for (
auto row = 0; row < substitution_matrix.rows(); row++) {
359 if ((row != row_min.at(col)) and (substitution_matrix(row, col) < second_minima(col))) {
360 second_minima(col) = substitution_matrix(row, col);
365 leaders_ = (minima_ - second_minima);
366 for (
auto col = 0; col < substitution_matrix.cols(); col++) {
367 if (second_minima(col) != 0) {
368 leaders_(col) /= second_minima(col);
373 intervals_ = maxima_ - minima_;
374 if (intervals_.mean() > 0) {
375 intervals_ /= intervals_.mean();
379 template<
class UserNodeLabel,
class UserEdgeLabel>
383 add_features_(
const Eigen::ArrayXXd & matrix, std::size_t row, std::size_t col, std::vector<double> & feature_vector)
const {
386 if (col == static_cast<std::size_t>(matrix.cols() - 1)) {
387 for (
unsigned short counter{0}; counter < 9; counter++) {
388 feature_vector.push_back(0.0);
394 feature_vector.push_back(maxima_(col));
397 feature_vector.push_back(minima_(col));
400 feature_vector.push_back(means_(col));
403 feature_vector.push_back(deviations_(col));
406 double uniqueness{(matrix.col(col) - matrix(row, col)).abs().maxCoeff()};
407 feature_vector.push_back(uniqueness);
410 double divergence{(matrix.col(col) - matrix(row, col)).abs().sum()};
411 if (((matrix.rows() - 1) * (matrix(row, col) - means_(col))) != 0) {
412 divergence /= ((matrix.rows() - 1) * (matrix(row, col) - means_(col)));
414 feature_vector.push_back(divergence);
417 feature_vector.push_back(leaders_(col));
420 feature_vector.push_back(intervals_(col));
423 double outlierness{matrix(row, col)};
424 if (means_(col) != deviations_(col)) {
425 outlierness /= (means_(col) - deviations_(col));
427 feature_vector.push_back(outlierness);
431 template<
class UserNodeLabel,
class UserEdgeLabel>
436 lsape_method_->populate_instance(g, h, lsape_instance);
437 lsape_instance_ = lsape_instance.
matrix();
440 template<
class UserNodeLabel,
class UserEdgeLabel>
444 global_features_.clear();
445 global_features_.push_back(substitution_matrix.maxCoeff());
446 global_features_.push_back(substitution_matrix.minCoeff());
447 global_features_.push_back(substitution_matrix.mean());
448 if ((substitution_matrix.rows() * substitution_matrix.cols()) <= 1) {
449 global_features_.push_back(0.0);
452 global_features_.push_back(std::sqrt((substitution_matrix - global_features_.at(2)).square().sum() / (substitution_matrix.rows() * substitution_matrix.cols() - 1)));
456 template<
class UserNodeLabel,
class UserEdgeLabel>
460 for (
auto feature = global_features_.begin(); feature != global_features_.end(); feature++) {
461 feature_vector.push_back(*feature);
465 template<
class UserNodeLabel,
class UserEdgeLabel>
468 add_cell_features_(std::size_t row, std::size_t col,
double node_cost, std::vector<double> & feature_vector)
const {
470 feature_vector.push_back(node_cost);
473 feature_vector.push_back(lsape_instance_(row, col) - node_cost);
Computes lower and upper bounds for general edit costs.
std::size_t num_nodes() const
Returns the number of nodes.
std::size_t num_threads_
The number of threads to be used.
Computes an upper bound for general edit costs.
const GEDData< UserNodeLabel, UserEdgeLabel > & ged_data_
The data on which the method is run.
virtual std::size_t ml_get_num_features_() final
Returns the number of features.
Uses characteristics of an LSAPE instance for defining feature vectors for node edit operations...
Computes lower and upper bounds for general edit costs.
virtual void ml_set_default_options_() final
Sets all options that are not among the ones shared by all derived classes of ged::MLBasedMethod to d...
LabelID get_node_label(NodeID node) const
Returns the label of a given node.
virtual void ml_populate_insertion_feature_vector_(const GEDGraph &h, GEDGraph::NodeID k, std::vector< double > &feature_vector) final
Computes insertion feature vector.
virtual void ml_init_() final
Initializes the method after initializing the global variables for the graphs.
Computes lower and upper bounds for general edit costs.
Computes lower and upper bounds for general edit costs.
Eigen::Matrix< ScalarT, Eigen::Dynamic, Eigen::Dynamic > & matrix()
Returns reference to the internal Eigen matrix.
The normalized input graphs used by GEDLIB. All labels are integers.
constexpr LabelID dummy_label()
Returns a dummy label.
virtual void ml_populate_substitution_feature_vector_(const GEDGraph &g, const GEDGraph &h, GEDGraph::NodeID i, GEDGraph::NodeID k, std::vector< double > &feature_vector) final
Computes substitution feature vector.
virtual bool ml_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::MLBasedMethod.
Global namespace for GEDLIB.
virtual void ml_populate_deletion_feature_vector_(const GEDGraph &g, GEDGraph::NodeID i, std::vector< double > &feature_vector) final
Computes deletion feature vector.
Computes upper bounds for general edit costs.
virtual void ml_init_feature_variables_(const GEDGraph &g, const GEDGraph &h, std::size_t num_threads) final
Initializes variables that are used for populating the feature vectors of assignments between two inp...
Computes an upper bound for general edit costs.
std::size_t NodeID
Internally used vertex ID type.
virtual std::string ml_valid_options_string_() const final
Returns string of all valid options that are not among the ones shared by all derived classes of ged:...