Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
GMatch4py
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
3
Issues
3
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Fize Jacques
GMatch4py
Commits
0ce8bd23
Commit
0ce8bd23
authored
Feb 07, 2019
by
Fize Jacques
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add parallelization + prepare test
parent
31bf928c
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
225 additions
and
136 deletions
+225
-136
gmatch4py/base.pxd
gmatch4py/base.pxd
+2
-0
gmatch4py/base.pyx
gmatch4py/base.pyx
+11
-0
gmatch4py/ged/abstract_graph_edit_dist.pxd
gmatch4py/ged/abstract_graph_edit_dist.pxd
+1
-0
gmatch4py/ged/abstract_graph_edit_dist.pyx
gmatch4py/ged/abstract_graph_edit_dist.pyx
+26
-2
gmatch4py/ged/bipartite_graph_matching_2.pyx
gmatch4py/ged/bipartite_graph_matching_2.pyx
+31
-9
gmatch4py/ged/graph_edit_dist.pxd
gmatch4py/ged/graph_edit_dist.pxd
+1
-0
gmatch4py/ged/graph_edit_dist.pyx
gmatch4py/ged/graph_edit_dist.pyx
+17
-25
gmatch4py/ged/graph_edit_dist_2.pyx
gmatch4py/ged/graph_edit_dist_2.pyx
+0
-68
gmatch4py/ged/greedy_edit_distance.pyx
gmatch4py/ged/greedy_edit_distance.pyx
+1
-9
gmatch4py/ged/hausdorff_edit_distance.pyx
gmatch4py/ged/hausdorff_edit_distance.pyx
+28
-5
gmatch4py/graph.pxd
gmatch4py/graph.pxd
+3
-1
gmatch4py/graph.pyx
gmatch4py/graph.pyx
+8
-4
gmatch4py/helpers/general.pyx
gmatch4py/helpers/general.pyx
+7
-0
gmatch4py/jaccard.pyx
gmatch4py/jaccard.pyx
+37
-2
gmatch4py/mcs.pyx
gmatch4py/mcs.pyx
+26
-2
gmatch4py/vertex_edge_overlap.pyx
gmatch4py/vertex_edge_overlap.pyx
+24
-7
setup.py
setup.py
+2
-2
test/test.py
test/test.py
+0
-0
No files found.
gmatch4py/base.pxd
View file @
0ce8bd23
...
...
@@ -7,9 +7,11 @@ cdef class Base:
## Methods
cpdef
np
.
ndarray
compare
(
self
,
list
graph_list
,
list
selected
)
cpdef
np
.
ndarray
compare_old
(
self
,
list
listgs
,
list
selected
)
cpdef
np
.
ndarray
distance
(
self
,
np
.
ndarray
matrix
)
cpdef
np
.
ndarray
similarity
(
self
,
np
.
ndarray
matrix
)
cpdef
bint
isAccepted
(
self
,
G
,
index
,
selected
)
cpdef
list
get_selected_array
(
self
,
selected
,
size_corpus
)
cpdef
intersection
(
G
,
H
)
cpdef
union_
(
G
,
H
)
gmatch4py/base.pyx
View file @
0ce8bd23
...
...
@@ -136,6 +136,17 @@ cdef class Base:
else
:
self
.
type_alg
=
type_alg
self
.
normalized
=
normalized
cpdef
list
get_selected_array
(
self
,
selected
,
size_corpus
):
cdef
list
selected_test
=
[
True
]
*
size_corpus
if
selected
:
selected_test
=
[
False
]
*
size_corpus
for
ix
in
range
(
len
(
selected
)):
selected_test
[
ix
]
=
True
return
selected
cpdef
np
.
ndarray
compare_old
(
self
,
list
listgs
,
list
selected
):
pass
cpdef
np
.
ndarray
compare
(
self
,
list
graph_list
,
list
selected
):
"""
Return the similarity/distance matrix using the current algorithm.
...
...
gmatch4py/ged/abstract_graph_edit_dist.pxd
View file @
0ce8bd23
...
...
@@ -16,3 +16,4 @@ cdef class AbstractGraphEditDistance(Base):
cdef
double
insert_cost
(
self
,
int
i
,
int
j
,
nodesH
,
H
)
cdef
double
delete_cost
(
self
,
int
i
,
int
j
,
nodesG
,
G
)
cpdef
double
substitute_cost
(
self
,
node1
,
node2
,
G
,
H
)
gmatch4py/ged/abstract_graph_edit_dist.pyx
View file @
0ce8bd23
...
...
@@ -4,14 +4,18 @@ from __future__ import print_function
import
sys
import
warnings
import
numpy
as
np
cimport
numpy
as
np
try
:
from
munkres
import
munkres
except
ImportError
:
warnings
.
warn
(
"To obtain optimal results install the Cython 'munkres' module at https://github.com/jfrelinger/cython-munkres-wrapper"
)
from
scipy.optimize
import
linear_sum_assignment
as
munkres
cimport
numpy
as
np
from
..base
cimport
Base
import
networkx
as
nx
from
..helpers.general
import
parsenx2graph
from
cython.parallel
cimport
prange
,
parallel
cdef
class
AbstractGraphEditDistance
(
Base
):
...
...
@@ -90,7 +94,7 @@ cdef class AbstractGraphEditDistance(Base):
cpdef
double
substitute_cost
(
self
,
node1
,
node2
,
G
,
H
):
raise
NotImplementedError
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cpdef
np
.
ndarray
compare
_old
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
np
.
ndarray
comparison_matrix
=
np
.
zeros
((
n
,
n
)).
astype
(
float
)
cdef
int
i
,
j
...
...
@@ -105,3 +109,23 @@ cdef class AbstractGraphEditDistance(Base):
#comparison_matrix[j, i] = comparison_matrix[i, j]
np
.
fill_diagonal
(
comparison_matrix
,
0
)
return
comparison_matrix
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
double
[:,:]
comparison_matrix
=
np
.
zeros
((
n
,
n
))
listgs
=
parsenx2graph
(
listgs
)
cdef
long
[:]
n_nodes
=
np
.
array
([
g
.
size
()
for
g
in
listgs
])
cdef
bint
[:]
selected_test
=
self
.
get_selected_array
(
selected
,
n
)
cdef
int
i
,
j
val
=
np
.
inf
with
nogil
,
parallel
(
num_threads
=
8
):
for
i
in
prange
(
n
,
schedule
=
'static'
):
for
j
in
range
(
n
):
if
n_nodes
[
i
]
>
0
and
n_nodes
[
j
]
>
0
and
selected_test
[
i
]
:
with
gil
:
comparison_matrix
[
i
][
j
]
=
self
.
distance_ged
(
listgs
[
i
],
listgs
[
j
])
else
:
comparison_matrix
[
i
][
j
]
=
0
#comparison_matrix[j, i] = comparison_matrix[i, j]
return
np
.
array
(
comparison_matrix
)
gmatch4py/ged/bipartite_graph_matching_2.pyx
View file @
0ce8bd23
...
...
@@ -2,7 +2,8 @@
import
numpy
as
np
cimport
numpy
as
np
from
..base
cimport
Base
from
cython.parallel
cimport
prange
,
parallel
from
..helpers.general
import
parsenx2graph
cdef
class
BP_2
(
Base
):
...
...
@@ -32,7 +33,7 @@ cdef class BP_2(Base):
self
.
edge_del
=
edge_del
self
.
edge_ins
=
edge_ins
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cpdef
np
.
ndarray
compare
_old
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
np
.
ndarray
comparison_matrix
=
np
.
zeros
((
n
,
n
)).
astype
(
float
)
cdef
int
i
,
j
...
...
@@ -48,6 +49,27 @@ cdef class BP_2(Base):
return
comparison_matrix
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
list
new_gs
=
parsenx2graph
(
listgs
)
cdef
double
[:,:]
comparison_matrix
=
np
.
zeros
((
n
,
n
))
cdef
bint
[:]
selected_test
=
self
.
get_selected_array
(
selected
,
n
)
cdef
int
i
,
j
cdef
long
[:]
n_nodes
=
np
.
array
([
g
.
size
()
for
g
in
new_gs
])
cdef
long
[:]
n_edges
=
np
.
array
([
g
.
density
()
for
g
in
new_gs
])
with
nogil
,
parallel
(
num_threads
=
4
):
for
i
in
prange
(
n
,
schedule
=
'static'
):
for
j
in
range
(
i
,
n
):
if
n_nodes
[
i
]
>
0
and
n_nodes
[
j
]
>
0
and
selected_test
[
i
]
==
True
:
with
gil
:
comparison_matrix
[
i
,
j
]
=
self
.
bp2
(
new_gs
[
i
],
new_gs
[
j
])
else
:
comparison_matrix
[
i
,
j
]
=
0
comparison_matrix
[
j
,
i
]
=
comparison_matrix
[
i
,
j
]
return
comparison_matrix
cdef
double
bp2
(
self
,
g1
,
g2
):
"""
...
...
@@ -100,8 +122,8 @@ cdef class BP_2(Base):
list containing costs from the optimal edit path
"""
cdef
list
psi_
=
[]
cdef
list
nodes1
=
list
(
g1
.
nodes
)
cdef
list
nodes2
=
list
(
g2
.
nodes
)
cdef
list
nodes1
=
list
(
g1
.
nodes
()
)
cdef
list
nodes2
=
list
(
g2
.
nodes
()
)
for
u
in
nodes1
:
v
=
None
for
w
in
nodes2
:
...
...
@@ -125,9 +147,9 @@ cdef class BP_2(Base):
:param g2: Second Graph
:return:
"""
cdef
np
.
ndarray
min_sum
=
np
.
zeros
(
len
(
g1
))
nodes1
=
list
(
g1
.
nodes
)
nodes2
=
list
(
g2
.
nodes
)
cdef
np
.
ndarray
min_sum
=
np
.
zeros
(
g1
.
size
(
))
nodes1
=
list
(
g1
.
nodes
()
)
nodes2
=
list
(
g2
.
nodes
()
)
nodes2
.
extend
([
None
])
cdef
np
.
ndarray
min_i
for
i
in
range
(
len
(
nodes1
)):
...
...
@@ -178,8 +200,8 @@ cdef class BP_2(Base):
"""
#if isinstance(g1, nx.MultiDiGraph):
cdef
list
edges1
=
list
(
g1
.
edges
(
n1
)
)
if
n1
else
[]
cdef
list
edges2
=
list
(
g2
.
edges
(
n2
)
)
if
n2
else
[]
cdef
list
edges1
=
g1
.
get_edges_no
(
n1
)
if
n1
else
[]
cdef
list
edges2
=
g2
.
get_edges_no
(
n2
)
if
n2
else
[]
cdef
np
.
ndarray
min_sum
=
np
.
zeros
(
len
(
edges1
))
edges2
.
extend
([
None
])
...
...
gmatch4py/ged/graph_edit_dist.pxd
View file @
0ce8bd23
...
...
@@ -4,6 +4,7 @@ from .abstract_graph_edit_dist cimport AbstractGraphEditDistance
cdef
class
GraphEditDistance
(
AbstractGraphEditDistance
):
cpdef
object
relabel_cost
(
self
,
node1
,
node2
,
G
,
H
)
cpdef
double
substitute_cost
(
self
,
node1
,
node2
,
G
,
H
)
cdef
double
delete_cost
(
self
,
int
i
,
int
j
,
nodesG
,
G
)
cdef
double
insert_cost
(
self
,
int
i
,
int
j
,
nodesH
,
H
)
\ No newline at end of file
gmatch4py/ged/graph_edit_dist.pyx
View file @
0ce8bd23
...
...
@@ -7,6 +7,7 @@ import numpy as np
cimport
numpy
as
np
from
.abstract_graph_edit_dist
cimport
AbstractGraphEditDistance
from
..base
cimport
intersection
,
union_
from
..graph
cimport
Graph
cdef
class
GraphEditDistance
(
AbstractGraphEditDistance
):
...
...
@@ -14,52 +15,43 @@ cdef class GraphEditDistance(AbstractGraphEditDistance):
def
__init__
(
self
,
node_del
,
node_ins
,
edge_del
,
edge_ins
,
weighted
=
False
):
AbstractGraphEditDistance
.
__init__
(
self
,
node_del
,
node_ins
,
edge_del
,
edge_ins
)
self
.
weighted
=
weighted
cpdef
double
substitute_cost
(
self
,
node1
,
node2
,
G
,
H
):
return
self
.
relabel_cost
(
node1
,
node2
,
G
,
H
)
def
add_edges
(
self
,
node1
,
node2
,
G
):
R
=
nx
.
create_empty_copy
(
G
)
try
:
R
.
add_edges_from
(
G
.
edges
(
node1
,
node2
))
except
Exception
as
e
:
# To counter bug with a None for attribute... weird ??
arr_
=
G
.
edges
(
node1
,
node2
)
new_list
=
[]
for
item
in
arr_
:
new_list
.
append
((
item
[
0
],
item
[
1
]))
R
.
add_edges_from
(
new_list
)
return
R
def
relabel_cost
(
self
,
node1
,
node2
,
G
,
H
):
cpdef
object
relabel_cost
(
self
,
node1
,
node2
,
G
,
H
):
## Si deux noeuds égaux
if
node1
==
node2
and
G
.
degree
(
node1
)
==
H
.
degree
(
node2
):
return
0.0
elif
node1
==
node2
and
G
.
degree
(
node1
)
!=
H
.
degree
(
node2
):
R
=
self
.
add_edges
(
node1
,
node2
,
G
)
R2
=
self
.
add_edges
(
node1
,
node2
,
H
)
inter_
=
intersection
(
R
,
R2
).
number_of_edges
()
add_diff
=
abs
(
R2
.
number_of_edges
()
-
inter_
)
del_diff
=
abs
(
R
.
number_of_edges
()
-
inter_
)
#R = Graph(self.add_edges(node1,node2,G),G.get_node_key(),G.get_egde_key())
#R2 = Graph(self.add_edges(node1,node2,H),H.get_node_key(),H.get_egde_key())
#inter_= R.size_edge_intersect(R2)
R
=
set
(
G
.
get_edges_no
(
node1
))
R2
=
set
(
H
.
get_edges_no
(
node2
))
inter_
=
R
.
intersection
(
R2
)
add_diff
=
abs
(
len
(
R2
)
-
len
(
inter_
))
#abs(R2.density()-inter_)
del_diff
=
abs
(
len
(
R
)
-
len
(
inter_
))
#abs(R.density()-inter_)
return
(
add_diff
*
self
.
edge_ins
)
+
(
del_diff
*
self
.
edge_del
)
#si deux noeuds connectés
if
(
node1
,
node2
)
in
G
.
edges
()
or
(
node2
,
node1
)
in
G
.
edges
(
):
if
G
.
has_edge
(
node1
,
node2
)
or
G
.
has_edge
(
node2
,
node1
):
return
self
.
node_ins
+
self
.
node_del
if
not
node2
in
G
:
nodesH
=
list
(
H
.
nodes
()
)
index
=
nodesH
.
index
(
node2
)
if
not
node2
in
G
.
nodes
()
:
nodesH
=
H
.
nodes
(
)
index
=
list
(
nodesH
)
.
index
(
node2
)
return
self
.
node_del
+
self
.
node_ins
+
self
.
insert_cost
(
index
,
index
,
nodesH
,
H
)
return
sys
.
maxsize
cdef
double
delete_cost
(
self
,
int
i
,
int
j
,
nodesG
,
G
):
if
i
==
j
:
return
self
.
node_del
+
(
G
.
degree
(
nodesG
[
i
],
weight
=
(
"weight"
if
self
.
weighted
else
None
)
)
*
self
.
edge_del
)
# Deleting a node implicate to delete in and out edges
return
self
.
node_del
+
(
G
.
degree
(
nodesG
[
i
],
weight
=
True
)
*
self
.
edge_del
)
# Deleting a node implicate to delete in and out edges
return
sys
.
maxsize
cdef
double
insert_cost
(
self
,
int
i
,
int
j
,
nodesH
,
H
):
if
i
==
j
:
deg
=
H
.
degree
(
nodesH
[
j
],
weight
=
(
"weight"
if
self
.
weighted
else
None
)
)
deg
=
H
.
degree
(
nodesH
[
j
],
weight
=
True
)
if
isinstance
(
deg
,
dict
):
deg
=
0
return
self
.
node_ins
+
(
deg
*
self
.
edge_ins
)
else
:
...
...
gmatch4py/ged/graph_edit_dist_2.pyx
deleted
100644 → 0
View file @
31bf928c
# -*- coding: UTF-8 -*-
import
sys
import
networkx
as
nx
import
numpy
as
np
cimport
numpy
as
np
from
.abstract_graph_edit_dist
cimport
AbstractGraphEditDistance
from
..base
cimport
intersection
,
union_
from
..graph
cimport
Graph
cdef
class
GraphEditDistance
(
AbstractGraphEditDistance
):
def
__init__
(
self
,
node_del
,
node_ins
,
edge_del
,
edge_ins
,
weighted
=
False
):
AbstractGraphEditDistance
.
__init__
(
self
,
node_del
,
node_ins
,
edge_del
,
edge_ins
)
self
.
weighted
=
weighted
cpdef
double
substitute_cost
(
self
,
node1
,
node2
,
G
,
H
):
return
self
.
relabel_cost
(
node1
,
node2
,
G
,
H
)
def
add_edges
(
self
,
node1
,
node2
,
G
):
R
=
nx
.
create_empty_copy
(
G
.
get_nx
())
try
:
R
.
add_edges_from
(
G
.
edges
(
node1
,
node2
))
except
Exception
as
e
:
# To counter bug with a None for attribute... weird ??
arr_
=
G
.
edges
(
node1
,
node2
)
new_list
=
[]
for
item
in
arr_
:
new_list
.
append
((
item
[
0
],
item
[
1
]))
R
.
add_edges_from
(
new_list
)
return
R
cpdef
relabel_cost
(
self
,
node1
,
node2
,
G
,
H
):
## Si deux noeuds égaux
if
node1
==
node2
and
G
.
degree
(
node1
)
==
H
.
degree
(
node2
):
return
0.0
elif
node1
==
node2
and
G
.
degree
(
node1
)
!=
H
.
degree
(
node2
):
R
=
Graph
(
self
.
add_edges
(
node1
,
node2
,
G
),
G
.
get_node_key
(),
G
.
get_egde_key
())
R2
=
Graph
(
self
.
add_edges
(
node1
,
node2
,
H
),
H
.
get_node_key
(),
H
.
get_egde_key
())
inter_
=
R
.
size_edge_intersect
(
R2
)
add_diff
=
abs
(
R2
.
density
()
-
inter_
)
del_diff
=
abs
(
R
.
density
()
-
inter_
)
return
(
add_diff
*
self
.
edge_ins
)
+
(
del_diff
*
self
.
edge_del
)
#si deux noeuds connectés
if
G
.
has_edge
(
*
(
node1
,
node2
))
or
G
.
has_edge
(
*
(
node2
,
node1
)):
return
self
.
node_ins
+
self
.
node_del
if
not
node2
in
G
:
nodesH
=
H
.
nodes
()
index
=
list
(
nodesH
).
index
(
node2
)
return
self
.
node_del
+
self
.
node_ins
+
self
.
insert_cost
(
index
,
index
,
nodesH
,
H
)
return
sys
.
maxsize
cdef
double
delete_cost
(
self
,
int
i
,
int
j
,
nodesG
,
G
):
if
i
==
j
:
return
self
.
node_del
+
(
G
.
degree
(
nodesG
[
i
],
weight
=
True
)
*
self
.
edge_del
)
# Deleting a node implicate to delete in and out edges
return
sys
.
maxsize
cdef
double
insert_cost
(
self
,
int
i
,
int
j
,
nodesH
,
H
):
if
i
==
j
:
deg
=
H
.
degree
(
nodesH
[
j
],
weight
=
True
)
if
isinstance
(
deg
,
dict
):
deg
=
0
return
self
.
node_ins
+
(
deg
*
self
.
edge_ins
)
else
:
return
sys
.
maxsize
\ No newline at end of file
gmatch4py/ged/greedy_edit_distance.pyx
View file @
0ce8bd23
...
...
@@ -4,6 +4,7 @@ import sys
from
.graph_edit_dist
cimport
GraphEditDistance
import
numpy
as
np
cimport
numpy
as
np
from
cython.parallel
cimport
prange
,
parallel
cdef
class
GreedyEditDistance
(
GraphEditDistance
):
"""
...
...
@@ -20,15 +21,6 @@ cdef class GreedyEditDistance(GraphEditDistance):
cdef
list
edit_costs
(
self
,
G
,
H
):
cdef
np
.
ndarray
cost_matrix
=
self
.
create_cost_matrix
(
G
,
H
)
"""
cdef np.ndarray cost_matrix_2=cost_matrix.copy()
cdef list psi=[]
for i in range(len(cost_matrix)):
phi_i=np.argmin((cost_matrix[i]))
cost_matrix=np.delete(cost_matrix,phi_i,1)
psi.append([i,phi_i+i]) #+i to compensate the previous column deletion
return [cost_matrix_2[psi[i][0]][psi[i][1]] for i in range(len(psi))]
"""
cdef
np
.
ndarray
cost_matrix_2
=
cost_matrix
.
copy
().
astype
(
np
.
double
)
cdef
list
psi
=
[]
for
i
in
range
(
len
(
cost_matrix
)):
...
...
gmatch4py/ged/hausdorff_edit_distance.pyx
View file @
0ce8bd23
...
...
@@ -3,6 +3,8 @@
import
numpy
as
np
cimport
numpy
as
np
from
..base
cimport
Base
from
cython.parallel
cimport
prange
,
parallel
from
..helpers.general
import
parsenx2graph
cdef
class
HED
(
Base
):
"""
...
...
@@ -27,7 +29,7 @@ cdef class HED(Base):
self
.
edge_ins
=
edge_ins
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cpdef
np
.
ndarray
compare
_old
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
np
.
ndarray
comparison_matrix
=
np
.
zeros
((
n
,
n
)).
astype
(
float
)
cdef
int
i
,
j
...
...
@@ -42,6 +44,27 @@ cdef class HED(Base):
comparison_matrix
[
j
,
i
]
=
comparison_matrix
[
i
,
j
]
return
comparison_matrix
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
list
new_gs
=
parsenx2graph
(
listgs
)
cdef
double
[:,:]
comparison_matrix
=
np
.
zeros
((
n
,
n
))
cdef
bint
[:]
selected_test
=
self
.
get_selected_array
(
selected
,
n
)
cdef
int
i
,
j
cdef
long
[:]
n_nodes
=
np
.
array
([
g
.
size
()
for
g
in
new_gs
])
cdef
long
[:]
n_edges
=
np
.
array
([
g
.
density
()
for
g
in
new_gs
])
with
nogil
,
parallel
(
num_threads
=
4
):
for
i
in
prange
(
n
,
schedule
=
'static'
):
for
j
in
range
(
i
,
n
):
if
n_nodes
[
i
]
>
0
and
n_nodes
[
j
]
>
0
and
selected_test
[
i
]
==
True
:
with
gil
:
comparison_matrix
[
i
,
j
]
=
self
.
hed
(
new_gs
[
i
],
new_gs
[
j
])
else
:
comparison_matrix
[
i
,
j
]
=
0
comparison_matrix
[
j
,
i
]
=
comparison_matrix
[
i
,
j
]
return
comparison_matrix
cdef
float
hed
(
self
,
g1
,
g2
):
...
...
@@ -61,8 +84,8 @@ cdef class HED(Base):
:return:
"""
cdef
np
.
ndarray
min_sum
=
np
.
zeros
(
len
(
g1
))
nodes1
=
list
(
g1
.
nodes
)
nodes2
=
list
(
g2
.
nodes
)
nodes1
=
list
(
g1
.
nodes
()
)
nodes2
=
list
(
g2
.
nodes
()
)
nodes2
.
extend
([
None
])
cdef
np
.
ndarray
min_i
for
i
in
range
(
len
(
nodes1
)):
...
...
@@ -113,8 +136,8 @@ cdef class HED(Base):
"""
#if isinstance(g1, nx.MultiDiGraph):
cdef
list
edges1
=
list
(
g1
.
edges
(
n1
)
)
if
n1
else
[]
cdef
list
edges2
=
list
(
g2
.
edges
(
n2
)
)
if
n2
else
[]
cdef
list
edges1
=
g1
.
get_edges_no
(
n1
)
if
n1
else
[]
cdef
list
edges2
=
g2
.
get_edges_no
(
n2
)
if
n2
else
[]
cdef
np
.
ndarray
min_sum
=
np
.
zeros
(
len
(
edges1
))
edges2
.
extend
([
None
])
...
...
gmatch4py/graph.pxd
View file @
0ce8bd23
...
...
@@ -38,6 +38,7 @@ cdef class Graph:
cdef
dict
degree_per_attr
# degree information per attr val
cdef
dict
degree_per_attr_weighted
# degree information per attr val
cdef
list
attr_nodes
# list of attr(dict) values for each node
cdef
dict
edges_of_nodes
# list of egdes connected to each node
# EDGES ATTRIBUTES
##################
...
...
@@ -107,7 +108,8 @@ cdef class Graph:
## GETTER
#########
cpdef
list
get_edges_
(
self
,
e1
,
e2
)
cpdef
list
get_edges_ed
(
self
,
str
e1
,
str
e2
)
cpdef
list
get_edges_no
(
self
,
str
n
)
cpdef
set
get_edges_hash
(
self
)
cpdef
set
get_nodes_hash
(
self
)
...
...
gmatch4py/graph.pyx
View file @
0ce8bd23
...
...
@@ -59,7 +59,9 @@ cdef class Graph:
self
.
degree_per_attr_weighted
=
{
attr_v
:{
n
:{
"in"
:
0
,
"out"
:
0
}
for
n
in
self
.
nodes_list
}
for
attr_v
in
self
.
unique_edge_attr_vals
}
# Retrieving Degree Information
self
.
edges_of_nodes
=
{}
for
n
in
self
.
nodes_list
:
self
.
edges_of_nodes
[
n
]
=
[
self
.
hash_edge_attr
(
e1
,
e2
,
attr_dict
[
self
.
edge_attr_key
])
if
self
.
is_edge_attr
else
self
.
hash_edge
(
e1
,
e2
)
for
e1
,
e2
,
attr_dict
in
G
.
edges
(
n
,
data
=
True
)]
degree_all
.
append
(
G
.
degree
(
n
))
degree_all_weighted
.
append
(
G
.
degree
(
n
,
weight
=
"weight"
))
if
self
.
is_directed
:
...
...
@@ -161,12 +163,12 @@ cdef class Graph:
cpdef
bint
has_edge
(
self
,
str
n_id1
,
str
n_id2
):
if
self
.
is_directed
:
if
n_id1
in
self
.
edges_hash_map
and
n_id2
in
self
.
edges_hash_map
[
n_id1
]
[
n_id2
]
:
if
n_id1
in
self
.
edges_hash_map
and
n_id2
in
self
.
edges_hash_map
[
n_id1
]:
return
True
else
:
if
n_id1
in
self
.
edges_hash_map
and
n_id2
in
self
.
edges_hash_map
[
n_id1
]
[
n_id2
]
:
if
n_id1
in
self
.
edges_hash_map
and
n_id2
in
self
.
edges_hash_map
[
n_id1
]:
return
True
if
n_id2
in
self
.
edges_hash_map
and
n_id1
in
self
.
edges_hash_map
[
n_id2
]
[
n_id1
]
:
if
n_id2
in
self
.
edges_hash_map
and
n_id1
in
self
.
edges_hash_map
[
n_id2
]:
return
True
return
False
...
...
@@ -199,12 +201,14 @@ cdef class Graph:
else
:
return
self
.
edges_list
cpdef
list
get_edges_
(
self
,
e1
,
e2
):
cpdef
list
get_edges_
ed
(
self
,
str
e1
,
str
e2
):
if
self
.
is_edge_attr
:
hashes
=
self
.
edges_hash_map
[
e1
][
e2
]
return
[(
e1
,
e2
,
self
.
edges_attr_list
[
self
.
edges_hash_idx
[
hash_
]])
for
hash_
in
hashes
]
else
:
return
[(
e1
,
e2
,
None
)]
cpdef
list
get_edges_no
(
self
,
str
n
):
return
self
.
edges_of_nodes
[
n
]
cpdef
dict
get_edge_attr
(
self
,
edge_hash
):
return
self
.
edges_attr_list
[
self
.
edges_hash_idx
[
edge_hash
]]
...
...
gmatch4py/helpers/general.pyx
0 → 100644
View file @
0ce8bd23
from
..graph
cimport
Graph
import
networkx
as
nx
def
parsenx2graph
(
list_gs
):
new_gs
=
[
nx
.
relabel_nodes
(
g
,{
node
:
str
(
node
)
for
node
in
list
(
g
.
nodes
)},
copy
=
True
)
for
g
in
list_gs
]
new_gs
=
[
Graph
(
g
)
for
g
in
new_gs
]
return
new_gs
gmatch4py/jaccard.pyx
View file @
0ce8bd23
...
...
@@ -5,14 +5,16 @@ cimport numpy as np
from
.base
cimport
Base
from
.base
cimport
intersection
,
union_
from
..helpers.general
import
parsenx2graph
from
cython.parallel
cimport
prange
,
parallel
cdef
class
Jaccard
(
Base
):
def
__init__
(
self
):
Base
.
__init__
(
self
,
0
,
True
)
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cpdef
np
.
ndarray
compare_old
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
np
.
ndarray
comparison_matrix
=
np
.
zeros
((
n
,
n
))
cdef
int
i
,
j
...
...
@@ -37,5 +39,38 @@ cdef class Jaccard(Base):
return
comparison_matrix
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
list
new_gs
=
parsenx2graph
(
listgs
)
cdef
double
[:,:]
comparison_matrix
=
np
.
zeros
((
n
,
n
))
cdef
long
[:]
n_nodes
=
np
.
array
([
g
.
size
()
for
g
in
new_gs
])
cdef
long
[:]
n_edges
=
np
.
array
([
g
.
density
()
for
g
in
new_gs
])
cdef
int
i
,
j
cdef
bint
[:]
selected_test
=
self
.
get_selected_array
(
selected
,
n
)
cdef
double
[:,:]
intersect_len_nodes
=
np
.
zeros
((
n
,
n
))
cdef
double
[:,:]
intersect_len_edges
=
np
.
zeros
((
n
,
n
))
cdef
double
[:,:]
union_len_nodes
=
np
.
zeros
((
n
,
n
))
cdef
double
[:,:]
union_len_edges
=
np
.
zeros
((
n
,
n
))
for
i
in
range
(
n
):
for
j
in
range
(
i
,
n
):
intersect_len_nodes
[
i
][
j
]
=
new_gs
[
i
].
size_node_intersect
(
new_gs
[
j
])
intersect_len_edges
[
i
][
j
]
=
new_gs
[
i
].
size_edge_intersect
(
new_gs
[
j
])
#len(set(hash_edges[i]).intersection(hash_edges[j]))
union_len_nodes
[
i
][
j
]
=
new_gs
[
i
].
size_node_union
(
new_gs
[
j
])
union_len_edges
[
i
][
j
]
=
new_gs
[
i
].
size_node_union
(
new_gs
[
j
])
with
nogil
,
parallel
(
num_threads
=
4
):
for
i
in
prange
(
n
,
schedule
=
'static'
):
for
j
in
range
(
i
,
n
):
if
n_nodes
[
i
]
>
0
and
n_nodes
[
j
]
>
0
and
selected_test
[
i
]:
if
union_len_edges
[
i
][
j
]
>
0
and
union_len_nodes
[
i
][
j
]
>
0
:
comparison_matrix
[
i
][
j
]
=
\
(
intersect_len_edges
[
i
][
j
]
/
union_len_edges
[
i
][
j
])
*
\
(
intersect_len_nodes
[
i
][
j
]
/
union_len_nodes
[
i
][
j
])
else
:
comparison_matrix
[
i
][
j
]
=
0.
comparison_matrix
[
j
][
i
]
=
comparison_matrix
[
i
][
j
]
return
np
.
array
(
comparison_matrix
)
gmatch4py/mcs.pyx
View file @
0ce8bd23
# coding = utf-8
import
numpy
as
np
cimport
numpy
as
np
from
.graph
cimport
Graph
from
.base
cimport
Base
from
cython.parallel
cimport
prange
,
parallel
from
..helpers.general
import
parsenx2graph
cdef
class
MCS
(
Base
):
"""
...
...
@@ -12,7 +14,7 @@ cdef class MCS(Base):
def
__init__
(
self
):
Base
.
__init__
(
self
,
0
,
True
)
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cpdef
np
.
ndarray
compare
_old
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
np
.
ndarray
comparison_matrix
=
np
.
zeros
((
n
,
n
))
for
i
in
range
(
n
):
...
...
@@ -25,6 +27,28 @@ cdef class MCS(Base):
comparison_matrix
[
i
,
j
]
=
0.
comparison_matrix
[
j
,
i
]
=
comparison_matrix
[
i
,
j
]
return
comparison_matrix
cpdef
np
.
ndarray
compare
(
self
,
list
listgs
,
list
selected
):
cdef
int
n
=
len
(
listgs
)
cdef
double
[:,:]
comparison_matrix
=
np
.
zeros
((
n
,
n
))
cdef
bint
[:]
selected_test
=
self
.
get_selected_array
(
selected
,
n
)
cdef
list
new_gs
=
parsenx2graph
(
listgs
)
cdef
long
[:]
n_nodes
=
np
.
array
([
g
.
size
()
for
g
in
new_gs
])
cdef
double
[:,:]
intersect_len_nodes
=
np
.
zeros
((
n
,
n
))
cdef
int
i
,
j
for
i
in
range
(
n
):
for
j
in
range
(
i
,
n
):
intersect_len_nodes
[
i
][
j
]
=
new_gs
[
i
].
size_node_intersect
(
new_gs
[
j
])
with
nogil
,
parallel
(
num_threads
=
4
):
for
i
in
prange
(
n
,
schedule
=
'static'
):
for
j
in
range
(
i
,
n
):
if
n_nodes
[
i
]
>
0
and
n_nodes
[
j
]
>
0
and
selected_test
[
i
]:
comparison_matrix
[
i
][
j
]
=
intersect_len_nodes
[
i
][
j
]
/
max
(
n_nodes
[
i
],
n_nodes
[
j
])
else
:
comparison_matrix
[
i
][
j
]
=
0.
comparison_matrix
[
j
][
i
]
=
comparison_matrix
[
i
][
j
]
return
np
.
array
(
comparison_matrix
)
def
s_mcs
(
self
,
G
,
H
):
"""
...
...
gmatch4py/vertex_edge_overlap.pyx
View file @
0ce8bd23
...
...
@@ -5,6 +5,7 @@ cimport numpy as np
from
.base
cimport
Base
,
intersection
from
.graph
cimport
Graph
from
cython.parallel
cimport
prange
,
parallel
from
..helpers.general
import
parsenx2graph
cdef
class
VertexEdgeOverlap
(
Base
):
...
...
@@ -18,19 +19,35 @@ cdef class VertexEdgeOverlap(Base):
def
__init__
(
self
):
Base
.
__init__
(
self
,
0
,
True
)
cpdef
np
.
ndarray
compare_old
(
self
,
list
listgs
,
list
selected
):
n
=
len
(
listgs
)