From d9dfc8ec68c87e64423e2d3a565463d4289d4090 Mon Sep 17 00:00:00 2001 From: Benoit GAUZERE Date: Fri, 17 Nov 2017 10:40:14 +0100 Subject: [PATCH] Update of costfunctions hierarchy to distinguish cost function for ged and for cost matrix --- ged/GED.py | 4 +- ged/bipartiteGED.py | 4 +- ged/costfunctions.py | 67 ++++--- notebooks/py-graph_test.ipynb | 428 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 433 insertions(+), 70 deletions(-) diff --git a/ged/GED.py b/ged/GED.py index 3e82942..1233329 100644 --- a/ged/GED.py +++ b/ged/GED.py @@ -1,10 +1,10 @@ -from ged.costfunctions import BasicCostFunction, RiesenCostFunction +from ged.costfunctions import ConstantCostFunction, RiesenCostFunction from ged.costfunctions import NeighboorhoodCostFunction from ged.bipartiteGED import computeBipartiteCostMatrix, getOptimalMapping from scipy.optimize import linear_sum_assignment def ged(G1, G2, method='Riesen', rho=None, varrho=None, - cf=BasicCostFunction(1, 3, 1, 3), + cf=ConstantCostFunction(1, 3, 1, 3), solver=linear_sum_assignment): """Compute Graph Edit Distance between G1 and G2 according to mapping encoded within rho and varrho. Graph's node must be indexed by a diff --git a/ged/bipartiteGED.py b/ged/bipartiteGED.py index 1372b7e..ab3aadf 100644 --- a/ged/bipartiteGED.py +++ b/ged/bipartiteGED.py @@ -1,9 +1,9 @@ import numpy as np from scipy.optimize import linear_sum_assignment -from ged.costfunctions import BasicCostFunction +from ged.costfunctions import ConstantCostFunction -def computeBipartiteCostMatrix(G1, G2, cf=BasicCostFunction(1, 3, 1, 3)): +def computeBipartiteCostMatrix(G1, G2, cf=ConstantCostFunction(1, 3, 1, 3)): """Compute a Cost Matrix according to cost function cf""" n = G1.number_of_nodes() m = G2.number_of_nodes() diff --git a/ged/costfunctions.py b/ged/costfunctions.py index 4d2be90..28318de 100644 --- a/ged/costfunctions.py +++ b/ged/costfunctions.py @@ -2,15 +2,17 @@ import numpy as np from scipy.optimize import linear_sum_assignment -class BasicCostFunction: +class ConstantCostFunction: + """ Define a symmetric constant cost fonction for edit operations """ def __init__(self, cns, cni, ces, cei): self.cns_ = cns self.cni_ = self.cnd_ = cni self.ces_ = ces self.cei_ = self.ced_ = cei - def cns(self, u, v, G1, G2): - return (G1.node[u]['label'] != G2.node[v]['label'])*self.cns_ + def cns(self, node_u, node_v, g1, g2): + """ return substitution edit operation cost between node_u of G1 and node_v of G2""" + return (g1.node[node_u]['label'] != g2.node[node_v]['label'])*self.cns_ def cnd(self, u, G1): return self.cnd_ @@ -30,9 +32,11 @@ class BasicCostFunction: return self.cei_ -class RiesenCostFunction(BasicCostFunction): - def __init__(self, cf): - BasicCostFunction.__init__(self, cf.cns_, cf.cni_, cf.ces_, cf.cei_) +class RiesenCostFunction(): + """ Cost function associated to the computation of a cost matrix between nodes for LSAP""" + def __init__(self, cf, lsap_solver=linear_sum_assignment): + self.cf_ = cf + self.lsap_solver_ = lsap_solver def cns(self, u, v, G1, G2): """ u et v sont des id de noeuds """ @@ -48,41 +52,43 @@ class RiesenCostFunction(BasicCostFunction): e1 = [u, nbr_u, G1[u][nbr_u]] for nbr_v in G2[v]: e2 = [v, nbr_v, G2[v][nbr_v]] - sub_C[i, j] = self.ces(e1, e2, G1, G2) + sub_C[i, j] = self.cf_.ces(e1, e2, G1, G2) j += 1 i += 1 i = 0 for nbr_u in l_nbr_u: - sub_C[i, m+i] = self.ced([u, nbr_u, G1[u][nbr_u]], G1) + sub_C[i, m+i] = self.cf_.ced([u, nbr_u, G1[u][nbr_u]], G1) i += 1 j = 0 for nbr_v in l_nbr_v: - sub_C[n+j, j] = self.cei([v, nbr_v, G2[v][nbr_v]], G2) + sub_C[n+j, j] = self.cf_.cei([v, nbr_v, G2[v][nbr_v]], G2) j += 1 - row_ind, col_ind = linear_sum_assignment(sub_C) + row_ind, col_ind = self.lsap_solver_(sub_C) cost = np.sum(sub_C[row_ind, col_ind]) - return BasicCostFunction.cns(self, u, v, G1, G2) + cost + return self.cf_.cns(u, v, G1, G2) + cost def cnd(self, u, G1): cost = 0 for nbr in G1[u]: - cost += BasicCostFunction.ced(self,[u,nbr,G1[u][nbr]],G1) + cost += self.cf_.ced([u,nbr,G1[u][nbr]],G1) - return BasicCostFunction.cnd(self,u,G1) + cost + return self.cf_.cnd(u,G1) + cost def cni(self, v, G2): cost = 0 for nbr in G2[v]: - cost += BasicCostFunction.cei(self, [v,nbr,G2[v][nbr]], G2) + cost += self.cf_.cei([v,nbr,G2[v][nbr]], G2) - return BasicCostFunction.cni(self, v, G2) + cost + return self.cf_.cni(v, G2) + cost -class NeighboorhoodCostFunction(BasicCostFunction): - def __init__(self, cf): - BasicCostFunction.__init__(self, cf.cns_, cf.cni_, cf.ces_, cf.cei_) +class NeighboorhoodCostFunction(): + """ Cost function associated to the computation of a cost matrix between nodes for LSAP""" + def __init__(self, cf, lsap_solver=linear_sum_assignment): + self.cf_ = cf + self.lsap_solver_ = lsap_solver def cns(self, u, v, G1, G2): """ u et v sont des id de noeuds """ @@ -98,36 +104,35 @@ class NeighboorhoodCostFunction(BasicCostFunction): e1 = [u, nbr_u, G1[u][nbr_u]] for nbr_v in G2[v]: e2 = [v, nbr_v, G2[v][nbr_v]] - sub_C[i, j] = self.ces(e1, e2, G1, G2) - sub_C[i, j] += BasicCostFunction.cns(self, - nbr_u, nbr_v, G1, G2) + sub_C[i, j] = self.cf_.ces(e1, e2, G1, G2) + sub_C[i, j] += self.cf_.cns(nbr_u, nbr_v, G1, G2) j += 1 i += 1 i = 0 for nbr_u in l_nbr_u: - sub_C[i, m+i] = self.ced([u, nbr_u, G1[u][nbr_u]], G1) - sub_C[i, m+i] += BasicCostFunction.cnd(self, nbr_u, G1) + sub_C[i, m+i] = self.cf_.ced([u, nbr_u, G1[u][nbr_u]], G1) + sub_C[i, m+i] += self.cf_.cnd(nbr_u, G1) i += 1 j = 0 for nbr_v in l_nbr_v: - sub_C[n+j, j] = self.cei([v, nbr_v, G2[v][nbr_v]], G2) - sub_C[n+j, j] += BasicCostFunction.cni(self, nbr_v, G2) + sub_C[n+j, j] = self.cf_.cei([v, nbr_v, G2[v][nbr_v]], G2) + sub_C[n+j, j] += self.cf_.cni(nbr_v, G2) j += 1 - row_ind, col_ind = linear_sum_assignment(sub_C) + row_ind, col_ind = self.lsap_solver_(sub_C) cost = np.sum(sub_C[row_ind, col_ind]) - return BasicCostFunction.cns(self, u, v, G1, G2) + cost + return self.cf_.cns(u, v, G1, G2) + cost def cnd(self, u, G1): cost = 0 for nbr in G1[u]: - cost += BasicCostFunction.ced(self, [u, nbr, G1[u][nbr]], G1) - return BasicCostFunction.cnd(self, u, G1) + cost + cost += self.cf_.ced([u, nbr, G1[u][nbr]], G1) + return self.cf_.cnd(u, G1) + cost def cni(self, v, G2): cost = 0 for nbr in G2[v]: - cost += BasicCostFunction.cei(self, [v, nbr, G2[v][nbr]], G2) - return BasicCostFunction.cni(self, v, G2) + cost + cost += self.cf_.cei([v, nbr, G2[v][nbr]], G2) + return self.cf_.cni(v, G2) + cost diff --git a/notebooks/py-graph_test.ipynb b/notebooks/py-graph_test.ipynb index b2e1815..ea50015 100644 --- a/notebooks/py-graph_test.ipynb +++ b/notebooks/py-graph_test.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "metadata": { "autoscroll": false, "collapsed": false, @@ -11,16 +11,7 @@ "slide_type": "-" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The autoreload extension is already loaded. To reload it, use:\n", - " %reload_ext autoreload\n" - ] - } - ], + "outputs": [], "source": [ "import numpy as np\n", "\n", @@ -28,13 +19,13 @@ "\n", "from ged.GED import ged\n", "from utils.graphfiles import loadDataset\n", - "from ged.costfunctions import RiesenCostFunction, BasicCostFunction\n", + "from ged.costfunctions import RiesenCostFunction, ConstantCostFunction\n", "from ged.bipartiteGED import computeBipartiteCostMatrix, getOptimalMapping" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "metadata": { "autoscroll": false, "collapsed": false, @@ -43,25 +34,7 @@ "slide_type": "-" } }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0, 1, 4]\n" - ] - } - ], + "outputs": [], "source": [ "import networkx as nx\n", "import numpy as np\n", @@ -73,7 +46,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "autoscroll": false, "collapsed": false, @@ -87,7 +60,392 @@ "name": "stderr", "output_type": "stream", "text": [ - "100%|██████████| 183/183 [03:48<00:00, 1.25s/it]\n" + "\r", + " 0%| | 0/183 [00:00