Commit c9d5bf47 authored by Fize Jacques's avatar Fize Jacques

- Change Module architecture (beginning by MCS)

- Clean setup.py
parent 45e037af
# coding = utf-8
from enum import Enum
class AlgorithmType(Enum):
similarity = 0
distance = 1
\ No newline at end of file
cimport numpy as np
cdef class Base:
## Attribute(s)
cdef int type_alg
cdef bint normalized
## Methods
cpdef np.ndarray compare(self,list graph_list, list selected)
cpdef np.ndarray distance(self, np.ndarray matrix)
cpdef np.ndarray similarity(self, np.ndarray matrix)
# coding = utf-8
import numpy as np
cimport numpy as np
cdef np.ndarray minmax_scale(np.ndarray matrix):
"""
Optimize so it can works with Cython
:param matrix:
:return:
"""
cdef double min_,max_
min_=np.min(matrix)
max_=np.max(matrix)
return matrix/(max_-min_)
cdef class Base:
def __cinit__(self):
self.type_alg=0
self.normalized=False
def __init__(self,type_alg,normalized):
if type_alg <0:
self.type_alg=0
elif type_alg >1 :
self.type_alg=1
else:
self.type_alg=type_alg
self.normalized=normalized
cpdef np.ndarray compare(self,list graph_list, list selected):
pass
cpdef np.ndarray distance(self, np.ndarray matrix):
"""
Return the distance matrix between the graphs
:return: np.ndarray
"""
if self.type_alg == 1:
return matrix
else:
if not self.normalized:
matrix=minmax_scale(matrix)
return 1-matrix
cpdef np.ndarray similarity(self, np.ndarray matrix):
"""
Return a the similarity value between the graphs
:return:
"""
if self.type_alg == 0:
return matrix
else:
if not self.normalized:
matrix=minmax_scale(matrix)
return 1-matrix
def mcs(self,g1,g2):
"""
Return the Most Common Subgraph
:param g1: graph1
:param g2: graph2
:return: np.ndarray
"""
R=g1.copy()
R.remove_nodes_from(n for n in g1 if n not in g2)
return R
......@@ -3,9 +3,10 @@
import numpy as np
cimport numpy as np
from .base cimport Base
def intersect(a, b):
return list(set(a) & set(b))
class Jaccard():
class Jaccard(Base):
__type__ = "sim"
......
# coding = utf-8
import networkx as nx
import numpy as np
cimport numpy as np
class MCS():
from .base cimport Base
cdef class MCS(Base):
"""
*A graph distance metric based on the maximal common subgraph, H. Bunke and K. Shearer,
Pattern Recognition Letters, 1998*
"""
@staticmethod
def compare(listgs,selected):
def __init__(self):
Base.__init__(self,0,True)
cpdef np.ndarray compare(self,list listgs, list selected):
cdef int n = len(listgs)
cdef np.ndarray comparison_matrix = np.zeros((n, n))
for i in range(n):
......@@ -23,52 +26,13 @@ class MCS():
if not i in selected:
f=False
if f:
comparison_matrix[i, j] = MCS.s_mcs(listgs[i],listgs[j])
comparison_matrix[i, j] = self.s_mcs(listgs[i],listgs[j])
else:
comparison_matrix[i, j] = 0.
comparison_matrix[j, i] = comparison_matrix[i, j]
return comparison_matrix
def s_mcs(self,g1, g2):
@staticmethod
def intersect(a, b):
return list(set(a) & set(b))
@staticmethod
def transform_edges(ed):
for e in range(len(ed)):
if "id" in ed[e][-1]:
del ed[e][-1]["id"]
return ed
@staticmethod
def intersect_edges(g1, g2):
cdef list ed1 = MCS.transform_edges(list(g1.edges(data=True)))
cdef list ed2 = MCS.transform_edges(list(g2.edges(data=True)))
inter_ed = []
for e1 in ed1:
for e2 in ed2:
if e1 == e2:
inter_ed.append(e1)
return inter_ed
@staticmethod
def intersect_nodes(g1, g2):
return MCS.intersect(list(g1.nodes), list(g2.nodes))
@staticmethod
def maximum_common_subgraph(g1, g2):
"""
Extract maximum common subgraph
"""
res = nx.MultiDiGraph()
res.add_nodes_from(MCS.intersect_nodes(g1, g2))
res.add_edges_from(MCS.intersect_edges(g1, g2))
return res
@staticmethod
def s_mcs(g1, g2):
return len(MCS.maximum_common_subgraph(g1, g2)) / float(max(len(g1), len(g2)))
return len(self.mcs(g1, g2)) / float(max(len(g1), len(g2)))
......@@ -2,53 +2,21 @@ import sys, os
from distutils.core import setup
from distutils.extension import Extension
# we'd better have Cython installed, or it's a no-go
from Cython.Build import cythonize
try:
from Cython.Build import cythonize
from Cython.Distutils import build_ext
except:
print("You don't seem to have Cython installed. Please get a")
print("copy from www.cython.org and install it")
sys.exit(1)
# scan the 'dvedit' directory for extension files, converting
# them to extension names in dotted notation
def scandir(dir, files=[]):
for file in os.listdir(dir):
path = os.path.join(dir, file)
if os.path.isfile(path) and path.endswith(".pyx"):
files.append(path.replace(os.path.sep, ".")[:-4])
elif os.path.isdir(path):
scandir(path, files)
return files
# generate an Extension object from its dotted name
def makeExtension(extName):
extPath = extName.replace(".", os.path.sep) + ".pyx"
return Extension(
extName,
[extPath],
language="c++",
extra_compile_args=["-O3", "-Wall", '-std=c++11', '-v'],
)
# get the list of extensions
extNames = scandir("gmatch4py")
# and build up the set of Extension objects
extensions = cythonize([makeExtension(name) for name in extNames])
# finally, we can pass all this to distutils
setup(
name="Gmatch4py",
description="A module for graph matching",
packages=["gmatch4py", "gmatch4py.ged", "gmatch4py.kernels"],
ext_modules=extensions,
ext_modules=cythonize([Extension("*", ["gmatch4py/*.pyx"])]),
cmdclass={'build_ext': build_ext},
setup_requires=["numpy","networkx"],
install_requires=["numpy","networkx"]
install_requires=["numpy","networkx"],
version="0.1"
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment