|
@@ -0,0 +1,195 @@ |
|
|
|
|
|
#!/usr/bin/env python3 |
|
|
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
""" |
|
|
|
|
|
Created on Thu Jun 18 15:52:35 2020 |
|
|
|
|
|
|
|
|
|
|
|
@author: ljia |
|
|
|
|
|
""" |
|
|
|
|
|
import numpy as np |
|
|
|
|
|
import time |
|
|
|
|
|
import networkx as nx |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GEDMethod(object): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, ged_data): |
|
|
|
|
|
self._initialized = False |
|
|
|
|
|
self._ged_data = ged_data |
|
|
|
|
|
self._options = None |
|
|
|
|
|
self._lower_bound = 0 |
|
|
|
|
|
self._upper_bound = np.inf |
|
|
|
|
|
self._node_map = [0, 0] # @todo |
|
|
|
|
|
self._runtime = None |
|
|
|
|
|
self._init_time = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def init(self): |
|
|
|
|
|
"""Initializes the method with options specified by set_options(). |
|
|
|
|
|
""" |
|
|
|
|
|
start = time.time() |
|
|
|
|
|
self._ged_init() |
|
|
|
|
|
end = time.time() |
|
|
|
|
|
self._init_time = end - start |
|
|
|
|
|
self._initialized = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_options(self, options): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Sets the options of the method. |
|
|
|
|
|
* @param[in] options String of the form <tt>[--@<option@> @<arg@>] [...]</tt>, where @p option contains neither spaces nor single quotes, |
|
|
|
|
|
* and @p arg contains neither spaces nor single quotes or is of the form <tt>'[--@<sub-option@> @<sub-arg@>] [...]'</tt>, |
|
|
|
|
|
* where both @p sub-option and @p sub-arg contain neither spaces nor single quotes. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
self._ged_set_default_options() |
|
|
|
|
|
for key, val in options.items(): |
|
|
|
|
|
if not self._ged_parse_option(key, val): |
|
|
|
|
|
raise Exception('Invalid option "', key, '". Usage: options = "' + self._ged_valid_options_string() + '".') # @todo: not implemented. |
|
|
|
|
|
self._initialized = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run(self, g_id, h_id): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Runs the method with options specified by set_options(). |
|
|
|
|
|
* @param[in] g_id ID of input graph. |
|
|
|
|
|
* @param[in] h_id ID of input graph. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
start = time.time() |
|
|
|
|
|
result = self.run_as_util(self._ged_data._graphs[g_id], self._ged_data._graphs[h_id]) |
|
|
|
|
|
end = time.time() |
|
|
|
|
|
self._lower_bound = result['lower_bound'] |
|
|
|
|
|
self._upper_bound = result['upper_bound'] |
|
|
|
|
|
if len(result['node_maps']) > 0: |
|
|
|
|
|
self._node_map = result['node_maps'][0] |
|
|
|
|
|
self._runtime = end - start |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_as_util(self, g, h): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Runs the method with options specified by set_options(). |
|
|
|
|
|
* @param[in] g Input graph. |
|
|
|
|
|
* @param[in] h Input graph. |
|
|
|
|
|
* @param[out] result Result variable. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
# Compute optimal solution and return if at least one of the two graphs is empty. |
|
|
|
|
|
if nx.number_of_nodes(g) == 0 or nx.number_of_nodes(h) == 0: |
|
|
|
|
|
print('This is not implemented.') |
|
|
|
|
|
pass # @todo: |
|
|
|
|
|
|
|
|
|
|
|
# Run the method. |
|
|
|
|
|
return self._ged_run(g, h) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_upper_bound(self): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Returns an upper bound. |
|
|
|
|
|
* @return Upper bound for graph edit distance provided by last call to run() or -1 if the method does not yield an upper bound. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
return self._upper_bound |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_lower_bound(self): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Returns a lower bound. |
|
|
|
|
|
* @return Lower bound for graph edit distance provided by last call to run() or -1 if the method does not yield a lower bound. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
return self._lower_bound |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_runtime(self): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Returns the runtime. |
|
|
|
|
|
* @return Runtime of last call to run() in seconds. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
return self._runtime |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_init_time(self): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Returns the initialization time. |
|
|
|
|
|
* @return Runtime of last call to init() in seconds. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
return self._init_time |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_node_map(self): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Returns a graph matching. |
|
|
|
|
|
* @return Constant reference to graph matching provided by last call to run() or to an empty matching if the method does not yield a matching. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
return self._node_map |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ged_init(self): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Initializes the method. |
|
|
|
|
|
* @note Must be overridden by derived classes that require initialization. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ged_parse_option(self, option, arg): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Parses one option. |
|
|
|
|
|
* @param[in] option The name of the option. |
|
|
|
|
|
* @param[in] arg The argument of the option. |
|
|
|
|
|
* @return Boolean @p true if @p option is a valid option name for the method and @p false otherwise. |
|
|
|
|
|
* @note Must be overridden by derived classes that have options. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ged_run(self, g, h): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Runs the method with options specified by set_options(). |
|
|
|
|
|
* @param[in] g Input graph. |
|
|
|
|
|
* @param[in] h Input graph. |
|
|
|
|
|
* @param[out] result Result variable. |
|
|
|
|
|
* @note Must be overridden by derived classes. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
return {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ged_valid_options_string(self): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Returns string of all valid options. |
|
|
|
|
|
* @return String of the form <tt>[--@<option@> @<arg@>] [...]</tt>. |
|
|
|
|
|
* @note Must be overridden by derived classes that have options. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
return '' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ged_set_default_options(self): |
|
|
|
|
|
""" |
|
|
|
|
|
/*! |
|
|
|
|
|
* @brief Sets all options to default values. |
|
|
|
|
|
* @note Must be overridden by derived classes that have options. |
|
|
|
|
|
*/ |
|
|
|
|
|
""" |
|
|
|
|
|
pass |
|
|
|
|
|
|