#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Thu Jun 18 16:09:29 2020 @author: ljia """ import numpy as np import networkx as nx from gklearn.ged.methods import LSAPEBasedMethod from gklearn.ged.util import LSAPESolver from gklearn.utils import SpecialLabel class Bipartite(LSAPEBasedMethod): def __init__(self, ged_data): super().__init__(ged_data) self._compute_lower_bound = False ########################################################################### # Inherited member functions from LSAPEBasedMethod. ########################################################################### def _lsape_populate_instance(self, g, h, master_problem): # #ifdef _OPENMP for row_in_master in range(0, nx.number_of_nodes(g)): for col_in_master in range(0, nx.number_of_nodes(h)): master_problem[row_in_master, col_in_master] = self._compute_substitution_cost(g, h, row_in_master, col_in_master) for row_in_master in range(0, nx.number_of_nodes(g)): master_problem[row_in_master, nx.number_of_nodes(h) + row_in_master] = self._compute_deletion_cost(g, row_in_master) for col_in_master in range(0, nx.number_of_nodes(h)): master_problem[nx.number_of_nodes(g) + col_in_master, col_in_master] = self._compute_insertion_cost(h, col_in_master) # for row_in_master in range(0, master_problem.shape[0]): # for col_in_master in range(0, master_problem.shape[1]): # if row_in_master < nx.number_of_nodes(g) and col_in_master < nx.number_of_nodes(h): # master_problem[row_in_master, col_in_master] = self._compute_substitution_cost(g, h, row_in_master, col_in_master) # elif row_in_master < nx.number_of_nodes(g): # master_problem[row_in_master, nx.number_of_nodes(h)] = self._compute_deletion_cost(g, row_in_master) # elif col_in_master < nx.number_of_nodes(h): # master_problem[nx.number_of_nodes(g), col_in_master] = self._compute_insertion_cost(h, col_in_master) ########################################################################### # Helper member functions. ########################################################################### def _compute_substitution_cost(self, g, h, u, v): # Collect node substitution costs. cost = self._ged_data.node_cost(g.nodes[u]['label'], h.nodes[v]['label']) # Initialize subproblem. d1, d2 = g.degree[u], h.degree[v] subproblem = np.ones((d1 + d2, d1 + d2)) * np.inf subproblem[d1:, d2:] = 0 # subproblem = np.empty((g.degree[u] + 1, h.degree[v] + 1)) # Collect edge deletion costs. i = 0 # @todo: should directed graphs be considered? for label in g[u].values(): # all u's neighbor subproblem[i, d2 + i] = self._ged_data.edge_cost(label['label'], SpecialLabel.DUMMY) # subproblem[i, h.degree[v]] = self._ged_data.edge_cost(label['label'], SpecialLabel.DUMMY) i += 1 # Collect edge insertion costs. i = 0 # @todo: should directed graphs be considered? for label in h[v].values(): # all u's neighbor subproblem[d1 + i, i] = self._ged_data.edge_cost(SpecialLabel.DUMMY, label['label']) # subproblem[g.degree[u], i] = self._ged_data.edge_cost(SpecialLabel.DUMMY, label['label']) i += 1 # Collect edge relabelling costs. i = 0 for label1 in g[u].values(): j = 0 for label2 in h[v].values(): subproblem[i, j] = self._ged_data.edge_cost(label1['label'], label2['label']) j += 1 i += 1 # Solve subproblem. subproblem_solver = LSAPESolver(subproblem) subproblem_solver.set_model(self._lsape_model) subproblem_solver.solve() # Update and return overall substitution cost. cost += subproblem_solver.minimal_cost() return cost def _compute_deletion_cost(self, g, v): # Collect node deletion cost. cost = self._ged_data.node_cost(g.nodes[v]['label'], SpecialLabel.DUMMY) # Collect edge deletion costs. for label in g[v].values(): cost += self._ged_data.edge_cost(label['label'], SpecialLabel.DUMMY) # Return overall deletion cost. return cost def _compute_insertion_cost(self, g, v): # Collect node insertion cost. cost = self._ged_data.node_cost(SpecialLabel.DUMMY, g.nodes[v]['label']) # Collect edge insertion costs. for label in g[v].values(): cost += self._ged_data.edge_cost(SpecialLabel.DUMMY, label['label']) # Return overall insertion cost. return cost