Merge lp:~nicholas-dahm/igraph/compat-fn into lp:~igraph/igraph/0.6-main-old

Proposed by Nicholas Dahm
Status: Merged
Merged at revision: 2762
Proposed branch: lp:~nicholas-dahm/igraph/compat-fn
Merge into: lp:~igraph/igraph/0.6-main-old
Diff against target: 818 lines (+297/-58)
5 files modified
examples/simple/igraph_isomorphic_vf2.c (+15/-15)
examples/simple/igraph_lcf.c (+1/-1)
include/igraph_topology.h (+60/-12)
interfaces/R/src/config.h.in (+3/-0)
src/topology.c (+218/-30)
To merge this branch: bzr merge lp:~nicholas-dahm/igraph/compat-fn
Reviewer Review Type Date Requested Status
Gábor Csárdi Approve
Nicholas Dahm (community) Needs Fixing
Review via email: mp+100732@code.launchpad.net

Description of the change

Added functionality to use custom node and edge checking functions when performing (sub)isomorphism operations using the VF2 algorithm.

To post a comment you must log in.
Revision history for this message
Nicholas Dahm (nicholas-dahm) wrote :

This is the updated version. I believe it is bug free and ready for merge. I have done my best to keep the documentation updated with these changes.

Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

Thanks Nick, this looks very nice. The only thing I would like to change is the handling of extra argument(s). For other igraph functions with callbacks this is just a void* and then it is up to the callback to do whatever it wants with it. So I think it would be better to have the same here.

Could you please check that 'make check' is clean. Maybe there are no tests at all for the VF2 functions, so nothing can go wrong here....

Thanks again!

review: Needs Fixing
Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

Btw. if you don't want to change the extra argument, I can do that, too. If you can do it, that is even better. :)

Revision history for this message
Nicholas Dahm (nicholas-dahm) wrote :

Gabor. I'm not sure you got my emails regarding this, but a decision needs to be made regarding the extra argument. The reason is that we are passing in [up to] 3 functions now, so technically there would be 3 arguments. This is why, after consulting with Tamas, I packaged the 3 args into a struct for ease of use. If you prefer to have 3 separate args, or want me to pack each function with an arg or anything like this, just let me know and I'll do it.

I'm going to propose this again, just so that you definitely get this message. Please don't take this as impatience on my part :)

review: Needs Resubmitting
Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

I think it is simpler to have just _one_ void* arg, and this is passed to all three functions. Then in the callback you can cast it to whatever you like, even a struct with three members if that's what you like. It is largely a matter of taste, but this is how it was done in other igraph functions.

Another small comment. Please try to avoid commit messages like 'misc', these are not very helpful. If it is really 'misc', then you might split it to multiple commits. You can use the 'bzr shelve' command to temporarily shelve part(s) of the modifications of the file, and then 'bzr unshelve' to get it back.

Anyway, I'll merge this today or tomorrow, and will change the extra argument.

Thanks again for the code!

Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

Btw. make check fails for some test cases.

Revision history for this message
Nicholas Dahm (nicholas-dahm) wrote :

The problem with using one void* arg and passing that to all callback functions is that some isomorphism functions have more callback functions than others, so the callback function can't know how many args are packed and which one they can use. I think it would be better to let the isomorphism functions take a void* arg which is then casted to a void** arg and then passes the correct arg[x] (where arg[x] is type void*) to the callback. This would also help keep the callback functions simple. This is what I came up with while consulting to Tamas, and he suggested to change it to the struct for readability. I'm happy to switch it back to void*'s if you prefer, just let me know.

Apologies about the misc commits. These were generally from when I save my work from one PC when going to another. I will try to make better comments for these in future.

review: Needs Fixing
Revision history for this message
Nicholas Dahm (nicholas-dahm) wrote :

Yes sorry I had forgotten about make check. I will check and fix these now.

Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

You can leave the struct for the extra argument, I'll see what I'll do with it.

Fixing 'make check' is not big deal, just need to update the function calls that have a new signature.

lp:~nicholas-dahm/igraph/compat-fn updated
2642. By Nicholas Dahm

fixed make checks for vf2

Revision history for this message
Nicholas Dahm (nicholas-dahm) wrote :

I fixed the make checks regarding vf2. There are still 2 failing checks regarding scg, but I can't see how they are related or understand what's wrong with these.

Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

The SCG checks are unrelated. Thanks!

Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

I have merged this in revision #2762 (0.6-main).

review: Approve
Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

Three more comments.

1 I eliminated the struct for the extra arguments, it is just a void* now everywhere.
2 It is useful to write a test case for a new functionality, see #2762.
3 From the test case it turns out quickly, that the edge-compatibility functions were never called, I have fixed this.

Thanks again for your code!

Revision history for this message
Nicholas Dahm (nicholas-dahm) wrote :

Thanks for doing that, I will write test cases in future :)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/simple/igraph_isomorphic_vf2.c'
2--- examples/simple/igraph_isomorphic_vf2.c 2012-05-20 02:19:29 +0000
3+++ examples/simple/igraph_isomorphic_vf2.c 2012-05-23 04:31:20 +0000
4@@ -61,7 +61,7 @@
5 }
6
7 /* Without colors, number of isomorphisms */
8- igraph_count_isomorphisms_vf2(&ring1, &ring2, 0, 0, 0, 0, &count);
9+ igraph_count_isomorphisms_vf2(&ring1, &ring2, 0, 0, 0, 0, &count, 0, 0, 0);
10 if (count != 200) {
11 fprintf(stderr, "Count without colors failed, expected %li, got %li.\n",
12 (long int) 200, (long int) count);
13@@ -71,7 +71,7 @@
14 /* Everything has the same colors */
15 igraph_vector_int_init(&color1, igraph_vcount(&ring1));
16 igraph_vector_int_init(&color2, igraph_vcount(&ring2));
17- igraph_isomorphic_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &iso, 0, 0);
18+ igraph_isomorphic_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &iso, 0, 0, 0, 0, 0);
19 if (!iso) {
20 fprintf(stderr, "Single color failed.\n");
21 return 3;
22@@ -82,7 +82,7 @@
23 VECTOR(color1)[i] = VECTOR(color2)[i] = 0;
24 VECTOR(color1)[i+1] = VECTOR(color2)[i] = 1;
25 }
26- igraph_count_isomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &count);
27+ igraph_count_isomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &count, 0, 0, 0);
28 if (count != 100) {
29 fprintf(stderr, "Count with two colors failed, expected %li, got %li.\n",
30 (long int) 100, (long int) count);
31@@ -93,7 +93,7 @@
32 for (i=0; i<igraph_vector_int_size(&color1); i++) {
33 VECTOR(color1)[i] = VECTOR(color2)[i] = i;
34 }
35- igraph_count_isomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &count);
36+ igraph_count_isomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &count, 0, 0, 0);
37 if (count != 1) {
38 fprintf(stderr, "Count with separate colors failed, expected %li, got %li.\n",
39 (long int) 1, (long int) count);
40@@ -104,7 +104,7 @@
41 igraph_vector_int_fill(&color1, 0);
42 igraph_vector_int_fill(&color2, 0);
43 VECTOR(color1)[0]=1;
44- igraph_isomorphic_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &iso, 0, 0);
45+ igraph_isomorphic_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &iso, 0, 0, 0, 0, 0);
46 if (iso) {
47 fprintf(stderr, "Negative test failed.\n");
48 return 6;
49@@ -115,7 +115,7 @@
50 igraph_vector_int_fill(&color2, 0);
51 VECTOR(color1)[0]=1; VECTOR(color1)[1]=1;
52 VECTOR(color2)[0]=1; VECTOR(color2)[2]=1;
53- igraph_isomorphic_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &iso, 0, 0);
54+ igraph_isomorphic_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &iso, 0, 0, 0, 0, 0);
55 if (iso) {
56 fprintf(stderr, "Second negative test failed.\n");
57 return 7;
58@@ -139,7 +139,7 @@
59 igraph_vector_int_init(&color1, igraph_vcount(&ring1));
60 igraph_vector_int_init(&color2, igraph_vcount(&ring2));
61 igraph_count_subisomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0,
62- &count);
63+ &count, 0, 0, 0);
64 if (count != 42) {
65 fprintf(stderr, "Count with one color failed, expected %li, got %li.\n",
66 (long int) 42, (long int) count);
67@@ -156,7 +156,7 @@
68 VECTOR(color2)[i+1] = 1;
69 }
70 igraph_count_subisomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0,
71- &count);
72+ &count, 0, 0, 0);
73 if (count != 21) {
74 fprintf(stderr, "Count with two colors failed, expected %li, got %li.\n",
75 (long int) 21, (long int) count);
76@@ -182,7 +182,7 @@
77 /* Everything has the same color */
78 igraph_vector_int_init(&color1, igraph_ecount(&ring1));
79 igraph_vector_int_init(&color2, igraph_ecount(&ring2));
80- igraph_isomorphic_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &iso, 0, 0);
81+ igraph_isomorphic_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &iso, 0, 0, 0, 0, 0);
82 if (!iso) {
83 fprintf(stderr, "Single edge-color failed.\n");
84 return 41;
85@@ -193,7 +193,7 @@
86 VECTOR(color1)[i] = VECTOR(color2)[i] = 0;
87 VECTOR(color1)[i+1] = VECTOR(color2)[i] = 1;
88 }
89- igraph_count_isomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &count);
90+ igraph_count_isomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &count, 0, 0, 0);
91 if (count != 100) {
92 fprintf(stderr, "Count with two edge colors failed, expected %li, got %li.\n",
93 (long int) 100, (long int) count);
94@@ -204,7 +204,7 @@
95 for (i=0; i<igraph_vector_int_size(&color1); i++) {
96 VECTOR(color1)[i] = VECTOR(color2)[i] = i;
97 }
98- igraph_count_isomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &count);
99+ igraph_count_isomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &count, 0, 0, 0);
100 if (count != 1) {
101 fprintf(stderr, "Count with separate edge colors failed, expected %li, got %li.\n",
102 (long int) 1, (long int) count);
103@@ -215,7 +215,7 @@
104 igraph_vector_int_fill(&color1, 0);
105 igraph_vector_int_fill(&color2, 0);
106 VECTOR(color1)[0]=1;
107- igraph_isomorphic_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &iso, 0, 0);
108+ igraph_isomorphic_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &iso, 0, 0, 0, 0, 0);
109 if (iso) {
110 fprintf(stderr, "Negative edge test failed.\n");
111 return 44;
112@@ -226,7 +226,7 @@
113 igraph_vector_int_fill(&color2, 0);
114 VECTOR(color1)[0]=1; VECTOR(color1)[1]=1;
115 VECTOR(color2)[0]=1; VECTOR(color2)[2]=1;
116- igraph_isomorphic_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &iso, 0, 0);
117+ igraph_isomorphic_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &iso, 0, 0, 0, 0, 0);
118 if (iso) {
119 fprintf(stderr, "Second negative edge test failed.\n");
120 return 45;
121@@ -249,7 +249,7 @@
122 igraph_vector_int_init(&color1, igraph_ecount(&ring1));
123 igraph_vector_int_init(&color2, igraph_ecount(&ring2));
124 igraph_count_subisomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2,
125- &count);
126+ &count, 0, 0, 0);
127 if (count != 42) {
128 fprintf(stderr, "Count with one edge color failed, expected %li, got %li.\n",
129 (long int) 42, (long int) count);
130@@ -266,7 +266,7 @@
131 VECTOR(color2)[i+1] = 1;
132 }
133 igraph_count_subisomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2,
134- &count);
135+ &count, 0, 0, 0);
136 if (count != 22) {
137 fprintf(stderr, "Count with two edge colors failed, expected %li, got %li.\n",
138 (long int) 22, (long int) count);
139
140=== modified file 'examples/simple/igraph_lcf.c'
141--- examples/simple/igraph_lcf.c 2012-05-20 02:19:29 +0000
142+++ examples/simple/igraph_lcf.c 2012-05-23 04:31:20 +0000
143@@ -34,7 +34,7 @@
144 igraph_isomorphic_vf2(&g, &g2,
145 /*vertex.color1=*/ 0, /*vertex.color2=*/ 0,
146 /*edge.color1=*/ 0, /*edge.color2=*/ 0,
147- &iso, 0, 0);
148+ &iso, 0, 0, 0, 0, 0);
149 if (!iso) {
150 printf("OOOPS!\n");
151 return 1;
152
153=== modified file 'include/igraph_topology.h'
154--- include/igraph_topology.h 2012-05-20 02:19:29 +0000
155+++ include/igraph_topology.h 2012-05-23 04:31:20 +0000
156@@ -73,45 +73,85 @@
157 * igraph_isomorphic_function_vf2() when it was called.
158 * \return Boolean, whether to continue with the isomorphism search.
159 */
160+
161+
162 typedef igraph_bool_t igraph_isohandler_t(const igraph_vector_t *map12,
163 const igraph_vector_t *map21, void *arg);
164
165+typedef igraph_bool_t igraph_isocompat_t(const igraph_t *graph1,
166+ const igraph_t *graph2,
167+ const igraph_integer_t g1_num,
168+ const igraph_integer_t g2_num,
169+ void *arg);
170+
171+/**
172+ * \struct igraph_isomorphic_function_vf2_args_t
173+ * Information about a BLISS run
174+ * Parameter bundle to be used for different subfunctions of vf2 algorithms.
175+ *
176+ * \member isohandler_fn_arg Argument passed through to isohandler_fn
177+ * \member node_compat_fn_arg Argument passed through to node_compat_fn
178+ * \member edge_compat_fn_arg Argument passed through to edge_compat_fn
179+ */
180+
181+typedef struct{
182+ void *isohandler_fn_arg;
183+ void *node_compat_fn_arg;
184+ void *edge_compat_fn_arg;
185+} igraph_isomorphic_function_vf2_args_t;
186+
187 int igraph_isomorphic_vf2(const igraph_t *graph1, const igraph_t *graph2,
188 const igraph_vector_int_t *vertex_color1,
189 const igraph_vector_int_t *vertex_color2,
190 const igraph_vector_int_t *edge_color1,
191 const igraph_vector_int_t *edge_color2,
192- igraph_bool_t *iso, igraph_vector_t *map12,
193- igraph_vector_t *map21);
194+ igraph_bool_t *iso,
195+ igraph_vector_t *map12,
196+ igraph_vector_t *map21,
197+ igraph_isocompat_t *node_compat_fn,
198+ igraph_isocompat_t *edge_compat_fn,
199+ igraph_isomorphic_function_vf2_args_t *args);
200 int igraph_isomorphic_function_vf2(const igraph_t *graph1, const igraph_t *graph2,
201 const igraph_vector_int_t *vertex_color1,
202 const igraph_vector_int_t *vertex_color2,
203 const igraph_vector_int_t *edge_color1,
204 const igraph_vector_int_t *edge_color2,
205 igraph_vector_t *map12, igraph_vector_t *map21,
206- igraph_isohandler_t *function,
207- void *arg);
208+ igraph_isohandler_t *isohandler_fn,
209+ igraph_isocompat_t *node_compat_fn,
210+ igraph_isocompat_t *edge_compat_fn,
211+ igraph_isomorphic_function_vf2_args_t *args);
212 int igraph_count_isomorphisms_vf2(const igraph_t *graph1, const igraph_t *graph2,
213 const igraph_vector_int_t *vertex_color1,
214 const igraph_vector_int_t *vertex_color2,
215 const igraph_vector_int_t *edge_color1,
216 const igraph_vector_int_t *edge_color2,
217- igraph_integer_t *count);
218+ igraph_integer_t *count,
219+ igraph_isocompat_t *node_compat_fn,
220+ igraph_isocompat_t *edge_compat_fn,
221+ igraph_isomorphic_function_vf2_args_t *args);
222 int igraph_get_isomorphisms_vf2(const igraph_t *graph1,
223 const igraph_t *graph2,
224 const igraph_vector_int_t *vertex_color1,
225 const igraph_vector_int_t *vertex_color2,
226 const igraph_vector_int_t *edge_color1,
227 const igraph_vector_int_t *edge_color2,
228- igraph_vector_ptr_t *maps);
229+ igraph_vector_ptr_t *maps,
230+ igraph_isocompat_t *node_compat_fn,
231+ igraph_isocompat_t *edge_compat_fn,
232+ igraph_isomorphic_function_vf2_args_t *args);
233
234 int igraph_subisomorphic_vf2(const igraph_t *graph1, const igraph_t *graph2,
235 const igraph_vector_int_t *vertex_color1,
236 const igraph_vector_int_t *vertex_color2,
237 const igraph_vector_int_t *edge_color1,
238 const igraph_vector_int_t *edge_color2,
239- igraph_bool_t *iso, igraph_vector_t *map12,
240- igraph_vector_t *map21);
241+ igraph_bool_t *iso,
242+ igraph_vector_t *map12,
243+ igraph_vector_t *map21,
244+ igraph_isocompat_t *node_compat_fn,
245+ igraph_isocompat_t *edge_compat_fn,
246+ igraph_isomorphic_function_vf2_args_t *args);
247 int igraph_subisomorphic_function_vf2(const igraph_t *graph1,
248 const igraph_t *graph2,
249 const igraph_vector_int_t *vertex_color1,
250@@ -120,21 +160,29 @@
251 const igraph_vector_int_t *edge_color2,
252 igraph_vector_t *map12,
253 igraph_vector_t *map21,
254- igraph_isohandler_t *function,
255- void *arg);
256+ igraph_isohandler_t *isohandler_fn,
257+ igraph_isocompat_t *node_compat_fn,
258+ igraph_isocompat_t *edge_compat_fn,
259+ igraph_isomorphic_function_vf2_args_t *args);
260 int igraph_count_subisomorphisms_vf2(const igraph_t *graph1, const igraph_t *graph2,
261 const igraph_vector_int_t *vertex_color1,
262 const igraph_vector_int_t *vertex_color2,
263 const igraph_vector_int_t *edge_color1,
264 const igraph_vector_int_t *edge_color2,
265- igraph_integer_t *count);
266+ igraph_integer_t *count,
267+ igraph_isocompat_t *node_compat_fn,
268+ igraph_isocompat_t *edge_compat_fn,
269+ igraph_isomorphic_function_vf2_args_t *args);
270 int igraph_get_subisomorphisms_vf2(const igraph_t *graph1,
271 const igraph_t *graph2,
272 const igraph_vector_int_t *vertex_color1,
273 const igraph_vector_int_t *vertex_color2,
274 const igraph_vector_int_t *edge_color1,
275 const igraph_vector_int_t *edge_color2,
276- igraph_vector_ptr_t *maps);
277+ igraph_vector_ptr_t *maps,
278+ igraph_isocompat_t *node_compat_fn,
279+ igraph_isocompat_t *edge_compat_fn,
280+ igraph_isomorphic_function_vf2_args_t *args);
281
282 /* BLISS family */
283 /**
284
285=== modified file 'interfaces/R/src/config.h.in'
286--- interfaces/R/src/config.h.in 2012-02-21 02:43:45 +0000
287+++ interfaces/R/src/config.h.in 2012-05-23 04:31:20 +0000
288@@ -84,6 +84,9 @@
289 /* Define to the one symbol short name of this package. */
290 #undef PACKAGE_TARNAME
291
292+/* Define to the home page for this package. */
293+#undef PACKAGE_URL
294+
295 /* Define to the version of this package. */
296 #undef PACKAGE_VERSION
297
298
299=== modified file 'src/topology.c'
300--- src/topology.c 2012-05-20 02:19:29 +0000
301+++ src/topology.c 2012-05-23 04:31:20 +0000
302@@ -794,7 +794,7 @@
303 } else if (nodes1==3 || nodes1==4) {
304 igraph_isomorphic_34(graph1, graph2, iso);
305 } else if (dir1) {
306- igraph_isomorphic_vf2(graph1, graph2, 0, 0, 0, 0, iso, 0, 0);
307+ igraph_isomorphic_vf2(graph1, graph2, 0, 0, 0, 0, iso, 0, 0, 0, 0, 0);
308 } else {
309 igraph_isomorphic_bliss(graph1, graph2, iso, 0, 0, /*sh1=*/0, /*sh2=*/0, 0, 0);
310 }
311@@ -1042,11 +1042,17 @@
312 * graphs are not isomorphic then a zero-length vector is returned.
313 * \param map21 This is the same as \p map12, but for the permutation
314 * taking \p graph2 to \p graph1.
315- * \param function The callback function to be called if an
316+ * \param isohandler_fn The callback function to be called if an
317 * isomorphism is found. See also \ref igraph_isohandler_t.
318- * \param arg An extra argument to pass to \p function. E.g. if \p
319- * function needs to store the isomorphisms found, then \p arg may
320- * point to a container for them.
321+ * \param node_compat_fn A pointer to a function of type \ref
322+ * igraph_isocompat_t. This function will be called by the algorithm to
323+ * determine whether two nodes are compatible.
324+ * \param edge_compat_fn A pointer to a function of type \ref
325+ * igraph_isocompat_t. This function will be called by the algorithm to
326+ * determine whether two edges are compatible.
327+ * \param args Extra arguments to supply to functions \p isohandler_fn, \p
328+ * node_compat_fn, \p edge_compat_fn. These arguments are packed into an
329+ * \ref igraph_isomorphic_function_vf2_args_t struct.
330 * \return Error code.
331 *
332 * Time complexity: exponential.
333@@ -1059,8 +1065,10 @@
334 const igraph_vector_int_t *edge_color2,
335 igraph_vector_t *map12,
336 igraph_vector_t *map21,
337- igraph_isohandler_t *function,
338- void *arg) {
339+ igraph_isohandler_t *isohandler_fn,
340+ igraph_isocompat_t *node_compat_fn,
341+ igraph_isocompat_t *edge_compat_fn,
342+ igraph_isomorphic_function_vf2_args_t *args) {
343
344 long int no_of_nodes=igraph_vcount(graph1);
345 long int no_of_edges=igraph_ecount(graph1);
346@@ -1075,6 +1083,14 @@
347 igraph_stack_t path;
348 igraph_lazy_adjlist_t inadj1, inadj2, outadj1, outadj2;
349 igraph_vector_t indeg1, indeg2, outdeg1, outdeg2;
350+ void *isohandler_fn_arg = 0;
351+ void *node_compat_fn_arg = 0;
352+ void *edge_compat_fn_arg = 0;
353+ if (args) {
354+ isohandler_fn_arg = args->isohandler_fn_arg;
355+ node_compat_fn_arg = args->node_compat_fn_arg;
356+ edge_compat_fn_arg = args->edge_compat_fn_arg;
357+ }
358
359 if (igraph_is_directed(graph1) != igraph_is_directed(graph2)) {
360 IGRAPH_ERROR("Cannot compare directed and undirected graphs",
361@@ -1347,6 +1363,9 @@
362 if (vertex_color1 && VECTOR(*vertex_color1)[cand1] != VECTOR(*vertex_color2)[cand2]) {
363 end=1;
364 }
365+ if (node_compat_fn && !node_compat_fn(graph1, graph2, cand1, cand2, node_compat_fn_arg)) {
366+ end=1;
367+ }
368
369 for (i=0; !end && i<igraph_vector_size(inneis_1); i++) {
370 long int node=VECTOR(*inneis_1)[i];
371@@ -1365,6 +1384,9 @@
372 VECTOR(*edge_color2)[(long int)eid2]) {
373 end=1;
374 }
375+ if (edge_compat_fn && !edge_compat_fn(graph1, graph2, eid1, eid2, edge_compat_fn_arg)) {
376+ end=1;
377+ }
378 }
379 } else {
380 if (VECTOR(in_1)[node] != 0) {
381@@ -1392,6 +1414,9 @@
382 VECTOR(*edge_color2)[(long int)eid2]) {
383 end=1;
384 }
385+ if (edge_compat_fn && !edge_compat_fn(graph1, graph2, eid1, eid2, edge_compat_fn_arg)) {
386+ end=1;
387+ }
388 }
389 } else {
390 if (VECTOR(in_1)[node] != 0) {
391@@ -1419,6 +1444,9 @@
392 VECTOR(*edge_color2)[(long int)eid2]) {
393 end=1;
394 }
395+ if (edge_compat_fn && !edge_compat_fn(graph1, graph2, eid1, eid2, edge_compat_fn_arg)) {
396+ end=1;
397+ }
398 }
399 } else {
400 if (VECTOR(in_2)[node] != 0) {
401@@ -1446,6 +1474,9 @@
402 VECTOR(*edge_color2)[(long int)eid2]) {
403 end=1;
404 }
405+ if (edge_compat_fn && !edge_compat_fn(graph1, graph2, eid1, eid2, edge_compat_fn_arg)) {
406+ end=1;
407+ }
408 }
409 } else {
410 if (VECTOR(in_2)[node] != 0) {
411@@ -1520,8 +1551,8 @@
412
413 }
414
415- if (matched_nodes==no_of_nodes && function) {
416- if (!function(core_1, core_2, arg)) {
417+ if (matched_nodes==no_of_nodes && isohandler_fn) {
418+ if (!isohandler_fn(core_1, core_2, isohandler_fn_arg)) {
419 break;
420 }
421 }
422@@ -1600,6 +1631,15 @@
423 * a NULL pointer then the mapping from \p graph2 to \p graph1 is
424 * stored here. If the graphs are not isomorphic then the vector is
425 * cleared (ie. has zero elements).
426+ * \param node_compat_fn A pointer to a function of type \ref
427+ * igraph_isocompat_t. This function will be called by the algorithm to
428+ * determine whether two nodes are compatible.
429+ * \param edge_compat_fn A pointer to a function of type \ref
430+ * igraph_isocompat_t. This function will be called by the algorithm to
431+ * determine whether two edges are compatible.
432+ * \param args Extra arguments to supply to functions \p isohandler_fn, \p
433+ * node_compat_fn, \p edge_compat_fn. These arguments are packed into an
434+ * \ref igraph_isomorphic_function_vf2_args_t struct.
435 * \return Error code.
436 *
437 * \sa \ref igraph_subisomorphic_vf2(),
438@@ -1617,8 +1657,19 @@
439 const igraph_vector_int_t *edge_color1,
440 const igraph_vector_int_t *edge_color2,
441 igraph_bool_t *iso, igraph_vector_t *map12,
442- igraph_vector_t *map21) {
443+ igraph_vector_t *map21,
444+ igraph_isocompat_t *node_compat_fn,
445+ igraph_isocompat_t *edge_compat_fn,
446+ igraph_isomorphic_function_vf2_args_t *args) {
447
448+ igraph_isomorphic_function_vf2_args_t newargs;
449+ newargs.isohandler_fn_arg = iso;
450+ newargs.node_compat_fn_arg = 0;
451+ newargs.edge_compat_fn_arg = 0;
452+ if (args) {
453+ newargs.node_compat_fn_arg = args->node_compat_fn_arg;
454+ newargs.edge_compat_fn_arg = args->edge_compat_fn_arg;
455+ }
456 *iso=0;
457 IGRAPH_CHECK(igraph_isomorphic_function_vf2(graph1, graph2,
458 vertex_color1, vertex_color2,
459@@ -1626,7 +1677,8 @@
460 map12, map21,
461 (igraph_isohandler_t*)
462 igraph_i_isomorphic_vf2,
463- iso));
464+ node_compat_fn, edge_compat_fn,
465+ &newargs));
466 if (! *iso) {
467 if (map12) { igraph_vector_clear(map12); }
468 if (map21) { igraph_vector_clear(map21); }
469@@ -1664,6 +1716,15 @@
470 * edge-colored.
471 * \param edge_color2 The edge color vector for the second graph.
472 * \param count Point to an integer, the result will be stored here.
473+ * \param node_compat_fn A pointer to a function of type \ref
474+ * igraph_isocompat_t. This function will be called by the algorithm to
475+ * determine whether two nodes are compatible.
476+ * \param edge_compat_fn A pointer to a function of type \ref
477+ * igraph_isocompat_t. This function will be called by the algorithm to
478+ * determine whether two edges are compatible.
479+ * \param args Extra arguments to supply to functions \p isohandler_fn, \p
480+ * node_compat_fn, \p edge_compat_fn. These arguments are packed into an
481+ * \ref igraph_isomorphic_function_vf2_args_t struct.
482 * \return Error code.
483 *
484 * Time complexity: exponential.
485@@ -1674,8 +1735,19 @@
486 const igraph_vector_int_t *vertex_color2,
487 const igraph_vector_int_t *edge_color1,
488 const igraph_vector_int_t *edge_color2,
489- igraph_integer_t *count) {
490+ igraph_integer_t *count,
491+ igraph_isocompat_t *node_compat_fn,
492+ igraph_isocompat_t *edge_compat_fn,
493+ igraph_isomorphic_function_vf2_args_t *args) {
494
495+ igraph_isomorphic_function_vf2_args_t newargs;
496+ newargs.isohandler_fn_arg = count;
497+ newargs.node_compat_fn_arg = 0;
498+ newargs.edge_compat_fn_arg = 0;
499+ if (args) {
500+ newargs.node_compat_fn_arg = args->node_compat_fn_arg;
501+ newargs.edge_compat_fn_arg = args->edge_compat_fn_arg;
502+ }
503 *count=0;
504 IGRAPH_CHECK(igraph_isomorphic_function_vf2(graph1, graph2,
505 vertex_color1, vertex_color2,
506@@ -1683,7 +1755,8 @@
507 0, 0,
508 (igraph_isohandler_t*)
509 igraph_i_count_isomorphisms_vf2,
510- count));
511+ node_compat_fn, edge_compat_fn,
512+ &newargs));
513 return 0;
514 }
515
516@@ -1747,6 +1820,15 @@
517 * <function>free()</function> and then 3) call \ref
518 * igraph_vector_ptr_destroy() on the pointer vector to deallocate all
519 * memory when \p maps is no longer needed.
520+ * \param node_compat_fn A pointer to a function of type \ref
521+ * igraph_isocompat_t. This function will be called by the algorithm to
522+ * determine whether two nodes are compatible.
523+ * \param edge_compat_fn A pointer to a function of type \ref
524+ * igraph_isocompat_t. This function will be called by the algorithm to
525+ * determine whether two edges are compatible.
526+ * \param args Extra arguments to supply to functions \p isohandler_fn, \p
527+ * node_compat_fn, \p edge_compat_fn. These arguments are packed into an
528+ * \ref igraph_isomorphic_function_vf2_args_t struct.
529 * \return Error code.
530 *
531 * Time complexity: exponential.
532@@ -1758,8 +1840,20 @@
533 const igraph_vector_int_t *vertex_color2,
534 const igraph_vector_int_t *edge_color1,
535 const igraph_vector_int_t *edge_color2,
536- igraph_vector_ptr_t *maps) {
537+ igraph_vector_ptr_t *maps,
538+ igraph_isocompat_t *node_compat_fn,
539+ igraph_isocompat_t *edge_compat_fn,
540+ igraph_isomorphic_function_vf2_args_t *args) {
541
542+ igraph_isomorphic_function_vf2_args_t newargs;
543+ newargs.isohandler_fn_arg = maps;
544+ newargs.node_compat_fn_arg = 0;
545+ newargs.edge_compat_fn_arg = 0;
546+ if (args) {
547+ newargs.node_compat_fn_arg = args->node_compat_fn_arg;
548+ newargs.edge_compat_fn_arg = args->edge_compat_fn_arg;
549+ }
550+
551 igraph_vector_ptr_clear(maps);
552 IGRAPH_FINALLY(igraph_i_get_isomorphisms_free, maps);
553 IGRAPH_CHECK(igraph_isomorphic_function_vf2(graph1, graph2,
554@@ -1768,7 +1862,8 @@
555 0, 0,
556 (igraph_isohandler_t*)
557 igraph_i_get_isomorphisms_vf2,
558- maps));
559+ node_compat_fn, edge_compat_fn,
560+ &newargs));
561 IGRAPH_FINALLY_CLEAN(1);
562 return 0;
563 }
564@@ -1795,7 +1890,7 @@
565 int igraph_subisomorphic(const igraph_t *graph1, const igraph_t *graph2,
566 igraph_bool_t *iso) {
567
568- return igraph_subisomorphic_vf2(graph1, graph2, 0, 0, 0, 0, iso, 0, 0);
569+ return igraph_subisomorphic_vf2(graph1, graph2, 0, 0, 0, 0, iso, 0, 0, 0, 0, 0);
570 }
571
572 /**
573@@ -1805,7 +1900,7 @@
574 * This function is the pair of \ref igraph_isomorphic_function_vf2(),
575 * for subgraph isomorphism problems. It searches for subgraphs of \p
576 * graph1 which are isomorphic to \p graph2. When it founds an
577- * isomorphic mapping it calls the supplied callback \p function.
578+ * isomorphic mapping it calls the supplied callback \p isohandler_fn.
579 * The mapping (and its inverse) and the additional \p arg argument
580 * are supplied to the callback.
581 * \param graph1 The first input graph, may be directed or
582@@ -1830,12 +1925,20 @@
583 * \param map21 Pointer to a vector ot \c NULL. If not \c NULL, then
584 * an isomorphic mapping from \p graph2 to \p graph1 is stored
585 * here.
586- * \param function A pointer to a function of type \ref
587+ * \param isohandler_fn A pointer to a function of type \ref
588 * igraph_isohandler_t. This will be called whenever a subgraph
589 * isomorphism is found. If the function returns with a non-zero value
590 * then the search is continued, otherwise it stops and the function
591 * returns.
592- * \param arg Extra argument to supply to the callback \p function.
593+ * \param node_compat_fn A pointer to a function of type \ref
594+ * igraph_isocompat_t. This function will be called by the algorithm to
595+ * determine whether two nodes are compatible.
596+ * \param edge_compat_fn A pointer to a function of type \ref
597+ * igraph_isocompat_t. This function will be called by the algorithm to
598+ * determine whether two edges are compatible.
599+ * \param args Extra arguments to supply to functions \p isohandler_fn, \p
600+ * node_compat_fn, \p edge_compat_fn. These arguments are packed into an
601+ * \ref igraph_isomorphic_function_vf2_args_t struct.
602 * \return Error code.
603 *
604 * Time complexity: exponential.
605@@ -1849,8 +1952,10 @@
606 const igraph_vector_int_t *edge_color2,
607 igraph_vector_t *map12,
608 igraph_vector_t *map21,
609- igraph_isohandler_t *function,
610- void *arg) {
611+ igraph_isohandler_t *isohandler_fn,
612+ igraph_isocompat_t *node_compat_fn,
613+ igraph_isocompat_t *edge_compat_fn,
614+ igraph_isomorphic_function_vf2_args_t *args) {
615
616 long int no_of_nodes1=igraph_vcount(graph1),
617 no_of_nodes2=igraph_vcount(graph2);
618@@ -1867,6 +1972,14 @@
619 igraph_stack_t path;
620 igraph_lazy_adjlist_t inadj1, inadj2, outadj1, outadj2;
621 igraph_vector_t indeg1, indeg2, outdeg1, outdeg2;
622+ void *isohandler_fn_arg = 0;
623+ void *node_compat_fn_arg = 0;
624+ void *edge_compat_fn_arg = 0;
625+ if (args) {
626+ isohandler_fn_arg = args->isohandler_fn_arg;
627+ node_compat_fn_arg = args->node_compat_fn_arg;
628+ edge_compat_fn_arg = args->edge_compat_fn_arg;
629+ }
630
631 if (igraph_is_directed(graph1) != igraph_is_directed(graph2)) {
632 IGRAPH_ERROR("Cannot compare directed and undirected graphs",
633@@ -2115,6 +2228,9 @@
634 if (vertex_color1 && VECTOR(*vertex_color1)[cand1] != VECTOR(*vertex_color2)[cand2]) {
635 end=1;
636 }
637+ if (node_compat_fn && !node_compat_fn(graph1, graph2, cand1, cand2, node_compat_fn_arg)) {
638+ end=1;
639+ }
640
641 for (i=0; !end && i<igraph_vector_size(inneis_1); i++) {
642 long int node=VECTOR(*inneis_1)[i];
643@@ -2155,6 +2271,9 @@
644 VECTOR(*edge_color2)[(long int)eid2]) {
645 end=1;
646 }
647+ if (edge_compat_fn && !edge_compat_fn(graph1, graph2, eid1, eid2, edge_compat_fn_arg)) {
648+ end=1;
649+ }
650 }
651 } else {
652 if (VECTOR(in_2)[node] != 0) {
653@@ -2182,6 +2301,9 @@
654 VECTOR(*edge_color2)[(long int)eid2]) {
655 end=1;
656 }
657+ if (edge_compat_fn && !edge_compat_fn(graph1, graph2, eid1, eid2, edge_compat_fn_arg)) {
658+ end=1;
659+ }
660 }
661 } else {
662 if (VECTOR(in_2)[node] != 0) {
663@@ -2256,8 +2378,8 @@
664
665 }
666
667- if (matched_nodes==no_of_nodes2 && function) {
668- if (!function(core_1, core_2, arg)) {
669+ if (matched_nodes==no_of_nodes2 && isohandler_fn) {
670+ if (!isohandler_fn(core_1, core_2, isohandler_fn_arg)) {
671 break;
672 }
673 }
674@@ -2330,6 +2452,15 @@
675 * \param map21 Pointer to a vector ot \c NULL. If not \c NULL, then
676 * an isomorphic mapping from \p graph2 to \p graph1 is stored
677 * here.
678+ * \param node_compat_fn A pointer to a function of type \ref
679+ * igraph_isocompat_t. This function will be called by the algorithm to
680+ * determine whether two nodes are compatible.
681+ * \param edge_compat_fn A pointer to a function of type \ref
682+ * igraph_isocompat_t. This function will be called by the algorithm to
683+ * determine whether two edges are compatible.
684+ * \param args Extra arguments to supply to functions \p isohandler_fn, \p
685+ * node_compat_fn, \p edge_compat_fn. These arguments are packed into an
686+ * \ref igraph_isomorphic_function_vf2_args_t struct.
687 * \return Error code.
688 *
689 * Time complexity: exponential.
690@@ -2341,8 +2472,20 @@
691 const igraph_vector_int_t *edge_color1,
692 const igraph_vector_int_t *edge_color2,
693 igraph_bool_t *iso, igraph_vector_t *map12,
694- igraph_vector_t *map21) {
695-
696+ igraph_vector_t *map21,
697+ igraph_isocompat_t *node_compat_fn,
698+ igraph_isocompat_t *edge_compat_fn,
699+ igraph_isomorphic_function_vf2_args_t *args) {
700+
701+ igraph_isomorphic_function_vf2_args_t newargs;
702+ newargs.isohandler_fn_arg = iso;
703+ newargs.node_compat_fn_arg = 0;
704+ newargs.edge_compat_fn_arg = 0;
705+ if (args) {
706+ newargs.node_compat_fn_arg = args->node_compat_fn_arg;
707+ newargs.edge_compat_fn_arg = args->edge_compat_fn_arg;
708+ }
709+
710 *iso=0;
711 IGRAPH_CHECK(igraph_subisomorphic_function_vf2(graph1, graph2,
712 vertex_color1, vertex_color2,
713@@ -2350,7 +2493,8 @@
714 map12, map21,
715 (igraph_isohandler_t *)
716 igraph_i_subisomorphic_vf2,
717- iso));
718+ node_compat_fn, edge_compat_fn,
719+ &newargs));
720 if (! *iso) {
721 if (map12) { igraph_vector_clear(map12); }
722 if (map21) { igraph_vector_clear(map21); }
723@@ -2391,6 +2535,15 @@
724 * \param edge_color2 The edge color vector for the second graph.
725 * \param count Pointer to an integer. The number of subgraph
726 * isomorphisms is stored here.
727+ * \param node_compat_fn A pointer to a function of type \ref
728+ * igraph_isocompat_t. This function will be called by the algorithm to
729+ * determine whether two nodes are compatible.
730+ * \param edge_compat_fn A pointer to a function of type \ref
731+ * igraph_isocompat_t. This function will be called by the algorithm to
732+ * determine whether two edges are compatible.
733+ * \param args Extra arguments to supply to functions \p isohandler_fn, \p
734+ * node_compat_fn, \p edge_compat_fn. These arguments are packed into an
735+ * \ref igraph_isomorphic_function_vf2_args_t struct.
736 * \return Error code.
737 *
738 * Time complexity: exponential.
739@@ -2401,8 +2554,20 @@
740 const igraph_vector_int_t *vertex_color2,
741 const igraph_vector_int_t *edge_color1,
742 const igraph_vector_int_t *edge_color2,
743- igraph_integer_t *count) {
744+ igraph_integer_t *count,
745+ igraph_isocompat_t *node_compat_fn,
746+ igraph_isocompat_t *edge_compat_fn,
747+ igraph_isomorphic_function_vf2_args_t *args) {
748
749+ igraph_isomorphic_function_vf2_args_t newargs;
750+ newargs.isohandler_fn_arg = count;
751+ newargs.node_compat_fn_arg = 0;
752+ newargs.edge_compat_fn_arg = 0;
753+ if (args) {
754+ newargs.node_compat_fn_arg = args->node_compat_fn_arg;
755+ newargs.edge_compat_fn_arg = args->edge_compat_fn_arg;
756+ }
757+
758 *count=0;
759 IGRAPH_CHECK(igraph_subisomorphic_function_vf2(graph1, graph2,
760 vertex_color1, vertex_color2,
761@@ -2410,7 +2575,8 @@
762 0, 0,
763 (igraph_isohandler_t*)
764 igraph_i_count_subisomorphisms_vf2,
765- count));
766+ node_compat_fn, edge_compat_fn,
767+ &newargs));
768 return 0;
769 }
770
771@@ -2474,6 +2640,15 @@
772 * <function>free()</function> and then 3) call \ref
773 * igraph_vector_ptr_destroy() on the pointer vector to deallocate all
774 * memory when \p maps is no longer needed.
775+ * \param node_compat_fn A pointer to a function of type \ref
776+ * igraph_isocompat_t. This function will be called by the algorithm to
777+ * determine whether two nodes are compatible.
778+ * \param edge_compat_fn A pointer to a function of type \ref
779+ * igraph_isocompat_t. This function will be called by the algorithm to
780+ * determine whether two edges are compatible.
781+ * \param args Extra arguments to supply to functions \p isohandler_fn, \p
782+ * node_compat_fn, \p edge_compat_fn. These arguments are packed into an
783+ * \ref igraph_isomorphic_function_vf2_args_t struct.
784 * \return Error code.
785 *
786 * Time complexity: exponential.
787@@ -2485,8 +2660,20 @@
788 const igraph_vector_int_t *vertex_color2,
789 const igraph_vector_int_t *edge_color1,
790 const igraph_vector_int_t *edge_color2,
791- igraph_vector_ptr_t *maps) {
792+ igraph_vector_ptr_t *maps,
793+ igraph_isocompat_t *node_compat_fn,
794+ igraph_isocompat_t *edge_compat_fn,
795+ igraph_isomorphic_function_vf2_args_t *args) {
796
797+ igraph_isomorphic_function_vf2_args_t newargs;
798+ newargs.isohandler_fn_arg = maps;
799+ newargs.node_compat_fn_arg = 0;
800+ newargs.edge_compat_fn_arg = 0;
801+ if (args) {
802+ newargs.node_compat_fn_arg = args->node_compat_fn_arg;
803+ newargs.edge_compat_fn_arg = args->edge_compat_fn_arg;
804+ }
805+
806 igraph_vector_ptr_clear(maps);
807 IGRAPH_FINALLY(igraph_i_get_subisomorphisms_free, maps);
808 IGRAPH_CHECK(igraph_subisomorphic_function_vf2(graph1, graph2,
809@@ -2495,7 +2682,8 @@
810 0, 0,
811 (igraph_isohandler_t*)
812 igraph_i_get_subisomorphisms_vf2,
813- maps));
814+ node_compat_fn, edge_compat_fn,
815+ &newargs));
816 IGRAPH_FINALLY_CLEAN(1);
817 return 0;
818 }

Subscribers

People subscribed via source and target branches