Skip to content

Commit b649298

Browse files
authored
Merge pull request #23 from jajupmochi/v0.2
V0.2
2 parents 6f0c1df + 0db57fe commit b649298

13 files changed

+3700
-71
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""
4+
Created on Thu Jun 25 11:31:46 2020
5+
6+
@author: ljia
7+
"""
8+
9+
def xp_check_results_of_GEDEnv():
10+
"""Compare results of GEDEnv to GEDLIB.
11+
"""
12+
"""**1. Get dataset.**"""
13+
14+
from gklearn.utils import Dataset
15+
16+
# Predefined dataset name, use dataset "MUTAG".
17+
ds_name = 'MUTAG'
18+
19+
# Initialize a Dataset.
20+
dataset = Dataset()
21+
# Load predefined dataset "MUTAG".
22+
dataset.load_predefined_dataset(ds_name)
23+
24+
results1 = compute_geds_by_GEDEnv(dataset)
25+
results2 = compute_geds_by_GEDLIB(dataset)
26+
27+
# Show results.
28+
import pprint
29+
pp = pprint.PrettyPrinter(indent=4) # pretty print
30+
print('Restuls using GEDEnv:')
31+
pp.pprint(results1)
32+
print()
33+
print('Restuls using GEDLIB:')
34+
pp.pprint(results2)
35+
36+
return results1, results2
37+
38+
39+
def compute_geds_by_GEDEnv(dataset):
40+
from gklearn.ged.env import GEDEnv
41+
import numpy as np
42+
43+
graph1 = dataset.graphs[0]
44+
graph2 = dataset.graphs[1]
45+
46+
ged_env = GEDEnv() # initailize GED environment.
47+
ged_env.set_edit_cost('CONSTANT', # GED cost type.
48+
edit_cost_constants=[3, 3, 1, 3, 3, 1] # edit costs.
49+
)
50+
for g in dataset.graphs[0:10]:
51+
ged_env.add_nx_graph(g, '')
52+
# ged_env.add_nx_graph(graph1, '') # add graph1
53+
# ged_env.add_nx_graph(graph2, '') # add graph2
54+
listID = ged_env.get_all_graph_ids() # get list IDs of graphs
55+
ged_env.init(init_type='LAZY_WITHOUT_SHUFFLED_COPIES') # initialize GED environment.
56+
options = {'threads': 1 # parallel threads.
57+
}
58+
ged_env.set_method('BIPARTITE', # GED method.
59+
options # options for GED method.
60+
)
61+
ged_env.init_method() # initialize GED method.
62+
63+
ged_mat = np.empty((10, 10))
64+
for i in range(0, 10):
65+
for j in range(i, 10):
66+
ged_env.run_method(i, j) # run.
67+
ged_mat[i, j] = ged_env.get_upper_bound(i, j)
68+
ged_mat[j, i] = ged_mat[i, j]
69+
70+
results = {}
71+
results['pi_forward'] = ged_env.get_forward_map(listID[0], listID[1]) # forward map.
72+
results['pi_backward'] = ged_env.get_backward_map(listID[0], listID[1]) # backward map.
73+
results['upper_bound'] = ged_env.get_upper_bound(listID[0], listID[1]) # GED bewteen two graphs.
74+
results['runtime'] = ged_env.get_runtime(listID[0], listID[1])
75+
results['init_time'] = ged_env.get_init_time()
76+
results['ged_mat'] = ged_mat
77+
78+
return results
79+
80+
81+
def compute_geds_by_GEDLIB(dataset):
82+
from gklearn.gedlib import librariesImport, gedlibpy
83+
from gklearn.ged.util import ged_options_to_string
84+
import numpy as np
85+
86+
graph1 = dataset.graphs[5]
87+
graph2 = dataset.graphs[6]
88+
89+
ged_env = gedlibpy.GEDEnv() # initailize GED environment.
90+
ged_env.set_edit_cost('CONSTANT', # GED cost type.
91+
edit_cost_constant=[3, 3, 1, 3, 3, 1] # edit costs.
92+
)
93+
# ged_env.add_nx_graph(graph1, '') # add graph1
94+
# ged_env.add_nx_graph(graph2, '') # add graph2
95+
for g in dataset.graphs[0:10]:
96+
ged_env.add_nx_graph(g, '')
97+
listID = ged_env.get_all_graph_ids() # get list IDs of graphs
98+
ged_env.init(init_option='LAZY_WITHOUT_SHUFFLED_COPIES') # initialize GED environment.
99+
options = {'initialization-method': 'RANDOM', # or 'NODE', etc.
100+
'threads': 1 # parallel threads.
101+
}
102+
ged_env.set_method('BIPARTITE', # GED method.
103+
ged_options_to_string(options) # options for GED method.
104+
)
105+
ged_env.init_method() # initialize GED method.
106+
107+
ged_mat = np.empty((10, 10))
108+
for i in range(0, 10):
109+
for j in range(i, 10):
110+
ged_env.run_method(i, j) # run.
111+
ged_mat[i, j] = ged_env.get_upper_bound(i, j)
112+
ged_mat[j, i] = ged_mat[i, j]
113+
114+
results = {}
115+
results['pi_forward'] = ged_env.get_forward_map(listID[0], listID[1]) # forward map.
116+
results['pi_backward'] = ged_env.get_backward_map(listID[0], listID[1]) # backward map.
117+
results['upper_bound'] = ged_env.get_upper_bound(listID[0], listID[1]) # GED bewteen two graphs.
118+
results['runtime'] = ged_env.get_runtime(listID[0], listID[1])
119+
results['init_time'] = ged_env.get_init_time()
120+
results['ged_mat'] = ged_mat
121+
122+
return results
123+
124+
125+
if __name__ == '__main__':
126+
results1, results2 = xp_check_results_of_GEDEnv()

gklearn/ged/env/ged_data.py

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ def __init__(self):
2323
self._edit_cost = None
2424
self._node_costs = None
2525
self._edge_costs = None
26+
self._node_label_costs = None
27+
self._edge_label_costs = None
2628
self._node_labels = []
2729
self._edge_labels = []
2830
self._init_type = Options.InitType.EAGER_WITHOUT_SHUFFLED_COPIES
@@ -41,6 +43,17 @@ def num_graphs(self):
4143
return len(self._graphs)
4244

4345

46+
def graph(self, graph_id):
47+
"""
48+
/*!
49+
* @brief Provides access to a graph.
50+
* @param[in] graph_id The ID of the graph.
51+
* @return Constant reference to the graph with ID @p graph_id.
52+
*/
53+
"""
54+
return self._graphs[graph_id]
55+
56+
4457
def shuffled_graph_copies_available(self):
4558
"""
4659
/*!
@@ -51,6 +64,16 @@ def shuffled_graph_copies_available(self):
5164
return (self._init_type == Options.InitType.EAGER_WITH_SHUFFLED_COPIES or self._init_type == Options.InitType.LAZY_WITH_SHUFFLED_COPIES)
5265

5366

67+
def num_graphs_without_shuffled_copies(self):
68+
"""
69+
/*!
70+
* @brief Returns the number of graphs in the instance without the shuffled copies.
71+
* @return Number of graphs without shuffled copies contained in the instance.
72+
*/
73+
"""
74+
return self._num_graphs_without_shuffled_copies
75+
76+
5477
def node_cost(self, label1, label2):
5578
"""
5679
/*!
@@ -63,15 +86,21 @@ def node_cost(self, label1, label2):
6386
* and 0 otherwise.
6487
*/
6588
"""
66-
if self._eager_init(): # @todo: check if correct
67-
return self._node_costs[label1, label2]
68-
if label1 == label2:
69-
return 0
70-
if label1 == SpecialLabel.DUMMY: # @todo: check dummy
71-
return self._edit_cost.node_ins_cost_fun(label2) # self._node_labels[label2 - 1]) # @todo: check
72-
if label2 == SpecialLabel.DUMMY: # @todo: check dummy
73-
return self._edit_cost.node_del_cost_fun(label1) # self._node_labels[label1 - 1])
74-
return self._edit_cost.node_rel_cost_fun(label1, label2) # self._node_labels[label1 - 1], self._node_labels[label2 - 1])
89+
if self._node_label_costs is None:
90+
if self._eager_init(): # @todo: check if correct
91+
return self._node_costs[label1, label2]
92+
if label1 == label2:
93+
return 0
94+
if label1 == SpecialLabel.DUMMY: # @todo: check dummy
95+
return self._edit_cost.node_ins_cost_fun(label2) # self._node_labels[label2 - 1]) # @todo: check
96+
if label2 == SpecialLabel.DUMMY: # @todo: check dummy
97+
return self._edit_cost.node_del_cost_fun(label1) # self._node_labels[label1 - 1])
98+
return self._edit_cost.node_rel_cost_fun(label1, label2) # self._node_labels[label1 - 1], self._node_labels[label2 - 1])
99+
# use pre-computed node label costs.
100+
else:
101+
id1 = 0 if label1 == SpecialLabel.DUMMY else self._node_label_to_id(label1) # @todo: this is slow.
102+
id2 = 0 if label2 == SpecialLabel.DUMMY else self._node_label_to_id(label2)
103+
return self._node_label_costs[id1, id2]
75104

76105

77106
def edge_cost(self, label1, label2):
@@ -86,15 +115,22 @@ def edge_cost(self, label1, label2):
86115
* and 0 otherwise.
87116
*/
88117
"""
89-
if self._eager_init(): # @todo: check if correct
90-
return self._node_costs[label1, label2]
91-
if label1 == label2:
92-
return 0
93-
if label1 == SpecialLabel.DUMMY:
94-
return self._edit_cost.edge_ins_cost_fun(label2) # self._edge_labels[label2 - 1])
95-
if label2 == SpecialLabel.DUMMY:
96-
return self._edit_cost.edge_del_cost_fun(label1) # self._edge_labels[label1 - 1])
97-
return self._edit_cost.edge_rel_cost_fun(label1, label2) # self._edge_labels[label1 - 1], self._edge_labels[label2 - 1])
118+
if self._edge_label_costs is None:
119+
if self._eager_init(): # @todo: check if correct
120+
return self._node_costs[label1, label2]
121+
if label1 == label2:
122+
return 0
123+
if label1 == SpecialLabel.DUMMY:
124+
return self._edit_cost.edge_ins_cost_fun(label2) # self._edge_labels[label2 - 1])
125+
if label2 == SpecialLabel.DUMMY:
126+
return self._edit_cost.edge_del_cost_fun(label1) # self._edge_labels[label1 - 1])
127+
return self._edit_cost.edge_rel_cost_fun(label1, label2) # self._edge_labels[label1 - 1], self._edge_labels[label2 - 1])
128+
129+
# use pre-computed edge label costs.
130+
else:
131+
id1 = 0 if label1 == SpecialLabel.DUMMY else self._edge_label_to_id(label1) # @todo: this is slow.
132+
id2 = 0 if label2 == SpecialLabel.DUMMY else self._edge_label_to_id(label2)
133+
return self._edge_label_costs[id1, id2]
98134

99135

100136
def compute_induced_cost(self, g, h, node_map):
@@ -177,5 +213,37 @@ def _set_edit_cost(self, edit_cost, edit_cost_constants):
177213
self._delete_edit_cost = True
178214

179215

216+
def id_to_node_label(self, label_id):
217+
if label_id > len(self._node_labels) or label_id == 0:
218+
raise Exception('Invalid node label ID', str(label_id), '.')
219+
return self._node_labels[label_id - 1]
220+
221+
222+
def _node_label_to_id(self, node_label):
223+
n_id = 0
224+
for n_l in self._node_labels:
225+
if n_l == node_label:
226+
return n_id + 1
227+
n_id += 1
228+
self._node_labels.append(node_label)
229+
return n_id + 1
230+
231+
232+
def id_to_edge_label(self, label_id):
233+
if label_id > len(self._edge_labels) or label_id == 0:
234+
raise Exception('Invalid edge label ID', str(label_id), '.')
235+
return self._edge_labels[label_id - 1]
236+
237+
238+
def _edge_label_to_id(self, edge_label):
239+
e_id = 0
240+
for e_l in self._edge_labels:
241+
if e_l == edge_label:
242+
return e_id + 1
243+
e_id += 1
244+
self._edge_labels.append(edge_label)
245+
return e_id + 1
246+
247+
180248
def _eager_init(self):
181249
return (self._init_type == Options.InitType.EAGER_WITHOUT_SHUFFLED_COPIES or self._init_type == Options.InitType.EAGER_WITH_SHUFFLED_COPIES)

0 commit comments

Comments
 (0)