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