1 /*
2 * graphe.cc
3 *
4 * (c) 2018 Luka Marohnić
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "giacPCH.h"
21 #include "giac.h"
22 #include "graphe.h"
23 #include <sstream>
24 #include <ctype.h>
25 #include <math.h>
26 #include <ctime>
27 #include <bitset>
28 #include <stdio.h>
29 #ifdef HAVE_LIBNAUTY
30 #include "nautywrapper.h"
31 #endif
32 using namespace std;
33
34 #ifndef NO_NAMESPACE_GIAC
35 namespace giac {
36 #endif // ndef NO_NAMESPACE_GIAC
37
38 const gen graphe::VRAI=gen(1).change_subtype(_INT_BOOLEAN);
39 const gen graphe::FAUX=gen(0).change_subtype(_INT_BOOLEAN);
40 bool graphe::verbose=true;
41 int graphe::default_edge_color=_BLUE;
42 int graphe::default_edge_width=_LINE_WIDTH_2;
43 int graphe::bold_edge_width=_LINE_WIDTH_4;
44 int graphe::default_highlighted_edge_color=_RED;
45 int graphe::default_highlighted_vertex_color=_GREEN;
46 int graphe::default_vertex_color=_YELLOW;
47 int graphe::default_vertex_label_color=_BLACK;
48 /*
49 * Special graphs are initialized with adjacency lists of integers or strings.
50 * Each list starts with the corresponding vertex, followed by its neighbors,
51 * and ends with -1 or an empty string. The graph specification terminates with
52 * -2 (for integers) or NULL (for strings).
53 */
54 const int graphe::clebsch_graph[] = {
55 0, 1,2,4,8,15,-1,
56 1, 3,5,9,14,-1,
57 2, 3,6,10,13,-1,
58 3, 7,11,12,-1,
59 4, 5,6,11,12,-1,
60 5, 7,10,13,-1,
61 6, 7,9,14,-1,
62 7, 8,15,-1,
63 8, 9,10,12,-1,
64 9, 11,13,-1,
65 10, 11,14,-1,
66 11, 15,-1,
67 12, 13,14,-1,
68 13, 15,-1,
69 14, 15,-1,
70 -2
71 };
72 const char* graphe::coxeter_graph[] = {
73 "a1", "a2","a7","z1","",
74 "a2", "a3","z2","",
75 "a3", "a4","z3","",
76 "a4", "a5","z4","",
77 "a5", "a6","z5","",
78 "a6", "a7","z6","",
79 "a7", "z7","",
80 "b1", "b3","b6","z1","",
81 "b2", "b4","b7","z2","",
82 "b3", "b5","z3","",
83 "b4", "b6","z4","",
84 "b5", "b7","z5","",
85 "b6", "z6","",
86 "b7", "z7","",
87 "c1", "c4","c5","z1","",
88 "c2", "c5","c6","z2","",
89 "c3", "c6","c7","z3","",
90 "c4", "c7","z4","",
91 "c5", "z5","",
92 "c6", "z6","",
93 "c7", "z7","",
94 NULL
95 };
96 const int graphe::dyck_graph[] = {
97 1, 2,20,32,-1,
98 2, 3,7,-1,
99 3, 4,30,-1,
100 4, 5,17,-1,
101 5, 6,24,-1,
102 6, 7,11,-1,
103 7, 8,-1,
104 8, 9,21,-1,
105 9, 10,28,-1,
106 10, 11,15,-1,
107 11, 12,-1,
108 12, 13,25,-1,
109 13, 14,32,-1,
110 14, 15,19,-1,
111 15, 16,-1,
112 16, 17,29,-1,
113 17, 18,-1,
114 18, 19,23,-1,
115 19, 20,-1,
116 20, 21,-1,
117 21, 22,-1,
118 22, 23,27,-1,
119 23, 24,-1,
120 24, 25,-1,
121 25, 26,-1,
122 26, 27,31,-1,
123 27, 28,-1,
124 28, 29,-1,
125 29, 30,-1,
126 30, 31,-1,
127 31, 32,-1,
128 -2
129 };
130 const int graphe::grinberg_graph[] = {
131 1, 2,3,4,-1,
132 2, 5,7,-1,
133 3, 6,10,-1,
134 4, 8,9,-1,
135 5, 6,21,-1,
136 6, 22,-1,
137 7, 8,30,-1,
138 8, 29,-1,
139 9, 10,14,-1,
140 10, 13,-1,
141 11, 12,13,14,-1,
142 12, 15,17,-1,
143 13, 16,-1,
144 14, 18,-1,
145 15, 16,39,-1,
146 16, 46,-1,
147 17, 18,40,-1,
148 18, 45,-1,
149 19, 20,21,22,-1,
150 20, 23,25,-1,
151 21, 24,-1,
152 22, 26,-1,
153 23, 24,36,-1,
154 24, 44,-1,
155 25, 26,37,-1,
156 26, 46,-1,
157 27, 28,29,30,-1,
158 28, 31,33,-1,
159 29, 32,-1,
160 30, 34,-1,
161 31, 32,42,-1,
162 32, 45,-1,
163 33, 34,43,-1,
164 34, 44,-1,
165 35, 36,43,44,-1,
166 36, 37,-1,
167 37, 38,-1,
168 38, 39,46,-1,
169 39, 40,-1,
170 40, 41,-1,
171 41, 42,45,-1,
172 42, 43,-1,
173 -2
174 };
175 const int graphe::grotzsch_graph[] = {
176 1, 2,5,7,10,-1,
177 2, 3,6,8,-1,
178 3, 4,7,9,-1,
179 4, 5,8,10,-1,
180 5, 6,9,-1,
181 6, 11,-1,
182 7, 11,-1,
183 8, 11,-1,
184 9, 11,-1,
185 10, 11,-1,
186 -2
187 };
188 const int graphe::heawood_graph[] = {
189 1, 2,6,14,-1,
190 2, 3,11,-1,
191 3, 4,8,-1,
192 4, 5,13,-1,
193 5, 6,10,-1,
194 6, 7,-1,
195 7, 8,12,-1,
196 8, 9,-1,
197 9, 10,14,-1,
198 10, 11,-1,
199 11, 12,-1,
200 12, 13,-1,
201 13, 14,-1,
202 -2
203 };
204 const int graphe::herschel_graph[] = {
205 1, 2,4,5,-1,
206 2, 3,6,7,-1,
207 3, 4,8,-1,
208 4, 9,10,-1,
209 5, 6,10,-1,
210 6, 11,-1,
211 7, 8,11,-1,
212 8, 9,-1,
213 9, 11,-1,
214 10, 11,-1,
215 -2
216 };
217 const int graphe::mcgee_graph[] = {
218 1, 2,13,24,-1,
219 2, 3,9,-1,
220 3, 4,20,-1,
221 4, 5,16,-1,
222 5, 6,12,-1,
223 6, 7,23,-1,
224 7, 8,19,-1,
225 8, 9,15,-1,
226 9, 10,-1,
227 10, 11,22,-1,
228 11, 12,18,-1,
229 12, 13,-1,
230 13, 14,-1,
231 14, 15,21,-1,
232 15, 16,-1,
233 16, 17,-1,
234 17, 18,24,-1,
235 18, 19,-1,
236 19, 20,-1,
237 20, 21,-1,
238 21, 22,-1,
239 22, 23,-1,
240 23, 24,-1,
241 -2
242 };
243 const int graphe::pappus_graph[] = {
244 1, 2,6,18,-1,
245 2, 3,9,-1,
246 3, 4,14,-1,
247 4, 5,11,-1,
248 5, 6,16,-1,
249 6, 7,-1,
250 7, 8,12,-1,
251 8, 9,15,-1,
252 9, 10,-1,
253 10, 11,17,-1,
254 11, 12,-1,
255 12, 13,-1,
256 13, 14,18,-1,
257 14, 15,-1,
258 15, 16,-1,
259 16, 17,-1,
260 17, 18,-1,
261 -2
262 };
263 const int graphe::robertson_graph[] = {
264 1, 2,5,9,19,-1,
265 2, 3,7,13,-1,
266 3, 4,10,15,-1,
267 4, 5,8,18,-1,
268 5, 6,12,-1,
269 6, 7,14,17,-1,
270 7, 8,11,-1,
271 8, 9,16,-1,
272 9, 10,14,-1,
273 10, 11,17,-1,
274 11, 12,19,-1,
275 12, 13,16,-1,
276 13, 14,18,-1,
277 14, 15,-1,
278 15, 16,19,-1,
279 16, 17,-1,
280 17, 18,-1,
281 18, 19,-1,
282 -2
283 };
284 const int graphe::soccer_ball_graph[] = {
285 1, 2,5,6,-1,
286 2, 3,11,-1,
287 3, 4,16,-1,
288 4, 5,21,-1,
289 5, 26,-1,
290 6, 7,10,-1,
291 7, 8,30,-1,
292 8, 9,49,-1,
293 9, 10,53,-1,
294 10, 12,-1,
295 11, 12,15,-1,
296 12, 13,-1,
297 13, 14,54,-1,
298 14, 15,58,-1,
299 15, 17,-1,
300 16, 17,20,-1,
301 17, 18,-1,
302 18, 19,59,-1,
303 19, 20,38,-1,
304 20, 22,-1,
305 21, 22,25,-1,
306 22, 23,-1,
307 23, 24,39,-1,
308 24, 25,43,-1,
309 25, 27,-1,
310 26, 27,30,-1,
311 27, 28,-1,
312 28, 29,44,-1,
313 29, 30,48,-1,
314 31, 32,35,36,-1,
315 32, 33,41,-1,
316 33, 34,46,-1,
317 34, 35,51,-1,
318 35, 56,-1,
319 36, 37,40,-1,
320 37, 38,60,-1,
321 38, 39,-1,
322 39, 40,-1,
323 40, 42,-1,
324 41, 42,45,-1,
325 42, 43,-1,
326 43, 44,-1,
327 44, 45,-1,
328 45, 47,-1,
329 46, 47,50,-1,
330 47, 48,-1,
331 48, 49,-1,
332 49, 50,-1,
333 50, 52,-1,
334 51, 52,55,-1,
335 52, 53,-1,
336 53, 54,-1,
337 54, 55,-1,
338 55, 57,-1,
339 56, 57,60,-1,
340 57, 58,-1,
341 58, 59,-1,
342 59, 60,-1,
343 -2
344 };
345 const int graphe::tetrahedron_graph[] = {
346 1, 2,3,4,-1,
347 2, 3,4,-1,
348 3, 4,-1,
349 -2
350 };
351 const int graphe::octahedron_graph[] = {
352 1, 3,6,5,4,-1,
353 2, 3,4,5,6,-1,
354 3, 5,6,-1,
355 4, 5,6,-1,
356 -2
357 };
358 const int graphe::dodecahedron_graph[] = {
359 1, 2,5,6,-1,
360 2, 3,7,-1,
361 3, 4,8,-1,
362 4, 5,9,-1,
363 5, 10,-1,
364 6, 11,15,-1,
365 7, 11,12,-1,
366 8, 12,13,-1,
367 9, 13,14,-1,
368 10, 14,15,-1,
369 11, 16,-1,
370 12, 17,-1,
371 13, 18,-1,
372 14, 19,-1,
373 15, 20,-1,
374 16, 17,20,-1,
375 17, 18,-1,
376 18, 19,-1,
377 19, 20,-1,
378 -2
379 };
380 const int graphe::icosahedron_graph[] = {
381 1, 2,3,4,5,9,-1,
382 2, 3,5,6,7,-1,
383 3, 7,8,9,-1,
384 4, 5,9,10,11,-1,
385 5, 6,10,-1,
386 6, 7,10,12,-1,
387 7, 8,12,-1,
388 8, 9,11,12,-1,
389 9, 11,-1,
390 10, 11,12,-1,
391 11, 12,-1,
392 -2
393 };
394 const int graphe::ljubljana_graph_lcf[] = {
395 47,-23,-31,39,25,-21,-31,-41,25,15,29,-41,-19,15,-49,33,39,-35,-21,17,-33,49,41,31,
396 -15,-29,41,31,-15,-25,21,31,-51,-25,23,9,-17,51,35,-29,21,-51,-39,33,-9,-51,51,-47,
397 -33,19,51,-21,29,21,-31,-39,0
398 };
399 const int graphe::harries_graph_lcf[] = {
400 -35,-27,27,-23,15,-15,-9,-35,23,-27,27,9,15,-15,0
401 };
402 const int graphe::harries_wong_graph_lcf[] = {
403 9,25,31,-17,17,33,9,-29,-15,-9,9,25,-25,29,17,-9,9,-27,35,-9,9,-17,21,27,-29,-9,-25,13,19,
404 -9,-33,-17,19,-31,27,11,-25,29,-33,13,-13,21,-29,-21,25,9,-11,-19,29,9,-27,-19,-13,-35,-9,
405 9,17,25,-9,9,27,-27,-21,15,-9,29,-29,33,-9,-25,0
406 };
407 const int graphe::balaban_10cage_lcf[] = {
408 -9,-25,-19,29,13,35,-13,-29,19,25,9,-29,29,17,33,21,9,-13,-31,-9,25,17,9,-31,27,-9,17,-19,-29,
409 27,-17,-9,-29,33,-25,25,-21,17,-17,29,35,-29,17,-17,21,-25,25,-33,29,9,17,-27,29,19,-17,9,-27,
410 31,-9,-17,-25,9,31,13,-9,-21,-33,-17,-29,29,0
411 };
412 const int graphe::balaban_11cage_lcf[] = {
413 44,26,-47,-15,35,-39,11,-27,38,-37,43,14,28,51,-29,-16,41,-11,-26,15,22,-51,-35,36,52,-14,-33,-26,-46,
414 52,26,16,43,33,-15,17,-53,23,-42,-35,-28,30,-22,45,-44,16,-38,-16,50,-55,20,28,-17,-43,47,34,-26,-41,11,
415 -36,-23,-16,41,17,-51,26,-33,47,17,-11,-20,-30,21,29,36,-43,-52,10,39,-28,-17,-52,51,26,37,-17,10,-10,
416 -45,-34,17,-26,27,-21,46,53,-10,29,-50,35,15,-47,-29,-41,26,33,55,-17,42,-26,-36,16,0
417 };
418 const int graphe::foster_graph_lcf[] = {
419 17,-9,37,-37,9,-17,0
420 };
421 const int graphe::bidiakis_cube_graph_lcf[] = {
422 -6,4,-4,0
423 };
424 const int graphe::franklin_graph_lcf[] = {
425 5,-5,0
426 };
427 const int graphe::frucht_graph_lcf[] = {
428 -5,-2,-4,2,5,-2,2,5,-2,-5,4,2,0
429 };
430 const int graphe::biggs_smith_graph_lcf[] = {
431 16,24,-38,17,34,48,-19,41,-35,47,-20,34,-36,21,14,48,-16,-36,-43,28,-17,21,29,-43,46,-24,28,-38,-14,-50,-45,21,8,
432 27,-21,20,-37,39,-34,-44,-8,38,-21,25,15,-34,18,-28,-41,36,8,-29,-21,-48,-28,-20,-47,14,-8,-15,-27,38,24,-48,-18,25,
433 38,31,-25,24,-46,-14,28,11,21,35,-39,43,36,-38,14,50,43,36,-11,-36,-24,45,8,19,-25,38,20,-24,-14,-21,-8,44,-31,-38,-28,37,0
434 };
435 const int graphe::folkman_graph_lcf[] = {
436 5,-7,-7,5,0
437 };
438 const int graphe::gray_graph_lcf[] = {
439 -25,7,-7,13,-13,25,0
440 };
441 const int graphe::tutte_12cage_lcf[] = {
442 17,27,-13,-59,-35,35,-11,13,-53,53,-27,21,57,11,-21,-57, 59,-17,0
443 };
444 const int graphe::tutte_8cage_lcf[] = {
445 -13,-9,7,-7,9,13,0
446 };
447 const int graphe::f26a_graph_lcf[] = {
448 -7,7,0
449 };
450 const int graphe::blanusa_graph[] = {
451 1, 2,6,8,-1,
452 2, 3,12,-1,
453 3, 4,13,-1,
454 4, 5,14,-1,
455 5, 6,18,-1,
456 6, 7,-1,
457 7, 9,17,-1,
458 8, 17,18,-1,
459 9, 10,18,-1,
460 10, 11,16,-1,
461 11, 13,14,-1,
462 12, 14,15,-1,
463 13, 15,-1,
464 15, 16,-1,
465 16, 17,-1,
466 -2
467 };
468 const int graphe::bull_graph[] = {
469 1, 2,3,-1,
470 2, 3,4,-1,
471 3, 5,-1,
472 -2
473 };
474 const int graphe::butterfly_graph[] = {
475 1, 2,3,4,5,-1,
476 2, 3,-1,
477 4, 5,-1,
478 -2
479 };
480 const int graphe::diamond_graph[] = {
481 1, 2,3,4,-1,
482 2, 3,-1,
483 3, 4,-1,
484 -2
485 };
486 const int graphe::chvatal_graph[] = {
487 1, 2,4,5,12,-1,
488 2, 3,6,7,-1,
489 3, 4,8,9,-1,
490 4, 10,11,-1,
491 5, 6,8,9,-1,
492 6, 11,10,-1,
493 7, 8,10,11,-1,
494 8, 12,-1,
495 9, 10,12,-1,
496 11, 12,-1,
497 -2
498 };
499 const int graphe::moser_spindle_graph[] = {
500 1, 2,5,6,7,-1,
501 2, 3,7,-1,
502 3, 4,7,-1,
503 4, 5,6,-1,
504 5, 6,-1,
505 -2
506 };
507 const int graphe::errera_graph[] = {
508 1, 2,3,4,14,15,-1,
509 2, 3,13,15,17,-1,
510 3, 13,14,16,-1,
511 4, 5,6,14,15,-1,
512 5, 6,7,8,14,16,-1,
513 6, 7,9,15,17,-1,
514 7, 8,9,10,-1,
515 8, 10,11,16,-1,
516 9, 10,12,17,-1,
517 10, 11,12,-1,
518 11, 12,13,16,-1,
519 12, 13,17,-1,
520 13, 16,17,-1,
521 14, 16,-1,
522 15, 17,-1,
523 -2
524 };
525 const int graphe::goldner_harary_graph[] = {
526 1, 2,3,4,5,6,9,10,11,-1,
527 2, 3,10,-1,
528 3, 4,7,8,9,10,-1,
529 4, 9,-1,
530 5, 9,11,-1,
531 6, 10,11,-1,
532 7, 9,11,-1,
533 8, 10,11,-1,
534 9, 11,-1,
535 10, 11,-1,
536 -2
537 };
538 const int graphe::golomb_graph[] = {
539 1, 2,3,4,-1,
540 2, 3,6,-1,
541 3, 8,-1,
542 4, 5,9,10,-1,
543 5, 6,10,-1,
544 6, 7,10,-1,
545 7, 8,10,-1,
546 8, 9,10,-1,
547 9, 10,-1,
548 -2
549 };
550 const int graphe::hoffman_graph_matrix[8][8] = {
551 {1,1,1,1,0,0,0,0},
552 {1,1,1,0,1,0,0,0},
553 {1,0,0,1,0,1,1,0},
554 {0,1,0,1,0,1,0,1},
555 {0,0,1,1,0,0,1,1},
556 {1,0,0,0,1,1,1,0},
557 {0,1,0,0,1,1,0,1},
558 {0,0,1,0,1,0,1,1}
559 };
560 const int graphe::poussin_graph[] = {
561 1, 2,3,4,5,10,-1,
562 2, 3,5,7,9,15,-1,
563 3, 4,6,8,15,-1,
564 4, 6,10,-1,
565 5, 7,10,-1,
566 6, 8,10,11,12,-1,
567 7, 9,10,11,13,-1,
568 8, 12,14,15,-1,
569 9, 13,14,15,-1,
570 10, 11,-1,
571 11, 12,13,-1,
572 12, 13,14,-1,
573 13, 14,-1,
574 14, 15,-1,
575 -2
576 };
577 const int graphe::wagner_graph[] = {
578 1, 2,5,8,-1,
579 2, 3,6,-1,
580 3, 4,7,-1,
581 4, 5,8,-1,
582 5, 6,-1,
583 6, 7,-1,
584 7, 8,-1,
585 -2
586 };
587 const int graphe::tietze_graph[] = {
588 1, 2,5,9,-1,
589 2, 3,7,-1,
590 3, 4,11,-1,
591 4, 5,8,-1,
592 5, 6,-1,
593 6, 7,12,-1,
594 7, 8,-1,
595 8, 9,-1,
596 9, 10,-1,
597 10, 11,12,-1,
598 11, 12,-1,
599 -2
600 };
601 const int graphe::tutte_fragment_graph[] = {
602 1, 2,4,-1,
603 2, 3,5,-1,
604 3, 4,7,-1,
605 4, 8,-1,
606 5, 6,9,-1,
607 6, 7,10,-1,
608 7, 11,-1,
609 8, 11,15,-1,
610 9, 10,13,-1,
611 10, 12,-1,
612 11, 12,-1,
613 12, 14,-1,
614 13, 14,-1,
615 14, 15,-1,
616 -2
617 };
618
619 /* messages */
620
message(const char * str) const621 void graphe::message(const char *str) const {
622 if (verbose)
623 *logptr(ctx) << str << "\n";
624 }
625
message(const char * format,int a) const626 void graphe::message(const char *format,int a) const {
627 char buffer[256];
628 sprintf(buffer,format,a);
629 if (verbose)
630 *logptr(ctx) << buffer << "\n";
631 }
632
message(const char * format,int a,int b) const633 void graphe::message(const char *format,int a,int b) const {
634 char buffer[256];
635 sprintf(buffer,format,a,b);
636 if (verbose)
637 *logptr(ctx) << buffer << "\n";
638 }
639
message(const char * format,int a,int b,int c) const640 void graphe::message(const char *format,int a,int b,int c) const {
641 char buffer[256];
642 sprintf(buffer,format,a,b,c);
643 if (verbose)
644 *logptr(ctx) << buffer << "\n";
645 }
646
giac_version() const647 string graphe::giac_version() const {
648 return genstring2str(_version(change_subtype(vecteur(0),_SEQ__VECT),ctx));
649 }
650
plusinf()651 gen graphe::plusinf() {
652 return symbolic(at_plus,_IDNT_infinity());
653 }
654
655 /* convert list of lists of integers into vecteur of vecteurs */
ivectors2vecteur(const ivectors & v,vecteur & res,bool sort_all) const656 void graphe::ivectors2vecteur(const ivectors &v,vecteur &res,bool sort_all) const {
657 res.resize(v.size());
658 for (ivectors_iter it=v.begin();it!=v.end();++it) {
659 res[it-v.begin()]=sort_all?_sort(get_node_labels(*it),ctx):get_node_labels(*it);
660 }
661 }
662
663 /* vertex class implementation */
assign_defaults()664 void graphe::vertex::assign_defaults() {
665 m_subgraph=-1;
666 m_visited=false;
667 m_ancestor=-1;
668 m_low=-1;
669 m_disc=-1;
670 m_color=0; // white
671 m_embedded=false;
672 m_number=-1;
673 }
674
vertex(bool support_attributes)675 graphe::vertex::vertex(bool support_attributes) {
676 m_attributes=support_attributes?new attrib():NULL;
677 m_neighbor_attributes=support_attributes?new map<int,attrib>():NULL;
678 assign_defaults();
679 }
680
vertex(const gen & lab,const attrib & attr)681 graphe::vertex::vertex(const gen &lab,const attrib &attr) {
682 m_attributes=new attrib();
683 m_neighbor_attributes=new map<int,attrib>();
684 assign_defaults();
685 if (!attr.empty())
686 set_attributes(attr);
687 set_label(lab);
688 }
689
assign(const vertex & other)690 void graphe::vertex::assign(const vertex &other) {
691 m_subgraph=other.subgraph();
692 m_visited=other.is_visited();
693 m_ancestor=other.ancestor();
694 m_low=other.low();
695 m_disc=other.disc();
696 m_color=other.color();
697 m_embedded=other.is_embedded();
698 m_number=other.number();
699 m_faces=other.edge_faces();
700 if (!other.supports_attributes()) {
701 if (supports_attributes()) {
702 delete m_attributes;
703 delete m_neighbor_attributes;
704 }
705 unsupport_attributes();
706 } else {
707 if (!supports_attributes()) {
708 m_attributes=new attrib();
709 m_neighbor_attributes=new map<int,attrib>();
710 }
711 m_neighbor_attributes->clear();
712 set_attributes(other.attributes());
713 }
714 m_multiedges.clear();
715 m_neighbors.resize(other.degree());
716 int k;
717 for (ivector_iter it=other.neighbors().begin();it!=other.neighbors().end();++it) {
718 m_neighbors[it-other.neighbors().begin()]=*it;
719 if (other.supports_attributes())
720 copy_attributes(other.neighbor_attributes(*it),(*m_neighbor_attributes)[*it]);
721 if ((k=other.multiedges(*it))>0)
722 m_multiedges.insert(make_pair(*it,k));
723 }
724 }
725
~vertex()726 graphe::vertex::~vertex() {
727 if (supports_attributes()) {
728 delete m_attributes;
729 delete m_neighbor_attributes;
730 }
731 }
732
multiedges(int v) const733 int graphe::vertex::multiedges(int v) const {
734 map<int,int>::const_iterator it=m_multiedges.find(v);
735 if (it!=m_multiedges.end())
736 return it->second;
737 return 0;
738 }
739
multiedge_count() const740 int graphe::vertex::multiedge_count() const {
741 int count=0;
742 for (map<int,int>::const_iterator it=m_multiedges.begin();it!=m_multiedges.end();++it) {
743 count+=it->second;
744 }
745 return count;
746 }
747
set_multiedge(int v,int k)748 void graphe::vertex::set_multiedge(int v,int k) {
749 map<int,int>::iterator it=m_multiedges.find(v);
750 if (k>0)
751 if (it!=m_multiedges.end())
752 it->second=k;
753 else m_multiedges.insert(make_pair(v,k));
754 else {
755 if (it!=m_multiedges.end())
756 m_multiedges.erase(it);
757 }
758 }
759
label() const760 gen graphe::vertex::label() const {
761 assert(supports_attributes());
762 attrib_iter it=m_attributes->find(_GT_ATTRIB_LABEL);
763 if (it==m_attributes->end())
764 return undef;
765 return it->second;
766 }
767
vertex(const vertex & other)768 graphe::vertex::vertex(const vertex &other) {
769 m_attributes=other.supports_attributes()?new attrib():NULL;
770 m_neighbor_attributes=other.supports_attributes()?new map<int,attrib>():NULL;
771 assign(other);
772 }
773
operator =(const vertex & other)774 graphe::vertex& graphe::vertex::operator =(const vertex &other) {
775 assign(other);
776 return *this;
777 }
778
add_neighbor(int i,const attrib & attr)779 void graphe::vertex::add_neighbor(int i,const attrib &attr) {
780 ivector::iterator it=m_neighbors.begin();
781 for (;it!=m_neighbors.end() && *it<i;++it);
782 if (it==m_neighbors.end()) m_neighbors.push_back(i);
783 else if (*it!=i) m_neighbors.insert(it,i);
784 else return;
785 if (supports_attributes())
786 copy_attributes(attr,(*m_neighbor_attributes)[i]);
787 }
788
is_temporary(int i) const789 bool graphe::vertex::is_temporary(int i) const {
790 const attrib &attr=neighbor_attributes(i);
791 attrib_iter it=attr.find(_GT_ATTRIB_TEMPORARY);
792 return it!=attr.end() && is_one(it->second);
793 }
794
neighbor_attributes(int i)795 graphe::attrib &graphe::vertex::neighbor_attributes(int i) {
796 assert(supports_attributes());
797 map<int,attrib>::iterator it=m_neighbor_attributes->find(i);
798 assert(it!=m_neighbor_attributes->end());
799 return it->second;
800 }
801
neighbor_attributes(int i) const802 const graphe::attrib &graphe::vertex::neighbor_attributes(int i) const {
803 assert(supports_attributes());
804 neighbor_iter it=m_neighbor_attributes->find(i);
805 assert(it!=m_neighbor_attributes->end());
806 return it->second;
807 }
808
remove_neighbor(int i)809 void graphe::vertex::remove_neighbor(int i) {
810 ivector::iterator it;
811 if ((it=std::find(m_neighbors.begin(),m_neighbors.end(),i))==m_neighbors.end())
812 return;
813 m_neighbors.erase(it);
814 if (supports_attributes()) {
815 map<int,attrib>::iterator jt=m_neighbor_attributes->find(i);
816 assert(jt!=m_neighbor_attributes->end());
817 m_neighbor_attributes->erase(jt);
818 }
819 map<int,int>::iterator kt=m_multiedges.find(i);
820 if (kt!=m_multiedges.end())
821 m_multiedges.erase(kt);
822 }
823
clear_neighbors()824 void graphe::vertex::clear_neighbors() {
825 m_neighbors.clear();
826 if (supports_attributes())
827 m_neighbor_attributes->clear();
828 m_multiedges.clear();
829 }
830
incident_faces(ivector & F) const831 void graphe::vertex::incident_faces(ivector &F) const {
832 F.resize(m_faces.size());
833 int i=0,f;
834 for (map<int,int>::const_iterator it=m_faces.begin();it!=m_faces.end();++it) {
835 assert((f=it->second)>0);
836 F[i++]=f-1;
837 }
838 }
839
840 /* set the given planar embedding */
set_embedding(const ivectors & faces)841 void graphe::set_embedding(const ivectors &faces) {
842 int n,f;
843 for (ivectors_iter it=faces.begin();it!=faces.end();++it) {
844 f=it-faces.begin();
845 const ivector &face=*it;
846 n=face.size();
847 for (int i=0;i<n;++i) {
848 vertex &v=node(face[i]);
849 v.add_edge_face(face[(i+1)%n],f);
850 }
851 }
852 }
853
854 /* clear the previously set embedding */
clear_embedding()855 void graphe::clear_embedding() {
856 for (std::vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
857 it->clear_edge_faces();
858 }
859 }
860
861 /* get the first neighbor of v in the subgraph sg */
first_neighbor_from_subgraph(const vertex & v,int sg) const862 int graphe::first_neighbor_from_subgraph(const vertex &v,int sg) const {
863 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
864 if (node(*it).subgraph()==sg)
865 return *it;
866 }
867 return -1;
868 }
869
870 /* just a safety measure, the stack should be empty before calling this function */
clear_node_stack()871 void graphe::clear_node_stack() {
872 while (!node_stack.empty())
873 node_stack.pop();
874 }
875
876 /* clear the node queue */
clear_node_queue()877 void graphe::clear_node_queue() {
878 while (!node_queue.empty())
879 node_queue.pop();
880 }
881
882 /* return true iff this graph has no edges */
is_empty() const883 bool graphe::is_empty() const {
884 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
885 if (!it->neighbors().empty())
886 return false;
887 }
888 return true;
889 }
890
891 /* store all subgraph indices */
save_subgraphs()892 void graphe::save_subgraphs() {
893 ivector sgr(node_count());
894 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
895 sgr[it-nodes.begin()]=it->subgraph();
896 }
897 saved_subgraphs.push(sgr);
898 }
899
900 /* restore previously saved subgraph indices */
restore_subgraphs()901 void graphe::restore_subgraphs() {
902 assert(!saved_subgraphs.empty() && int(saved_subgraphs.top().size())==node_count());
903 const ivector &sgr=saved_subgraphs.top();
904 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
905 it->set_subgraph(sgr[it-nodes.begin()]);
906 }
907 saved_subgraphs.pop();
908 }
909
910 /* dotgraph class implementation */
dotgraph()911 graphe::dotgraph::dotgraph() {
912 m_index=0;
913 pos=0;
914 m_chain=ivector(1,0);
915 }
916
dotgraph(int i)917 graphe::dotgraph::dotgraph(int i) {
918 m_index=i;
919 pos=0;
920 m_chain=ivector(1,0);
921 }
922
assign(const dotgraph & other)923 void graphe::dotgraph::assign(const dotgraph &other) {
924 m_index=other.index();
925 copy_attributes(other.vertex_attributes(),vertex_attr);
926 copy_attributes(other.edge_attributes(),edge_attr);
927 copy_attributes(other.chain_attributes(),chain_attr);
928 m_chain=other.chain();
929 pos=other.position();
930 }
931
dotgraph(const dotgraph & other)932 graphe::dotgraph::dotgraph(const dotgraph &other) {
933 assign(other);
934 }
935
operator =(const dotgraph & other)936 graphe::dotgraph& graphe::dotgraph::operator =(const dotgraph &other) {
937 assign(other);
938 return *this;
939 }
940
941 /* rectangle class implementation */
rectangle()942 graphe::rectangle::rectangle() {
943 m_x=m_y=m_width=m_height=0;
944 L=NULL;
945 }
946
rectangle(double X,double Y,double W,double H,layout * ly)947 graphe::rectangle::rectangle(double X,double Y,double W,double H,layout *ly) {
948 m_x=X;
949 m_y=Y;
950 m_width=W;
951 m_height=H;
952 L=ly;
953 }
954
assign(const rectangle & other)955 void graphe::rectangle::assign(const rectangle &other) {
956 m_x=other.x();
957 m_y=other.y();
958 m_width=other.width();
959 m_height=other.height();
960 L=other.get_layout();
961 }
962
rectangle(const rectangle & rect)963 graphe::rectangle::rectangle(const rectangle &rect) {
964 assign(rect);
965 }
966
operator =(const rectangle & other)967 graphe::rectangle& graphe::rectangle::operator =(const rectangle &other) {
968 assign(other);
969 return *this;
970 }
971
intersects(const rectangle & other) const972 bool graphe::rectangle::intersects(const rectangle &other) const {
973 return x()<other.x()+other.width() &&
974 x()+width()>other.x() &&
975 y()<other.y()+other.height() &&
976 y()+height()>other.y();
977 }
978
intersects(const vector<rectangle> & rectangles) const979 bool graphe::rectangle::intersects(const vector<rectangle> &rectangles) const {
980 vector<rectangle>::const_iterator it=rectangles.begin();
981 for (;it!=rectangles.end();++it) {
982 if (intersects(*it))
983 return true;
984 }
985 return false;
986 }
987
intersects(vector<rectangle>::const_iterator first,vector<rectangle>::const_iterator last) const988 bool graphe::rectangle::intersects(vector<rectangle>::const_iterator first,vector<rectangle>::const_iterator last) const {
989 vector<rectangle>::const_iterator it=first;
990 for (;it!=last;++it) {
991 if (intersects(*it))
992 return true;
993 }
994 return false;
995 }
996
997 /* test if g is a real constant */
is_real_number(const gen & g)998 bool graphe::is_real_number(const gen &g) {
999 gen e=_evalf(g,context0);
1000 return e.type==_DOUBLE_ || e.type==_FLOAT_;
1001 }
1002
1003 /* convert number to binary format and return it as gen of type string */
to_binary(int number,int chars)1004 gen graphe::to_binary(int number,int chars) {
1005 return str2gen(bitset<1024>((unsigned long)number).to_string().substr(1024-chars),true);
1006 }
1007
1008 /* make a copy of attr */
copy_attributes(const attrib & src,attrib & dest)1009 void graphe::copy_attributes(const attrib &src,attrib &dest) {
1010 dest.clear();
1011 for (attrib_iter it=src.begin();it!=src.end();++it) {
1012 dest.insert(make_pair(it->first,gen(it->second)));
1013 }
1014 }
1015
1016 /* fill the vecteur V with first n integers (0- or 1- based, depending on the mode) */
make_default_labels(vecteur & labels,int n,int n0,int offset) const1017 void graphe::make_default_labels(vecteur &labels,int n,int n0,int offset) const {
1018 int ofs=offset<0?array_start(ctx):offset;
1019 labels.resize(n);
1020 for (int i=0;i<n;++i) {
1021 labels[i]=i+ofs+n0;
1022 }
1023 }
1024
1025 /* create identifier */
make_idnt(const char * name,int index,bool intern)1026 gen graphe::make_idnt(const char* name,int index,bool intern) {
1027 stringstream ss;
1028 if (intern)
1029 ss << " ";
1030 ss << string(name);
1031 if (index>=0)
1032 ss << index;
1033 return identificateur(ss.str().c_str());
1034 }
1035
1036 /* convert word to gen of type string */
word2gen(const string & word)1037 gen graphe::word2gen(const string &word) {
1038 stringstream ss;
1039 gen g;
1040 ss << "\"" << word << "\"";
1041 ss >> g;
1042 return g;
1043 }
1044
1045 /* convert string to gen */
str2gen(const string & str,bool isstring)1046 gen graphe::str2gen(const string &str,bool isstring) {
1047 stringstream ss(str);
1048 if (isstring) {
1049 string buf;
1050 vector<string> words;
1051 gen space=_char(32,context0);
1052 while (ss >> buf) {
1053 words.push_back(buf);
1054 }
1055 vecteur res;
1056 for (vector<string>::const_iterator it=words.begin();it!=words.end();++it) {
1057 res.push_back(word2gen(*it));
1058 if (it+1!=words.end())
1059 res.push_back(space);
1060 }
1061 return _cat(change_subtype(res,_SEQ__VECT),context0);
1062 }
1063 gen g;
1064 ss >> g;
1065 return g;
1066 }
1067
1068 /* convert gen string to std::string (no quotes) */
genstring2str(const gen & g)1069 string graphe::genstring2str(const gen &g) {
1070 assert(g.type==_STRNG);
1071 int len=_size(g,context0).val;
1072 return string(g._STRNGptr->begin(),g._STRNGptr->begin()+len);
1073 }
1074
1075 /* convert gen to string */
gen2str(const gen & g)1076 string graphe::gen2str(const gen &g) {
1077 stringstream ss;
1078 ss << g;
1079 return ss.str();
1080 }
1081
1082 /* return random permutation of {0,1,..,n-1} */
rand_permu(int n) const1083 graphe::ivector graphe::rand_permu(int n) const {
1084 ivector res=vecteur_2_vector_int(*_randperm(n,ctx)._VECTptr);
1085 int ofs=array_start(ctx);
1086 for (ivector::iterator it=res.begin();it!=res.end();++it) {
1087 *it-=ofs;
1088 }
1089 return res;
1090 }
1091
1092 /* compute the union of A and B and store it in U */
sets_union(const iset & A,const iset & B,iset & U)1093 size_t graphe::sets_union(const iset &A,const iset &B,iset &U) {
1094 U.clear();
1095 set_union(A.begin(),A.end(),B.begin(),B.end(),std::inserter(U,U.begin()));
1096 return U.size();
1097 }
1098
1099 /* compute the intersection of A and B and store it in I */
sets_intersection(const iset & A,const iset & B,iset & I)1100 size_t graphe::sets_intersection(const iset &A,const iset &B,iset &I) {
1101 I.clear();
1102 set_intersection(A.begin(),A.end(),B.begin(),B.end(),std::inserter(I,I.begin()));
1103 return I.size();
1104 }
1105
1106 /* compute the intersection of A and B and store it in I */
sets_intersection(const ivector & A,const iset & B,iset & I)1107 size_t graphe::sets_intersection(const ivector &A,const iset &B,iset &I) {
1108 I.clear();
1109 set_intersection(A.begin(),A.end(),B.begin(),B.end(),std::inserter(I,I.begin()));
1110 return I.size();
1111 }
1112
1113 /* compute the set difference of A and B and store it in D */
sets_difference(const iset & A,const iset & B,iset & D)1114 size_t graphe::sets_difference(const iset &A,const iset &B,iset &D) {
1115 D.clear();
1116 set_difference(A.begin(),A.end(),B.begin(),B.end(),std::inserter(D,D.begin()));
1117 return D.size();
1118 }
1119
1120 /* compute the set difference of A and B and store it in D */
sets_difference(const iset & A,const ivector & B,iset & D)1121 size_t graphe::sets_difference(const iset &A,const ivector &B,iset &D) {
1122 D.clear();
1123 set_difference(A.begin(),A.end(),B.begin(),B.end(),std::inserter(D,D.begin()));
1124 return D.size();
1125 }
1126
1127 /* binary search for an element a in sorted list first...last */
binsearch(ivector_iter first,ivector_iter last,int a)1128 graphe::ivector_iter graphe::binsearch(ivector_iter first,ivector_iter last,int a) {
1129 ivector_iter mid;
1130 while (first!=last) {
1131 mid=first+int(last-first)/2;
1132 if (*mid==a) return mid;
1133 if (*mid>a) last=mid;
1134 else first=mid+1;
1135 }
1136 return first;
1137 }
1138
1139 /* return the intersection size by double binary search (Baeza-Yates) */
intersect_fast(ivector_iter min1,ivector_iter max1,ivector_iter min2,ivector_iter max2)1140 size_t graphe::intersect_fast(ivector_iter min1,ivector_iter max1,ivector_iter min2,ivector_iter max2) {
1141 if (min1==max1 || min2==max2) return 0;
1142 size_t result=0;
1143 ivector_iter mid2=min2+int(max2-min2)/2;
1144 ivector_iter mid1=binsearch(min1,max1,*mid2);
1145 result+=intersect_hybrid(min1,mid1,min2,mid2);
1146 if (*mid1==*mid2) {
1147 ++result;
1148 ++mid1;
1149 }
1150 return result+intersect_hybrid(mid1,max1,mid2+1,max2);
1151 }
1152
1153 /* return the intersection size for sorted lists A and B */
intersect_linear(ivector_iter min1,ivector_iter max1,ivector_iter min2,ivector_iter max2)1154 size_t graphe::intersect_linear(ivector_iter min1,ivector_iter max1,ivector_iter min2,ivector_iter max2) {
1155 if (min1==max1 || min2==max2 || *min1>*(max2-1) || *min2>*(max1-1)) return 0;
1156 if (*min1>*min2) min2=binsearch(min2,max2,*min1);
1157 else if (*min2>*min1) min1=binsearch(min1,max1,*min2);
1158 size_t result=0;
1159 while (min1!=max1 && min2!=max2) {
1160 if (*min1<*min2) ++min1;
1161 else if (*min2<*min1) ++min2;
1162 else {
1163 result++;
1164 ++min1; ++min2;
1165 }
1166 }
1167 return result;
1168 }
1169
1170 /* hybrid set intersection */
intersect_hybrid(ivector_iter min1,ivector_iter max1,ivector_iter min2,ivector_iter max2)1171 size_t graphe::intersect_hybrid(ivector_iter min1,ivector_iter max1,ivector_iter min2,ivector_iter max2) {
1172 int A_sz=max1-min1,B_sz=max2-min2;
1173 if (A_sz==0 || B_sz==0)
1174 return 0;
1175 if (double(A_sz)/double(B_sz)>12.5) // fast is better (the factor 12.5 is measured)
1176 return intersect_fast(min1,max1,min2,max2);
1177 if (double(B_sz)/double(A_sz)>12.5)
1178 return intersect_fast(min2,max2,min1,max1);
1179 return intersect_linear(min1,max1,min2,max2);
1180 }
1181
1182 /* graphe default constructor */
graphe(GIAC_CONTEXT,bool support_attributes)1183 graphe::graphe(GIAC_CONTEXT,bool support_attributes) {
1184 ctx=contextptr;
1185 m_supports_attributes=support_attributes;
1186 set_graph_attribute(_GT_ATTRIB_DIRECTED,FAUX);
1187 set_graph_attribute(_GT_ATTRIB_WEIGHTED,FAUX);
1188 //nodes.reserve(1024);
1189 }
1190
1191 /* graphe constructor, create a copy of G */
graphe(const graphe & G)1192 graphe::graphe(const graphe &G) {
1193 m_supports_attributes=G.supports_attributes();
1194 set_graph_attribute(_GT_ATTRIB_DIRECTED,boole(G.is_directed()));
1195 set_graph_attribute(_GT_ATTRIB_WEIGHTED,boole(G.is_weighted()));
1196 ctx=G.giac_context();
1197 G.copy(*this);
1198 }
1199
1200 /* graphe constructor, create special graph with the specified name */
graphe(const string & name,GIAC_CONTEXT)1201 graphe::graphe(const string &name,GIAC_CONTEXT) {
1202 ctx=contextptr;
1203 m_supports_attributes=true;
1204 set_graph_attribute(_GT_ATTRIB_DIRECTED,FAUX);
1205 set_graph_attribute(_GT_ATTRIB_WEIGHTED,FAUX);
1206 ivector hull;
1207 layout x;
1208 if (name=="clebsch") {
1209 reserve_nodes(16);
1210 for (int i=0;i<16;++i) {
1211 add_node(i);
1212 }
1213 read_special(clebsch_graph);
1214 vecteur labels;
1215 for (int i=0;i<16;++i) {
1216 labels.push_back(to_binary(i,4));
1217 }
1218 relabel_nodes(labels);
1219 } else if (name=="coxeter") {
1220 read_special(coxeter_graph);
1221 stringstream ss;
1222 for (int i=1;i<=7;++i) {
1223 ss.str("");
1224 ss << "a" << i;
1225 hull.push_back(node_index(str2gen(ss.str(),true)));
1226 }
1227 make_circular_layout(x,hull,3.5);
1228 } else if (name=="desargues") {
1229 make_petersen_graph(10,3,&x);
1230 } else if (name=="bidiakis") {
1231 make_lcf_graph(bidiakis_cube_graph_lcf,4);
1232 for (int i=0;i<node_count();++i) hull.push_back(i);
1233 make_circular_layout(x,hull);
1234 layout_best_rotation(x);
1235 } else if (name=="bull") {
1236 read_special(bull_graph);
1237 make_spring_layout(x,2);
1238 layout_best_rotation(x);
1239 } else if (name=="butterfly") {
1240 read_special(butterfly_graph);
1241 make_spring_layout(x,2);
1242 layout_best_rotation(x);
1243 } else if (name=="blanusa") {
1244 vecteur l1=makevecteur(1,2,3,4,5,6,7,8,9);
1245 vecteur l2=makevecteur(10,11,12,13,14,15,16,17,18);
1246 add_nodes(mergevecteur(l1,l2));
1247 read_special(blanusa_graph);
1248 for (int i=0;i<6;++i) hull.push_back(i);
1249 add_temporary_edge(0,9);
1250 add_temporary_edge(1,9);
1251 add_temporary_edge(3,15);
1252 add_temporary_edge(4,15);
1253 make_circular_layout(x,hull,2.5,0.005,0.618);
1254 remove_temporary_edges();
1255 } else if (name=="diamond") {
1256 read_special(diamond_graph);
1257 make_spring_layout(x,2);
1258 layout_best_rotation(x);
1259 } else if (name=="chvatal") {
1260 read_special(chvatal_graph);
1261 x.resize(12);
1262 for (layout::iterator it=x.begin();it!=x.end();++it) it->resize(2);
1263 x[0][0]=-4; x[0][1]=4; x[1][0]=4; x[1][1]=4;
1264 x[5][0]=4; x[5][1]=-4; x[2][0]=-4; x[2][1]=-4;
1265 x[3][0]=-1; x[3][1]=2; x[6][0]=1; x[6][1]=2;
1266 x[7][0]=2; x[7][1]=1; x[8][0]=2; x[8][1]=-1;
1267 x[9][0]=1; x[9][1]=-2; x[10][0]=-1; x[10][1]=-2;
1268 x[11][0]=-2; x[11][1]=-1; x[4][0]=-2; x[4][1]=1;
1269 } else if (name=="dodecahedron") {
1270 read_special(dodecahedron_graph);
1271 for (int i=1;i<=5;++i) hull.push_back(node_index(i));
1272 make_circular_layout(x,hull,2.5);
1273 layout_best_rotation(x);
1274 } else if (name=="errera") {
1275 read_special(errera_graph);
1276 for (int i=0;i<3;++i) hull.push_back(i);
1277 make_circular_layout(x,hull);
1278 layout_best_rotation(x);
1279 } else if (name=="poussin") {
1280 read_special(poussin_graph);
1281 make_planar_layout(x);
1282 layout_best_rotation(x);
1283 } else if (name=="franklin") {
1284 make_lcf_graph(franklin_graph_lcf,6);
1285 for (int i=0;i<node_count();++i) hull.push_back(i);
1286 make_circular_layout(x,hull);
1287 layout_best_rotation(x);
1288 } else if (name=="frucht") {
1289 make_lcf_graph(frucht_graph_lcf,1);
1290 make_planar_layout(x);
1291 layout_best_rotation(x);
1292 } else if (name=="biggs-smith") {
1293 make_lcf_graph(biggs_smith_graph_lcf,1);
1294 for (int i=0;i<node_count();++i) hull.push_back(i);
1295 make_circular_layout(x,hull);
1296 } else if (name=="durer") {
1297 make_petersen_graph(6,2,&x);
1298 } else if (name=="dyck") {
1299 read_special(dyck_graph);
1300 for (int i=0;i<node_count();++i) hull.push_back(i);
1301 make_circular_layout(x,hull);
1302 } else if (name=="folkman") {
1303 make_lcf_graph(folkman_graph_lcf,5);
1304 for (int i=0;i<node_count();++i) hull.push_back(i);
1305 make_circular_layout(x,hull);
1306 } else if (name=="gray") {
1307 make_lcf_graph(gray_graph_lcf,9);
1308 for (int i=0;i<node_count();++i) hull.push_back(i);
1309 make_circular_layout(x,hull);
1310 } else if (name=="grinberg") {
1311 read_special(grinberg_graph);
1312 make_planar_layout(x);
1313 layout_best_rotation(x);
1314 } else if (name=="goldner-harary") {
1315 read_special(goldner_harary_graph);
1316 make_planar_layout(x);
1317 layout_best_rotation(x);
1318 } else if (name=="golomb") {
1319 read_special(golomb_graph);
1320 for (int i=0;i<3;++i) hull.push_back(i);
1321 add_temporary_edge(0,6);
1322 add_temporary_edge(1,6);
1323 add_temporary_edge(1,9);
1324 add_temporary_edge(2,9);
1325 add_temporary_edge(0,7);
1326 add_temporary_edge(2,7);
1327 make_circular_layout(x,hull);
1328 remove_temporary_edges();
1329 layout_best_rotation(x);
1330 } else if (name=="grotzsch") {
1331 read_special(grotzsch_graph);
1332 for (int i=1;i<=5;++i) hull.push_back(node_index(i));
1333 make_circular_layout(x,hull,2.5);
1334 } else if (name=="f26a") {
1335 make_lcf_graph(f26a_graph_lcf,13);
1336 for (int i=0;i<node_count();++i) hull.push_back(i);
1337 make_circular_layout(x,hull);
1338 } else if (name=="harries") {
1339 make_lcf_graph(harries_graph_lcf,5);
1340 for (int i=0;i<node_count();++i) hull.push_back(i);
1341 make_circular_layout(x,hull);
1342 } else if (name=="harries-wong") {
1343 make_lcf_graph(harries_wong_graph_lcf,1);
1344 for (int i=0;i<node_count();++i) hull.push_back(i);
1345 make_circular_layout(x,hull);
1346 } else if (name=="balaban10") {
1347 make_lcf_graph(balaban_10cage_lcf,1);
1348 for (int i=0;i<node_count();++i) hull.push_back(i);
1349 make_circular_layout(x,hull);
1350 } else if (name=="balaban11") {
1351 make_lcf_graph(balaban_11cage_lcf,1);
1352 for (int i=0;i<node_count();++i) hull.push_back(i);
1353 make_circular_layout(x,hull);
1354 } else if (name=="heawood") {
1355 read_special(heawood_graph);
1356 } else if (name=="herschel") {
1357 read_special(herschel_graph);
1358 make_planar_layout(x);
1359 layout_best_rotation(x);
1360 } else if (name=="hoffman") {
1361 vecteur labels;
1362 make_default_labels(labels,16);
1363 add_nodes(labels);
1364 for (int i=0;i<16;++i) for (int j=0;j<16;++j) {
1365 if ((i<8 && j<8) || (i>=8 && j>=8)) continue;
1366 if (hoffman_graph_matrix[i<j?j-8:i-8][i<j?i:j]==1)
1367 add_edge(i,j);
1368 }
1369 make_spring_layout(x,2);
1370 layout_best_rotation(x);
1371 } else if (name=="icosahedron") {
1372 read_special(icosahedron_graph);
1373 make_planar_layout(x);
1374 layout_best_rotation(x);
1375 } else if (name=="levi") {
1376 make_lcf_graph(tutte_8cage_lcf,5);
1377 for (int i=0;i<node_count();++i) hull.push_back(i);
1378 make_circular_layout(x,hull);
1379 } else if (name=="ljubljana") {
1380 make_lcf_graph(ljubljana_graph_lcf,2);
1381 } else if (name=="foster") {
1382 make_lcf_graph(foster_graph_lcf,15);
1383 for (int i=0;i<node_count();++i) hull.push_back(i);
1384 make_circular_layout(x,hull);
1385 } else if (name=="mcgee") {
1386 read_special(mcgee_graph);
1387 for (int i=0;i<node_count();++i) hull.push_back(i);
1388 make_circular_layout(x,hull);
1389 } else if (name=="mobius-kantor") {
1390 make_petersen_graph(8,3,&x);
1391 } else if (name=="moser") {
1392 read_special(moser_spindle_graph);
1393 make_planar_layout(x);
1394 layout_best_rotation(x);
1395 } else if (name=="nauru") {
1396 make_petersen_graph(12,5,&x);
1397 } else if (name=="octahedron") {
1398 read_special(octahedron_graph);
1399 make_planar_layout(x);
1400 layout_best_rotation(x);
1401 } else if (name=="pappus") {
1402 read_special(pappus_graph);
1403 for (int i=0;i<node_count();++i) hull.push_back(i);
1404 make_circular_layout(x,hull);
1405 } else if (name=="petersen") {
1406 make_petersen_graph(5,2,&x);
1407 } else if (name=="robertson") {
1408 read_special(robertson_graph);
1409 for (int i=0;i<node_count();++i) hull.push_back(i);
1410 make_circular_layout(x,hull);
1411 } else if (name=="soccerball") {
1412 read_special(soccer_ball_graph);
1413 for (int i=16;i<=20;++i) hull.push_back(node_index(i));
1414 make_circular_layout(x,hull,2.5);
1415 } else if (name=="shrikhande") {
1416 make_shrikhande_graph();
1417 for (int i=0;i<4;++i) {
1418 add_temporary_edge(i,i+8);
1419 hull.push_back(i);
1420 }
1421 add_temporary_edge(8,10);
1422 add_temporary_edge(9,11);
1423 add_temporary_edge(4,6);
1424 add_temporary_edge(5,7);
1425 make_circular_layout(x,hull);
1426 remove_temporary_edges();
1427 } else if (name=="tetrahedron") {
1428 read_special(tetrahedron_graph);
1429 make_planar_layout(x);
1430 layout_best_rotation(x);
1431 } else if (name=="tietze") {
1432 read_special(tietze_graph);
1433 hull.push_back(0); hull.push_back(1); hull.push_back(4);
1434 hull.push_back(6); hull.push_back(2); hull.push_back(9);
1435 hull.push_back(5); hull.push_back(8); hull.push_back(3);
1436 make_circular_layout(x,hull);
1437 layout_best_rotation(x);
1438 } else if (name=="tutte") {
1439 make_tutte_graph();
1440 vecteur l=makevecteur(28,12,15,13,42,45,43,27,30);
1441 for (const_iterateur it=l.begin();it!=l.end();++it) {
1442 hull.push_back(node_index(*it));
1443 }
1444 make_circular_layout(x,hull);
1445 layout_best_rotation(x);
1446 } else if (name=="tutte12") {
1447 make_lcf_graph(tutte_12cage_lcf,7);
1448 for (int i=0;i<node_count();++i) hull.push_back(i);
1449 make_circular_layout(x,hull);
1450 } else if (name=="wagner") {
1451 read_special(wagner_graph);
1452 hull.push_back(0); hull.push_back(1);
1453 hull.push_back(4); hull.push_back(6);
1454 hull.push_back(2); hull.push_back(5);
1455 hull.push_back(7); hull.push_back(3);
1456 make_circular_layout(x,hull);
1457 layout_best_rotation(x);
1458 }
1459 if (!x.empty()) {
1460 double sep=1.0;
1461 scale_layout(x,sep*std::sqrt((double)node_count()));
1462 rectangle rect=layout_bounding_rect(x,sep/PLASTIC_NUMBER_3);
1463 translate_layout(x,make_point(-rect.x(),-rect.y()));
1464 store_layout(x);
1465 }
1466 }
1467
1468 /* export this graph as a Giac gen object */
to_gen()1469 gen graphe::to_gen() {
1470 assert(supports_attributes());
1471 int n=node_count();
1472 vecteur res(2+int(user_tags.size())+n+edge_count()*(is_directed()?1:2));
1473 int cnt=0;
1474 gen_map attr;
1475 attrib2genmap(attributes,attr);
1476 res[cnt++]=n;
1477 res[cnt++]=attr;
1478 for (vector<string>::const_iterator it=user_tags.begin();it!=user_tags.end();++it) {
1479 res[cnt++]=str2gen(*it,true);
1480 }
1481 for (int i=0;i<n;++i) {
1482 gen_map vattr;
1483 const vertex &v=node(i);
1484 attrib2genmap(v.attributes(),vattr);
1485 vattr[-1]=v.neighbors().size();
1486 res[cnt++]=vattr;
1487 }
1488 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1489 const vertex &v=*it;
1490 for (ivector_iter jt=v.neighbors().begin();jt!=v.neighbors().end();++jt) {
1491 gen_map nattr;
1492 attrib2genmap(v.neighbor_attributes(*jt),nattr);
1493 nattr[-1]=*jt;
1494 res[cnt++]=nattr;
1495 }
1496 }
1497 return change_subtype(res,_GRAPH__VECT);
1498 }
1499
1500 /* allocate, initialize and return an integer array of adjacency lists of this graph,
1501 * in form [c1,a11,a12,..,-1,c2,a21,a22,..,-1,..], where c1,c2,... are vertex colors */
to_array(int & sz,bool reduce) const1502 int *graphe::to_array(int &sz,bool reduce) const {
1503 assert(!reduce || !is_directed());
1504 sz=0;
1505 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1506 sz+=it->neighbors().size();
1507 }
1508 if (reduce) {
1509 assert((sz%2)==0);
1510 sz/=2;
1511 }
1512 sz+=2*node_count();
1513 int *res=new int[sz];
1514 int i=0,c;
1515 attrib_iter ait;
1516 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1517 if (supports_attributes()) {
1518 c=default_vertex_color;
1519 if ((ait=it->attributes().find(_GT_ATTRIB_COLOR))!=it->attributes().end()) {
1520 c=ait->second.val;
1521 }
1522 } else c=it->color();
1523 res[i++]=c;
1524 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
1525 if (!reduce || *jt>int(it-nodes.begin()))
1526 res[i++]=*jt;
1527 }
1528 res[i++]=-1;
1529 }
1530 return res;
1531 }
1532
1533 /* return index associated with the specified attribute tag */
tag2index(const string & tag)1534 int graphe::tag2index(const string &tag) {
1535 if (tag=="label")
1536 return _GT_ATTRIB_LABEL;
1537 if (tag=="directed")
1538 return _GT_ATTRIB_DIRECTED;
1539 if (tag=="weighted")
1540 return _GT_ATTRIB_WEIGHTED;
1541 if (tag=="weight")
1542 return _GT_ATTRIB_WEIGHT;
1543 if (tag=="color")
1544 return _GT_ATTRIB_COLOR;
1545 if (tag=="style")
1546 return _GT_ATTRIB_STYLE;
1547 if (tag=="shape")
1548 return _GT_ATTRIB_SHAPE;
1549 if (tag=="pos")
1550 return _GT_ATTRIB_POSITION;
1551 if (tag=="name")
1552 return _GT_ATTRIB_NAME;
1553 if (tag=="temp")
1554 return _GT_ATTRIB_TEMPORARY;
1555 return register_user_tag(tag);
1556 }
1557
1558 /* return attribute tag associated with the specified index */
index2tag(int index) const1559 string graphe::index2tag(int index) const {
1560 int len;
1561 switch (index) {
1562 case _GT_ATTRIB_LABEL:
1563 return "label";
1564 case _GT_ATTRIB_DIRECTED:
1565 return "directed";
1566 case _GT_ATTRIB_WEIGHTED:
1567 return "weighted";
1568 case _GT_ATTRIB_COLOR:
1569 return "color";
1570 case _GT_ATTRIB_STYLE:
1571 return "style";
1572 case _GT_ATTRIB_SHAPE:
1573 return "shape";
1574 case _GT_ATTRIB_WEIGHT:
1575 return "weight";
1576 case _GT_ATTRIB_POSITION:
1577 return "pos";
1578 case _GT_ATTRIB_NAME:
1579 return "name";
1580 case _GT_ATTRIB_TEMPORARY:
1581 return "temp";
1582 case _GT_ATTRIB_USER:
1583 default:
1584 len=index-_GT_ATTRIB_USER;
1585 assert(int(user_tags.size())>len);
1586 return user_tags[len];
1587 }
1588 }
1589
1590 /* register custom user attribute tag */
register_user_tag(const string & tag)1591 int graphe::register_user_tag(const string &tag) {
1592 int i=_GT_ATTRIB_USER;
1593 vector<string>::const_iterator it=user_tags.begin();
1594 for (;it!=user_tags.end();++it) {
1595 if (*it==tag)
1596 return i;
1597 ++i;
1598 }
1599 user_tags.push_back(tag);
1600 return i;
1601 }
1602
1603 /* register custom user tags */
register_user_tags(const vector<string> & tags)1604 void graphe::register_user_tags(const vector<string> &tags) {
1605 for (vector<string>::const_iterator it=tags.begin();it!=tags.end();++it) {
1606 register_user_tag(*it);
1607 }
1608 }
1609
1610 /* fill V with marked vertices */
get_marked_nodes(vecteur & V) const1611 void graphe::get_marked_nodes(vecteur &V) const {
1612 V.clear();
1613 for (ivector_iter it=marked_nodes.begin();it!=marked_nodes.end();++it) {
1614 V.push_back(node_label(*it));
1615 }
1616 }
1617
1618 /* fill m with marked nodes belonging to the s-th subgraph */
get_marked_nodes_in_subgraph(int s,ivector & m) const1619 void graphe::get_marked_nodes_in_subgraph(int s,ivector &m) const {
1620 m.clear();
1621 m.reserve(marked_nodes.size());
1622 for (ivector_iter it=marked_nodes.begin();it!=marked_nodes.end();++it) {
1623 if (node(*it).subgraph()==s)
1624 m.push_back(*it);
1625 }
1626 }
1627
1628 /* mark vertex with index v */
mark_node(int v)1629 void graphe::mark_node(int v) {
1630 if (find(marked_nodes.begin(),marked_nodes.end(),v)==marked_nodes.end())
1631 marked_nodes.push_back(v);
1632 }
1633
1634 /* remove vertex v from the list of marked vertices */
unmark_node(int v)1635 bool graphe::unmark_node(int v) {
1636 ivector::iterator it;
1637 if ((it=find(marked_nodes.begin(),marked_nodes.end(),v))!=marked_nodes.end()) {
1638 marked_nodes.erase(it);
1639 return true;
1640 }
1641 return false;
1642 }
1643
1644 /* set edge {i,j} visited */
set_edge_visited(int i,int j)1645 void graphe::set_edge_visited(int i,int j) {
1646 if (visited_edges.empty())
1647 visited_edges.resize(node_count());
1648 ivector &ngh=visited_edges[i<j?i:j];
1649 int k=i<j?j:i;
1650 if (ngh.empty())
1651 ngh.push_back(k);
1652 else {
1653 ivector::iterator it=ngh.begin();
1654 while (it!=ngh.end() && *it<k) ++it;
1655 ngh.insert(it,k);
1656 }
1657 }
1658
1659 /* return true iff edge {i,j} is visited */
is_edge_visited(int i,int j) const1660 bool graphe::is_edge_visited(int i,int j) const {
1661 if (visited_edges.empty())
1662 return false;
1663 const ivector &ngh=visited_edges[i<j?i:j];
1664 return binary_search(ngh.begin(),ngh.end(),i<j?j:i);
1665 }
1666
1667 /* return edge as pair of vertex indices */
make_edge(const vecteur & v) const1668 graphe::ipair graphe::make_edge(const vecteur &v) const {
1669 assert(v.size()==2);
1670 int i=node_index(v.front()),j=node_index(v.back());
1671 return make_pair(i,j);
1672 }
1673
1674 /* convert vecteur E to list of ipairs representing edges, return false iff error occurs,
1675 if edge is not found set notfound=true */
edges2ipairs(const vecteur & E,ipairs & ev,bool & notfound) const1676 bool graphe::edges2ipairs(const vecteur &E,ipairs &ev,bool ¬found) const {
1677 if (E.empty())
1678 return false;
1679 int i,j;
1680 if (ckmatrix(E)) {
1681 if (E.front()._VECTptr->size()!=2)
1682 return false;
1683 for (const_iterateur it=E.begin();it!=E.end();++it) {
1684 i=node_index(it->_VECTptr->front());
1685 j=node_index(it->_VECTptr->back());
1686 if (i<0 || j<0 || !has_edge(i,j)) {
1687 notfound=true;
1688 return false;
1689 }
1690 ev.push_back(make_pair(i,j));
1691 }
1692 } else {
1693 if (E.size()!=2)
1694 return false;
1695 i=node_index(E.front());
1696 j=node_index(E.back());
1697 if (i<0 || j<0 || !has_edge(i,j)) {
1698 notfound=true;
1699 return false;
1700 }
1701 ev.push_back(make_pair(i,j));
1702 }
1703 return true;
1704 }
1705
1706 /* convert ipairs to edges */
ipairs2edges(const ipairs & E) const1707 vecteur graphe::ipairs2edges(const ipairs &E) const {
1708 vecteur res(E.size());
1709 for (ipairs_iter it=E.begin();it!=E.end();++it) {
1710 res[it-E.begin()]=makevecteur(node_label(it->first),node_label(it->second));
1711 }
1712 return res;
1713 }
1714
1715 /* convert ipairs to ipairs */
ipairs2edgeset(const ipairs & E,edgeset & Eset)1716 void graphe::ipairs2edgeset(const ipairs &E,edgeset &Eset) {
1717 Eset.clear();
1718 for (ipairs_iter it=E.begin();it!=E.end();++it) {
1719 Eset.insert(*it);
1720 }
1721 }
1722
1723 /* return total number of edges/arcs */
edge_count(int sg) const1724 int graphe::edge_count(int sg) const {
1725 int count=0,dup=0;
1726 bool isdir=is_directed();
1727 for(node_iter it=nodes.begin();it!=nodes.end();++it) {
1728 if (sg>=0 && it->subgraph()!=sg)
1729 continue;
1730 if (sg<0)
1731 count+=it->degree();
1732 else {
1733 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
1734 if (sg<0 || node(*jt).subgraph()==sg) count++;
1735 }
1736 }
1737 if (!isdir)
1738 dup+=it->multiedge_count();
1739 }
1740 if (!isdir) {
1741 count/=2;
1742 count+=dup;
1743 }
1744 return count;
1745 }
1746
1747 /* return number of arcs going in the vertex with the specified index (when directed) */
in_degree(int index,int sg) const1748 int graphe::in_degree(int index,int sg) const {
1749 assert(index>=0 && index<node_count());
1750 int count=0;
1751 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1752 if ((sg<0 || it->subgraph()==sg) && it->has_neighbor(index))
1753 count++;
1754 }
1755 return count;
1756 }
1757
1758 /* return number of arcs going out of vertex with the specified index (when directed) */
out_degree(int index,int sg) const1759 int graphe::out_degree(int index,int sg) const {
1760 assert(index>=0 && index<node_count());
1761 const vertex &v=node(index);
1762 if (sg<0)
1763 return v.degree();
1764 int cnt=0;
1765 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
1766 if (node(*it).subgraph()==sg)
1767 ++cnt;
1768 }
1769 return cnt;
1770 }
1771
1772 /* return degree of vertex with the specified index */
degree(int index,int sg) const1773 int graphe::degree(int index,int sg) const {
1774 if (is_directed())
1775 return in_degree(index,sg)+out_degree(index,sg);
1776 return out_degree(index,sg);
1777 }
1778
1779 /* compute in and out degrees and store them */
compute_in_out_degrees(ivector & ind,ivector & outd) const1780 void graphe::compute_in_out_degrees(ivector &ind,ivector &outd) const {
1781 int n=node_count();
1782 ind.resize(n,0);
1783 outd.resize(n);
1784 for (int i=0;i<n;++i) {
1785 const vertex &v=node(i);
1786 outd[i]=v.neighbors().size();
1787 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
1788 ++ind[*it];
1789 }
1790 }
1791 }
1792
1793 /* return the maximum vertex degree */
maximum_degree() const1794 int graphe::maximum_degree() const {
1795 int maxdeg=0,d;
1796 for (int i=0;i<node_count();++i) {
1797 if ((d=degree(i))>maxdeg)
1798 maxdeg=d;
1799 }
1800 return maxdeg;
1801 }
1802
1803 /* return the minimum vertex degree */
minimum_degree() const1804 int graphe::minimum_degree() const {
1805 int mindeg=RAND_MAX,d;
1806 for (int i=0;i<node_count();++i) {
1807 if ((d=degree(i))<mindeg)
1808 mindeg=d;
1809 }
1810 return mindeg;
1811 }
1812
1813 /* return the degree sequence of this graph */
degree_sequence(int sg) const1814 vecteur graphe::degree_sequence(int sg) const {
1815 vecteur res;
1816 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1817 if (sg>=0 && it->subgraph()!=sg)
1818 continue;
1819 res.push_back(degree(it-nodes.begin()));
1820 }
1821 return res;
1822 }
1823
1824 /* sort the vertices by order of their degrees, starting from the highest */
sort_by_degrees()1825 void graphe::sort_by_degrees() {
1826 int n=node_count();
1827 ipairs lst(n);
1828 for (int i=0;i<n;++i) {
1829 lst[i]=make_pair(degree(i),i);
1830 }
1831 sort(lst.rbegin(),lst.rend());
1832 ivector sigma(n);
1833 for (ipairs_iter it=lst.begin();it!=lst.end();++it) {
1834 sigma[it-lst.begin()]=it->second;
1835 }
1836 graphe G(*this);
1837 G.isomorphic_copy(*this,sigma);
1838 }
1839
1840 /* create the adjacency matrix of this graph */
adjacency_matrix(matrice & m) const1841 void graphe::adjacency_matrix(matrice &m) const {
1842 int n=node_count(),i,j;
1843 m=*_matrix(makesequence(n,n),context0)._VECTptr;
1844 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1845 i=it-nodes.begin();
1846 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
1847 j=*jt;
1848 m[i]._VECTptr->at(j)=1;
1849 }
1850 }
1851 }
1852
1853 /* create the adjacency matrix as a sparse matrix */
adjacency_sparse_matrix(sparsemat & sm) const1854 void graphe::adjacency_sparse_matrix(sparsemat &sm) const {
1855 sm.clear();
1856 int i,j;
1857 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1858 i=it-nodes.begin();
1859 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
1860 j=*jt;
1861 sm[i][j]=make_pair(1,1);
1862 }
1863 }
1864 }
1865
1866 /* create the Laplacian matrix of this graph */
laplacian_matrix(matrice & m,bool normalize) const1867 void graphe::laplacian_matrix(matrice &m,bool normalize) const {
1868 int n=node_count(),i,j;
1869 bool isdir=is_directed();
1870 vecteur ds=degree_sequence();
1871 ipairs E;
1872 get_edges_as_pairs(E);
1873 m=*_matrix(makesequence(n,n,0),ctx)._VECTptr;
1874 for (i=0;i<n;++i) {
1875 m[i]._VECTptr->at(i)=normalize?(is_zero(ds[i])?0:1):ds[i];
1876 }
1877 for (ipairs_iter it=E.begin();it!=E.end();++it) {
1878 i=it->first; j=it->second;
1879 m[i]._VECTptr->at(j)=normalize?-fraction(1,sqrt(ds[i]*ds[j],ctx)):gen(-1);
1880 if (!isdir)
1881 m[j]._VECTptr->at(i)=normalize?-fraction(1,sqrt(ds[i]*ds[j],ctx)):gen(-1);
1882 }
1883 }
1884
1885 /* return incidence matrix of this graph */
incidence_matrix(matrice & m) const1886 void graphe::incidence_matrix(matrice &m) const {
1887 ipairs E;
1888 get_edges_as_pairs(E);
1889 int nr=node_count(),nc=E.size();
1890 m=*_matrix(makesequence(nr,nc,0),context0)._VECTptr;
1891 bool isdir=is_directed();
1892 for (int i=0;i<nr;++i) {
1893 for (int j=0;j<nc;++j) {
1894 gen &mij=m[i]._VECTptr->at(j);
1895 const ipair &e=E[j];
1896 if (isdir) {
1897 if (i==e.first)
1898 mij=-1;
1899 else if (i==e.second)
1900 mij=1;
1901 } else if (i==e.first || i==e.second)
1902 mij=1;
1903 }
1904 }
1905 }
1906
1907 /* return weight associated with edge {i,j} or arc [i,j] */
weight(int i,int j) const1908 gen graphe::weight(int i,int j) const {
1909 const attrib &attr=edge_attributes(i,j);
1910 attrib_iter it=attr.find(_GT_ATTRIB_WEIGHT);
1911 if (it==attr.end())
1912 return undef;
1913 return it->second;
1914 }
1915
1916 /* return weight matrix */
weight_matrix(matrice & W) const1917 void graphe::weight_matrix(matrice &W) const {
1918 assert(is_weighted());
1919 int n=node_count(),i,j;
1920 W=*_matrix(makesequence(n,n,0),context0)._VECTptr;
1921 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1922 i=it-nodes.begin();
1923 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
1924 j=*jt;
1925 W[i]._VECTptr->at(j)=weight(i,j);
1926 }
1927 }
1928 }
1929
1930 /* return list of vertices (in the given subgraph) */
vertices(int sg) const1931 vecteur graphe::vertices(int sg) const {
1932 vecteur V;
1933 V.reserve(node_count());
1934 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1935 if (sg<0 || it->subgraph()==sg)
1936 V.push_back(it->label());
1937 }
1938 return V;
1939 }
1940
1941 /* make all vertices (in the given subgraph) unvisited */
unvisit_all_nodes(int sg)1942 void graphe::unvisit_all_nodes(int sg) {
1943 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
1944 if (sg<0 || it->subgraph()==sg)
1945 it->set_visited(false);
1946 }
1947 }
1948
1949 /* unset ancestors for all vertices (in the given subgraph) */
unset_all_ancestors(int sg)1950 void graphe::unset_all_ancestors(int sg) {
1951 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
1952 if (sg<0 || it->subgraph()==sg)
1953 it->unset_ancestor();
1954 }
1955 }
1956
1957 /* turn the color of each vertex to white */
uncolor_all_nodes(int base_color,int sg)1958 void graphe::uncolor_all_nodes(int base_color,int sg) {
1959 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
1960 if (sg<0 || it->subgraph()==sg)
1961 it->set_color(base_color);
1962 }
1963 }
1964
1965 /* fill the list E with edges (in the given subgraph) represented as pairs of vertex indices */
get_edges_as_pairs(ipairs & E,int sg) const1966 void graphe::get_edges_as_pairs(ipairs &E,int sg) const {
1967 int i,j;
1968 bool isdir=is_directed();
1969 E.clear();
1970 E.reserve(edge_count());
1971 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
1972 if (sg>=0 && it->subgraph()!=sg)
1973 continue;
1974 i=it-nodes.begin();
1975 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
1976 j=*jt;
1977 if ((isdir || j>i) && (sg<0 || node(j).subgraph()==sg))
1978 E.push_back(make_pair(i,j));
1979 }
1980 }
1981 }
1982
1983 /* return list of edges/arcs (in the given subgraph) */
edges(bool include_weights,int sg) const1984 vecteur graphe::edges(bool include_weights,int sg) const {
1985 ipairs E;
1986 get_edges_as_pairs(E,sg);
1987 vecteur edge(2),ret(E.size());
1988 int i=0;
1989 bool isdir=is_directed();
1990 for (ipairs_iter it=E.begin();it!=E.end();++it) {
1991 edge[0]=node(it->first).label();
1992 edge[1]=node(it->second).label();
1993 if (!isdir)
1994 edge=*_sort(edge,ctx)._VECTptr;
1995 ret[i++]=include_weights?makevecteur(edge,weight(*it)):edge;
1996 }
1997 return ret;
1998 }
1999
2000 /* return the sequence of edge multiplicities */
edge_multiplicities() const2001 graphe::ivector graphe::edge_multiplicities() const {
2002 ipairs E;
2003 get_edges_as_pairs(E);
2004 int m=E.size();
2005 ivector res(m);
2006 for (ipairs_iter it=E.begin();it!=E.end();++it) {
2007 res[it-E.begin()]=multiedges(*it)+1;
2008 }
2009 return res;
2010 }
2011
2012 /* return the total number of edges, counting multiple edges too */
sum_of_edge_multiplicities() const2013 int graphe::sum_of_edge_multiplicities() const {
2014 ivector mult=edge_multiplicities();
2015 int res=0;
2016 for (ivector_iter it=mult.begin();it!=mult.end();++it) {
2017 res+=*it;
2018 }
2019 return res;
2020 }
2021
2022 /* write attributes to dot file */
write_attrib(ofstream & dotfile,const attrib & attr) const2023 void graphe::write_attrib(ofstream &dotfile,const attrib &attr) const {
2024 dotfile << "[";
2025 for (attrib_iter it=attr.begin();it!=attr.end();++it) {
2026 if (it!=attr.begin())
2027 dotfile << ",";
2028 dotfile << index2tag(it->first) << "=" << it->second;
2029 }
2030 dotfile << "]";
2031 }
2032
2033 /* export the drawing of this graph in latex format */
write_latex(const string & filename,const gen & drawing) const2034 bool graphe::write_latex(const string &filename,const gen &drawing) const {
2035 ofstream texfile;
2036 texfile.open(filename.c_str());
2037 if (!texfile.is_open())
2038 return false;
2039 show_axes(0,ctx);
2040 string picture=genstring2str(_latex(drawing,ctx));
2041 texfile << "% this file was generated by " << giac_version() << "\n";
2042 texfile << "\\documentclass{standalone}\n" << "\\usepackage[T1]{fontenc}\n"
2043 << "\\usepackage[utf8]{inputenc}\n" << "\\usepackage{pstricks}\n"
2044 << "\\begin{document}\n" << picture << "\\end{document}\n";
2045 texfile.close();
2046 return true;
2047 }
2048
2049 /* export this graph to dot file */
write_dot(const string & filename) const2050 bool graphe::write_dot(const string &filename) const {
2051 ofstream dotfile;
2052 dotfile.open(filename.c_str());
2053 if (!dotfile.is_open())
2054 return false;
2055 dotfile << "# this file was generated by " << giac_version() << "\n";
2056 ivector u,v;
2057 string indent(" "),edgeop(is_directed()?" -> ":" -- ");
2058 dotfile << (is_directed()?"digraph ":"graph ");
2059 string graph_name=name();
2060 if (graph_name.empty())
2061 dotfile << "{\n";
2062 else
2063 dotfile << graph_name << " {\n";
2064 if (!attributes.empty()) {
2065 dotfile << indent << "graph ";
2066 write_attrib(dotfile,attributes);
2067 dotfile << "\n";
2068 }
2069 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2070 if (!it->attributes().empty()) {
2071 dotfile << indent << it->label() << " ";
2072 write_attrib(dotfile,it->attributes());
2073 dotfile << ";\n";
2074 }
2075 u.clear();
2076 v.clear();
2077 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
2078 if (it->neighbor_attributes(*jt).empty())
2079 u.push_back(*jt);
2080 else
2081 v.push_back(*jt);
2082 }
2083 if (!u.empty()) {
2084 dotfile << indent << it->label() << edgeop << "{ ";
2085 for (ivector_iter kt=u.begin();kt!=u.end();++kt) {
2086 dotfile << node(*kt).label() << " ";
2087 }
2088 dotfile << "};\n";
2089 }
2090 for (ivector_iter kt=v.begin();kt!=v.end();++kt) {
2091 dotfile << indent << it->label() << edgeop << node(*kt).label() << " ";
2092 write_attrib(dotfile,it->neighbor_attributes(*kt));
2093 dotfile << ";\n";
2094 }
2095 }
2096 dotfile << "}\n";
2097 dotfile.close();
2098 return true;
2099 }
2100
2101 static int dot_comment_type;
2102 static int dot_subgraph_level;
2103 static bool dot_reading_attributes;
2104 static bool dot_reading_value;
2105 static int dot_newline_count;
2106 static int dot_token_type;
2107
2108 /* returns true iff last read token is an identifier, number or string */
dot_token_is_id()2109 bool dot_token_is_id() {
2110 return dot_token_type==_GT_DOT_TOKEN_TYPE_IDENTIFIER ||
2111 dot_token_type==_GT_DOT_TOKEN_TYPE_NUMBER ||
2112 dot_token_type==_GT_DOT_TOKEN_TYPE_STRING;
2113 }
2114
2115 /* return true iff char c is one of dot format delimiters */
dot_is_id_delim(const char & c)2116 bool dot_is_id_delim(const char &c) {
2117 return c=='{' || c=='}' || c=='[' || c==']' || c=='-' ||
2118 c==',' || c==';' || c=='=' || c=='/' || isspace(c);
2119 }
2120
2121 /* read next token in dot file 'dotfile' */
dot_read_token(ifstream & dotfile,string & token)2122 int dot_read_token(ifstream &dotfile,string &token) {
2123 char c=0,pc,nc;
2124 bool last=false;
2125 dot_token_type=0;
2126 token=string("");
2127 while (true) {
2128 if ((dot_token_type==_GT_DOT_TOKEN_TYPE_IDENTIFIER || dot_token_type==_GT_DOT_TOKEN_TYPE_NUMBER)
2129 && dot_is_id_delim(dotfile.peek()))
2130 break;
2131 pc=c;
2132 if (!dotfile.get(c))
2133 break;
2134 if (c=='\n')
2135 ++dot_newline_count;
2136 if (dot_token_type==_GT_DOT_TOKEN_TYPE_IDENTIFIER) {
2137 if (isalnum(c) || c=='_')
2138 token.push_back(c);
2139 else return 0;
2140 continue;
2141 }
2142 if (dot_token_type==_GT_DOT_TOKEN_TYPE_NUMBER) {
2143 if (isdigit(c) || c=='.')
2144 token.push_back(c);
2145 else return 0;
2146 continue;
2147 }
2148 nc=dotfile.peek();
2149 if (nc==EOF)
2150 last=true;
2151 if (dot_comment_type!=0) {
2152 if (((c=='\n' || c=='\r') && dot_comment_type==1) ||
2153 ((c=='/' && pc=='*') && dot_comment_type==2)) {
2154 if (token.empty()) {
2155 dot_comment_type=0;
2156 continue;
2157 }
2158 break;
2159 }
2160 continue;
2161 }
2162 if (c=='"') {
2163 if (dot_token_type==_GT_DOT_TOKEN_TYPE_STRING) {
2164 if (pc=='\\') {
2165 token.erase(token.end()-1);
2166 token.push_back(c);
2167 continue;
2168 }
2169 break;
2170 }
2171 dot_token_type=_GT_DOT_TOKEN_TYPE_STRING;
2172 continue;
2173 }
2174 if (dot_token_type==_GT_DOT_TOKEN_TYPE_STRING) {
2175 if (last)
2176 return 0;
2177 token.push_back(c);
2178 continue;
2179 }
2180 if (isblank(c) || (dot_subgraph_level>0 && c==';') ||
2181 (dot_reading_attributes && c==',') || (!dot_reading_attributes && isspace(c))) {
2182 if (isspace(c))
2183 continue;
2184 token=string(1,c);
2185 dot_token_type=_GT_DOT_TOKEN_TYPE_DELIMITER;
2186 return 1;
2187 }
2188 if (c=='{' || c=='}') {
2189 dot_subgraph_level+=c=='{'?1:-1;
2190 token=string(1,c);
2191 dot_token_type=_GT_DOT_TOKEN_TYPE_DELIMITER;
2192 return 1;
2193 }
2194 if (c=='[' || c==']') {
2195 dot_reading_attributes=c=='[';
2196 token=string(1,c);
2197 dot_token_type=_GT_DOT_TOKEN_TYPE_DELIMITER;
2198 return 1;
2199 }
2200 if (c=='=') {
2201 dot_reading_value=true;
2202 token=string(1,c);
2203 dot_token_type=_GT_DOT_TOKEN_TYPE_OPERATOR;
2204 return 1;
2205 }
2206 if (c=='#' && (pc==0 || pc=='\n' || pc=='\r')) {
2207 dot_comment_type=1;
2208 continue;
2209 }
2210 if (c=='/') {
2211 if (last)
2212 return 0;
2213 if (nc=='/')
2214 dot_comment_type=1;
2215 if (nc=='*')
2216 dot_comment_type=2;
2217 return 0;
2218 }
2219 if (token.empty() && (isalpha(c) || c=='_')) {
2220 dot_token_type=_GT_DOT_TOKEN_TYPE_IDENTIFIER;
2221 token.push_back(c);
2222 continue;
2223 }
2224 if (token.empty() && (isdigit(c) || (c=='-' && isdigit(nc)))) {
2225 dot_token_type=_GT_DOT_TOKEN_TYPE_NUMBER;
2226 token.push_back(c);
2227 continue;
2228 }
2229 if ((c=='-' || c=='>') && pc=='-') {
2230 dot_token_type=_GT_DOT_TOKEN_TYPE_OPERATOR;
2231 token=string("-")+c;
2232 return 1;
2233 }
2234 }
2235 if (dot_token_is_id())
2236 dot_reading_value=false;
2237 return dot_token_type==0?-1:1;
2238 }
2239
2240 /* insert attribute key=val to attr [and overwrite existing value] */
insert_attribute(attrib & attr,int key,const gen & val,bool overwrite)2241 bool graphe::insert_attribute(attrib &attr,int key,const gen &val,bool overwrite) {
2242 pair<attrib::iterator,bool> res;
2243 if ((res=attr.insert(make_pair(key,val))).second==false && overwrite)
2244 (res.first)->second=val;
2245 return res.second;
2246 }
2247
2248 /* remove attribute with key 'key' from attr */
remove_attribute(attrib & attr,int key)2249 bool graphe::remove_attribute(attrib &attr,int key) {
2250 attrib::iterator it=attr.find(key);
2251 if (it==attr.end())
2252 return false;
2253 attr.erase(it);
2254 return true;
2255 }
2256
2257 /* parse attributes from dot file */
dot_parse_attributes(ifstream & dotfile,attrib & attr)2258 bool graphe::dot_parse_attributes(ifstream &dotfile,attrib &attr) {
2259 string token;
2260 int key;
2261 while(true) {
2262 if (dot_read_token(dotfile,token)!=1)
2263 return false;
2264 if (token=="]")
2265 break;
2266 if (token==";" || token==",")
2267 continue;
2268 if (!dot_token_is_id())
2269 return false;
2270 key=tag2index(token);
2271 if (key==-1 || dot_read_token(dotfile,token)!=1 || token!="=" ||
2272 dot_read_token(dotfile,token)!=1 || dot_reading_value || !dot_token_is_id())
2273 return false;
2274 if (key==_GT_ATTRIB_WEIGHT && !is_weighted()) set_weighted(true);
2275 insert_attribute(attr,key,str2gen(token,dot_token_type==_GT_DOT_TOKEN_TYPE_STRING));
2276 }
2277 return true;
2278 }
2279
2280 /* initialize graph from dot file */
read_dot(const string & filename)2281 bool graphe::read_dot(const string &filename) {
2282 ifstream dotfile;
2283 dotfile.open(filename.c_str());
2284 if (!dotfile.is_open())
2285 return false;
2286 dot_subgraph_level=0;
2287 dot_reading_attributes=false;
2288 dot_reading_value=false;
2289 dot_comment_type=0;
2290 dot_newline_count=0;
2291 map<int,attrib> delayed_attributes;
2292 string token;
2293 int res,gtype,subgraph_count=0,index;
2294 bool strict=false,error_raised=false,has_root_graph=false;
2295 vector<dotgraph> subgraphs;
2296 while (true) {
2297 res=dot_read_token(dotfile,token);
2298 if (res!=1) { error_raised=(bool)(res+1); break; }
2299 switch (dot_token_type) {
2300 case _GT_DOT_TOKEN_TYPE_IDENTIFIER:
2301 if (token=="strict") {
2302 strict=true;
2303 continue;
2304 } else if (token=="graph" || token=="digraph" || token=="subgraph") {
2305 if (token=="digraph") {
2306 if (dot_subgraph_level>0) { error_raised=true; break; }
2307 set_directed(true);
2308 gtype=1;
2309 } else if (token=="subgraph") {
2310 gtype=2;
2311 } else gtype=0;
2312 if (gtype!=2 && strict)
2313 strict=false;
2314 if (dot_read_token(dotfile,token)!=1) { error_raised=true; break; }
2315 if (dot_token_type!=_GT_DOT_TOKEN_TYPE_DELIMITER) {
2316 if (!dot_token_is_id()) { error_raised=true; break; }
2317 if (gtype!=2)
2318 set_name(token);
2319 if (dot_read_token(dotfile,token)!=1 ||
2320 dot_token_type!=_GT_DOT_TOKEN_TYPE_DELIMITER) { error_raised=true; break; }
2321 } else if (token=="[") {
2322 if (gtype!=0 || !dot_parse_attributes(dotfile,attributes))
2323 error_raised=true;
2324 break;
2325 }
2326 if ((gtype!=2 && has_root_graph) || token!="{")
2327 error_raised=true;
2328 subgraphs.push_back(dotgraph(subgraph_count++));
2329 if (gtype!=2)
2330 has_root_graph=true;
2331 break;
2332 } else if (token=="node" || token=="edge") {
2333 if (dot_read_token(dotfile,token)!=1 || dot_token_type!=_GT_DOT_TOKEN_TYPE_DELIMITER ||
2334 token!="[" || !dot_parse_attributes(dotfile,token=="node"?
2335 subgraphs.back().vertex_attributes():
2336 subgraphs.back().edge_attributes()))
2337 error_raised=true;
2338 break;
2339 }
2340 case _GT_DOT_TOKEN_TYPE_NUMBER:
2341 case _GT_DOT_TOKEN_TYPE_STRING:
2342 index=add_node(str2gen(token,dot_token_type!=_GT_DOT_TOKEN_TYPE_NUMBER));
2343 if (subgraphs.empty()) { error_raised=true; break; }
2344 node(index).set_subgraph(subgraphs.back().index());
2345 subgraphs.back().set_index(index+1);
2346 break;
2347 case _GT_DOT_TOKEN_TYPE_DELIMITER:
2348 if (token==";") {
2349 if (subgraphs.back().chain_empty())
2350 continue;
2351 if (!subgraphs.back().chain_completed()) { error_raised=true; break; }
2352 ivector &ch=subgraphs.back().chain();
2353 attrib &attr=subgraphs.back().chain_attributes();
2354 if (subgraphs.back().position()==0) {
2355 if (ch.front()<=0) { error_raised=true; break; }
2356 delayed_attributes[ch.front()-1]=subgraphs.back().chain_attributes();
2357 }
2358 int lh,rh;
2359 for (int i=0;i<=subgraphs.back().position()-1;++i) {
2360 lh=ch[i];
2361 rh=ch[i+1];
2362 if (lh==0 || rh==0) { error_raised=true; break; }
2363 if (lh>0 && rh>0)
2364 add_edge(lh-1,rh-1,attr);
2365 else if (lh<0 && rh<0) {
2366 int j=0,k=0;
2367 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2368 if (it->subgraph()==-lh) {
2369 for (node_iter jt=nodes.begin();jt!=nodes.end();++jt) {
2370 if (jt->subgraph()==-rh)
2371 add_edge(j,k,attr);
2372 ++k;
2373 }
2374 }
2375 ++j;
2376 }
2377 } else {
2378 int j=0;
2379 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2380 if (it->subgraph()==(lh>0?-rh:-lh))
2381 add_edge(lh>0?lh-1:j,lh>0?j:rh-1,attr);
2382 ++j;
2383 }
2384 }
2385 }
2386 subgraphs.back().clear_chain();
2387 } else if (token=="[") {
2388 attrib &attr=subgraphs.back().chain_attributes();
2389 if (!attr.empty() || !dot_parse_attributes(dotfile,attr))
2390 error_raised=true;
2391 } else if (token=="{") {
2392 if (dot_subgraph_level<2) { error_raised=true; break; }
2393 subgraphs.push_back(dotgraph(subgraph_count++));
2394 } else if (token=="}") {
2395 if (subgraphs.empty()) { error_raised=true; break; }
2396 index=subgraphs.back().index();
2397 subgraphs.pop_back();
2398 if (!subgraphs.empty())
2399 subgraphs.back().set_index(-index);
2400 }
2401 break;
2402 case _GT_DOT_TOKEN_TYPE_OPERATOR:
2403 if (dot_subgraph_level<1) { error_raised=true; break; }
2404 if (token=="--" || token=="->") {
2405 if ((is_directed() && token=="--") || (!is_directed() && token=="->")) { error_raised=true; break; }
2406 subgraphs.back().incr();
2407 }
2408 break;
2409 default:
2410 message((string("Error: unknown token '")+token+"'").c_str());
2411 break;
2412 }
2413 if (error_raised || strict)
2414 break;
2415 }
2416 dotfile.close();
2417 if (dot_subgraph_level!=0 || strict || dot_reading_value || dot_reading_attributes)
2418 error_raised=true;
2419 else {
2420 /* set delayed attributes to nodes */
2421 for (map<int,attrib>::const_iterator it=delayed_attributes.begin();it!=delayed_attributes.end();++it) {
2422 vertex &v=node(it->first);
2423 for (attrib_iter ait=it->second.begin();ait!=it->second.end();++ait) {
2424 v.set_attribute(ait->first,ait->second);
2425 }
2426 }
2427 }
2428 return !error_raised;
2429 }
2430
2431 /* assign weights from matrix m to edges/arcs of this graph */
make_weighted(const matrice & m)2432 void graphe::make_weighted(const matrice &m) {
2433 assert(is_squarematrix(m) && int(m.size())==node_count());
2434 int i;
2435 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
2436 i=it-nodes.begin();
2437 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
2438 if (is_directed() || i<*jt)
2439 insert_attribute(it->neighbor_attributes(*jt),_GT_ATTRIB_WEIGHT,m[i][*jt]);
2440 }
2441 }
2442 set_graph_attribute(_GT_ATTRIB_WEIGHTED,VRAI);
2443 }
2444
2445 /* make this graph unweighted */
make_unweighted()2446 void graphe::make_unweighted() {
2447 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
2448 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
2449 remove_attribute(it->neighbor_attributes(*jt),_GT_ATTRIB_WEIGHT);
2450 }
2451 }
2452 set_graph_attribute(_GT_ATTRIB_WEIGHTED,FAUX);
2453 }
2454
2455 /* randomize edge weights, generating them in segment [a,b] */
randomize_edge_weights(double a,double b,bool integral_weights)2456 void graphe::randomize_edge_weights(double a,double b,bool integral_weights) {
2457 assert(a<=b);
2458 if (!is_weighted())
2459 set_graph_attribute(_GT_ATTRIB_WEIGHTED,boole(true));
2460 int m,n;
2461 if (integral_weights) {
2462 m=std::floor(a);
2463 n=std::floor(b);
2464 }
2465 int nc=node_count();
2466 gen w;
2467 for (int i=0;i<nc;++i) {
2468 for (int j=is_directed()?0:i+1;j<nc;++j) {
2469 if (!has_edge(i,j))
2470 continue;
2471 if (integral_weights)
2472 w=gen(rand_integer(n-m+1)+m);
2473 else
2474 w=gen(a+rand_uniform()*(b-a));
2475 set_edge_attribute(i,j,_GT_ATTRIB_WEIGHT,w);
2476 }
2477 }
2478 }
2479
2480 /* store the underlying graph to G (convert arcs to edges and strip all attributes) */
underlying(graphe & G) const2481 void graphe::underlying(graphe &G) const {
2482 assert(supports_attributes() || !G.supports_attributes());
2483 int n=node_count();
2484 G.clear();
2485 G.set_directed(false);
2486 G.reserve_nodes(n);
2487 if (G.supports_attributes())
2488 G.add_nodes(vertices());
2489 else G.add_nodes(n);
2490 int i;
2491 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2492 i=it-nodes.begin();
2493 G.node(i).set_subgraph(it->subgraph());
2494 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
2495 G.add_edge(i,*jt);
2496 }
2497 }
2498 }
2499
2500 /* store the complement of this graph in G */
complement(graphe & G) const2501 void graphe::complement(graphe &G) const {
2502 assert(supports_attributes() || !G.supports_attributes());
2503 int n=node_count();
2504 G.clear();
2505 G.reserve_nodes(n);
2506 if (G.supports_attributes())
2507 G.add_nodes(vertices());
2508 else G.add_nodes(n);
2509 bool isdir=is_directed();
2510 G.set_directed(isdir);
2511 for (int i=0;i<n;++i) {
2512 for (int j=G.is_directed()?0:i+1;j<n;++j) {
2513 if (!has_edge(i,j))
2514 G.add_edge(i,j);
2515 }
2516 }
2517 }
2518
2519 /* read contents of gen_map and write it to attrib */
genmap2attrib(const gen_map & m,attrib & attr)2520 bool graphe::genmap2attrib(const gen_map &m,attrib &attr) {
2521 attr.clear();
2522 for (gen_map::const_iterator it=m.begin();it!=m.end();++it) {
2523 if (!it->first.is_integer())
2524 return false;
2525 attr.insert(make_pair(it->first.val,it->second));
2526 }
2527 return true;
2528 }
2529
2530 /* convert attrib to gen_map */
attrib2genmap(const attrib & attr,gen_map & m)2531 void graphe::attrib2genmap(const attrib &attr, gen_map &m) {
2532 m.clear();
2533 for (attrib_iter it=attr.begin();it!=attr.end();++it) {
2534 m[it->first]=it->second;
2535 }
2536 }
2537
gmap_find(const gen_map & gmap,const gen & key,gen & val)2538 bool gmap_find(const gen_map &gmap,const gen &key,gen &val) {
2539 gen_map::const_iterator it=gmap.find(key);
2540 if (it==gmap.end())
2541 return false;
2542 val=it->second;
2543 return true;
2544 }
2545
2546 /* initialize graph from Giac gen object */
read_gen(const gen & g)2547 bool graphe::read_gen(const gen &g) {
2548 if (g.type!=_VECT || g.subtype!=_GRAPH__VECT)
2549 return false;
2550 this->clear();
2551 int n;
2552 const vecteur &gv=*g._VECTptr;
2553 if (gv.empty() || !gv.front().is_integer() ||
2554 (n=gv.front().val)<0 || int(gv.size())<2+n || gv[1].type!=_MAP)
2555 return false;
2556 if (!genmap2attrib(*gv[1]._MAPptr,this->attributes))
2557 return false;
2558 int i0=2;
2559 for (const_iterateur it=gv.begin()+2;it!=gv.end() && it->type==_STRNG;++it) {
2560 register_user_tag(genstring2str(*it));
2561 ++i0;
2562 }
2563 gen val;
2564 attrib attr;
2565 int deg,start=n+i0,k;
2566 for (int i=0;i<n;++i) {
2567 const gen &elm=gv[i+i0];
2568 if (elm.type!=_MAP)
2569 return false;
2570 gen_map &mp=*elm._MAPptr;
2571 if (!gmap_find(mp,-1,val) || !val.is_integer() ||
2572 (deg=val.val)<0 || !genmap2attrib(mp,attr))
2573 return false;
2574 vertex vert(supports_attributes());
2575 if (supports_attributes()) {
2576 attr.erase(attr.find(-1));
2577 vert.set_attributes(attr);
2578 }
2579 if (int(gv.size())<start+deg)
2580 return false;
2581 for (int j=0;j<deg;++j) {
2582 const gen &ngh=gv[start+j];
2583 if (ngh.type!=_MAP)
2584 return false;
2585 gen_map &nmap=*ngh._MAPptr;
2586 attrib nattr;
2587 if (!gmap_find(nmap,-1,val) || !val.is_integer() ||
2588 (k=val.val)<0 || k>=n || !genmap2attrib(nmap,nattr))
2589 return false;
2590 if (supports_attributes()) nattr.erase(nattr.find(-1));
2591 vert.add_neighbor(k,nattr);
2592 }
2593 start+=deg;
2594 nodes.push_back(vert);
2595 }
2596 return true;
2597 }
2598
2599 /* read special graph from a list of adjacency lists of integers */
read_special(const int * special_graph)2600 void graphe::read_special(const int *special_graph) {
2601 int state=1;
2602 gen v,w;
2603 for(const int *p=special_graph;*p!=-2;++p) {
2604 if (*p==-1) {
2605 state=1;
2606 } else if (state==1) {
2607 v=gen(*p);
2608 state=2;
2609 } else if (state==2) {
2610 w=gen(*p);
2611 add_edge(v,w);
2612 }
2613 }
2614 }
2615
2616 /* read special graph from a list of adjacency lists of strings */
read_special(const char ** special_graph)2617 void graphe::read_special(const char **special_graph) {
2618 const char **p=special_graph;
2619 int state=1;
2620 gen v,w;
2621 string s;
2622 do {
2623 s=string(*p);
2624 if (s.empty()) {
2625 state=1;
2626 } else if (state==1) {
2627 state=2;
2628 v=str2gen(s,true);
2629 } else if (state==2) {
2630 w=str2gen(s,true);
2631 add_edge(v,w);
2632 }
2633 ++p;
2634 } while (*p!=NULL);
2635 }
2636
operator =(const graphe & other)2637 graphe &graphe::operator =(const graphe &other) {
2638 nodes.clear();
2639 m_supports_attributes=other.supports_attributes();
2640 other.copy(*this);
2641 return *this;
2642 }
2643
2644 /* make a copy of this graph and store it in G */
copy(graphe & G) const2645 void graphe::copy(graphe &G) const {
2646 assert(supports_attributes() || !G.supports_attributes());
2647 G.clear();
2648 G.set_name(name());
2649 G.register_user_tags(user_tags);
2650 G.set_graph_attributes(attributes);
2651 G.copy_nodes(nodes);
2652 G.copy_marked_nodes(get_marked_nodes());
2653 }
2654
copy_nodes(const vector<vertex> & V)2655 void graphe::copy_nodes(const vector<vertex> &V) {
2656 nodes=V;
2657 if (!supports_attributes()) {
2658 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
2659 it->unsupport_attributes();
2660 }
2661 }
2662 }
2663
2664 /* returns true iff graph has edge {i,j} */
has_edge(int i,int j,int sg) const2665 bool graphe::has_edge(int i,int j,int sg) const {
2666 if (i<0 || i>=node_count() || j<0 || j>=node_count())
2667 return false;
2668 if (sg>=0 && (node(i).subgraph()!=sg || node(j).subgraph()!=sg))
2669 return false;
2670 return node(i).has_neighbor(j);
2671 }
2672
2673 /* returns true iff i-th and j-th vertices are adjacent */
nodes_are_adjacent(int i,int j) const2674 bool graphe::nodes_are_adjacent(int i,int j) const {
2675 return node(i).has_neighbor(j) || node(j).has_neighbor(i);
2676 }
2677
2678 /* returns the attributes of the i-th node */
node_attributes(int i) const2679 const graphe::attrib &graphe::node_attributes(int i) const {
2680 assert(i>=0 && i<node_count() && supports_attributes());
2681 return node(i).attributes();
2682 }
2683
2684 /* return const reference to the attributes assigned to edge [i,j] */
edge_attributes(int i,int j) const2685 const graphe::attrib &graphe::edge_attributes(int i,int j) const {
2686 assert(supports_attributes());
2687 if (is_directed())
2688 return node(i).neighbor_attributes(j);
2689 return node(i<j?i:j).neighbor_attributes(i<j?j:i);
2690 }
2691
2692 /* return the modifiable reference to the attributes assigned to edge [i,j] */
edge_attributes(int i,int j)2693 graphe::attrib &graphe::edge_attributes(int i,int j) {
2694 assert(supports_attributes());
2695 if (is_directed())
2696 return node(i).neighbor_attributes(j);
2697 return node(i<j?i:j).neighbor_attributes(i<j?j:i);
2698 }
2699
2700 /* convert attrib to pair of vecteurs */
attrib2vecteurs(const attrib & attr,vecteur & tags,vecteur & values) const2701 void graphe::attrib2vecteurs(const attrib &attr,vecteur &tags,vecteur &values) const {
2702 for (attrib_iter it=attr.begin();it!=attr.end();++it) {
2703 tags.push_back(str2gen(index2tag(it->first),true));
2704 values.push_back(it->second);
2705 }
2706 }
2707
2708 /* add edge {i,j} or arc [i,j], depending on the type (undirected or directed) */
add_edge(int i,int j,const gen & w)2709 void graphe::add_edge(int i,int j,const gen &w) {
2710 assert(i>=0 && i<node_count() && j>=0 && j<node_count());
2711 if (has_edge(i,j))
2712 return;
2713 node(i).add_neighbor(j);
2714 if (!is_directed())
2715 node(j).add_neighbor(i);
2716 if (is_weighted()) {
2717 assert(supports_attributes());
2718 set_edge_attribute(i,j,_GT_ATTRIB_WEIGHT,w);
2719 }
2720 }
2721
2722 /* add edge {i,j} or arc [i,j] with attributes */
add_edge(int i,int j,const attrib & attr)2723 void graphe::add_edge(int i,int j,const attrib &attr) {
2724 assert(i>=0 && i<node_count() && j>=0 && j<node_count() && supports_attributes());
2725 if (has_edge(i,j))
2726 return;
2727 if (is_directed())
2728 node(i).add_neighbor(j,attr);
2729 else {
2730 int v=i<j?i:j,w=i<j?j:i;
2731 node(v).add_neighbor(w,attr);
2732 node(w).add_neighbor(v);
2733 }
2734 }
2735
2736 /* add edge {v,w} or arc [v,w], adding vertices v and/or w if necessary */
add_edge(const gen & v,const gen & w,const gen & weight)2737 graphe::ipair graphe::add_edge(const gen &v,const gen &w,const gen &weight) {
2738 assert(supports_attributes());
2739 int i=add_node(v),j=add_node(w);
2740 add_edge(i,j,weight);
2741 if (is_directed())
2742 return make_pair(i,j);
2743 return make_pair(i<j?i:j,i<j?j:i);
2744 }
2745
2746 /* add edge {v,w} or arc [v,w], adding vertices v and/or w if necessary */
add_edge(const gen & v,const gen & w,const attrib & attr)2747 graphe::ipair graphe::add_edge(const gen &v,const gen &w,const attrib &attr) {
2748 assert(supports_attributes());
2749 int i=add_node(v),j=add_node(w);
2750 add_edge(i,j,attr);
2751 if (is_directed())
2752 return make_pair(i,j);
2753 return make_pair(i<j?i:j,i<j?j:i);
2754 }
2755
2756 /* add temporary edge from i-th to j-th vertex */
add_temporary_edge(int i,int j)2757 void graphe::add_temporary_edge(int i,int j) {
2758 assert(!has_edge(i,j));
2759 add_edge(i,j);
2760 if (supports_attributes())
2761 set_edge_attribute(i,j,_GT_ATTRIB_TEMPORARY,boole(true));
2762 }
2763
2764 /* return true iff the edge {i,j} is temporary */
is_temporary_edge(int i,int j) const2765 bool graphe::is_temporary_edge(int i,int j) const {
2766 assert(supports_attributes());
2767 assert(has_edge(i,j));
2768 gen val;
2769 get_edge_attribute(i,j,_GT_ATTRIB_TEMPORARY,val);
2770 return is_one(val);
2771 }
2772
2773 /* remove all temporary edges */
remove_temporary_edges()2774 void graphe::remove_temporary_edges() {
2775 assert(supports_attributes());
2776 stack<ipair> edges;
2777 int i;
2778 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
2779 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
2780 i=it-nodes.begin();
2781 if (is_temporary_edge(i,*jt))
2782 edges.push(make_pair(i,*jt));
2783 }
2784 }
2785 while (!edges.empty()) {
2786 remove_edge(edges.top());
2787 edges.pop();
2788 }
2789 }
2790
2791 /* remove edge {v,w} or arc [v,w] */
remove_edge(int i,int j)2792 bool graphe::remove_edge(int i,int j) {
2793 if (!has_edge(i,j))
2794 return false;
2795 node(i).remove_neighbor(j);
2796 if (!is_directed())
2797 node(j).remove_neighbor(i);
2798 return true;
2799 }
2800
2801 /* add new vertex to the graph */
add_node()2802 int graphe::add_node() {
2803 assert(!supports_attributes());
2804 nodes.push_back(vertex(false));
2805 return node_count()-1;
2806 }
2807
2808 /* add vertex v to the graph */
add_node(const gen & v,const attrib & attr)2809 int graphe::add_node(const gen &v,const attrib &attr) {
2810 assert(supports_attributes());
2811 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2812 if (it->label()==v)
2813 return it-nodes.begin();
2814 }
2815 nodes.push_back(vertex(v,attr));
2816 return node_count()-1;
2817 }
2818
2819 /* add vertices from list v to the graph */
add_nodes(const vecteur & v)2820 void graphe::add_nodes(const vecteur &v) {
2821 assert(supports_attributes());
2822 for (const_iterateur it=v.begin();it!=v.end();++it) {
2823 add_node(*it);
2824 }
2825 }
2826
2827 /* adds n new nodes to the graph */
add_nodes(int n)2828 void graphe::add_nodes(int n) {
2829 assert(!supports_attributes());
2830 for (int i=0;i<n;++i) {
2831 nodes.push_back(vertex(false));
2832 }
2833 }
2834
2835 /* remove all nodes with indices from V */
isolate_nodes(const iset & V)2836 void graphe::isolate_nodes(const iset &V) {
2837 ivector adj;
2838 bool isdir=is_directed();
2839 for (iset_iter it=V.begin();it!=V.end();++it) {
2840 adjacent_nodes(*it,adj);
2841 for (ivector_iter jt=adj.begin();jt!=adj.end();++jt) {
2842 remove_edge(*it,*jt);
2843 if (isdir)
2844 remove_edge(*jt,*it);
2845 }
2846 }
2847 }
2848
2849 /* convert list of labels to set of vertex indices */
labels2iset(const vecteur & labels,iset & s)2850 bool graphe::labels2iset(const vecteur &labels,iset &s) {
2851 int i;
2852 for (const_iterateur it=labels.begin();it!=labels.end();++it) {
2853 if ((i=node_index(*it))==-1)
2854 return false;
2855 s.insert(i);
2856 }
2857 return true;
2858 }
2859
2860 /* return vector of node labels */
get_node_labels(const ivector & v) const2861 vecteur graphe::get_node_labels(const ivector &v) const {
2862 assert(supports_attributes());
2863 vecteur V(v.size());
2864 for (ivector_iter it=v.begin();it!=v.end();++it) {
2865 V[it-v.begin()]=node_label(*it);
2866 }
2867 return V;
2868 }
2869
2870 /* return index of vertex v */
node_index(const gen & v) const2871 int graphe::node_index(const gen &v) const {
2872 assert(supports_attributes());
2873 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2874 if (it->label()==v)
2875 return it-nodes.begin();
2876 }
2877 return -1;
2878 }
2879
2880 /* return index of edge (i,j) as returned by get_edges_as_pairs */
edge_index(const ipair & e) const2881 int graphe::edge_index(const ipair &e) const {
2882 int i,j,cnt=0;
2883 bool isdir=is_directed();
2884 ipair edge=e;
2885 if (!isdir && e.first>e.second) {
2886 int tmp=edge.first;
2887 edge.first=edge.second;
2888 edge.second=tmp;
2889 }
2890 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2891 i=it-nodes.begin();
2892 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
2893 j=*jt;
2894 if (isdir || j>i) {
2895 if (i==edge.first && j==edge.second)
2896 return cnt;
2897 ++cnt;
2898 }
2899 }
2900 }
2901 return -1;
2902 }
2903
2904 /* set 'subgraph' field of all nodes in v to s */
set_subgraph(const ivector & v,int s)2905 void graphe::set_subgraph(const ivector &v,int s) {
2906 for (ivector_iter it=v.begin();it!=v.end();++it) {
2907 node(*it).set_subgraph(s);
2908 }
2909 }
2910
2911 /* set 'subgraph' field for nodes in subgraph induced by e */
set_subgraph(const ipairs & e,int s)2912 void graphe::set_subgraph(const ipairs &e,int s) {
2913 for (ipairs_iter it=e.begin();it!=e.end();++it) {
2914 vertex &v=node(it->first),&w=node(it->second);
2915 v.set_subgraph(s);
2916 w.set_subgraph(s);
2917 }
2918 }
2919
2920 /* collect all vertices within the given subgraph in list v */
get_subgraph(int sg,ivector & v) const2921 void graphe::get_subgraph(int sg,ivector &v) const {
2922 v.clear();
2923 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2924 if (it->subgraph()==sg)
2925 v.push_back(it-nodes.begin());
2926 }
2927 }
2928
2929 /* return the index of the first vertex with subgraph field equal to sg,
2930 * or -1 if no such vertices exist */
first_vertex_from_subgraph(int sg) const2931 int graphe::first_vertex_from_subgraph(int sg) const {
2932 if (sg<0)
2933 return 0;
2934 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2935 if (it->subgraph()==sg)
2936 return it-nodes.begin();
2937 }
2938 return -1;
2939 }
2940
2941 /* return the size of subgraph sg */
subgraph_size(int sg) const2942 int graphe::subgraph_size(int sg) const {
2943 if (sg<0)
2944 return node_count();
2945 int cnt=0;
2946 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2947 if (it->subgraph()==sg)
2948 ++cnt;
2949 }
2950 return cnt;
2951 }
2952
2953 /* merge subgraphs s and t, such that the resulting subgraph has index s */
merge_subgraphs(int s,int t)2954 void graphe::merge_subgraphs(int s,int t) {
2955 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
2956 if (it->subgraph()==t)
2957 it->set_subgraph(s);
2958 }
2959 }
2960
2961 /* set subgraph field to default_sg (by default -1) for every vertex in the graph */
unset_subgraphs(int default_sg)2962 void graphe::unset_subgraphs(int default_sg) {
2963 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
2964 it->set_subgraph(default_sg);
2965 }
2966 }
2967
2968 /* return maximal subgraph index in this graph */
max_subgraph_index() const2969 int graphe::max_subgraph_index() const {
2970 int mi=-2;
2971 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
2972 if (it->subgraph()>mi)
2973 mi=it->subgraph();
2974 }
2975 return mi;
2976 }
2977
2978 /* make cycle graph with n vertices */
make_cycle_graph()2979 void graphe::make_cycle_graph() {
2980 int n=node_count();
2981 for (int i=0;i<n;++i) {
2982 add_edge(i,(i+1)%n);
2983 }
2984 }
2985
2986 /* set vertex attribute key=val */
set_node_attribute(int index,int key,const gen & val)2987 void graphe::set_node_attribute(int index,int key,const gen &val) {
2988 assert (index>=0 && index<node_count());
2989 node(index).set_attribute(key,val);
2990 }
2991
2992 /* set edge {i,j} attribute key=val */
set_edge_attribute(int i,int j,int key,const gen & val)2993 void graphe::set_edge_attribute(int i,int j,int key,const gen &val) {
2994 attrib &attr=edge_attributes(i,j);
2995 attr[key]=val;
2996 }
2997
2998 /* return the value corresponding to the graph attribute specified by key */
get_graph_attribute(int key,gen & val) const2999 bool graphe::get_graph_attribute(int key,gen &val) const {
3000 attrib_iter it=attributes.find(key);
3001 if (it==attributes.end()) {
3002 val=undef;
3003 return false;
3004 }
3005 val=it->second;
3006 return true;
3007 }
3008
3009 /* return the value corresponding to the i-th node attribute specified by key */
get_node_attribute(int i,int key,gen & val) const3010 bool graphe::get_node_attribute(int i,int key,gen &val) const {
3011 assert (i>=0 && i<node_count());
3012 const attrib &attr=node(i).attributes();
3013 attrib_iter it=attr.find(key);
3014 if (it==attr.end()) {
3015 val=undef;
3016 return false;
3017 }
3018 val=it->second;
3019 return true;
3020 }
3021
3022 /* return the value corresponding to the attribute assigned to edge [i,j] and specified by key */
get_edge_attribute(int i,int j,int key,gen & val) const3023 bool graphe::get_edge_attribute(int i,int j,int key,gen &val) const {
3024 const attrib &attr=edge_attributes(i,j);
3025 attrib_iter it=attr.find(key);
3026 if (it==attr.end()) {
3027 val=undef;
3028 return false;
3029 }
3030 val=it->second;
3031 return true;
3032 }
3033
3034 /* discard the graph attribute specified by key */
discard_graph_attribute(int key)3035 void graphe::discard_graph_attribute(int key) {
3036 attrib::iterator it=attributes.find(key);
3037 if (it!=attributes.end())
3038 attributes.erase(it);
3039 }
3040
3041 /* discard the attribute assigned to i-th node and specified by key */
discard_node_attribute(int i,int key)3042 void graphe::discard_node_attribute(int i,int key) {
3043 attrib &attr=node(i).attributes();
3044 attrib::iterator it=attr.find(key);
3045 if (it!=attr.end())
3046 attr.erase(it);
3047 }
3048
3049 /* discard the attribute assigned to edge [i,j] and specified by key */
discard_edge_attribute(int i,int j,int key)3050 void graphe::discard_edge_attribute(int i,int j,int key) {
3051 attrib &attr=edge_attributes(i,j);
3052 attrib::iterator it=attr.find(key);
3053 if (it!=attr.end())
3054 attr.erase(it);
3055 }
3056
3057 /* return true iff the graph is directed */
is_directed() const3058 bool graphe::is_directed() const {
3059 attrib_iter it=attributes.find(_GT_ATTRIB_DIRECTED);
3060 assert(it!=attributes.end() && it->second.is_integer());
3061 return (bool)it->second.val;
3062 }
3063
3064 /* return true iff the graph is weighted */
is_weighted() const3065 bool graphe::is_weighted() const {
3066 attrib_iter it=attributes.find(_GT_ATTRIB_WEIGHTED);
3067 assert(it!=attributes.end() && it->second.is_integer());
3068 return (bool)it->second.val;
3069 }
3070
3071 /* create the subgraph defined by vertices from 'vi' and store it in G */
induce_subgraph(const ivector & vi,graphe & G) const3072 void graphe::induce_subgraph(const ivector &vi,graphe &G) const {
3073 assert(supports_attributes() || !G.supports_attributes());
3074 int n=node_count();
3075 G.clear();
3076 G.reserve_nodes(vi.size());
3077 if (!G.supports_attributes())
3078 G.add_nodes(vi.size());
3079 ivector sg_pos(n,-1);
3080 bool isdir=is_directed();
3081 G.set_directed(isdir);
3082 G.set_weighted(is_weighted());
3083 for (ivector_iter it=vi.begin();it!=vi.end();++it) {
3084 sg_pos[*it]=it-vi.begin();
3085 if (G.supports_attributes()) {
3086 gen v_label=node_label(*it);
3087 const attrib &attri=node(*it).attributes();
3088 G.add_node(v_label,attri);
3089 }
3090 }
3091 int i,j,k;
3092 for (ivector_iter it=vi.begin();it!=vi.end();++it) {
3093 const vertex &v=node(*it);
3094 i=it-vi.begin();
3095 for (ivector_iter jt=v.neighbors().begin();jt!=v.neighbors().end();++jt) {
3096 if ((j=sg_pos[*jt])>=0 && (isdir || i<j)) {
3097 ipair e=make_pair(i,j);
3098 ipair Ge=make_pair(*it,*jt);
3099 if (G.supports_attributes())
3100 G.add_edge(e,edge_attributes(Ge));
3101 else G.add_edge(e);
3102 if (!isdir && (k=multiedges(Ge))>0) {
3103 G.set_multiedge(e,k);
3104 }
3105 }
3106 }
3107 }
3108 }
3109
3110 /* create the subgraph G defined by a list of edges E */
extract_subgraph(const ipairs & E,graphe & G) const3111 void graphe::extract_subgraph(const ipairs &E,graphe &G) const {
3112 assert(supports_attributes() || !G.supports_attributes());
3113 G.clear();
3114 bool isdir=is_directed();
3115 G.set_directed(isdir);
3116 G.set_weighted(is_weighted());
3117 iset vset;
3118 for (ipairs_iter it=E.begin();it!=E.end();++it) {
3119 vset.insert(it->first);
3120 vset.insert(it->second);
3121 }
3122 G.reserve_nodes(vset.size());
3123 map<int,int> index_map;
3124 for (iset_iter it=vset.begin();it!=vset.end();++it) {
3125 const vertex &v=node(*it);
3126 index_map[*it]=G.supports_attributes()?G.add_node(v.label(),v.attributes()):G.add_node();
3127 }
3128 ipair e;
3129 for (ipairs_iter it=E.begin();it!=E.end();++it) {
3130 e=make_pair(index_map[it->first],index_map[it->second]);
3131 if (G.supports_attributes())
3132 G.add_edge(e,edge_attributes(*it));
3133 else G.add_edge(e);
3134 if (!isdir)
3135 G.set_multiedge(e,multiedges(*it));
3136 }
3137 }
3138
3139 /* return true iff this graph is subgraph of G */
is_subgraph(const graphe & G) const3140 bool graphe::is_subgraph(const graphe &G) const {
3141 assert(supports_attributes() && G.supports_attributes());
3142 if (is_directed()!=G.is_directed() ||
3143 node_count()>G.node_count() ||
3144 edge_count()>G.edge_count())
3145 return false;
3146 int i,j;
3147 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
3148 i=G.node_index(it->label());
3149 if (i<0)
3150 return false;
3151 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
3152 j=G.node_index(node(*jt).label());
3153 if (j<0 || !G.has_edge(i,j))
3154 return false;
3155 }
3156 }
3157 return true;
3158 }
3159
3160 /* fill the list adj with vertices adjacent to the i-th one */
adjacent_nodes(int i,ivector & adj,bool include_temp_edges) const3161 void graphe::adjacent_nodes(int i,ivector &adj,bool include_temp_edges) const {
3162 assert(i>=0 && i<node_count());
3163 const vertex &v=node(i);
3164 adj.clear();
3165 adj.reserve(degree(i));
3166 int j;
3167 iset s;
3168 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
3169 j=*it;
3170 if (include_temp_edges || !is_temporary_edge(i,j))
3171 s.insert(j);
3172 }
3173 if (is_directed()) {
3174 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
3175 j=it-nodes.begin();
3176 if (i!=j && it->has_neighbor(i) &&
3177 (include_temp_edges || !is_temporary_edge(i,j)))
3178 s.insert(j);
3179 }
3180 }
3181 for (iset::const_iterator it=s.begin();it!=s.end();++it) {
3182 adj.push_back(*it);
3183 }
3184 }
3185
3186 /* return a maximal independent set of vertices in undirected graph */
maximal_independent_set(ivector & ind) const3187 void graphe::maximal_independent_set(ivector &ind) const {
3188 int n=node_count(),i;
3189 ivector V(n),gain(n);
3190 for (i=0;i<n;++i) {
3191 V[i]=i;
3192 gain[i]=degree(i);
3193 }
3194 ivector::iterator pos;
3195 ind.clear();
3196 ind.reserve(n);
3197 while (!V.empty()) {
3198 i=V.front();
3199 pos=V.begin();
3200 for (ivector::iterator it=V.begin();it!=V.end();++it) {
3201 if (gain[i]<gain[*it]) {
3202 i=*it;
3203 pos=it;
3204 }
3205 }
3206 V.erase(pos);
3207 ind.push_back(i);
3208 const vertex &v=node(i);
3209 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
3210 if ((pos=find(V.begin(),V.end(),*it))==V.end())
3211 continue;
3212 V.erase(pos);
3213 const vertex &w=node(*it);
3214 for (ivector_iter jt=w.neighbors().begin();jt!=w.neighbors().end();++jt) {
3215 if (find(V.begin(),V.end(),*jt)==V.end())
3216 continue;
3217 gain[*jt]++;
3218 }
3219 }
3220 }
3221 sort(ind.begin(),ind.end());
3222 }
3223
3224 /* return pair <root,distance-from-root> of the tree in forest containing v */
forest_root_info(const ivector & forest,int v)3225 graphe::ipair graphe::forest_root_info(const ivector &forest,int v) {
3226 assert(v>=0 && v<int(forest.size()));
3227 int p=v,q,d=0;
3228 do {
3229 q=forest[p];
3230 assert(q>-2);
3231 if (q>=0) {
3232 ++d;
3233 p=q;
3234 }
3235 } while (q>=0);
3236 return make_pair(p,d);
3237 }
3238
3239 /* find augmenting path, a part of Edmonds' blossom algorithm */
find_augmenting_path(ivector & ap,map<int,int> & matching)3240 bool graphe::find_augmenting_path(ivector &ap,map<int,int> &matching) {
3241 ap.clear();
3242 int n=node_count();
3243 ivector forest(n,-2),blossom,part;
3244 vector<bool> in_blossom(n,false);
3245 ivectors blossom_adjacents;
3246 ipairs blossom_matched_edges,blossom_inner_edges;
3247 unvisit_all_edges();
3248 unvisit_all_nodes();
3249 /* make all matched edges visited */
3250 map<int,int>::const_iterator mit;
3251 for (mit=matching.begin();mit!=matching.end();++mit) {
3252 set_edge_visited(mit->first,mit->second);
3253 }
3254 for (int i=0;i<n;++i) {
3255 if ((mit=matching.find(i))==matching.end() && !node(i).neighbors().empty()) {
3256 /* i-th vertex is exposed and can start a path, add it to the forest */
3257 forest[i]=-1;
3258 }
3259 }
3260 int v,w,x,r;
3261 ipair root_info;
3262 while (true) {
3263 /* find an unmarked vertex v in the forest with distance(v,root(v)) even */
3264 v=-1;
3265 for (int i=0;i<n;++i) {
3266 if (node(i).is_visited() || forest[i]==-2)
3267 continue;
3268 root_info=forest_root_info(forest,i);
3269 if (root_info.second%2==0) {
3270 v=i;
3271 break;
3272 }
3273 }
3274 if (v<0) break;
3275 vertex &vert=node(v);
3276 r=root_info.first;
3277 while (true) {
3278 /* find an unmarked edge (v,w) */
3279 w=-1;
3280 for (ivector_iter it=vert.neighbors().begin();it!=vert.neighbors().end();++it) {
3281 if (!is_edge_visited(v,*it)) {
3282 w=*it;
3283 break;
3284 }
3285 }
3286 if (w<0) break;
3287 if (forest[w]==-2) {
3288 /* w is not in forest, w is matched, add edges (v,w) and (w,x) to forest */
3289 assert(matching.find(w)!=matching.end());
3290 forest[w]=v;
3291 x=matching[w];
3292 assert(forest[x]==-2);
3293 forest[x]=w;
3294 } else {
3295 root_info=forest_root_info(forest,w);
3296 if (root_info.second%2!=0) {
3297 /* do nothing */
3298 ;
3299 } else {
3300 if (root_info.first!=r) {
3301 /* found an augmenting path, report it */
3302 int p=v;
3303 do { ap.push_back(p); } while ((p=forest[p])>=0);
3304 std::reverse(ap.begin(),ap.end());
3305 p=w;
3306 do { ap.push_back(p); } while ((p=forest[p])>=0);
3307 return true;
3308 } else {
3309 /* blossom found, construct it and record all relevant edges */
3310 unvisit_all_nodes();
3311 int p=v;
3312 do {
3313 node(p).set_visited(true);
3314 blossom.push_back(p);
3315 } while ((p=forest[p])>=0);
3316 p=w;
3317 while (!node(p).is_visited()) {
3318 part.push_back(p);
3319 p=forest[p];
3320 assert(p>=0);
3321 }
3322 blossom.erase(find(blossom.begin(),blossom.end(),p)+1,blossom.end());
3323 blossom.insert(blossom.begin(),part.rbegin(),part.rend());
3324 std::reverse(blossom.begin(),blossom.end());
3325 for (ivector_iter it=blossom.begin();it!=blossom.end();++it) {
3326 in_blossom[*it]=true;
3327 }
3328 int bs=blossom.size(),u;
3329 for (int i=1;i<bs;i+=2) {
3330 assert(i+1<bs);
3331 blossom_matched_edges.push_back(make_pair(blossom[i],blossom[i+1]));
3332 }
3333 set<int> adj;
3334 for (ivector_iter it=blossom.begin();it!=blossom.end();++it) {
3335 const vertex &V=node(*it);
3336 for (ivector_iter nt=V.neighbors().begin();nt!=V.neighbors().end();++nt) {
3337 if (!in_blossom[*nt])
3338 adj.insert(*nt);
3339 }
3340 for (ivector_iter jt=it+1;jt!=blossom.end();++jt) {
3341 if (has_edge(*it,*jt))
3342 blossom_inner_edges.push_back(make_pair(*it,*jt));
3343 }
3344 }
3345 for (set<int>::const_iterator it=adj.begin();it!=adj.end();++it) {
3346 ivector adjacents;
3347 adjacents.push_back(*it);
3348 const vertex &V=node(*it);
3349 for (ivector_iter nt=V.neighbors().begin();nt!=V.neighbors().end();++nt) {
3350 if (in_blossom[*nt])
3351 adjacents.push_back(*nt);
3352 }
3353 blossom_adjacents.push_back(adjacents);
3354 }
3355 /* contract the blossom */
3356 for (int i=0;i<bs;++i) {
3357 remove_edge(blossom[i],blossom[(i+1)%bs]);
3358 }
3359 for (ipairs_iter it=blossom_inner_edges.begin();it!=blossom_inner_edges.end();++it) {
3360 remove_edge(*it);
3361 }
3362 r=blossom.front(); // the root of the blossom
3363 for (ivectors_iter it=blossom_adjacents.begin();it!=blossom_adjacents.end();++it) {
3364 u=it->front();
3365 for (ivector_iter ait=it->begin()+1;ait!=it->end();++ait) {
3366 remove_edge(u,*ait);
3367 }
3368 add_edge(u,r);
3369 }
3370 /* remove the contracted matched edges from matching and recurse */
3371 for (ipairs_iter it=blossom_matched_edges.begin();it!=blossom_matched_edges.end();++it) {
3372 assert((mit=matching.find(it->first))!=matching.end());
3373 assert(mit->second==it->second);
3374 matching.erase(it->first);
3375 assert((mit=matching.find(it->second))!=matching.end());
3376 assert(mit->second==it->first);
3377 matching.erase(it->second);
3378 }
3379 bool res=find_augmenting_path(ap,matching);
3380 /* restore the blossom and all edges incident to it */
3381 for (int i=0;i<bs;++i) {
3382 add_edge(blossom[i],blossom[(i+1)%bs]);
3383 }
3384 for (ivectors_iter it=blossom_adjacents.begin();it!=blossom_adjacents.end();++it) {
3385 u=it->front();
3386 remove_edge(u,r);
3387 for (ivector_iter jt=it->begin()+1;jt!=it->end();++jt) {
3388 add_edge(u,*jt);
3389 }
3390 }
3391 for (ipairs_iter it=blossom_inner_edges.begin();it!=blossom_inner_edges.end();++it) {
3392 add_edge(*it);
3393 }
3394 for (ipairs_iter it=blossom_matched_edges.begin();it!=blossom_matched_edges.end();++it) {
3395 matching[it->first]=it->second;
3396 matching[it->second]=it->first;
3397 }
3398 if (!res)
3399 return false; // if contracted graph has no augmenting path then there is none in this graph
3400 int root=-1;
3401 for (ivector_iter it=ap.begin();it!=ap.end();++it) {
3402 if (*it==r) {
3403 root=it-ap.begin();
3404 break;
3405 }
3406 }
3407 if (root<0)
3408 return true; // the augmenting path does not contain the blossom root
3409 if (root==0 || matching.find(r)->second==ap[root-1]) {
3410 std::reverse(ap.begin(),ap.end());
3411 root=ap.size()-1-root;
3412 }
3413 int pos,dir,i=0;
3414 for (;i+1!=root;++i);
3415 /* reached the blossom */
3416 const vertex &V=node(ap[i]);
3417 u=-1;
3418 for (ivector_iter it=V.neighbors().begin();it!=V.neighbors().end();++it) {
3419 if (in_blossom[*it]) {
3420 u=*it;
3421 break;
3422 }
3423 }
3424 assert(u>=0);
3425 if (u==r)
3426 return true; // the blossom is avoided
3427 /* lift the augmenting path */
3428 part.clear();
3429 pos=find(blossom.begin(),blossom.end(),u)-blossom.begin();
3430 assert(pos>0 && pos<bs);
3431 dir=matching[u]==blossom[pos-1]?-1:1;
3432 for (;pos>0 && pos<bs;pos+=dir) {
3433 part.push_back(blossom[pos]);
3434 }
3435 ap.insert(ap.begin()+root,part.begin(),part.end());
3436 return true;
3437 }
3438 }
3439 }
3440 set_edge_visited(v,w);
3441 }
3442 vert.set_visited(true);
3443 }
3444 return false;
3445 }
3446
3447 /* find maximum matching by using Edmonds' blossom algorithm, time complexity O(n^2*m) */
find_maximum_matching(ipairs & M)3448 void graphe::find_maximum_matching(ipairs &M) {
3449 ivector ap;
3450 int n,i,j;
3451 map<int,int> matching;
3452 while (find_augmenting_path(ap,matching)) {
3453 n=ap.size();
3454 for (int k=0;k<n;k+=2) {
3455 i=ap[k];
3456 j=ap[k+1];
3457 matching[i]=j;
3458 matching[j]=i;
3459 }
3460 }
3461 M.clear();
3462 for (map<int,int>::const_iterator it=matching.begin();it!=matching.end();++it) {
3463 i=it->first;
3464 j=it->second;
3465 if (i<j)
3466 M.push_back(make_pair(i,j));
3467 }
3468 }
3469
3470 /* find a maximal matching in an undirected graph (fast algorithm) */
find_maximal_matching(ipairs & matching) const3471 void graphe::find_maximal_matching(ipairs &matching) const {
3472 int i,j,n=node_count();
3473 ivector match(n,-1);
3474 vector<bool> node_marked(n,false);
3475 while (true) {
3476 for (i=0;i<n;++i) {
3477 if (!node_marked[i] && match[i]<0)
3478 break;
3479 }
3480 if (i==n)
3481 break;
3482 node_marked[i]=true;
3483 const vertex &v=node(i);
3484 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
3485 if (match[*it]<0) {
3486 match[*it]=i;
3487 match[i]=*it;
3488 break;
3489 }
3490 }
3491 }
3492 ivector skip;
3493 matching.clear();
3494 for (i=0;i<int(match.size());++i) {
3495 j=match[i];
3496 if (j<0 || find(skip.begin(),skip.end(),i)!=skip.end())
3497 continue;
3498 skip.push_back(j);
3499 matching.push_back(make_pair(i,j));
3500 }
3501 }
3502
pred(int i,int n)3503 int graphe::pred(int i,int n) {
3504 if (i>0)
3505 return i-1;
3506 return n-1;
3507 }
3508
succ(int i,int n)3509 int graphe::succ(int i,int n) {
3510 if (i<n-1)
3511 return i+1;
3512 return 0;
3513 }
3514
3515 /* return arc path from i-th to j-th vertex (inclusive), going in clockwise direction */
arc_path(int i,int j,const ivector & cycle,ivector & path)3516 void graphe::arc_path(int i,int j,const ivector &cycle,ivector &path) {
3517 int n=cycle.size(),k=i,m=j-i,l=0;
3518 if (m<0)
3519 m+=n;
3520 path.resize(m+1);
3521 path.front()=cycle[i];
3522 while (k++!=j) {
3523 if (k==n)
3524 k=0;
3525 path[++l]=cycle[k];
3526 }
3527 }
3528
3529 /* find the main chords of the given face */
find_chords(const ivector & face,ipairs & chords)3530 void graphe::find_chords(const ivector &face,ipairs &chords) {
3531 int n=face.size(),h=n%2==0?n/2:(n-1)/2;
3532 ivector D;
3533 for (int k=0;k<n;++k) {
3534 if (degree(face[k])>2)
3535 D.push_back(k);
3536 }
3537 if (D.empty())
3538 return;
3539 chords.clear();
3540 int m=D.size(),k=0,i,j,k_next,l,v,w,r,f;
3541 map<int,bool> face_switch;
3542 ivector ifaces;
3543 while (true) {
3544 i=D[k];
3545 v=face[i];
3546 l=k;
3547 k_next=succ(k,m);
3548 ipair c=make_pair(i,-1);
3549 face_switch.clear();
3550 node(v).incident_faces(ifaces);
3551 for (ivector_iter it=ifaces.begin();it!=ifaces.end();++it) {
3552 face_switch[*it]=true;
3553 }
3554 while (true) {
3555 l=succ(l,m);
3556 j=D[l];
3557 r=j-i;
3558 if (r<0)
3559 r+=n;
3560 if (r==0 || r>h || (n%2==0 && r==h && i>=h))
3561 break;
3562 w=face[j];
3563 node(w).incident_faces(ifaces);
3564 f=-1;
3565 for (ivector_iter it=ifaces.begin();it!=ifaces.end();++it) {
3566 if (face_switch[*it])
3567 face_switch[f=*it]=false;
3568 }
3569 if (r>1 && (f>=0 || has_edge(v,w))) {
3570 c.second=j;
3571 k_next=l;
3572 }
3573 }
3574 if (c.second>=0)
3575 chords.push_back(c);
3576 if (k_next<k)
3577 break;
3578 k=k_next;
3579 }
3580 if (chords.size()>1) {
3581 int end=chords.back().second;
3582 if (end<chords.back().first) {
3583 ipairs::iterator it=chords.begin();
3584 while (it->first<end) ++it;
3585 chords.erase(chords.begin(),it);
3586 }
3587 }
3588 }
3589
3590 /* fold the face along its main chords */
fold_face(const ivector & face,bool subdivide,int & label)3591 void graphe::fold_face(const ivector &face,bool subdivide,int &label) {
3592 ipairs chords;
3593 find_chords(face,chords);
3594 int n=face.size(),k=chords.size(),i,j,p,q,r,s,t,u;
3595 if (k==0)
3596 return;
3597 if (subdivide) {
3598 vector<bool> visited(n,false);
3599 i=add_node(++label);
3600 for (ipairs_iter it=chords.begin();it!=chords.end();++it) {
3601 p=it->first;
3602 q=it->second;
3603 visited[p]=visited[q]=true;
3604 for (j=(p+1)%n;j!=q;j=(j+1)%n) {
3605 add_edge(i,face[j]);
3606 visited[j]=true;
3607 }
3608 }
3609 for (j=0;j<n;++j) {
3610 if (!visited[j])
3611 add_edge(i,face[j]);
3612 }
3613 } else if (k==1) {
3614 i=chords.front().first;
3615 q=succ(i,n);
3616 t=pred(i,n);
3617 add_temporary_edge(face[q],face[t]);
3618 if (n>4) {
3619 j=chords.front().second;
3620 r=pred(j,n);
3621 u=succ(j,n);
3622 add_temporary_edge(face[r],face[u]);
3623 }
3624 } else if (k>1) {
3625 q=succ(chords.front().first,n);
3626 r=succ(chords[1].first,n);
3627 if (k==2 && q==pred(chords.front().second,n) && r==pred(chords[1].second,n)) {
3628 add_temporary_edge(face[q],face[r]);
3629 } else {
3630 ivector P(0);
3631 ivector Q;
3632 for (s=0;s<k;++s) {
3633 i=s<k-1?chords[s+1].first:chords.front().first;
3634 j=chords[s].second;
3635 q=pred(j,n);
3636 r=succ(i,n);
3637 add_temporary_edge(face[q],face[r]);
3638 arc_path(succ(chords[s].first,n),q,face,Q);
3639 P.insert(P.end(),Q.begin(),Q.end());
3640 }
3641 if (P.size()>3)
3642 fold_face(P,subdivide,label);
3643 }
3644 }
3645 }
3646
3647 /* augment the biconnected planar graph for spring drawing */
augment(const ivectors & faces,int outer_face,bool subdivide)3648 void graphe::augment(const ivectors &faces,int outer_face,bool subdivide) {
3649 set_embedding(faces);
3650 int label=largest_integer_label();
3651 for (ivectors_iter it=faces.begin();it!=faces.end();++it) {
3652 if (it->size()<4 || outer_face==int(it-faces.begin()))
3653 continue;
3654 fold_face(*it,subdivide,label);
3655 }
3656 }
3657
3658 /* add point b to point a */
add_point(point & a,const point & b)3659 void graphe::add_point(point &a,const point &b) {
3660 int d=a.size();
3661 assert(int(b.size())==d);
3662 for (int i=0;i<d;++i) {
3663 a[i]+=b[i];
3664 }
3665 }
3666
3667 /* subtract point b from point a */
subtract_point(point & a,const point & b)3668 void graphe::subtract_point(point &a,const point &b) {
3669 int d=a.size();
3670 assert(int(b.size())==d);
3671 for (int i=0;i<d;++i) {
3672 a[i]-=b[i];
3673 }
3674 }
3675
3676 /* scale coordinates of point p by factor s */
scale_point(point & p,double s)3677 void graphe::scale_point(point &p,double s) {
3678 int d=p.size();
3679 for (int i=0;i<d;++i) {
3680 p[i]*=s;
3681 }
3682 }
3683
3684 /* compute v_x*w_y-v_y*w_x */
point_vecprod2d(const point & v,const point & w)3685 double graphe::point_vecprod2d(const point &v,const point &w) {
3686 assert(v.size()==2 && w.size()==2);
3687 return v[0]*w[1]-v[1]*w[0];
3688 }
3689
3690 /* compute dot product of vectors p and q */
point_dotprod(const point & p,const point & q)3691 double graphe::point_dotprod(const point &p,const point &q) {
3692 int n=p.size();
3693 assert((n==2 || n==3) && n==int(q.size()));
3694 double res=0;
3695 for (int i=0;i<n;++i) {
3696 res+=p[i]*q[i];
3697 }
3698 return res;
3699 }
3700
3701 /* set all coordinates of point p to zero */
clear_point_coords(point & p)3702 void graphe::clear_point_coords(point &p) {
3703 for (point::iterator it=p.begin();it!=p.end();++it) {
3704 *it=0;
3705 }
3706 }
3707
3708 /* convert point to Giac representation (cplx or point(x,y,[z])) */
point2gen(const point & p,bool vect)3709 gen graphe::point2gen(const point &p,bool vect) {
3710 /*
3711 if (p.size()==2)
3712 return makecomplex(p[0],p[1]);
3713 */
3714 vecteur coords;
3715 for (point::const_iterator it=p.begin();it!=p.end();++it) {
3716 coords.push_back(*it);
3717 }
3718 if (vect)
3719 return coords;
3720 return symbolic(at_point,_feuille(coords,context0));
3721 }
3722
3723 /* compute the square root of sum of squares of coordinates of point p */
point_displacement(const point & p,bool sqroot)3724 double graphe::point_displacement(const point &p,bool sqroot) {
3725 double norm=0,d;
3726 for (point::const_iterator it=p.begin();it!=p.end();++it) {
3727 d=*it;
3728 norm+=d*d;
3729 }
3730 return sqroot?std::sqrt(norm):norm;
3731 }
3732
3733 /* return the distance between points p and q */
point_distance(const point & p,const point & q,point & pq)3734 double graphe::point_distance(const point &p,const point &q,point &pq) {
3735 copy_point(q,pq);
3736 subtract_point(pq,p);
3737 return point_displacement(pq);
3738 }
3739
3740 /* compute the point dest which is a reflection of src wrt. the line ax+by+c=0 */
point_mirror(double a,double b,double c,const point & src,point & dest)3741 void graphe::point_mirror(double a,double b,double c,const point &src,point &dest) {
3742 double p=src[0],q=src[1],a2=a*a,b2=b*b,r=a2+b2,s=a2-b2;
3743 dest.resize(2);
3744 dest[0]=(p*s-2*b*(a*q+c))/r;
3745 dest[1]=-(q*s+2*a*(b*p+c))/r;
3746 }
3747
3748 /* write d1*p+d2*q to res */
point_lincomb(const point & p,const point & q,double d1,double d2,point & res)3749 void graphe::point_lincomb(const point &p,const point &q,double d1,double d2,point &res) {
3750 copy_point(p,res);
3751 if (d2==0)
3752 scale_point(res,d1);
3753 else {
3754 scale_point(res,d1/d2);
3755 add_point(res,q);
3756 scale_point(res,d2);
3757 }
3758 }
3759
3760 /* copy layout src to dest (both must be initialized first) */
copy_layout(const layout & src,layout & dest)3761 void graphe::copy_layout(const layout &src,layout &dest) {
3762 layout_iter st=src.begin();
3763 layout::iterator dt=dest.begin();
3764 for (;st!=src.end() && dt!=dest.end();++st,++dt) {
3765 *dt=*st;
3766 }
3767 }
3768
3769 /* copy point src to dest (both must be initialized first) */
copy_point(const point & src,point & dest)3770 void graphe::copy_point(const point &src,point &dest) {
3771 point::const_iterator st=src.begin();
3772 point::iterator dt=dest.begin();
3773 for (;st!=src.end() && dt!=dest.end();++st,++dt) {
3774 *dt=*st;
3775 }
3776 }
3777
3778 /* generate uniformly random point p on the origin-centered sphere with the specified radius */
rand_point(point & p,double radius)3779 void graphe::rand_point(point &p,double radius) {
3780 double R;
3781 do {
3782 R=0;
3783 for (point::iterator it=p.begin();it!=p.end();++it) {
3784 *it=rand_normal();
3785 R+=std::pow(*it,2.0);
3786 }
3787 } while (R==0);
3788 scale_point(p,radius/std::sqrt(R));
3789 }
3790
3791 /* convert point from cartesian to polar representation (2d only) */
point2polar(point & p,double & r,double & phi)3792 void graphe::point2polar(point &p,double &r,double &phi) {
3793 int d=p.size();
3794 assert(d==2);
3795 double x=p[0],y=p[1];
3796 r=std::sqrt(std::pow(x,2.0)+std::pow(y,2.0));
3797 phi=atan2(y,x);
3798 }
3799
3800 /* translate layout x by dx */
translate_layout(layout & x,const point & dx)3801 void graphe::translate_layout(layout &x,const point &dx) {
3802 for (layout::iterator it=x.begin();it!=x.end();++it) {
3803 add_point(*it,dx);
3804 }
3805 }
3806
3807 /* rotate layout x about the point p by the angle phi (2d only) */
rotate_layout(layout & x,double phi)3808 void graphe::rotate_layout(layout &x,double phi) {
3809 if (x.empty())
3810 return;
3811 double r,phi0;
3812 for (layout::iterator it=x.begin();it!=x.end();++it) {
3813 point &p=*it;
3814 point2polar(p,r,phi0);
3815 p[0]=r*std::cos(phi0+phi);
3816 p[1]=r*std::sin(phi0+phi);
3817 }
3818 }
3819
3820 /* determine minimum of d-th components among layout points */
layout_min(const layout & x,int d)3821 double graphe::layout_min(const layout &x,int d) {
3822 double m=DBL_MAX;
3823 for (layout_iter it=x.begin();it!=x.end();++it) {
3824 if (it->at(d)<m)
3825 m=it->at(d);
3826 }
3827 return m;
3828 }
3829
3830 /* determine the diameter of the layout (distance between the pair of farthest vertices) */
layout_diameter(const layout & x)3831 double graphe::layout_diameter(const layout &x) {
3832 point p(2);
3833 double diam=0,d;
3834 for (layout_iter it=x.begin();it!=x.end();++it) {
3835 for (layout_iter jt=it+1;jt!=x.end();++jt) {
3836 copy_point(*it,p);
3837 subtract_point(p,*jt);
3838 d=point_displacement(p,false);
3839 if (d>diam)
3840 diam=d;
3841 }
3842 }
3843 return std::sqrt(diam);
3844 }
3845
3846 /* return the bounding rectangle of layout x */
layout_bounding_rect(layout & ly,double padding)3847 graphe::rectangle graphe::layout_bounding_rect(layout &ly,double padding) {
3848 double xmin=DBL_MAX,xmax=-DBL_MAX,ymin=DBL_MAX,ymax=-DBL_MAX,x,y;
3849 for (layout_iter it=ly.begin();it!=ly.end();++it) {
3850 x=it->front();
3851 y=it->at(1);
3852 if (x<xmin)
3853 xmin=x;
3854 if (x>xmax)
3855 xmax=x;
3856 if (y<ymin)
3857 ymin=y;
3858 if (y>ymax)
3859 ymax=y;
3860 }
3861 return rectangle(xmin-padding,ymin-padding,xmax-xmin+2*padding,ymax-ymin+2*padding,&ly);
3862 }
3863
3864 /* compute the center of layout x */
layout_center(const layout & x)3865 graphe::point graphe::layout_center(const layout &x) {
3866 assert(!x.empty());
3867 int d=x.front().size();
3868 point center(d);
3869 clear_point_coords(center);
3870 for (layout_iter it=x.begin();it!=x.end();++it) {
3871 add_point(center,*it);
3872 }
3873 scale_point(center,1.0/x.size());
3874 return center;
3875 }
3876
3877 /* scale layout x to have the diameter equal to diam */
scale_layout(layout & x,double diam)3878 void graphe::scale_layout(layout &x,double diam) {
3879 if (x.empty())
3880 return;
3881 int d=x.front().size();
3882 point M(d,-DBL_MAX),m(d,DBL_MAX);
3883 for (layout_iter it=x.begin();it!=x.end();++it) {
3884 const point &p=*it;
3885 for (int i=0;i<d;++i) {
3886 if (p[i]<m[i])
3887 m[i]=p[i];
3888 if (p[i]>M[i])
3889 M[i]=p[i];
3890 }
3891 }
3892 double D=0;
3893 for (int i=0;i<d;++i) {
3894 if (M[i]-m[i]>D)
3895 D=M[i]-m[i];
3896 }
3897 if (D==0)
3898 return;
3899 double s=diam/D;
3900 for (layout::iterator it=x.begin();it!=x.end();++it) {
3901 scale_point(*it,s);
3902 }
3903 }
3904
3905 /* randomize layout x using a Gaussian random generator */
create_random_layout(layout & x,int dim)3906 void graphe::create_random_layout(layout &x,int dim) {
3907 for (layout::iterator it=x.begin();it!=x.end();++it) {
3908 it->resize(dim);
3909 it->at(0)=rand_uniform();
3910 it->at(1)=rand_uniform();
3911 if (dim==3)
3912 it->at(2)=rand_uniform();
3913 }
3914 }
3915
3916 /* lay out the graph using a force-directed algorithm with spring-electrical model */
force_directed_placement(layout & x,double K,double R,double tol,bool ac)3917 void graphe::force_directed_placement(layout &x,double K,double R,double tol,bool ac) {
3918 double step_length=K,shrinking_factor=0.9,eps=K*tol,C=0.01,D=C*K*K;
3919 double energy=DBL_MAX,energy0,norm,max_displacement;
3920 int progress=0,n=x.size(),i,j;
3921 if (n==0)
3922 return;
3923 assert (n==node_count() && n>0);
3924 int d=x.front().size();
3925 point force(d),p(d),f(d);
3926 /* keep updating the positions until the system freezes */
3927 do {
3928 energy0=energy;
3929 energy=0;
3930 max_displacement=0;
3931 for (node_iter nt=nodes.begin();nt!=nodes.end();++nt) {
3932 i=nt-nodes.begin();
3933 point &xi=x[i];
3934 clear_point_coords(force);
3935 /* compute the attractive forces between vertices adjacent to the i-th vertex */
3936 for (ivector_iter it=nt->neighbors().begin();it!=nt->neighbors().end();++it) {
3937 j=*it;
3938 scale_point(p,point_distance(xi,x[j],p)/K);
3939 add_point(force,p);
3940 }
3941 /* compute the repulsive forces for all vertices j!=i which are not too far from the i-th vertex */
3942 for (layout_iter it=x.begin();it!=x.end();++it) {
3943 j=it-x.begin();
3944 if (i!=j) {
3945 norm=point_distance(*it,xi,f);
3946 if (norm>R)
3947 continue;
3948 if (norm==0)
3949 rand_point(f,norm=shrinking_factor*eps);
3950 scale_point(f,D/(norm*norm));
3951 add_point(force,f);
3952 }
3953 }
3954 /* move the location of the i-th vertex in the direction of the force f */
3955 norm=point_displacement(force);
3956 if (norm==0)
3957 continue;
3958 if (step_length<norm) {
3959 scale_point(force,step_length/norm);
3960 norm=step_length;
3961 }
3962 add_point(xi,force);
3963 /* update the maximal displacement for this iteration */
3964 if (norm>max_displacement)
3965 max_displacement=norm;
3966 energy+=norm*norm;
3967 }
3968 /* update step length */
3969 if (ac) {
3970 /* adaptive cooling scheme */
3971 if (energy<energy0) {
3972 ++progress;
3973 if (progress>=5) {
3974 progress=0;
3975 step_length/=shrinking_factor;
3976 }
3977 } else {
3978 progress=0;
3979 step_length*=shrinking_factor;
3980 }
3981 } else step_length*=shrinking_factor; /* simple cooling scheme */
3982 } while (max_displacement>eps);
3983 }
3984
3985 /* compute optimal positions of edge labels and store them as "position" attributes of the respective edges */
edge_labels_placement(const layout & x)3986 void graphe::edge_labels_placement(const layout &x) {
3987 if (x.empty())
3988 return;
3989 int dim=x.front().size();
3990 ipairs E;
3991 get_edges_as_pairs(E);
3992 int n=E.size();
3993 vector<double> D(n);
3994 bool initialize=n>300;
3995 point pq(dim);
3996 bool isdir=is_directed();
3997 for (int i=0;i<n;++i) {
3998 ipair &edge=E[i];
3999 D[i]=point_distance(x[edge.first],x[edge.second],pq);
4000 if (initialize || D[i]==0)
4001 set_edge_attribute(edge.first,edge.second,_GT_ATTRIB_POSITION,isdir?0.6:0.5);
4002 }
4003 if (!initialize) {
4004 vector<double> dist;
4005 int i,k0;
4006 double maxs,s;
4007 point c(dim);
4008 for (ipairs_iter it=E.begin();it!=E.end();++it) {
4009 i=it-E.begin();
4010 double &d=D[i];
4011 if (d==0)
4012 continue;
4013 const point &p=x[it->first];
4014 dist.clear();
4015 for (ipairs_iter jt=E.begin();jt!=E.end();++jt) {
4016 if (edges_incident(*it,*jt))
4017 continue;
4018 if (edges_crossing(*it,*jt,x,c))
4019 dist.push_back(point_distance(p,c,pq)/d);
4020 }
4021 sort(dist.begin(),dist.end());
4022 dist.insert(dist.begin(),MARGIN_FACTOR);
4023 for (int k=dist.size();k-->1;) {
4024 if (dist[k]<=dist.front())
4025 dist.erase(dist.begin()+k);
4026 }
4027 while (dist.size()>1 && dist.back()>=1.0-MARGIN_FACTOR) {
4028 dist.pop_back();
4029 }
4030 dist.push_back(1.0-MARGIN_FACTOR);
4031 n=dist.size();
4032 maxs=0;
4033 k0=-1;
4034 for (int k=0;k<n-1;++k) {
4035 s=dist[k+1]-dist[k];
4036 if (s>maxs) {
4037 maxs=s;
4038 k0=k;
4039 }
4040 }
4041 assert(k0>=0);
4042 set_edge_attribute(it->first,it->second,_GT_ATTRIB_POSITION,1.0-(dist[k0]+maxs*(isdir?0.4:0.5)));
4043 }
4044 }
4045 }
4046
4047 /* retrieve element in A at position (i,j) and store it in val, return true iff there is such element */
sparse_matrix_element(const sparsemat & A,int i,int j,ipair & val)4048 bool graphe::sparse_matrix_element(const sparsemat &A,int i,int j,ipair &val) {
4049 sparsemat::const_iterator it;
4050 map<int,ipair>::const_iterator jt;
4051 if ((it=A.find(i))==A.end() || (jt=it->second.find(j))==it->second.end())
4052 return false;
4053 val=jt->second;
4054 return true;
4055 }
4056
4057 /* convert a rational number r to ipair */
rat2ipair(const gen & r)4058 graphe::ipair graphe::rat2ipair(const gen &r) {
4059 gen num=_numer(r,context0),den=_denom(r,context0);
4060 assert(num.is_integer() && den.is_integer());
4061 return make_pair(num.val,den.val);
4062 }
4063
4064 /* convert a pair of integers to rational number */
ipair2rat(const ipair & p)4065 gen graphe::ipair2rat(const ipair &p) {
4066 if (p.first==0)
4067 return 0;
4068 assert(p.second!=0);
4069 return fraction(p.first,p.second);
4070 }
4071
4072 /* compute the product A*B and store it in P (ncols is equal to the number of columns of A),
4073 * if A*B=B*A and A and B are symmetric then enabling 'symmetric=true' speeds up the computation */
multiply_sparse_matrices(const sparsemat & A,const sparsemat & B,sparsemat & P,int ncols,bool symmetric)4074 void graphe::multiply_sparse_matrices(const sparsemat &A,const sparsemat &B,sparsemat &P,int ncols,bool symmetric) {
4075 int i,isempty;
4076 ipair p;
4077 gen elm;
4078 for (sparsemat::const_iterator it=A.begin();it!=A.end();++it) {
4079 i=it->first;
4080 map<int,ipair> &row=P[i];
4081 isempty=true;
4082 for (int j=symmetric?i:0;j<ncols;++j) {
4083 elm=0;
4084 for (map<int,ipair>::const_iterator jt=it->second.begin();jt!=it->second.end();++jt) {
4085 if (sparse_matrix_element(B,jt->first,j,p))
4086 elm+=fraction(jt->second.first*p.first,jt->second.second*p.second);
4087 }
4088 if (!is_exactly_zero(elm)) {
4089 isempty=false;
4090 row[j]=rat2ipair(elm);
4091 if (symmetric)
4092 P[j][i]=rat2ipair(elm);
4093 }
4094 }
4095 if (isempty)
4096 P.erase(P.find(i));
4097 }
4098 }
4099
4100 /* store the transposition of A in T */
transpose_sparsemat(const sparsemat & A,sparsemat & T)4101 void graphe::transpose_sparsemat(const sparsemat &A, sparsemat &T) {
4102 for (sparsemat::const_iterator it=A.begin();it!=A.end();++it) {
4103 for(map<int,ipair>::const_iterator jt=it->second.begin();jt!=it->second.end();++jt) {
4104 T[jt->first][it->first]=jt->second;
4105 }
4106 }
4107 }
4108
4109 /* return number of vertices in V which are incident to the i-th vertex */
mdeg(const ivector & V,int i) const4110 int graphe::mdeg(const ivector &V, int i) const {
4111 int d=0;
4112 for (ivector_iter it=V.begin();it!=V.end();++it) {
4113 if (i==*it)
4114 return 1;
4115 if (has_edge(i,*it))
4116 ++d;
4117 }
4118 return d;
4119 }
4120
4121 /* coarsening of the graph with respect to the prolongation matrix P */
coarsening(graphe & G,const sparsemat & P,const ivector & V) const4122 void graphe::coarsening(graphe &G,const sparsemat &P,const ivector &V) const {
4123 sparsemat Q,I,R,IG;
4124 int n=node_count();
4125 transpose_sparsemat(P,Q);
4126 /* create sparse symmetric incidence matrix I of this graph */
4127 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
4128 const ivector &ngh=it->neighbors();
4129 if (ngh.empty())
4130 continue;
4131 map<int,ipair> &row=I[it-nodes.begin()];
4132 for (ivector_iter jt=ngh.begin();jt!=ngh.end();++jt) {
4133 row[*jt]=make_pair(1,1);
4134 }
4135 }
4136 /* use Galerkin product Q*I*P as the incidence matrix IG for graph G */
4137 multiply_sparse_matrices(Q,I,R,n);
4138 multiply_sparse_matrices(R,P,IG,n);
4139 for (ivector_iter it=V.begin();it!=V.end();++it) {
4140 G.add_node(node_label(*it));
4141 }
4142 int i=0,j;
4143 for (sparsemat::const_iterator it=IG.begin();it!=IG.end();++it) {
4144 i=it->first;
4145 for (map<int,ipair>::const_iterator jt=it->second.begin();jt!=it->second.end();++jt) {
4146 j=jt->first;
4147 if (i<j && jt->second.first!=0)
4148 G.add_edge(i,j);
4149 }
4150 }
4151 }
4152
4153 /* make coarser graph G by restricting to maximal independent set */
coarsening_mis(const ivector & V,graphe & G,sparsemat & P) const4154 void graphe::coarsening_mis(const ivector &V,graphe &G,sparsemat &P) const {
4155 int n=node_count(),m=V.size();
4156 for (int i=0;i<n;++i) {
4157 int md=mdeg(V,i);
4158 assert(md>0);
4159 for (int j=0;j<m;++j) {
4160 if (i==V[j])
4161 P[i][j]=make_pair(1,1);
4162 else if (has_edge(i,V[j]))
4163 P[i][j]=make_pair(1,md);
4164 }
4165 }
4166 coarsening(G,P,V);
4167 }
4168
4169 /* make coarser graph by collapsing edges found in maximal matching */
coarsening_ec(const ipairs & M,graphe & G,sparsemat & P) const4170 void graphe::coarsening_ec(const ipairs &M,graphe &G,sparsemat &P) const {
4171 ivector removed_nodes,V;
4172 for (ipairs_iter it=M.begin();it!=M.end();++it) {
4173 removed_nodes.push_back(it->second);
4174 }
4175 int n=node_count(),m=removed_nodes.size(),J;
4176 ivector::iterator ivt;
4177 for (int i=0;i<n;++i) {
4178 if ((ivt=find(removed_nodes.begin(),removed_nodes.end(),i))==removed_nodes.end())
4179 V.push_back(i);
4180 else
4181 removed_nodes.erase(ivt);
4182 }
4183 for (int i=0;i<n;++i) {
4184 for (int j=0;j<n-m;++j) {
4185 if (i==(J=V[j]) || find(M.begin(),M.end(),make_pair(J,i))!=M.end())
4186 P[i][j]=make_pair(1,1);
4187 }
4188 }
4189 coarsening(G,P,V);
4190 }
4191
4192 static int multilevel_depth;
4193 static bool multilevel_mis;
4194
multilevel_recursion(layout & x,int d,double R,double K,double tol,int depth)4195 void graphe::multilevel_recursion(layout &x,int d,double R,double K,double tol,int depth) {
4196 ivector mis;
4197 ipairs M;
4198 if (multilevel_mis)
4199 maximal_independent_set(mis);
4200 else
4201 find_maximal_matching(M);
4202 int n=node_count(),m=multilevel_mis?mis.size():n-int(M.size());
4203 x.resize(n);
4204 if (m>0.75*n) {
4205 /* coarsening is slow, switch from EC to MIS method since it's faster */
4206 multilevel_mis=true;
4207 multilevel_recursion(x,d,R,K,tol,depth);
4208 return;
4209 }
4210 if (m<2) {
4211 /* the coarsest level, apply force directed algorithm on a random initial layout */
4212 multilevel_depth=depth;
4213 create_random_layout(x,d);
4214 force_directed_placement(x,K,R*(depth+1)*K,tol,false);
4215 } else {
4216 /* create coarser graph H and lay it out */
4217 graphe G(ctx);
4218 sparsemat P; // prolongation matrix
4219 if (multilevel_mis)
4220 coarsening_mis(mis,G,P);
4221 else
4222 coarsening_ec(M,G,P);
4223 layout y;
4224 G.multilevel_recursion(y,d,R,K,tol,depth+1);
4225 /* compute x=P*y (layout lifting) */
4226 ipair pij;
4227 point yj(d);
4228 for (int i=0;i<n;++i) {
4229 x[i]=point(d,0);
4230 for (int j=0;j<m;++j) {
4231 if (sparse_matrix_element(P,i,j,pij)) {
4232 copy_point(y[j],yj);
4233 scale_point(yj,_evalf(ipair2rat(pij),ctx).DOUBLE_val());
4234 add_point(x[i],yj);
4235 }
4236 }
4237 }
4238 /* make the natural spring length K shorter with respect to
4239 * the current depth level and subsequently refine x */
4240 double L=K*std::pow(PLASTIC_NUMBER,depth-multilevel_depth);
4241 force_directed_placement(x,L,R*(depth+1)*L,K*tol/L,false);
4242 }
4243 }
4244
4245 /* apply multilevel force directed algorithm to layout x */
make_spring_layout(layout & x,int d,double tol)4246 void graphe::make_spring_layout(layout &x,int d,double tol) {
4247 int n=node_count();
4248 if (n==0)
4249 return;
4250 if (n==1) {
4251 x.resize(1);
4252 x.front().resize(d,0);
4253 } else if (n<30) {
4254 x.resize(n);
4255 create_random_layout(x,d);
4256 force_directed_placement(x,10.0,DBL_MAX,tol);
4257 } else {
4258 multilevel_mis=false;
4259 multilevel_recursion(x,d,DBL_MAX,10.0,tol);
4260 }
4261 if (d==3) {
4262 /* z-center the layout */
4263 double minz=DBL_MAX,maxz=-DBL_MAX;
4264 for (layout_iter it=x.begin();it!=x.end();++it) {
4265 if (it->back()>maxz)
4266 maxz=it->back();
4267 if (it->back()<minz)
4268 minz=it->back();
4269 }
4270 double dz=-(minz+maxz)/2.0;
4271 for (layout::iterator it=x.begin();it!=x.end();++it) {
4272 it->back()+=dz;
4273 }
4274 }
4275 }
4276
4277 /* layout face as a regular polygon inscribed in circle of radius R */
make_regular_polygon_layout(layout & x,const ivector & v,double R,double elongate)4278 void graphe::make_regular_polygon_layout(layout &x,const ivector &v,double R,double elongate) {
4279 int n=v.size(),i;
4280 double step=2.0*M_PI/(double)n,phi=(n%2)==0?M_PI_2*(1+2.0/n):M_PI_2;
4281 for (int k=0;k<n;++k) {
4282 i=v[k];
4283 point &p=x[i];
4284 p.resize(2);
4285 p[0]=R*std::cos(phi);
4286 p[1]=R*std::sin(phi);
4287 if (elongate>0) {
4288 if (p[0]>.001) p[0]+=elongate;
4289 else if (p[0]<-.001) p[0]-=elongate;
4290 }
4291 phi-=step;
4292 }
4293 }
4294
4295 /* apply force directed algorithm to this graph (must be triconnected), with the specified outer hull,
4296 * using the algorithm by Bor Plestenjak in "An Algorithm for Drawing Planar Graphs" */
make_circular_layout(layout & x,const ivector & hull,double A,double tol,double elongate)4297 void graphe::make_circular_layout(layout &x,const ivector &hull,double A,double tol,double elongate) {
4298 int n=node_count(),iter_count=0,maxper=0,j;
4299 /* place facial vertices on the unit circle and all other vertices in the origin */
4300 x.resize(n);
4301 make_regular_polygon_layout(x,hull,1.0,elongate);
4302 if (n==int(hull.size())) // there are no vertices to place inside the circle
4303 return;
4304 vector<bool> is_hull_vertex(n,false);
4305 for (ivector_iter it=hull.begin();it!=hull.end();++it) {
4306 is_hull_vertex[*it]=true;
4307 }
4308 /* compute vertex periphericity */
4309 ivector per(n);
4310 periphericity(hull,per);
4311 for (ivector_iter pt=per.begin();pt!=per.end();++pt) {
4312 if (*pt>maxper)
4313 maxper=*pt;
4314 }
4315 layout force(n);
4316 for (int i=0;i<n;++i) {
4317 force[i].resize(2);
4318 if (is_hull_vertex[i])
4319 continue;
4320 point &p=x[i];
4321 p.resize(2,0.0);
4322 }
4323 /* cool down the system iteratively */
4324 double d,cool,C=std::sqrt((double)n/M_PI),eps=tol/std::sqrt((double)n);
4325 do {
4326 ++iter_count;
4327 /* compute the resultant force for each non-outer vertex */
4328 for (int i=0;i<n;++i) {
4329 if (is_hull_vertex[i])
4330 continue;
4331 vertex &v=node(i);
4332 point &f=force[i],&p=x[i];
4333 clear_point_coords(f);
4334 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
4335 j=*it;
4336 point &q=x[j];
4337 point r(2);
4338 copy_point(q,r);
4339 subtract_point(r,p);
4340 d=C*std::exp(A*(2.0*maxper-per[i]-per[j])/(double)maxper)*point_displacement(r,false);
4341 scale_point(r,d);
4342 add_point(f,r);
4343 }
4344 }
4345 /* move each vertex in the direction of the force */
4346 cool=1.0/(C+std::pow(iter_count,1.5)/C);
4347 for (int i=0;i<n;++i) {
4348 if (is_hull_vertex[i])
4349 continue;
4350 point &f=force[i],&p=x[i];
4351 d=point_displacement(f);
4352 if (d>0) {
4353 scale_point(f,std::min(d,cool)/d);
4354 add_point(p,f);
4355 }
4356 }
4357 } while (cool>eps);
4358 }
4359
4360 /* apply Tutte's barycentric method for vertex placement */
make_tutte_layout(layout & x,const ivector & outer_face)4361 void graphe::make_tutte_layout(layout &x,const ivector &outer_face) {
4362 /* place facial vertices on the unit circle and all other vertices in the origin */
4363 int n=node_count();
4364 x.resize(n);
4365 make_regular_polygon_layout(x,outer_face);
4366 if (n==int(outer_face.size()))
4367 return; /* there are no vertices to place inside the circle */
4368 vector<bool> is_outer(n,false);
4369 for (ivector_iter it=outer_face.begin();it!=outer_face.end();++it) {
4370 is_outer[*it]=true;
4371 }
4372 for (int i=0;i<n;++i) {
4373 if (!is_outer[i]) {
4374 point &p=x[i];
4375 p.resize(2);
4376 p[0]=p[1]=0;
4377 }
4378 }
4379 double tol=1e-5;
4380 point old(2),r(2);
4381 bool converged;
4382 int j;
4383 do {
4384 converged=true;
4385 for (int i=0;i<n;++i) {
4386 if (is_outer[i])
4387 continue;
4388 vertex &v=node(i);
4389 point &p=x[i];
4390 copy_point(p,old);
4391 clear_point_coords(p);
4392 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
4393 j=*it;
4394 add_point(p,x[j]);
4395 }
4396 scale_point(p,1.0/(double)v.degree());
4397 if (point_distance(p,old,r)>tol)
4398 converged=false;
4399 }
4400 } while (!converged);
4401 }
4402
4403 /* Tomita recursive algorithm (a variant of Bron-Kerbosch) for maximal cliques */
tomita(iset & R,iset & P,iset & X,map<int,int> & m,int mode)4404 void graphe::tomita(iset &R,iset &P,iset &X,map<int,int> &m,int mode) {
4405 if (P.empty() && X.empty()) {
4406 if (mode==1) { // store matching
4407 if (R.size()==2)
4408 m[*R.begin()]=*R.rbegin();
4409 } else if (mode==2 || mode==3) { // store the clique
4410 ivector cliq;
4411 cliq.reserve(R.size());
4412 for (iset_iter it=R.begin();it!=R.end();++it) cliq.push_back(*it);
4413 maxcliques.push_back(cliq);
4414 }
4415 if (mode==0 || mode==3)
4416 ++m[R.size()];
4417 } else {
4418 /* choose as the pivot element the node with the highest number of neighbors in P, say i-th */
4419 iset PUX,PP,XX,S;
4420 sets_union(P,X,PUX);
4421 int i=*PUX.begin(),mn=0,n;
4422 for (iset_iter it=PUX.begin();it!=PUX.end();++it) {
4423 const vertex &w=node(*it);
4424 sets_intersection(w.neighbors(),P,S);
4425 if ((n=int(S.size()))>mn) {
4426 mn=n;
4427 i=*it;
4428 }
4429 }
4430 sets_difference(P,node(i).neighbors(),S);
4431 for (iset_iter it=S.begin();it!=S.end();++it) {
4432 const ivector &ngh=node(*it).neighbors();
4433 R.insert(*it);
4434 sets_intersection(ngh,P,PP);
4435 sets_intersection(ngh,X,XX);
4436 tomita(R,PP,XX,m,mode);
4437 R.erase(*it);
4438 P.erase(*it);
4439 X.insert(*it);
4440 }
4441 }
4442 }
4443
4444 /* a modified version of the Bron-Kerbosch algorithm for listing all maximal cliques,
4445 * developed by Tomita et al. Number of k-cliques will be stored to m[k] for each k.
4446 * If store_matching is true, store 2-cliques (v,w) as m[v]=w. */
clique_stats(map<int,int> & m,int mode)4447 void graphe::clique_stats(map<int,int> &m,int mode) {
4448 iset R,X,P;
4449 for (int i=0;i<node_count();++i) P.insert(i);
4450 tomita(R,P,X,m,mode);
4451 }
4452
4453 /* generate a clique vertex cover of this graph */
find_maximal_cliques()4454 void graphe::find_maximal_cliques() {
4455 map<int,int> m;
4456 iset R,X,P;
4457 for (int i=0;i<node_count();++i) P.insert(i);
4458 clear_maximal_cliques();
4459 tomita(R,P,X,m,2);
4460 }
4461
4462 /* CP recursive subroutine */
cp_recurse(ivector & C,ivector & P,ivector & incumbent)4463 void graphe::cp_recurse(ivector &C,ivector &P,ivector &incumbent) {
4464 if (C.size()>incumbent.size())
4465 incumbent=C;
4466 if (C.size()+P.size()>incumbent.size()) {
4467 int p,k;
4468 ivector Q,Cup;
4469 while (!P.empty()) {
4470 p=P.back();
4471 P.pop_back();
4472 Cup=C;
4473 if (find(Cup.begin(),Cup.end(),p)==Cup.end())
4474 Cup.push_back(p);
4475 const vertex &v=node(p);
4476 Q.clear();
4477 Q.resize(std::min(P.size(),v.neighbors().size()));
4478 k=0;
4479 for (ivector_iter it=P.begin();it!=P.end();++it) {
4480 if (v.has_neighbor(*it))
4481 Q[k++]=*it;
4482 }
4483 Q.resize(k);
4484 cp_recurse(Cup,Q,incumbent);
4485 }
4486 }
4487 }
4488
4489 /* Carraghan-Pardalos algorithm for finding maximum clique in a sparse graph */
cp_maxclique(ivector & clique)4490 int graphe::cp_maxclique(ivector &clique) {
4491 int n=node_count();
4492 ivector P(n),C;
4493 /* initialize P and sort all adjacency lists */
4494 for (int i=0;i<n;++i)
4495 P[i]=i;
4496 /* sort vertices by degree in descending order */
4497 degree_comparator comp(this);
4498 sort(P.begin(),P.end(),comp);
4499 std::reverse(P.begin(),P.end());
4500 cp_recurse(C,P,clique);
4501 return clique.size();
4502 }
4503
4504 /*
4505 * Östergård class for finding maximum clique
4506 *
4507 * implemented as described in "A fast algorithm for the maximum clique problem",
4508 * Discrete Applied Mathematics 120 (2002) 197–207
4509 */
4510
recurse(ivector & U,int size,ivector & position)4511 void graphe::ostergard::recurse(ivector &U,int size,ivector &position) {
4512 if (U.empty()) {
4513 if (size>maxsize) {
4514 maxsize=size;
4515 incumbent=clique_nodes;
4516 found=true;
4517 }
4518 return;
4519 }
4520 if (timeout>0 && double(clock()-start)/CLOCKS_PER_SEC>timeout && !incumbent.empty()) {
4521 timed_out=true;
4522 return;
4523 }
4524 int i,j,minpos,p;
4525 ivector::iterator it;
4526 ivector V;
4527 while (!U.empty()) {
4528 if (size+int(U.size())<=maxsize)
4529 break;
4530 i=U.front();
4531 it=U.begin();
4532 minpos=-1;
4533 for (ivector::iterator jt=U.begin();jt!=U.end();++jt) {
4534 j=*jt;
4535 p=position[j];
4536 if (minpos<0 || p<minpos) {
4537 minpos=p;
4538 i=j;
4539 it=jt;
4540 }
4541 }
4542 const vertex &v=G->node(i);
4543 assert(v.low()>0);
4544 if (size+v.low()<=maxsize)
4545 break;
4546 U.erase(it);
4547 V.resize(std::min(U.size(),v.neighbors().size()));
4548 j=0;
4549 for (it=U.begin();it!=U.end();++it) {
4550 if (*it<*v.neighbors().begin() || *it>*v.neighbors().rbegin())
4551 continue;
4552 if (v.has_neighbor(*it))
4553 V[j++]=*it;
4554 }
4555 V.resize(j);
4556 clique_nodes.push_back(i);
4557 recurse(V,size+1,position);
4558 clique_nodes.pop_back();
4559 if (found || timed_out)
4560 break;
4561 }
4562 }
4563
4564 /* return the size of maximum clique */
maxclique(ivector & clique)4565 int graphe::ostergard::maxclique(ivector &clique) {
4566 int n=G->node_count();
4567 ivector S(n),U,position(n,0);
4568 for (int i=0;i<n;++i) {
4569 S[i]=i;
4570 vertex &v=G->node(i);
4571 v.set_low(0);
4572 }
4573 G->greedy_vertex_coloring_biggs(S);
4574 std::reverse(S.begin(),S.end());
4575 G->node(S.back()).set_low(1);
4576 for (ivector_iter it=S.begin();it!=S.end();++it) {
4577 position[*it]=it-S.begin();
4578 }
4579 maxsize=0;
4580 clique_nodes.clear();
4581 int k;
4582 start=clock();
4583 timed_out=false;
4584 for (int i=n;i-->0;) {
4585 found=false;
4586 k=S[i];
4587 vertex &v=G->node(k);
4588 U.clear();
4589 for (ivector_iter it=S.begin()+i;it!=S.end();++it) {
4590 if (v.has_neighbor(*it))
4591 U.push_back(*it);
4592 }
4593 clique_nodes.push_back(k);
4594 recurse(U,1,position);
4595 if (timed_out)
4596 break;
4597 clique_nodes.pop_back();
4598 v.set_low(maxsize);
4599 }
4600 clique=incumbent;
4601 return clique.size();
4602 }
4603
4604 /*
4605 * End of ostergard class
4606 */
4607
4608 /* find maximum clique in this graph and return its size */
maximum_clique(ivector & clique)4609 int graphe::maximum_clique(ivector &clique) {
4610 assert(!is_directed());
4611 clique.clear();
4612 int n=node_count(),m=edge_count();
4613 if (20*m<=n*(n-1)) // edge density smaller than or equal to 0.1
4614 return cp_maxclique(clique);
4615 ostergard ost(this);
4616 return ost.maxclique(clique);
4617 }
4618
4619 /* remove a maximal clique from vertex set V using a fast greedy algorithm
4620 * (Johnson, J. Comp. Syst. Sci. 1974) */
remove_maximal_clique(iset & V) const4621 void graphe::remove_maximal_clique(iset &V) const {
4622 iset U=V,W,tmp;
4623 int s,smax,v;
4624 do {
4625 smax=0;
4626 v=*U.begin();
4627 W.clear();
4628 for (iset_iter it=U.begin();it!=U.end();++it) {
4629 if ((s=sets_intersection(node(*it).neighbors(),U,tmp))>smax) {
4630 smax=s;
4631 W=tmp;
4632 v=*it;
4633 }
4634 }
4635 V.erase(v);
4636 } while (!(U=W).empty());
4637 }
4638
4639 /* approximate neighborhood clique cover number for every vertex */
greedy_neighborhood_clique_cover_numbers(ivector & cover_numbers)4640 void graphe::greedy_neighborhood_clique_cover_numbers(ivector &cover_numbers) {
4641 int n=node_count();
4642 cover_numbers.resize(n,0);
4643 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
4644 iset V;
4645 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
4646 V.insert(*jt);
4647 }
4648 int &cn=cover_numbers[it-nodes.begin()];
4649 while (!V.empty()) {
4650 remove_maximal_clique(V);
4651 ++cn;
4652 }
4653 }
4654 }
4655
4656 /* return the number of differently colored and uncolored vertices adjacent to the i-th vertex */
adjacent_color_count(int i) const4657 graphe::ipair graphe::adjacent_color_count(int i) const {
4658 std::set<int> colors;
4659 int c,unc=0;
4660 const vertex &v=node(i);
4661 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
4662 c=node(*it).color();
4663 if (c>0)
4664 colors.insert(c);
4665 else ++unc;
4666 }
4667 return make_pair(colors.size(),unc);
4668 }
4669
4670 /* insert colors adjacent to the i-th vertex to the given set */
adjacent_colors(int i,std::set<int> & colors) const4671 bool graphe::adjacent_colors(int i,std::set<int> &colors) const {
4672 const vertex &v=node(i);
4673 if (v.color()>0)
4674 return false;
4675 int c;
4676 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
4677 if ((c=node(*it).color())>0)
4678 colors.insert(c);
4679 }
4680 return true;
4681 }
4682
4683 /*
4684 * painter class implementation
4685 */
4686
4687 #ifdef HAVE_LIBGLPK
compute_bounds(const ivector & icol,int max_colors)4688 void graphe::painter::compute_bounds(const ivector &icol,int max_colors) {
4689 G->greedy_neighborhood_clique_cover_numbers(cover_number);
4690 G->uncolor_all_nodes();
4691 lb=(initially_colored=icol).size();
4692 ub=max_colors;
4693 if (ub==0) {
4694 for (ivector_iter it=initially_colored.begin();it!=initially_colored.end();++it) {
4695 G->set_node_color(*it,it-initially_colored.begin()+1);
4696 }
4697 G->dsatur();
4698 ub=G->color_count();
4699 }
4700 if ((generate_clique_cuts=G->node_count()<=100))
4701 G->find_maximal_cliques();
4702 }
4703
make_values()4704 void graphe::painter::make_values() {
4705 int n=G->node_count(),col=0,k;
4706 ivector_iter pos;
4707 values.resize(n);
4708 for (int i=0;i<n;++i) {
4709 ivector &x=values[i];
4710 x.resize(ub);
4711 pos=find(initially_colored.begin(),initially_colored.end(),i);
4712 k=pos==initially_colored.end()?-1:int(pos-initially_colored.begin());
4713 for (int j=0;j<ub;++j) {
4714 if (k<0) {
4715 if (j<lb && G->node(initially_colored[j]).has_neighbor(i))
4716 x[j]=-2;
4717 else {
4718 x[j]=++col;
4719 col2ij.push_back(make_pair(i,j));
4720 }
4721 } else
4722 x[j]=j==k?-1:-2;
4723 }
4724 }
4725 nxcols=col;
4726 }
4727
formulate_mip()4728 void graphe::painter::formulate_mip() {
4729 mip=glp_create_prob();
4730 glp_set_obj_dir(mip,GLP_MIN);
4731 int n=G->node_count(),i,j,k;
4732 iscliq.resize(n,false);
4733 for (ivector_iter it=initially_colored.begin();it!=initially_colored.end();++it) {
4734 iscliq[*it]=true;
4735 }
4736 /* create row variables and count nonzero entries in the constraint matrix */
4737 int nonzeros=0,cnt=0,rs,cn,val;
4738 int nrows=n*(ub+2)-3*lb;
4739 glp_add_rows(mip,nrows);
4740 for (i=0;i<n;++i) {
4741 if (!iscliq[i]) {
4742 glp_set_row_bnds(mip,++cnt,GLP_FX,1.0,1.0);
4743 ivector &vals=values[i];
4744 for (ivector_iter it=vals.begin();it!=vals.end();++it) {
4745 if (*it>0)
4746 ++nonzeros;
4747 }
4748 }
4749 }
4750 for (k=0;k<n;++k) {
4751 cn=cover_number[k];
4752 const vertex &v=G->node(k);
4753 for (j=0;j<ub;++j) {
4754 if (j<lb && k==initially_colored[j])
4755 continue;
4756 nonzeros+=2;
4757 rs=j<lb?cn:0;
4758 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
4759 i=*it;
4760 if ((val=values[i][j])>0)
4761 ++nonzeros;
4762 else rs-=val+2;
4763 }
4764 glp_set_row_bnds(mip,++cnt,GLP_UP,0.0,rs);
4765 }
4766 }
4767 for (i=0;i<n;++i) {
4768 if (!iscliq[i]) {
4769 glp_set_row_bnds(mip,++cnt,GLP_UP,0.0,lb);
4770 nonzeros+=ub-lb;
4771 ivector &vals=values[i];
4772 for (ivector_iter it=vals.begin();it!=vals.end();++it) {
4773 if (*it>0)
4774 ++nonzeros;
4775 }
4776 }
4777 }
4778 assert(cnt==nrows);
4779 /* create column variables */
4780 int ncols=nxcols+ub-lb;
4781 glp_add_cols(mip,ncols);
4782 for (i=0;i<ncols;++i) {
4783 glp_set_col_kind(mip,i+1,GLP_BV);
4784 if (i>=nxcols)
4785 glp_set_obj_coef(mip,i+1,1.0);
4786 }
4787 /* create the constraint matrix */
4788 int *ia=new int[nonzeros+1];
4789 int *ja=new int[nonzeros+1];
4790 double *ar=new double[nonzeros+1];
4791 int row=0,col;
4792 bool ok;
4793 cnt=0;
4794 for (i=0;i<n;++i) {
4795 if (iscliq[i])
4796 continue;
4797 ++row;
4798 ivector &vals=values[i];
4799 ok=false;
4800 for (ivector_iter it=vals.begin();it!=vals.end();++it) {
4801 if ((col=*it)>0) {
4802 ia[++cnt]=row; ja[cnt]=col;
4803 ar[cnt]=1.0;
4804 ok=true;
4805 } else assert(col==-2);
4806 }
4807 assert(ok);
4808 }
4809 for (k=0;k<n;++k) {
4810 cn=cover_number[k];
4811 const vertex &v=G->node(k);
4812 for (j=0;j<ub;++j) {
4813 if (j<lb && k==initially_colored[j])
4814 continue;
4815 ++row;
4816 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
4817 col=values[*it][j];
4818 if (col>0) {
4819 ia[++cnt]=row; ja[cnt]=col;
4820 ar[cnt]=1.0;
4821 }
4822 }
4823 if ((col=values[k][j])>0) {
4824 ia[++cnt]=row; ja[cnt]=col;
4825 ar[cnt]=cn;
4826 }
4827 if (j>=lb) {
4828 col=1+nxcols+j-lb;
4829 ia[++cnt]=row; ja[cnt]=col;
4830 ar[cnt]=-cn;
4831 }
4832 }
4833 }
4834 for (i=0;i<n;++i) {
4835 if (iscliq[i])
4836 continue;
4837 ++row;
4838 ivector &vals=values[i];
4839 for (ivector_iter it=vals.begin();it!=vals.end();++it) {
4840 j=it-vals.begin();
4841 if ((col=*it)>0) {
4842 ia[++cnt]=row; ja[cnt]=col;
4843 ar[cnt]=j+1;
4844 }
4845 }
4846 for (col=nxcols+1;col<=ncols;++col) {
4847 ia[++cnt]=row; ja[cnt]=col;
4848 ar[cnt]=-1.0;
4849 }
4850 }
4851 assert(cnt<=nonzeros && row==nrows);
4852 /* assign the constraint matrix to the MIP */
4853 glp_load_matrix(mip,cnt,ia,ja,ar);
4854 delete[] ia; delete[] ja;
4855 delete[] ar;
4856 for (i=0;i<nrows;++i) {
4857 glp_set_row_stat(mip,i+1,GLP_BS);
4858 }
4859 }
4860
callback(glp_tree * tree,void * info)4861 void graphe::painter::callback(glp_tree *tree,void *info) {
4862 painter *pt=static_cast<painter*>(info);
4863 int j;
4864 switch (glp_ios_reason(tree)) {
4865 case GLP_IBRANCH:
4866 /* select the branching variable */
4867 if ((j=pt->select_branching_variable(tree))>0)
4868 glp_ios_branch_upon(tree,j,GLP_DN_BRNCH);
4869 break;
4870 case GLP_IHEUR:
4871 /* obtain a heuristic solution */
4872 pt->heur_solution(tree);
4873 break;
4874 case GLP_IROWGEN:
4875 /* generate clique and block color inequalities */
4876 pt->generate_rows(tree);
4877 break;
4878 default:
4879 /* ignore call for other reasons */
4880 break;
4881 }
4882 }
4883
4884 /* generate constraints violated by the current subproblem relaxation solution */
generate_rows(glp_tree * tree)4885 void graphe::painter::generate_rows(glp_tree *tree) {
4886 glp_prob *prob=glp_ios_get_prob(tree);
4887 int n=G->node_count(),col,w,len,r=glp_ios_curr_node(tree),best_len=-1;
4888 int *data=(int*)glp_ios_node_data(tree,r);
4889 if (*data>maxiter)
4890 return;
4891 (*data)+=1;
4892 double rh,lh,h,maxh=0;
4893 /* block color cuts */
4894 for (int c=ub;c-->lb;) {
4895 w=nxcols+c-lb+1;
4896 for (int i=0;i<n;++i) {
4897 if (iscliq[i])
4898 continue;
4899 rh=0.0;
4900 len=0;
4901 for (int j=c;j<ub;++j) {
4902 col=values[i][j];
4903 if (col<0)
4904 rh-=col+2;
4905 else {
4906 row_indices[++len]=col;
4907 row_coeffs[len]=1.0;
4908 }
4909 }
4910 if (len==0)
4911 continue;
4912 row_indices[++len]=w;
4913 row_coeffs[len]=-1.0;
4914 lh=0;
4915 for (int k=0;k<len;++k) {
4916 lh+=row_coeffs[k+1]*glp_get_col_prim(prob,row_indices[k+1]);
4917 }
4918 h=lh-rh;
4919 //h/=len;
4920 if (h>maxh) {
4921 maxh=h;
4922 memcpy(best_indices+1,row_indices+1,len*sizeof(int));
4923 memcpy(best_coeffs+1,row_coeffs+1,len*sizeof(double));
4924 best_len=len;
4925 }
4926 }
4927 }
4928 if (best_len>0)
4929 add_row(prob,best_len,best_indices,best_coeffs,rh);
4930 /* clique cuts */
4931 if (generate_clique_cuts) {
4932 const ivectors &cover=G->maximal_cliques();
4933 double lim=30.0/double(cover.size());
4934 int nc=0;
4935 for (int c=ub;c-->lb;) {
4936 w=nxcols+c-lb+1;
4937 for (ivectors_iter it=cover.begin();it!=cover.end();++it) {
4938 if (G->rand_uniform()>=lim)
4939 continue;
4940 const ivector &cliq=*it;
4941 rh=0.0;
4942 len=0;
4943 for (ivector_iter jt=cliq.begin();jt!=cliq.end();++jt) {
4944 col=values[*jt][c];
4945 if (col<0)
4946 rh-=col+2;
4947 else {
4948 row_indices[++len]=col;
4949 row_coeffs[len]=1.0;
4950 }
4951 }
4952 if (len==0)
4953 continue;
4954 row_indices[++len]=w;
4955 row_coeffs[len]=-1.0;
4956 lh=0;
4957 for (int k=0;k<len;++k) {
4958 lh+=row_coeffs[k+1]*glp_get_col_prim(prob,row_indices[k+1]);
4959 }
4960 h=lh-rh;
4961 //h/=len;
4962 if (h>0) {
4963 add_row(prob,len,row_indices,row_coeffs,rh);
4964 ++nc;
4965 }
4966 }
4967 }
4968 }
4969 }
4970
add_row(glp_prob * prob,int len,int * indices,double * coeffs,double rh)4971 void graphe::painter::add_row(glp_prob *prob,int len,int *indices,double *coeffs,double rh) {
4972 int r=glp_add_rows(prob,1);
4973 glp_set_row_bnds(prob,r,GLP_UP,-DBL_MAX,rh);
4974 glp_set_mat_row(prob,r,len,indices,coeffs);
4975 }
4976
4977 /* color the nodes for which the colors are known */
fixed_coloring(glp_tree * tree)4978 void graphe::painter::fixed_coloring(glp_tree *tree) {
4979 glp_prob *prob=glp_ios_get_prob(tree); // current subproblem
4980 G->uncolor_all_nodes();
4981 for (ivector_iter it=initially_colored.begin();it!=initially_colored.end();++it) {
4982 G->set_node_color(*it,int(it-initially_colored.begin())+1);
4983 }
4984 for (int j=nxcols;j-->0;) {
4985 ipair &ij=col2ij[j];
4986 if (!glp_ios_can_branch(tree,j+1) && glp_get_col_prim(prob,j+1)==1)
4987 G->set_node_color(ij.first,lb+ij.second+1);
4988 }
4989 }
4990
4991 /* fast construction of a heuristic solution using greedy coloring */
heur_solution(glp_tree * tree)4992 void graphe::painter::heur_solution(glp_tree *tree) {
4993 if (maxiter==0) {
4994 fixed_coloring(tree);
4995 /* dsatur coloring, quadratic time */
4996 G->dsatur();
4997 assign_heur(tree);
4998 }
4999 int iter_count=0;
5000 while (++iter_count<=maxiter) {
5001 /* greedy coloring, linear time */
5002 fixed_coloring(tree);
5003 int n=G->node_count(),i,j;
5004 ordering=G->rand_permu(n);
5005 for (ivector_iter ot=ordering.begin();ot!=ordering.end();++ot) {
5006 i=*ot;
5007 used_colors.clear();
5008 if (!G->adjacent_colors(i,used_colors))
5009 continue;
5010 j=0;
5011 std::set<int>::const_iterator it=used_colors.begin();
5012 for (;it!=used_colors.end();++it) {
5013 if (*it!=++j) {
5014 G->set_node_color(i,j);
5015 break;
5016 }
5017 }
5018 if (it==used_colors.end())
5019 G->set_node_color(i,j+1);
5020 }
5021 if (assign_heur(tree)==0)
5022 break;
5023 }
5024 }
5025
5026 /* offer heuristic solution to MIP solver */
assign_heur(glp_tree * tree)5027 int graphe::painter::assign_heur(glp_tree *tree) {
5028 G->get_node_colors(temp_colors);
5029 int nc=G->color_count(),i,j;
5030 if (nc>ub)
5031 return 1;
5032 nc-=lb;
5033 for (int col=1;col<=nxcols;++col) {
5034 const ipair &p=col2ij[col-1];
5035 i=p.first;
5036 j=p.second;
5037 *(heur+col)=temp_colors[i]==j+1?1.0:0.0;
5038 }
5039 for (i=0;i<ub-lb;++i) {
5040 *(heur+nxcols+1+i)=i<nc?1.0:0.0;
5041 }
5042 return glp_ios_heur_sol(tree,heur);
5043 }
5044
5045 /* the custom branching rule for MVCP (Brelaz): a fractionable vertex with
5046 * the largest number of different adjacent colors is chosen, ties are broken by
5047 * choosing the vertex with the maximal degree in the uncolored subgraph */
select_branching_variable(glp_tree * tree)5048 int graphe::painter::select_branching_variable(glp_tree *tree) {
5049 glp_prob *prob=glp_ios_get_prob(tree); // current subproblem
5050 std::fill(branch_candidates.begin(),branch_candidates.end(),-1);
5051 fixed_coloring(tree);
5052 double fr;
5053 for (int j=nxcols;j-->0;) {
5054 ipair &ij=col2ij[j];
5055 if (glp_ios_can_branch(tree,j+1)) {
5056 int &bc=branch_candidates[ij.first];
5057 fr=std::abs(glp_get_col_prim(prob,j+1)-0.5);
5058 if (bc<0 || fr<fracts[ij.first]) {
5059 bc=ij.second;
5060 fracts[ij.first]=fr;
5061 }
5062 }
5063 }
5064 int i,j=0;
5065 ipair nc,nc_max=make_pair(-1,-1);
5066 for (ivector_iter it=branch_candidates.begin();it!=branch_candidates.end();++it) {
5067 if (*it<0)
5068 continue;
5069 i=it-branch_candidates.begin();
5070 nc=G->adjacent_color_count(i);
5071 if (nc>nc_max) {
5072 nc_max=nc;
5073 j=values[i][*it];
5074 }
5075 }
5076 return j;
5077 }
5078
color_vertices(ivector & colors,const ivector & icol,int max_colors)5079 int graphe::painter::color_vertices(ivector &colors,const ivector &icol,int max_colors) {
5080 compute_bounds(icol,max_colors);
5081 if (ub<lb)
5082 return 0;
5083 int n=G->node_count();
5084 make_values();
5085 formulate_mip();
5086 glp_smcp lparm;
5087 glp_init_smcp(&lparm);
5088 lparm.msg_lev=GLP_MSG_OFF;
5089 glp_simplex(mip,&lparm);
5090 glp_iocp parm;
5091 glp_init_iocp(&parm);
5092 parm.msg_lev=GLP_MSG_OFF;
5093 parm.gmi_cuts=GLP_OFF;
5094 parm.mir_cuts=GLP_OFF;
5095 parm.clq_cuts=GLP_ON;
5096 parm.cov_cuts=GLP_ON;
5097 parm.presolve=GLP_OFF;
5098 parm.bt_tech=GLP_BT_DFS;
5099 parm.cb_size=sizeof(int);
5100 parm.cb_func=&callback;
5101 parm.cb_info=static_cast<void*>(this);
5102 branch_candidates.resize(n);
5103 fracts.resize(n);
5104 maxiter=std::ceil(15.0*std::exp(-std::pow(n,2)*0.000321887582487));
5105 heur=new double[nxcols+ub-lb+1];
5106 row_indices=new int[nxcols+ub-lb+1];
5107 row_coeffs=new double[nxcols+ub-lb+1];
5108 best_indices=new int[nxcols+ub-lb+1];
5109 best_coeffs=new double[nxcols+ub-lb+1];
5110 int ncolors=0,res=glp_intopt(mip,&parm);
5111 if (res==0) {
5112 switch (glp_get_status(mip)) { // solution status:
5113 case GLP_UNDEF:
5114 G->message("Error: MIP solution undefined");
5115 break;
5116 case GLP_FEAS: // feasible but not necessarily optimal
5117 G->message("Warning: optimality of the solution is not guaranteed");
5118 case GLP_OPT: // optimal
5119 ncolors=lb+glp_mip_obj_val(mip);
5120 /* color the vertices */
5121 for (int k=0;k<nxcols;++k) {
5122 ipair &p=col2ij[k];
5123 if (glp_mip_col_val(mip,k+1)>0)
5124 G->set_node_color(p.first,p.second+1);
5125 }
5126 G->get_node_colors(colors);
5127 break;
5128 case GLP_NOFEAS: // not feasible
5129 G->message("Error: MIP has no feasible solutions");
5130 break;
5131 }
5132 } // else G->message("Error: MIP solver failure");
5133 glp_delete_prob(mip);
5134 delete[] heur;
5135 delete[] row_indices;
5136 delete[] row_coeffs;
5137 delete[] best_indices;
5138 delete[] best_coeffs;
5139 return ncolors;
5140 }
5141 #endif
5142
5143 /*
5144 * end of painter class
5145 */
5146
5147 /* find optimal vertex coloring using an exact algorithm, requires GLPK */
exact_vertex_coloring(int max_colors)5148 int graphe::exact_vertex_coloring(int max_colors) {
5149 int ncolors=0;
5150 #ifndef HAVE_LIBGLPK
5151 message("Error: GLPK library is required for graph coloring");
5152 #else
5153 int n=node_count();
5154 if (is_clique()) {
5155 for (int i=0;i<n;++i) {
5156 set_node_color(i,i+1);
5157 }
5158 return n;
5159 }
5160 painter pt(this);
5161 ivector colors,clique;
5162 ostergard ost(this,5.0);
5163 ost.maxclique(clique);
5164 ncolors=pt.color_vertices(colors,clique,max_colors);
5165 if (ncolors>0 && find(colors.begin(),colors.end(),0)!=colors.end()) {
5166 uncolor_all_nodes();
5167 ncolors=0;
5168 }
5169 #endif
5170 return ncolors;
5171 }
5172
5173 /* color the edges of this graph using D or D+1 colors,
5174 * return 1 in the former case, 2 in the latter, 0 on error */
exact_edge_coloring(ivector & colors,int * numcol)5175 int graphe::exact_edge_coloring(ivector &colors,int *numcol) {
5176 graphe L(ctx,false);
5177 ipairs E;
5178 line_graph(L,E);
5179 /* find the vertex with maximum degree in G (this graph) */
5180 int m=E.size(),maxdeg=0,deg,i,j,k;
5181 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
5182 if ((deg=it->neighbors().size())>maxdeg) {
5183 maxdeg=deg;
5184 i=it-nodes.begin();
5185 }
5186 }
5187 ivector icol(maxdeg);
5188 k=0;
5189 for (j=0;j<m;++j) {
5190 const ipair &e=E[j];
5191 if (e.first==i || e.second==i)
5192 icol[k++]=j;
5193 }
5194 assert(k==maxdeg);
5195 #ifdef HAVE_LIBGLPK
5196 painter pt(&L);
5197 int ncolors=pt.color_vertices(colors,icol,maxdeg+1);
5198 #else
5199 message("Error: GLPK library is required for graph coloring");
5200 int ncolors=0;
5201 #endif
5202 for (k=0;k<maxdeg;++k) {
5203 colors[icol[k]]=k+1;
5204 }
5205 if (ncolors==0 || find(colors.begin(),colors.end(),0)!=colors.end())
5206 return 0;
5207 for (j=0;j<m;++j) {
5208 const ipair &e=E[j];
5209 set_edge_attribute(e.first,e.second,_GT_ATTRIB_COLOR,colors[j]);
5210 }
5211 if (numcol!=NULL)
5212 *numcol=ncolors;
5213 return ncolors-maxdeg+1;
5214 }
5215
5216 /* returns true iff there is a clique cover of order not larger than k and finds that cover */
clique_cover(ivectors & cover,int k)5217 bool graphe::clique_cover(ivectors &cover,int k) {
5218 if (triangle_count()==0) {
5219 /* clique cover consists of matched edges and singleton vertex sets */
5220 ipairs matching;
5221 find_maximum_matching(matching);
5222 int m=matching.size(),n=node_count(),i=0;
5223 if (k>0 && n-m>k)
5224 return false;
5225 vector<bool> matched(n);
5226 cover.resize(n-m);
5227 for (ipairs_iter it=matching.begin();it!=matching.end();++it) {
5228 ivector &clique=cover[i++];
5229 clique.resize(2);
5230 matched[(clique.front()=it->first)]=true;
5231 matched[(clique.back()=it->second)]=true;
5232 }
5233 for (vector<bool>::const_iterator it=matched.begin();it!=matched.end();++it) {
5234 if (!*it) {
5235 ivector &clique=cover[i++];
5236 clique.resize(1);
5237 clique.front()=it-matched.begin();
5238 }
5239 }
5240 return true;
5241 }
5242 graphe C(ctx,false);
5243 complement(C);
5244 int ncliques=C.exact_vertex_coloring();
5245 if (ncliques==0 || (k>0 && ncliques>k))
5246 return false;
5247 cover.clear();
5248 cover.resize(ncliques);
5249 for (int i=node_count();i-->0;) {
5250 const vertex &v=C.node(i);
5251 cover[v.color()-1].push_back(i);
5252 }
5253 return true;
5254 }
5255
5256 /* return true iff the graph is complete (i.e., a clique) */
is_clique(int sg) const5257 bool graphe::is_clique(int sg) const {
5258 assert(!is_directed());
5259 int i,j,n=node_count();
5260 for (i=0;i<n;++i) {
5261 if (sg>=0 && node(i).subgraph()!=sg)
5262 continue;
5263 for (j=i+1;j<n;++j) {
5264 if (sg>=0 && node(j).subgraph()!=sg)
5265 continue;
5266 if (!has_edge(i,j))
5267 return false;
5268 }
5269 }
5270 return true;
5271 }
5272
5273 /* find maximum independent set in this graph and return its size */
maximum_independent_set(ivector & v) const5274 int graphe::maximum_independent_set(ivector &v) const {
5275 graphe C(ctx,false);
5276 complement(C);
5277 return C.maximum_clique(v);
5278 }
5279
5280 /* return the number of (directed) triangles in (di)graph */
triangle_count(ivectors * dest,bool ccoeff,bool exact)5281 gen graphe::triangle_count(ivectors *dest,bool ccoeff,bool exact) {
5282 if (is_directed()) {
5283 sparsemat M,M2;
5284 adjacency_sparse_matrix(M);
5285 multiply_sparse_matrices(M,M,M2,node_count(),false);
5286 ipair p;
5287 gen trace=0;
5288 for (sparsemat::const_iterator it=M.begin();it!=M.end();++it) {
5289 for (map<int,ipair>::const_iterator jt=it->second.begin();jt!=it->second.end();++jt) {
5290 if (sparse_matrix_element(M2,jt->first,it->first,p))
5291 trace+=fraction(jt->second.first*p.first,jt->second.second*p.second);
5292 }
5293 }
5294 return _ratnormal(trace/gen(3),ctx);
5295 }
5296 gen c(0);
5297 int n=node_count(),i,j,sz1,sz2,sz3,isz,p1,p2,p3;
5298 double sum=0.0;
5299 ivector offset(n,0),intersection,trg(3);
5300 ivector_iter iter;
5301 sort_by_degrees();
5302 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
5303 i=it-nodes.begin();
5304 const ivector &vn=it->neighbors();
5305 if (ccoeff) { sz1=vn.size(); p1=(sz1*(sz1-1))/2; }
5306 for (ivector_iter jt=vn.begin();jt!=vn.end();++jt) {
5307 if ((j=*jt)<i) continue;
5308 const ivector &wn=node(j).neighbors();
5309 if (ccoeff) { sz2=wn.size(); p2=(sz2*(sz2-1))/2; }
5310 if (!ccoeff && dest==NULL)
5311 c+=intersect_linear(vn.begin(),vn.begin()+offset[i],wn.begin(),wn.begin()+offset[j]);
5312 else {
5313 intersection.resize(std::min(offset[i],offset[j]));
5314 iter=set_intersection(vn.begin(),vn.begin()+offset[i],wn.begin(),wn.begin()+offset[j],intersection.begin());
5315 intersection.resize(isz=iter-intersection.begin());
5316 for (ivector_iter kt=intersection.begin();kt!=intersection.end();++kt) {
5317 if (ccoeff) { sz3=node(*kt).neighbors().size(); p3=(sz3*(sz3-1))/2; }
5318 if (!ccoeff) {
5319 trg[0]=i; trg[1]=j; trg[2]=*kt;
5320 dest->push_back(trg);
5321 c+=1;
5322 } else if (exact) c+=gen(1)/harmonic_mean_exact(p1,p2,p3);
5323 else sum+=1.0/harmonic_mean(p1,p2,p3);
5324 }
5325 }
5326 ++offset[j];
5327 }
5328 }
5329 if (!ccoeff) return c;
5330 if (!exact) return 3.0*sum/double(n);
5331 return _ratnormal(gen(3)*c/gen(n),ctx);
5332 }
5333
5334 /* remove i-th node which is assumed to be isolated */
remove_isolated_nodes(const iset & I,graphe & G)5335 void graphe::remove_isolated_nodes(const iset &I,graphe &G) {
5336 int n=node_count();
5337 ivector sigma(n);
5338 for (int k=0;k<n;++k) {
5339 sigma[k]=k;
5340 }
5341 for (iset::const_reverse_iterator it=I.rbegin();it!=I.rend();++it) {
5342 sigma.erase(sigma.begin()+*it);
5343 sigma.push_back(*it);
5344 }
5345 isomorphic_copy(G,sigma);
5346 for (int i=I.size();i-->0;) G.nodes.pop_back();
5347 }
5348
5349 /* return true iff this is a multigraph */
is_multigraph() const5350 bool graphe::is_multigraph() const {
5351 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
5352 if (it->has_multiedges())
5353 return true;
5354 }
5355 return false;
5356 }
5357
5358 /* return the number of copies of edge e */
multiedges(const ipair & e) const5359 int graphe::multiedges(const ipair &e) const {
5360 int i=e.first,j=e.second;
5361 return node(i<j?i:j).multiedges(i<j?j:i);
5362 }
5363
5364 /* add k duplicates of e to the graph */
set_multiedge(const ipair & e,int k)5365 void graphe::set_multiedge(const ipair &e,int k) {
5366 int i=e.first,j=e.second;
5367 node(i<j?i:j).set_multiedge(i<j?j:i,k);
5368 }
5369
5370 /* convert integral edge weights to multiedges, returns false if an edge
5371 * has a weight which is not a positive integer */
weights2multiedges()5372 bool graphe::weights2multiedges() {
5373 assert(!is_directed() && is_weighted());
5374 ipairs E;
5375 get_edges_as_pairs(E);
5376 gen w;
5377 int k;
5378 for (ipairs_iter it=E.begin();it!=E.end();++it) {
5379 const ipair &e=*it;
5380 w=weight(e);
5381 if (w.is_integer() && (k=w.val-1)>=0) {
5382 set_multiedge(e,k);
5383 } else return false;
5384 }
5385 return true;
5386 }
5387
5388 /* contract the edge {i,j}, leaving j-th node isolated (not connected to any other node) */
contract_edge(int i,int j,bool adjust_positions)5389 void graphe::contract_edge(int i,int j,bool adjust_positions) {
5390 /* assuming that the graph is undirected */
5391 assert(has_edge(i,j) && multiedges(make_pair(i,j))==0);
5392 ivector adj;
5393 ipair e,e_old;
5394 adjacent_nodes(j,adj);
5395 int m=sum_of_edge_multiplicities();
5396 for (ivector_iter it=adj.begin();it!=adj.end();++it) {
5397 e_old=make_pair(j,*it);
5398 if (*it!=i) {
5399 e=make_pair(i,*it);
5400 if (has_edge(e)) {
5401 set_multiedge(e,multiedges(e_old)+multiedges(e)+1);
5402 } else {
5403 add_edge(e);
5404 set_multiedge(e,multiedges(e_old));
5405 }
5406 }
5407 remove_edge(e_old);
5408 }
5409 assert(m==1+sum_of_edge_multiplicities());
5410 if (adjust_positions) {
5411 vertex &v=node(i),&w=node(j);
5412 point p,q,r;
5413 if (get_node_position(v.attributes(),p) && get_node_position(w.attributes(),q) && p.size()==q.size()) {
5414 r.resize(p.size());
5415 copy_point(p,r);
5416 add_point(r,q);
5417 scale_point(r,0.5);
5418 v.set_attribute(_GT_ATTRIB_POSITION,point2gen(r));
5419 }
5420 }
5421 }
5422
5423 /* subdivide the edge e with r new vertices */
subdivide_edge(const ipair & e,int n,int & label)5424 void graphe::subdivide_edge(const ipair &e,int n,int &label) {
5425 remove_edge(e);
5426 int i=e.first,j,nv=node_count();
5427 for (int k=0;k<n;++k) {
5428 j=add_node(++label);
5429 add_edge(i,j);
5430 i=j;
5431 }
5432 add_edge(i,e.second);
5433 vertex &v=node(e.first),&w=node(e.second);
5434 point p,q,r;
5435 if (get_node_position(v.attributes(),p) && get_node_position(w.attributes(),q) && p.size()==q.size()) {
5436 r.resize(p.size());
5437 copy_point(q,r);
5438 subtract_point(r,p);
5439 scale_point(r,1.0/double(n+1));
5440 for (i=nv;i<node_count();++i) {
5441 add_point(p,r);
5442 node(i).set_attribute(_GT_ATTRIB_POSITION,point2gen(p));
5443 }
5444 }
5445 }
5446
5447 /* put all edges incident to nodes in V to set E */
incident_edges(const ivector & V,edgeset & E)5448 void graphe::incident_edges(const ivector &V,edgeset &E) {
5449 if (is_directed()) {
5450 ivector adj;
5451 for (ivector_iter it=V.begin();it!=V.end();++it) {
5452 adjacent_nodes(*it,adj);
5453 for (ivector_iter jt=adj.begin();jt!=adj.end();++jt) {
5454 if (has_edge(*it,*jt))
5455 E.insert(make_pair(*it,*jt));
5456 if (has_edge(*jt,*it))
5457 E.insert(make_pair(*jt,*it));
5458 }
5459 }
5460 } else {
5461 int i,j;
5462 for (ivector_iter it=V.begin();it!=V.end();++it) {
5463 i=*it;
5464 vertex &v=node(i);
5465 for (ivector_iter jt=v.neighbors().begin();jt!=v.neighbors().end();++jt) {
5466 j=*jt;
5467 E.insert(make_pair(i<j?i:j,i<j?j:i));
5468 }
5469 }
5470 }
5471 }
5472
5473 /* make a list of all n-tuples of k integers 0,1,...,k-1 */
ntupk(graphe::ivectors & v,int n,int k,const graphe::ivector & elem,int i)5474 void ntupk(graphe::ivectors &v,int n,int k,const graphe::ivector &elem,int i) {
5475 for (int j=0;j<k;++j) {
5476 graphe::ivector e(elem);
5477 e[i]=j;
5478 if (i<n-1)
5479 ntupk(v,n,k,e,i+1);
5480 else
5481 v.push_back(e);
5482 }
5483 }
5484
5485 /* return true iff the vertices u and v of sierpinski graph are adjacent */
is_sierpinski_match(const graphe::ivector & u,const graphe::ivector & v,int n,int h)5486 bool is_sierpinski_match(const graphe::ivector &u,const graphe::ivector &v,int n,int h) {
5487 int t=0;
5488 for (;t<=h-1;++t) {
5489 if (u[t]!=v[t])
5490 return false;
5491 }
5492 if (u[h]==v[h])
5493 return false;
5494 for (t=h+1;t<n;++t) {
5495 if (u[t]!=v[h] || v[t]!=u[h])
5496 return false;
5497 }
5498 return true;
5499 }
5500
5501 /* create a graph from decreasing degree sequence L by using Havel-Hakimi algorithm,
5502 * return false iff L is not a graphic sequence */
hakimi(const ivector & L)5503 bool graphe::hakimi(const ivector &L) {
5504 assert(node_count()==int(L.size()));
5505 int n=L.size(),d,i,z;
5506 if (n==0)
5507 return true;
5508 ipairs D(n);
5509 for (int i=0;i<n;++i) {
5510 D[i]=make_pair(L[i],i);
5511 }
5512 do {
5513 sort(D.begin(),D.end());
5514 d=D.back().first;
5515 i=D.back().second;
5516 D.pop_back();
5517 for (int k=0;k<d;++k) {
5518 ipair &p=D[D.size()-1-k];
5519 if (--p.first<0)
5520 return false;
5521 add_edge(i,p.second);
5522 }
5523 z=0;
5524 for (ipairs_iter it=D.begin();it!=D.end();++it) {
5525 if (it->first==0)
5526 ++z;
5527 }
5528 } while (z<int(D.size()));
5529 return true;
5530 }
5531
5532 /* return the (odd) girth of this graph (the length of the shortest (odd) cycle),
5533 * return -1 if there are no cycles */
girth(bool odd,int sg)5534 int graphe::girth(bool odd,int sg) {
5535 assert(node_queue.empty());
5536 int g=RAND_MAX,h,i,j;
5537 bool hascycle=false;
5538 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
5539 unvisit_all_nodes(sg);
5540 i=it-nodes.begin();
5541 vertex &v=node(i);
5542 if (sg>=0 && v.subgraph()!=sg)
5543 continue;
5544 v.unset_ancestor();
5545 v.set_disc(0);
5546 node_queue.push(i);
5547 while (!node_queue.empty()) {
5548 j=node_queue.front();
5549 node_queue.pop();
5550 vertex &w=node(j);
5551 w.set_visited(true);
5552 for (ivector_iter jt=w.neighbors().begin();jt!=w.neighbors().end();++jt) {
5553 vertex &u=node(*jt);
5554 if (*jt==w.ancestor() || (sg>=0 && u.subgraph()!=sg))
5555 continue;
5556 if (!u.is_visited()) {
5557 u.set_ancestor(j);
5558 u.set_disc(w.disc()+1);
5559 node_queue.push(*jt);
5560 } else {
5561 h=w.disc()+u.disc()+1;
5562 if (h<g && (!odd || h%2!=0)) {
5563 hascycle=true;
5564 g=h;
5565 }
5566 }
5567 }
5568 }
5569 }
5570 return hascycle?g:-1;
5571 }
5572
5573 /* create a graph from LCF notation [jumps]^e */
make_lcf_graph(const ivector & jumps,int e)5574 void graphe::make_lcf_graph(const ivector &jumps,int e) {
5575 this->clear();
5576 int m=jumps.size(),n=m*e;
5577 vecteur V;
5578 make_default_labels(V,n);
5579 reserve_nodes(n);
5580 add_nodes(V);
5581 make_cycle_graph();
5582 int j=0,k;
5583 for (int i=0;i<n;++i) {
5584 k=(i+jumps[j])%n;
5585 if (k<0)
5586 k+=n;
5587 add_edge(i,k);
5588 j=(j+1)%m;
5589 }
5590 }
5591
5592 /* create LCF graph from int pointer (list must end with 0) */
make_lcf_graph(const int * j,int e)5593 void graphe::make_lcf_graph(const int *j,int e) {
5594 ivector jumps;
5595 const int *it=j;
5596 while (*it!=0) {
5597 jumps.push_back(*it);
5598 ++it;
5599 }
5600 make_lcf_graph(jumps,e);
5601 }
5602
5603 /* create Sierpinski (triangle) graph */
make_sierpinski_graph(int n,int k,bool triangle)5604 void graphe::make_sierpinski_graph(int n,int k,bool triangle) {
5605 this->clear();
5606 ivectors tuples;
5607 ivector elem(n,0);
5608 ntupk(tuples,n,k,elem,0);
5609 int N=std::pow(k,n);
5610 vecteur V;
5611 make_default_labels(V,N,0);
5612 reserve_nodes(N);
5613 add_nodes(V);
5614 for (int i=0;i<N;++i) {
5615 ivector &u=tuples[i];
5616 for (int j=i+1;j<N;++j) {
5617 ivector &v=tuples[j];
5618 int h=0;
5619 for (;h<n;++h) {
5620 if (is_sierpinski_match(u,v,n,h))
5621 break;
5622 }
5623 if (h<n)
5624 add_edge(i,j);
5625 }
5626 }
5627 if (triangle && k>1) {
5628 /* remove all non-clique edges to obtain Sierpinski triangle graph */
5629 map<int,int> m;
5630 clique_stats(m,1);
5631 iset isolated_nodes;
5632 for (map<int,int>::const_iterator it=m.begin();it!=m.end();++it) {
5633 int v=it->first,w=it->second;
5634 contract_edge(v,w,false);
5635 isolated_nodes.insert(w);
5636 }
5637 graphe G(ctx);
5638 remove_isolated_nodes(isolated_nodes,G);
5639 G.copy(*this);
5640 vecteur labels;
5641 make_default_labels(labels,node_count());
5642 relabel_nodes(labels);
5643 }
5644 }
5645
5646 /* create the Shrikhande graph */
make_shrikhande_graph()5647 void graphe::make_shrikhande_graph() {
5648 this->clear();
5649 vecteur labels;
5650 make_default_labels(labels,16);
5651 reserve_nodes(16);
5652 add_nodes(labels);
5653 ipairs v(16);
5654 int k=0,m,n;
5655 for (int i=0;i<4;++i) {
5656 for (int j=0;j<4;++j) {
5657 v[k++]=make_pair(i,j);
5658 }
5659 }
5660 for (int i=0;i<16;++i) {
5661 const ipair &vi=v[i];
5662 for (int j=i+1;j<16;++j) {
5663 const ipair &vj=v[j];
5664 m=(vi.first-vj.first+4)%4;
5665 n=(vi.second-vj.second+4)%4;
5666 if ((m*n==0 && (m+n)%2!=0) || (m==n && (m*n)%2!=0))
5667 add_edge(i,j);
5668 }
5669 }
5670 }
5671
5672 /* create the Tutte graph by joining three copies of Tutte's fragment */
make_tutte_graph()5673 void graphe::make_tutte_graph() {
5674 this->clear();
5675 vecteur labels;
5676 make_default_labels(labels,46);
5677 reserve_nodes(46);
5678 add_nodes(labels);
5679 graphe fragment(ctx);
5680 fragment.read_special(tutte_fragment_graph);
5681 ipairs E;
5682 fragment.get_edges_as_pairs(E);
5683 for (int i=0;i<3;++i) {
5684 for (ipairs_iter it=E.begin();it!=E.end();++it) {
5685 add_edge(1+15*i+it->first,1+15*i+it->second);
5686 }
5687 add_edge(0,1+15*i);
5688 add_edge(15*i+12,15*((i+1)%3)+13);
5689 }
5690 }
5691
5692 /* create complete graph with vertices from list V */
make_complete_graph()5693 void graphe::make_complete_graph() {
5694 int n=node_count();
5695 for (int i=0;i<n;++i) {
5696 for (int j=i+1;j<n;++j) {
5697 add_edge(i,j);
5698 }
5699 }
5700 }
5701
5702 /* create complete k-partite graph with given partition sizes */
make_complete_multipartite_graph(const ivector & partition_sizes,layout * x)5703 void graphe::make_complete_multipartite_graph(const ivector &partition_sizes,layout *x) {
5704 int k=partition_sizes.size();
5705 ivectors partitions;
5706 int ntotal=0,n;
5707 vecteur v;
5708 for (ivector_iter it=partition_sizes.begin();it!=partition_sizes.end();++it) {
5709 n=*it;
5710 make_default_labels(v,n,ntotal);
5711 add_nodes(v);
5712 ivector iv(n);
5713 for (int i=0;i<n;++i) iv[i]=ntotal+i;
5714 partitions.push_back(iv);
5715 ntotal+=n;
5716 }
5717 assert(node_count()==ntotal);
5718 for (int ip=0;ip<k;++ip) {
5719 ivector &pi=partitions[ip];
5720 for (int jp=ip+1;jp<k;++jp) {
5721 ivector &pj=partitions[jp];
5722 for (int i=0;i<int(pi.size());++i) {
5723 for (int j=0;j<int(pj.size());++j) {
5724 add_edge(pi[i],pj[j]);
5725 }
5726 }
5727 }
5728 }
5729 if (x!=NULL && partition_sizes.size()==2 && partition_sizes.front()==1 && partition_sizes.back()>2) {
5730 /* create the star layout */
5731 n=partition_sizes.back();
5732 ivector hull(n);
5733 for (int i=0;i<n;++i) hull[i]=i+1;
5734 make_circular_layout(*x,hull);
5735 }
5736 }
5737
5738 /* create generalized Petersen graph G(n,k) using Watkins' notation */
make_petersen_graph(int n,int k,layout * x)5739 void graphe::make_petersen_graph(int n,int k,layout *x) {
5740 this->clear();
5741 vecteur V;
5742 make_default_labels(V,2*n);
5743 reserve_nodes(2*n);
5744 add_nodes(V);
5745 /* add the outer cycle first */
5746 for (int i=0;i<n;++i) {
5747 add_edge(i,(i+1)%n);
5748 }
5749 /* add the inner edges */
5750 for (int i=0;i<n;++i) {
5751 add_edge(i,i+n);
5752 add_edge(i+n,(i+k)%n+n);
5753 }
5754 if (x!=NULL) {
5755 /* layout the graph */
5756 ivector hull(n);
5757 for (int i=0;i<n;++i) hull[i]=i;
5758 make_circular_layout(*x,hull,2.5);
5759 }
5760 }
5761
5762 /* generate all k-sets in a n-set */
generate_nk_sets(int n,int k,vector<ulong> & v)5763 void graphe::generate_nk_sets(int n,int k,vector<ulong> &v) {
5764 ulong N=std::pow(2,n);
5765 int i=0;
5766 for (ulong m=1;m<N;++m) {
5767 bitset<32> b(m);
5768 if (b.count()==(size_t)k)
5769 v[i++]=m;
5770 }
5771 }
5772
5773 /* create Kneser graph with parameters n (<=20) and k */
make_kneser_graph(int n,int k)5774 bool graphe::make_kneser_graph(int n,int k) {
5775 this->clear();
5776 assert(n>1 && n<21 && k>0 && k<n);
5777 int nchoosek=comb(n,k).val; // number of vertices
5778 vecteur V;
5779 make_default_labels(V,nchoosek);
5780 reserve_nodes(nchoosek);
5781 add_nodes(V);
5782 vector<ulong> vert(nchoosek);
5783 generate_nk_sets(n,k,vert);
5784 ulong a,b;
5785 for (int i=0;i<nchoosek;++i) {
5786 a=vert[i];
5787 for (int j=i+1;j<nchoosek;++j) {
5788 b=vert[j];
5789 if ((a & b)==0)
5790 add_edge(i,j);
5791 }
5792 }
5793 return true;
5794 }
5795
5796 /* create path graph with n vertices */
make_path_graph()5797 void graphe::make_path_graph() {
5798 int n=node_count();
5799 for (int i=0;i<n-1;++i) {
5800 add_edge(i,i+1);
5801 }
5802 }
5803
5804 /* create n times m grid graph (triangular if mode=1, torus if mode=2) */
make_grid_graph(int m,int n,bool torus)5805 void graphe::make_grid_graph(int m,int n,bool torus) {
5806 this->clear();
5807 vecteur V;
5808 graphe X(ctx),Y(ctx);
5809 X.make_default_labels(V,m);
5810 X.reserve_nodes(m);
5811 X.add_nodes(V);
5812 Y.make_default_labels(V,n);
5813 Y.reserve_nodes(n);
5814 Y.add_nodes(V);
5815 if (torus) {
5816 X.make_cycle_graph();
5817 Y.make_cycle_graph();
5818 } else {
5819 X.make_path_graph();
5820 Y.make_path_graph();
5821 }
5822 X.cartesian_product(Y,*this);
5823 }
5824
5825 /* create n times m web graph as the cartesian product of n-cycle and m-path graphs */
make_web_graph(int n,int m,layout * x)5826 void graphe::make_web_graph(int n,int m,layout *x) {
5827 this->clear();
5828 vecteur V;
5829 graphe C(ctx);
5830 C.make_default_labels(V,n);
5831 C.reserve_nodes(n);
5832 C.add_nodes(V);
5833 C.make_cycle_graph();
5834 graphe P(ctx);
5835 P.make_default_labels(V,m);
5836 P.reserve_nodes(m);
5837 P.add_nodes(V);
5838 P.make_path_graph();
5839 C.cartesian_product(P,*this);
5840 if (x!=NULL) {
5841 /* layout the graph */
5842 ivector hull(n);
5843 for (int i=0;i<n;++i) hull[i]=m*i;
5844 make_circular_layout(*x,hull);
5845 }
5846 }
5847
5848 /* create wheel graph with n+1 vertices */
make_wheel_graph(int n,layout * x)5849 void graphe::make_wheel_graph(int n,layout *x) {
5850 this->clear();
5851 vecteur V;
5852 make_default_labels(V,n,0,1);
5853 reserve_nodes(n);
5854 add_nodes(V);
5855 make_cycle_graph();
5856 int i=add_node(0);
5857 for (int j=0;j<n;++j) {
5858 add_edge(i,j);
5859 }
5860 if (x!=NULL) {
5861 /* layout the graph */
5862 ivector hull(n);
5863 for (int i=0;i<n;++i) hull[i]=i;
5864 make_circular_layout(*x,hull);
5865 }
5866 }
5867
5868 /* create antiprism graph of order n (with 2n vertices and 4n edges) */
make_antiprism_graph(int n,layout * x)5869 void graphe::make_antiprism_graph(int n,layout *x) {
5870 this->clear();
5871 vecteur V;
5872 make_default_labels(V,2*n,0);
5873 reserve_nodes(2*n);
5874 add_nodes(V);
5875 int j;
5876 for (int i=0;i<n;++i) {
5877 j=(i+1)%n;
5878 add_edge(2*i,2*j);
5879 add_edge(2*i+1,2*j+1);
5880 add_edge(2*j,2*i+1);
5881 add_edge(2*j,2*j+1);
5882 }
5883 if (x!=NULL) {
5884 /* layout the graph */
5885 ivector hull(n);
5886 for (int i=0;i<n;++i) hull[i]=2*i;
5887 make_circular_layout(*x,hull,-1.0);
5888 }
5889 }
5890
5891 /* create the complete k-ary tree with depth d */
make_complete_kary_tree(int k,int d)5892 void graphe::make_complete_kary_tree(int k,int d) {
5893 assert(k>=2);
5894 this->clear();
5895 int n=((int)std::pow(k,d+1)-1)/(k-1),v=0,w=1,len=1;
5896 vecteur V;
5897 make_default_labels(V,n);
5898 reserve_nodes(n);
5899 add_nodes(V);
5900 for (int i=0;i<d;++i) {
5901 for (int j=0;j<len;++j) {
5902 for (int m=0;m<k;++m) {
5903 add_edge(v,w++);
5904 }
5905 ++v;
5906 }
5907 len*=k;
5908 }
5909 }
5910
5911 /* find all connected components of an undirected graph and store them */
connected_components(ivectors & components,int sg,bool skip_embedded,int * count)5912 void graphe::connected_components(ivectors &components,int sg,bool skip_embedded,int *count) {
5913 unvisit_all_nodes(sg);
5914 unset_all_ancestors(sg);
5915 disc_time=0;
5916 if (count==NULL)
5917 components.resize(node_count());
5918 int c=0;
5919 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
5920 if ((sg<0 || it->subgraph()==sg) && (!skip_embedded || !it->is_embedded()) && !it->is_visited())
5921 dfs(it-nodes.begin(),true,false,&components[c++],sg,skip_embedded);
5922 }
5923 if (count==NULL)
5924 components.resize(c);
5925 else
5926 *count=c;
5927 }
5928
5929 /* find all biconnected components as vertex lists */
biconnected_components(ivectors & components,int sg)5930 void graphe::biconnected_components(ivectors &components,int sg) {
5931 ivectors ccomp;
5932 connected_components(ccomp,sg);
5933 int s=max_subgraph_index(),cnt;
5934 vector<ipairs> blocks;
5935 set<int> vset;
5936 components.clear();
5937 for (ivectors_iter it=ccomp.begin();it!=ccomp.end();++it) {
5938 if (it->size()<3) {
5939 components.push_back(*it);
5940 continue;
5941 }
5942 set_subgraph(*it,++s);
5943 blocks.clear();
5944 find_blocks(blocks,s);
5945 set_subgraph(*it,sg);
5946 for (vector<ipairs>::const_iterator it=blocks.begin();it!=blocks.end();++it) {
5947 const ipairs &b=*it;
5948 vset.clear();
5949 for (ipairs_iter jt=b.begin();jt!=b.end();++jt) {
5950 vset.insert(jt->first);
5951 vset.insert(jt->second);
5952 }
5953 components.resize(components.size()+1);
5954 ivector &c=components.back();
5955 c.resize(vset.size());
5956 cnt=0;
5957 for (set<int>::const_iterator jt=vset.begin();jt!=vset.end();++jt) {
5958 c[cnt++]=*jt;
5959 }
5960 }
5961 }
5962 }
5963
5964 /* return the number of connected components in this graph */
connected_component_count(int sg)5965 int graphe::connected_component_count(int sg) {
5966 unvisit_all_nodes(sg);
5967 unset_all_ancestors(sg);
5968 disc_time=0;
5969 int count=0;
5970 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
5971 if ((sg<0 || it->subgraph()==sg) && !it->is_visited()) {
5972 dfs(it-nodes.begin(),false,false,NULL,sg);
5973 ++count;
5974 }
5975 }
5976 return count;
5977 }
5978
strongconnect_dfs(ivectors & components,vector<bool> & onstack,int i,int sg)5979 void graphe::strongconnect_dfs(ivectors &components,vector<bool> &onstack,int i,int sg) {
5980 vertex &v=node(i);
5981 v.set_visited(true);
5982 v.set_disc(disc_time++);
5983 v.set_low(v.disc());
5984 node_stack.push(i);
5985 onstack[i]=true;
5986 int j;
5987 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
5988 vertex &w=node(j=*it);
5989 if (sg>=0 && w.subgraph()!=sg)
5990 continue;
5991 if (!w.is_visited()) {
5992 strongconnect_dfs(components,onstack,j,sg);
5993 v.set_low(std::min(v.low(),w.low()));
5994 } else if (onstack[j])
5995 v.set_low(std::min(v.low(),w.disc()));
5996 }
5997 if (v.low()==v.disc()) {
5998 /* output a strongly connected component */
5999 components.resize(components.size()+1);
6000 ivector &component=components.back();
6001 do {
6002 j=node_stack.top();
6003 node_stack.pop();
6004 component.push_back(j);
6005 onstack[j]=false;
6006 } while (j!=i);
6007 }
6008 }
6009
6010 /* find all strongly connected components in directed graph using Tarjan's algorithm */
strongly_connected_components(ivectors & components,int sg)6011 void graphe::strongly_connected_components(ivectors &components,int sg) {
6012 assert(node_stack.empty());
6013 unvisit_all_nodes(sg);
6014 vector<bool> onstack(node_count(),false);
6015 disc_time=0;
6016 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
6017 if ((sg<0 || it->subgraph()==sg) && !it->is_visited())
6018 strongconnect_dfs(components,onstack,it-nodes.begin(),sg);
6019 }
6020 }
6021
6022 /* create the condensation of tis graph by contracting strongly connected components */
condensation(graphe & G)6023 void graphe::condensation(graphe &G) {
6024 assert(is_directed());
6025 ivectors comp;
6026 strongly_connected_components(comp);
6027 int n=comp.size(),dir;
6028 G.clear();
6029 G.set_directed(true);
6030 if (G.supports_attributes()) {
6031 vecteur labels;
6032 G.make_default_labels(labels,n);
6033 G.add_nodes(labels);
6034 } else G.add_nodes(n);
6035 for (ivectors_iter it=comp.begin();it!=comp.end();++it) {
6036 for (ivectors_iter jt=it+1;jt!=comp.end();++jt) {
6037 dir=0;
6038 for (ivector_iter kt=it->begin();kt!=it->end() && dir==0;++kt) {
6039 for (ivector_iter lt=jt->begin();lt!=jt->end() && dir==0;++lt) {
6040 if (has_edge(*kt,*lt)) dir=1;
6041 else if (has_edge(*lt,*kt)) dir=-1;
6042 }
6043 }
6044 switch (dir) {
6045 case 1:
6046 G.add_edge(it-comp.begin(),jt-comp.begin());
6047 break;
6048 case -1:
6049 G.add_edge(jt-comp.begin(),it-comp.begin());
6050 break;
6051 default:
6052 break;
6053 }
6054 }
6055 }
6056 }
6057
6058 /* return true iff the connected graph is not biconnected (i.e. has an articulation point) */
has_cut_vertex(int sg,int i)6059 bool graphe::has_cut_vertex(int sg,int i) {
6060 vertex &v=node(i);
6061 if (i==0) {
6062 unvisit_all_nodes();
6063 unset_all_ancestors();
6064 disc_time=0;
6065 }
6066 if (sg>=0 && v.subgraph()!=sg)
6067 return i==node_count()-1?false:has_cut_vertex(sg,i+1);
6068 v.set_visited(true);
6069 ++disc_time;
6070 v.set_disc(disc_time);
6071 v.set_low(disc_time);
6072 int children=0;
6073 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
6074 int j=*it;
6075 vertex &w=node(j);
6076 if (sg>=0 && w.subgraph()!=sg)
6077 continue;
6078 if (!w.is_visited()) {
6079 ++children;
6080 w.set_ancestor(i);
6081 if (has_cut_vertex(sg,j))
6082 return true;
6083 if (v.ancestor()<0) {
6084 if (children==2)
6085 return true;
6086 } else {
6087 v.set_low(std::min(v.low(),w.low()));
6088 if (w.low()>=v.disc())
6089 return true;
6090 }
6091 } else if (j!=v.ancestor() && w.disc()<v.disc())
6092 v.set_low(std::min(v.low(),w.disc()));
6093 }
6094 return false;
6095 }
6096
find_cut_vertices_dfs(int i,std::set<int> & ap,int sg)6097 void graphe::find_cut_vertices_dfs(int i,std::set<int> &ap,int sg) {
6098 vertex &v=node(i);
6099 v.set_visited(true);
6100 ++disc_time;
6101 v.set_disc(disc_time);
6102 v.set_low(disc_time);
6103 int children=0;
6104 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
6105 int j=*it;
6106 vertex &w=node(j);
6107 if (sg>=0 && w.subgraph()!=sg)
6108 continue;
6109 if (!w.is_visited()) {
6110 ++children;
6111 w.set_ancestor(i);
6112 find_cut_vertices_dfs(j,ap,sg);
6113 if (v.ancestor()<0) {
6114 if (children==2)
6115 ap.insert(i);
6116 } else {
6117 v.set_low(std::min(v.low(),w.low()));
6118 if (w.low()>=v.disc())
6119 ap.insert(i);
6120 }
6121 } else if (j!=v.ancestor() && w.disc()<v.disc())
6122 v.set_low(std::min(v.low(),w.disc()));
6123 }
6124 }
6125
6126 /* return list of cut vertices obtained by using depth-first search, time complexity O(n+m) */
find_cut_vertices(ivector & articulation_points,int sg)6127 void graphe::find_cut_vertices(ivector &articulation_points,int sg) {
6128 unvisit_all_nodes();
6129 unset_all_ancestors();
6130 disc_time=0;
6131 std::set<int> ap;
6132 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
6133 if ((sg<0 || it->subgraph()==sg) && !it->is_visited())
6134 find_cut_vertices_dfs(it-nodes.begin(),ap,sg);
6135 }
6136 for (std::set<int>::const_iterator it=ap.begin();it!=ap.end();++it) {
6137 articulation_points.push_back(*it);
6138 }
6139 }
6140
find_blocks_dfs(int i,vector<ipairs> & blocks,int sg)6141 void graphe::find_blocks_dfs(int i,vector<ipairs> &blocks,int sg) {
6142 ++disc_time;
6143 vertex &v=node(i);
6144 v.set_disc(disc_time);
6145 v.set_low(disc_time);
6146 v.set_visited(true);
6147 int j;
6148 ipair edge;
6149 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
6150 j=*it;
6151 vertex &w=node(j);
6152 if (sg>=0 && w.subgraph()!=sg)
6153 continue;
6154 edge=make_pair(i<j?i:j,i<j?j:i);
6155 if (!w.is_visited()) {
6156 w.set_ancestor(i);
6157 edge_stack.push(edge);
6158 find_blocks_dfs(j,blocks,sg);
6159 v.set_low(std::min(v.low(),w.low()));
6160 if (w.low()>=v.disc()) {
6161 /* output biconnected component to 'blocks' */
6162 blocks.resize(blocks.size()+1);
6163 ipairs &block=blocks.back();
6164 do {
6165 block.push_back(edge_stack.top());
6166 edge_stack.pop();
6167 } while (block.back()!=edge);
6168 }
6169 } else if (w.disc()<v.disc() && j!=v.ancestor()) {
6170 edge_stack.push(edge);
6171 v.set_low(std::min(v.low(),w.disc()));
6172 }
6173 }
6174 }
6175
6176 /* create list of all biconnected components (as lists of edges) of the graph */
find_blocks(vector<ipairs> & blocks,int sg)6177 void graphe::find_blocks(vector<ipairs> &blocks,int sg) {
6178 assert(edge_stack.empty());
6179 unvisit_all_nodes(sg);
6180 unset_all_ancestors(sg);
6181 disc_time=0;
6182 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
6183 if ((sg<0 || it->subgraph()==sg) && !it->is_visited())
6184 find_blocks_dfs(it-nodes.begin(),blocks,sg);
6185 }
6186 while (!edge_stack.empty()) edge_stack.pop();
6187 }
6188
6189 /* create list of simple ears in the graph, which must be biconnected and not a cycle */
find_ears(ivectors & ears,int sg)6190 void graphe::find_ears(ivectors &ears,int sg) {
6191 assert(!is_directed() && node_stack.empty());
6192 ears.clear();
6193 int n=node_count(),root,d,ad,maxd=-1,i,k,p;
6194 for (i=0;i<n;++i) {
6195 const vertex &v=node(i);
6196 if ((sg<0 || v.subgraph()==sg) &&
6197 (d=v.neighbors().size())>maxd) {
6198 maxd=d;
6199 root=i;
6200 }
6201 }
6202 if (maxd<3)
6203 return;
6204 dfs(root,true,true,NULL,sg);
6205 bool rec=false;
6206 for (ivector_iter it=disc_nodes.begin();it!=disc_nodes.end();++it) {
6207 const vertex &v=node(i=*it);
6208 if (degree(i,sg)==2) {
6209 assert((p=v.ancestor())>=0); // v is not the root
6210 ad=degree(p,sg);
6211 if (multiedges(make_pair(v.ancestor(),i))>0)
6212 continue;
6213 if (ad>2) {
6214 /* start an ear */
6215 assert(!rec && node_stack.empty());
6216 node_stack.push(v.ancestor());
6217 rec=true;
6218 }
6219 if (!rec)
6220 continue;
6221 node_stack.push(i);
6222 k=-1;
6223 for (ivector_iter nt=v.neighbors().begin();nt!=v.neighbors().end();++nt) {
6224 if ((sg<0 || node(*nt).subgraph()==sg) && *nt!=v.ancestor())
6225 k=*nt;
6226 }
6227 if (k<0 || multiedges(make_pair(i,k))>0) { // dead end
6228 clear_node_stack();
6229 rec=false;
6230 } else if (degree(k,sg)>2) {
6231 /* stop the ear */
6232 node_stack.push(k);
6233 ivector ear;
6234 ear.reserve(node_stack.size());
6235 while (!node_stack.empty()) {
6236 ear.push_back(node_stack.top());
6237 node_stack.pop();
6238 }
6239 if (ear.front()!=ear.back() && !has_edge(ear.front(),ear.back()))
6240 ears.push_back(ear);
6241 rec=false;
6242 }
6243 }
6244 }
6245 }
6246
find_bridges_dfs(int i,ipairs & B,int sg)6247 void graphe::find_bridges_dfs(int i,ipairs &B,int sg) {
6248 vertex &v=node(i);
6249 v.set_visited(true);
6250 ++disc_time;
6251 v.set_disc(disc_time);
6252 v.set_low(disc_time);
6253 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
6254 int j=*it;
6255 vertex &w=node(j);
6256 if (sg>=0 && w.subgraph()!=sg)
6257 continue;
6258 if (!w.is_visited()) {
6259 w.set_ancestor(i);
6260 find_bridges_dfs(j,B,sg);
6261 v.set_low(std::min(v.low(),w.low()));
6262 if (w.low()>v.disc())
6263 B.push_back(make_pair(i<j?i:j,i<j?j:i));
6264 } else if (j!=v.ancestor() && w.disc()<v.disc())
6265 v.set_low(std::min(v.low(),w.disc()));
6266 }
6267 }
6268
6269 /* create list B of all bridges in an undirected graph */
find_bridges(ipairs & B,int sg)6270 void graphe::find_bridges(ipairs &B,int sg) {
6271 assert(!is_directed());
6272 unvisit_all_nodes(sg);
6273 unset_all_ancestors(sg);
6274 disc_time=0;
6275 B.clear();
6276 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
6277 if ((sg<0 || it->subgraph()==sg) && !it->is_visited())
6278 find_bridges_dfs(it-nodes.begin(),B,sg);
6279 }
6280 }
6281
6282 /* Fleury's algorithm for eulerian trail, time complexity O(m^2) */
fleury(int start,ivector & path)6283 bool graphe::fleury(int start,ivector &path) {
6284 /* assuming that the graph is undirected and (semi-)eulerian */
6285 int m=edge_count(),i=start,j;
6286 path.resize(m+1);
6287 path.back()=i;
6288 ipairs bridges;
6289 ipair edge;
6290 while (m>0) {
6291 vertex &v=node(i);
6292 find_bridges(bridges);
6293 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
6294 j=*it;
6295 edge=make_pair(i<j?i:j,i<j?j:i);
6296 if (find(bridges.begin(),bridges.end(),edge)==bridges.end())
6297 break;
6298 }
6299 remove_edge(edge);
6300 path[--m]=j;
6301 i=j;
6302 }
6303 return true;
6304 }
6305
6306 /* Hierholzer algorithm for eulerian cycle, time complexity O(m) */
hierholzer(ivector & path)6307 void graphe::hierholzer(ivector &path) {
6308 /* assuming that the graph is eulerian */
6309 int i,j,pos=path.size();
6310 ivector_iter it;
6311 while (pos>0) {
6312 --pos;
6313 /* find a closed trail starting in path[pos] */
6314 j=i=path[pos];
6315 do {
6316 vertex &v=node(j);
6317 for (it=v.neighbors().begin();it!=v.neighbors().end();++it) {
6318 if (!is_edge_visited(j,*it))
6319 break;
6320 }
6321 if (it==v.neighbors().end())
6322 break;
6323 path.insert(path.begin()+(++pos),*it);
6324 set_edge_visited(j,*it);
6325 j=*it;
6326 } while (i!=j);
6327 }
6328 }
6329
6330 /* return the node in which an eulerian trail may begin, or -1 if the graph has no such trail */
eulerian_trail_start(bool & iscycle) const6331 int graphe::eulerian_trail_start(bool &iscycle) const {
6332 /* assuming that the graph is connected */
6333 int n=node_count(),count=0,start_node=-1,d;
6334 for (int i=0;i<n;++i) {
6335 d=degree(i);
6336 if (d%2!=0) {
6337 ++count;
6338 start_node=i;
6339 } else if (start_node<0 && d%2==0 && d>0)
6340 start_node=i;
6341 }
6342 if (count!=0 && count!=2)
6343 return -1;
6344 iscycle=count==0;
6345 return start_node;
6346 }
6347
6348 /* attempt to find an eulerian trail in this graph, return true iff one exists */
find_eulerian_trail(ivector & path)6349 bool graphe::find_eulerian_trail(ivector &path) {
6350 int start;
6351 bool iscycle;
6352 ivectors components;
6353 connected_components(components);
6354 int ic=0;
6355 for (ivectors_iter it=components.begin();it!=components.end();++it) {
6356 if (it->size()>1) ++ic;
6357 }
6358 if (ic!=1 || (start=eulerian_trail_start(iscycle))<0)
6359 return false;
6360 /* use Hierholzer's algorithm */
6361 assert(visited_edges.empty());
6362 path.clear();
6363 path.reserve(edge_count()+1);
6364 if (!iscycle) {
6365 /* find a path between two odd-degree nodes and delete it */
6366 dfs(start,false);
6367 int j,k=-1;
6368 for (int i=node_count();i-->0;) {
6369 if (i!=start && degree(i)%2!=0) {
6370 k=i;
6371 break;
6372 }
6373 }
6374 assert(k>=0);
6375 while (k!=start) {
6376 path.push_back(k);
6377 const vertex &v=node(k);
6378 j=v.ancestor();
6379 set_edge_visited(j,k);
6380 k=j;
6381 }
6382 }
6383 path.push_back(start);
6384 hierholzer(path);
6385 unvisit_all_edges();
6386 return true;
6387 }
6388
find_cycle_dfs(int i,int sg)6389 int graphe::find_cycle_dfs(int i,int sg) {
6390 vertex &v=node(i);
6391 v.set_visited(true);
6392 node_stack.push(i);
6393 int j,k;
6394 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
6395 j=*it;
6396 vertex &w=node(j);
6397 if (sg>=0 && w.subgraph()!=sg)
6398 continue;
6399 if (w.is_visited()) {
6400 if (v.ancestor()!=j)
6401 return j;
6402 continue;
6403 }
6404 w.set_ancestor(i);
6405 k=find_cycle_dfs(j,sg);
6406 if (k>=0)
6407 return k;
6408 }
6409 node_stack.pop();
6410 return -1;
6411 }
6412
find_cycle(ivector & cycle,int sg)6413 bool graphe::find_cycle(ivector &cycle,int sg) {
6414 assert(node_stack.empty());
6415 if (is_null())
6416 return false;
6417 int n=node_count(),initv,i;
6418 unvisit_all_nodes(sg);
6419 unset_all_ancestors(sg);
6420 cycle.clear();
6421 cycle.reserve(n);
6422 if (sg>=0) {
6423 for (initv=0;initv<n && node(initv).subgraph()!=sg;++initv);
6424 if (initv==n)
6425 return false;
6426 } else initv=rand_integer(n);
6427 if ((i=find_cycle_dfs(initv,sg))>=0) {
6428 do {
6429 cycle.push_back(node_stack.top());
6430 node_stack.pop();
6431 } while (cycle.back()!=i);
6432 clear_node_stack();
6433 return true;
6434 }
6435 return false;
6436 }
6437
find_path_dfs(int dest,int i,int sg,bool skip_embedded)6438 bool graphe::find_path_dfs(int dest,int i,int sg,bool skip_embedded) {
6439 node_stack.push(i);
6440 if (i==dest)
6441 return true;
6442 vertex &v=node(i);
6443 v.set_visited(true);
6444 int j;
6445 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
6446 j=*it;
6447 vertex &w=node(j);
6448 if ((skip_embedded && w.is_embedded()) || w.subgraph()!=sg || w.is_visited())
6449 continue;
6450 if (find_path_dfs(dest,j,sg,skip_embedded))
6451 return true;
6452 }
6453 node_stack.pop();
6454 return false;
6455 }
6456
6457 /* return a path from i-th to j-th vertex using DFS (graph is assumed to be connected) */
find_path(int i,int j,ivector & path,int sg,bool skip_embedded)6458 bool graphe::find_path(int i,int j,ivector &path,int sg,bool skip_embedded) {
6459 assert(node_stack.empty());
6460 unvisit_all_nodes(sg);
6461 if (find_path_dfs(i,j,sg,skip_embedded)) {
6462 path.resize(node_stack.size());
6463 while (!node_stack.empty()) {
6464 path[node_stack.size()-1]=node_stack.top();
6465 node_stack.pop();
6466 }
6467 return true;
6468 }
6469 clear_node_stack();
6470 return false;
6471 }
6472
6473 /* clear the graph, deleting all nodes and vertices */
clear()6474 void graphe::clear() {
6475 unmark_all_nodes();
6476 nodes.clear();
6477 }
6478
6479 /* return true iff the given face contains the edge {i,j} */
face_has_edge(const ivector & face,int i,int j)6480 int graphe::face_has_edge(const ivector &face,int i,int j) {
6481 int v,w,k;
6482 for (ivector_iter it=face.begin();it!=face.end();++it) {
6483 v=*it;
6484 k=(it-face.begin()+1)%face.size();
6485 w=face[k];
6486 if ((i==v && j==w) || (i==w && j==v))
6487 return k;
6488 }
6489 return -1;
6490 }
6491
6492 /* set 'embedded' field of all given nodes to 'true' */
set_nodes_embedded(const ivector & v,bool yes)6493 void graphe::set_nodes_embedded(const ivector &v,bool yes) {
6494 for (ivector_iter it=v.begin();it!=v.end();++it) {
6495 node(*it).set_embedded(yes);
6496 }
6497 }
6498
6499 /* set 'embedded' filed for all nodes to 'false' */
unembed_all_nodes()6500 void graphe::unembed_all_nodes() {
6501 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
6502 it->set_embedded(false);
6503 }
6504 }
6505
6506 /* finds planar embedding of a biconnected graph as a list of faces,
6507 * returns true iff the graph is planar */
demoucron(ivectors & faces,int sg)6508 bool graphe::demoucron(ivectors &faces,int sg) {
6509 ivector cycle,path,updated_face;
6510 ivectors bridges,components(node_count());
6511 ipairs admissible_faces;
6512 int i,j,k,n,f,s=sg,bc=max_subgraph_index(),cnt;
6513 ivectors_iter ft;
6514 ivector_iter ct;
6515 std::set<int> contact_nodes;
6516 unembed_all_nodes();
6517 save_subgraphs();
6518 /* adding two initial faces, obtained by finding a cycle in graph */
6519 find_cycle(cycle,s);
6520 set_nodes_embedded(cycle);
6521 faces.clear();
6522 faces.push_back(ivector(cycle.begin(),cycle.end()));
6523 faces.push_back(ivector(cycle.rbegin(),cycle.rend()));
6524 while (true) {
6525 /* find bridges */
6526 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
6527 const vertex &v=*it;
6528 if (!v.is_embedded() || (s>=0 && v.subgraph()!=s))
6529 continue;
6530 i=it-nodes.begin();
6531 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
6532 const vertex &w=node(j=*jt);
6533 if (!w.is_embedded() || (w.subgraph()==s && j<i))
6534 continue;
6535 for (ft=faces.begin();ft!=faces.end();++ft) {
6536 if (face_has_edge(*ft,i,j)>=0)
6537 break;
6538 }
6539 if (ft==faces.end()) {
6540 /* create a bridge consisting only of edge (i,j) */
6541 ivector bridge(4);
6542 bridge.front()=++bc; // subgraph index
6543 bridge[1]=0; // bridge size
6544 bridge[2]=i; // contact vertex 1
6545 bridge[3]=j; // contact vertex 2
6546 bridges.push_back(bridge);
6547 }
6548 }
6549 }
6550 n=bridges.size();
6551 connected_components(components,s,true,&cnt);
6552 bridges.resize(n+cnt);
6553 for (k=0;k<cnt;++k) {
6554 ivector comp=components[k];
6555 ivector &bridge=bridges[n++];
6556 bridge.clear();
6557 bridge.push_back(++bc);
6558 bridge.push_back(comp.size());
6559 contact_nodes.clear();
6560 for (ivector_iter it=comp.begin();it!=comp.end();++it) {
6561 vertex &v=node(*it);
6562 v.set_subgraph(bc);
6563 for (ivector_iter jt=v.neighbors().begin();jt!=v.neighbors().end();++jt) {
6564 if (node(*jt).is_embedded())
6565 contact_nodes.insert(*jt);
6566 }
6567 }
6568 bridge.resize(2+contact_nodes.size());
6569 i=2;
6570 for (std::set<int>::const_iterator it=contact_nodes.begin();it!=contact_nodes.end();++it) {
6571 bridge[i++]=*it;
6572 }
6573 }
6574 if (bridges.empty())
6575 break;
6576 /* for each bridge, find all faces in which it can be drawn (admissible faces) */
6577 admissible_faces.resize(bridges.size());
6578 for (ivectors_iter it=bridges.begin();it!=bridges.end();++it) {
6579 ipair &admissible=admissible_faces[it-bridges.begin()];
6580 admissible.first=0;
6581 for (ivectors_iter ft=faces.begin();ft!=faces.end();++ft) {
6582 for (ct=it->begin()+2;ct!=it->end();++ct) {
6583 if (find(ft->begin(),ft->end(),*ct)==ft->end())
6584 break;
6585 }
6586 if (ct==it->end()) {
6587 admissible.first++;
6588 admissible.second=ft-faces.begin();
6589 }
6590 }
6591 if (admissible.first==0) { // the graph is not planar
6592 restore_subgraphs();
6593 return false;
6594 }
6595 }
6596 /* select the first bridge with the smallest number of admissible faces */
6597 n=RAND_MAX;
6598 for (ipairs_iter it=admissible_faces.begin();it!=admissible_faces.end();++it) {
6599 if (it->first<n) {
6600 k=it-admissible_faces.begin();
6601 if ((n=it->first)==1)
6602 break;
6603 }
6604 }
6605 ivector &bridge=bridges[k];
6606 /* draw a path between the first two connecting vertices to the admissible face */
6607 s=bridge.front(); // subgraph index
6608 if ((n=bridge[1])>0) {
6609 i=first_neighbor_from_subgraph(node(bridge[2]),s);
6610 j=first_neighbor_from_subgraph(node(bridge[3]),s);
6611 assert(i>=0 && j>=0);
6612 find_path(i,j,path,s,true);
6613 set_nodes_embedded(path);
6614 } else path.clear();
6615 f=admissible_faces[k].second;
6616 faces.resize(faces.size()+1);
6617 ivector &face=faces[f],&new_face=faces.back();
6618 i=find(face.begin(),face.end(),bridge[2])-face.begin();
6619 j=find(face.begin(),face.end(),bridge[3])-face.begin();
6620 arc_path(i,j,face,updated_face);
6621 arc_path(j,i,face,new_face);
6622 if (path.size()>0) {
6623 updated_face.insert(updated_face.end(),path.begin(),path.end());
6624 new_face.insert(new_face.end(),path.rbegin(),path.rend());
6625 }
6626 face=updated_face;
6627 bridges.erase(bridges.begin()+k); // we're done with this bridge
6628 }
6629 restore_subgraphs();
6630 return true;
6631 }
6632
6633 /* return the common element of two sorted lists of integers if there is one, else return -1 */
common_element(const ivector & v1,const ivector & v2,int offset)6634 int graphe::common_element(const ivector &v1,const ivector &v2,int offset) {
6635 ivector_iter it1=v1.begin()+offset,it2=v2.begin()+offset;
6636 if (it1==v1.end() || it2==v2.end())
6637 return -1;
6638 while (it1!=v1.end() && it2!=v2.end()) {
6639 if (*it1==*it2)
6640 return *it1;
6641 while (*it1<*it2 && it1!=v1.end()) ++it1;
6642 while (*it2<*it1 && it2!=v2.end()) ++it2;
6643 }
6644 return -1;
6645 }
6646
6647 /* recursively build up a tree of blocks */
build_block_tree(int i,ivectors & blocks)6648 void graphe::build_block_tree(int i,ivectors &blocks) {
6649 int n=blocks.size(),c;
6650 /* block structure: [is_visited (0 or 1), parent_index, connecting_vertex, ap_1, ap_2, ..., ap_n] */
6651 ivector &parent=blocks[i];
6652 parent.front()=1; // mark block as visited
6653 for (int j=0;j<n;++j) {
6654 /* find children */
6655 ivector &block=blocks[j];
6656 if (i==j || block.front()==1 || (c=common_element(parent,block,3))==-1)
6657 continue;
6658 /* block is a child connected in the vertex c */
6659 block.erase(find(block.begin()+3,block.end(),c));
6660 block[1]=i;
6661 block[2]=c;
6662 build_block_tree(j,blocks);
6663 }
6664 }
6665
6666 /* choose a face to embed among those containing the vertex v */
choose_embedding_face(const ivectors & faces,int v)6667 int graphe::choose_embedding_face(const ivectors &faces,int v) {
6668 ivector candidates;
6669 for (ivectors_iter ft=faces.begin();ft!=faces.end();++ft) {
6670 if (find(ft->begin(),ft->end(),v)!=ft->end())
6671 candidates.push_back(ft-faces.begin());
6672 }
6673 return candidates[rand_integer(candidates.size())];
6674 }
6675
6676 /* embed children blocks to its parent, for each embedding add one temporary edge */
embed_children_blocks(int i,ivectors & block_tree,vector<ivectors> & blocks_faces)6677 void graphe::embed_children_blocks(int i,ivectors &block_tree,vector<ivectors> &blocks_faces) {
6678 /* find all children of the i-th block */
6679 ivector children;
6680 for (ivectors_iter it=block_tree.begin();it!=block_tree.end();++it) {
6681 if (it->at(1)==i)
6682 children.push_back(it-block_tree.begin());
6683 }
6684 if (children.empty()) // this is a leaf node in the tree
6685 return;
6686 /* embed each child to the largest available face of the parent */
6687 ivectors &parent_faces=blocks_faces[i];
6688 int c,pf,cf,k,n;
6689 ivector::iterator vt;
6690 ivector::reverse_iterator wt;
6691 for (ivector_iter it=children.begin();it!=children.end();++it) {
6692 embed_children_blocks(*it,block_tree,blocks_faces);
6693 ivectors &child_faces=blocks_faces[*it];
6694 c=block_tree[*it][2]; // articulation vertex connecting the child with its parent
6695 /* find the suitable parent and child faces that contain c */
6696 pf=choose_embedding_face(parent_faces,c);
6697 cf=choose_embedding_face(child_faces,c);
6698 assert(pf>=0 && cf>=0);
6699 n=parent_faces.size();
6700 parent_faces.resize(n+child_faces.size());
6701 /* Add all child faces different than child_face to parent_faces,
6702 * add a new triangular face obtained by connecting neighbors of c in child and parent,
6703 * and modify the parent_face by adding child_face edges and removing two edges. */
6704 k=n;
6705 for (ivectors::iterator ft=child_faces.begin();ft!=child_faces.end();++ft) {
6706 if (int(ft-child_faces.begin())==cf)
6707 continue;
6708 parent_faces[k++].swap(*ft);
6709 }
6710 ivector &parent_face=parent_faces[pf],&child_face=child_faces[cf],&new_face=parent_faces.back();
6711 /* get v, w as neighbors of c in parent resp. child face */
6712 vt=find(parent_face.begin(),parent_face.end(),c)+1;
6713 if (vt==parent_face.end())
6714 vt=parent_face.begin();
6715 wt=find(child_face.rbegin(),child_face.rend(),c)+1;
6716 if (wt==child_face.rend())
6717 wt=child_face.rbegin();
6718 assert(*vt!=*wt);
6719 add_temporary_edge(*vt,*wt);
6720 /* construct the new face */
6721 new_face.resize(3);
6722 new_face[0]=*wt;
6723 new_face[1]=c;
6724 new_face[2]=*vt;
6725 /* modify the parent_face */
6726 ivector path(child_face.size()-1);
6727 k=0;
6728 while (*wt!=c) {
6729 path[k++]=*(wt++);
6730 if (wt==child_face.rend())
6731 wt=child_face.rbegin();
6732 }
6733 std::reverse(path.begin(),path.end());
6734 parent_face.insert(vt,path.begin(),path.end());
6735 }
6736 }
6737
6738 /* return the index of the largest face of the given embedding */
choose_outer_face(const ivectors & faces)6739 int graphe::choose_outer_face(const ivectors &faces) {
6740 int f,fsize,maxsize=0;
6741 for (ivectors_iter it=faces.begin();it!=faces.end();++it) {
6742 if ((fsize=it->size())>maxsize) {
6743 maxsize=fsize;
6744 f=it-faces.begin();
6745 }
6746 }
6747 return f;
6748 }
6749
6750 /* finds planar embedding of a connected graph as a list of faces,
6751 * returns the index of the outer face or -1 if the graph is not planar */
planar_embedding(ivectors & faces)6752 int graphe::planar_embedding(ivectors &faces) {
6753 /* split graph to blocks */
6754 vector<ipairs> blocks;
6755 find_blocks(blocks);
6756 if (blocks.size()==1)
6757 return demoucron(faces)?choose_outer_face(faces):-1;
6758 /* there exist at least one articulation point */
6759 unset_subgraphs();
6760 int sg=0;
6761 vector<ivectors> blocks_faces(blocks.size());
6762 ivector cv;
6763 find_cut_vertices(cv);
6764 int i=0,nf,ssz;
6765 for (vector<ipairs>::const_iterator it=blocks.begin();it!=blocks.end();++it) {
6766 /* test each block separately */
6767 set_subgraph(*it,++sg);
6768 ivectors &block_faces=blocks_faces[i++];
6769 if ((ssz=subgraph_size(sg))>2) {
6770 /* block has three or more vertices */
6771 if (int(it->size())+6>3*ssz || !demoucron(block_faces,sg))
6772 return -1;
6773 } else {
6774 /* block contains only one edge (a bridge) */
6775 assert(it->size()==1);
6776 ivector bface(2);
6777 bface.front()=it->front().first;
6778 bface.back()=it->front().second;
6779 block_faces.push_back(bface);
6780 }
6781 /* push back a vector of articulation points which belong to this component */
6782 nf=block_faces.size();
6783 block_faces.resize(block_faces.size()+1);
6784 ivector &face_cv=block_faces.back();
6785 for (int k=0;k<nf;++k) {
6786 ivector &face=block_faces[k];
6787 for (ivector_iter cvit=cv.begin();cvit!=cv.end();++cvit) {
6788 if (find(face.begin(),face.end(),*cvit)!=face.end())
6789 face_cv.push_back(*cvit);
6790 }
6791 }
6792 assert(!face_cv.empty());
6793 sort(face_cv.begin(),face_cv.end());
6794 }
6795 /* Graph is planar and we have a list of faces for each block.
6796 * Now blocks are embedded into each other, starting from peripheral blocks,
6797 * by adding temporary edges. */
6798 /* make a tree of blocks */
6799 ivectors block_tree(blocks.size());
6800 for (ivectors::iterator it=block_tree.begin();it!=block_tree.end();++it) {
6801 it->push_back(0);
6802 it->push_back(-1);
6803 it->push_back(-1);
6804 ivectors &fv=blocks_faces[it-block_tree.begin()];
6805 it->insert(it->end(),fv.back().begin(),fv.back().end());
6806 }
6807 build_block_tree(0,block_tree);
6808 for (vector<ivectors>::iterator it=blocks_faces.begin();it!=blocks_faces.end();++it) {
6809 it->pop_back();
6810 }
6811 /* embed all blocks to the root block by climbing up the tree recursively */
6812 for (ivectors_iter bt=block_tree.begin();bt!=block_tree.end();++bt) {
6813 if (bt->at(1)<0) {
6814 // root found
6815 i=bt-block_tree.begin();
6816 embed_children_blocks(i,block_tree,blocks_faces);
6817 ivectors &block_faces=blocks_faces[i];
6818 faces.resize(block_faces.size());
6819 for (ivectors::iterator it=block_faces.begin();it!=block_faces.end();++it) {
6820 faces[it-block_faces.begin()].swap(*it);
6821 }
6822 break;
6823 }
6824 }
6825 return choose_outer_face(faces);
6826 }
6827
6828 /* compute the periphericity of the vertices with respect to
6829 * the outer face by applying BFS (starting in each of the outer vertices) */
periphericity(const ivector & outer_face,ivector & p)6830 void graphe::periphericity(const ivector &outer_face,ivector &p) {
6831 assert(node_queue.empty());
6832 int level,i,j;
6833 std::fill(p.begin(),p.end(),RAND_MAX);
6834 for (ivector_iter jt=outer_face.begin();jt!=outer_face.end();++jt) {
6835 p[*jt]=0;
6836 }
6837 for (ivector_iter it=outer_face.begin();it!=outer_face.end();++it) {
6838 unvisit_all_nodes();
6839 node_queue.push(*it);
6840 level=1;
6841 while (!node_queue.empty()) {
6842 i=node_queue.front();
6843 vertex &v=node(i);
6844 for (ivector_iter jt=v.neighbors().begin();jt!=v.neighbors().end();++jt) {
6845 j=*jt;
6846 vertex &w=node(j);
6847 if (w.is_visited() || p[j]==0) // skip the outer vertices
6848 continue;
6849 if (level<p[j])
6850 p[j]=level;
6851 node_queue.push(j);
6852 w.set_visited(true);
6853 }
6854 ++level;
6855 node_queue.pop();
6856 }
6857 }
6858 }
6859
6860 /*
6861 * TREE NODE POSITIONING ALGORITHM
6862 */
6863
6864 /* traverse the tree from top to bottom using DFS */
walk(int i,int pass,int level,double modsum)6865 void graphe::walker::walk(int i,int pass,int level,double modsum) {
6866 vertex &v=G->node(i);
6867 v.set_visited(true);
6868 double m=0;
6869 if (pass==3) {
6870 point &p=x->at(i);
6871 p.resize(2);
6872 p[0]=prelim[i]+modsum;
6873 p[1]=-level*vsep;
6874 m=modifier[i];
6875 }
6876 int j;
6877 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
6878 vertex &w=G->node(j=*it);
6879 if (w.is_visited())
6880 continue;
6881 if (pass==1) {
6882 w.set_ancestor(i);
6883 ++children[i];
6884 }
6885 walk(j,pass,level+1,modsum+m);
6886 }
6887 if (pass==1) {
6888 ++node_counters[level];
6889 depth=std::max(depth,level+1);
6890 } else if (pass==2) {
6891 if (node_counters[level]>0 && G->node(levels[level][node_counters[level]-1]).ancestor()!=v.ancestor())
6892 ++gap_counters[level];
6893 position[i]=node_counters[level]++;
6894 levels[level][position[i]]=i;
6895 if (children[i]>0) {
6896 gaps[i]=gap_counters[level];
6897 gap_counters[level]=0;
6898 }
6899 }
6900 }
6901
6902 /* set prelim and modifier for each node in V (they are on the same level) */
process_level(int i)6903 void graphe::walker::process_level(int i) {
6904 ivector &L=levels[i];
6905 int lastp=G->node(L.front()).ancestor(),p,n=0,m=placed.size(),j;
6906 double ppos=0,xpos=0,dist,shift=0,ssep=0,step=1,min_dist;
6907 if (m>0) {
6908 j=placed.front();
6909 xpos=prelim[j]-position[j]*hsep;
6910 }
6911 for (ivector_iter it=L.begin();it!=L.end();++it) {
6912 const vertex &v=G->node(*it);
6913 p=v.ancestor();
6914 if (p!=lastp) {
6915 prelim[lastp]=ppos/n;
6916 placed.push(lastp);
6917 lastp=p;
6918 ppos=0;
6919 n=0;
6920 xpos+=ssep;
6921 }
6922 if (children[*it]==0) {
6923 prelim[*it]=xpos;
6924 } else {
6925 prelim[*it]+=(modifier[*it]=shift);
6926 xpos=prelim[*it];
6927 step=1;
6928 ssep=0;
6929 placed.pop();
6930 --m;
6931 if (m>0) {
6932 vertex &w=G->node(j=placed.front());
6933 dist=prelim[j]+shift-xpos;
6934 min_dist=(position[j]-position[*it])*hsep;
6935 if (dist<min_dist)
6936 shift+=min_dist-dist;
6937 else if (v.ancestor()==w.ancestor())
6938 step=dist/min_dist;
6939 else
6940 ssep=(dist-min_dist)/gaps[j];
6941 }
6942 }
6943 ppos+=prelim[*it];
6944 ++n;
6945 xpos+=hsep*step;
6946 }
6947 assert(m==0);
6948 prelim[lastp]=ppos/n;
6949 placed.push(lastp);
6950 }
6951
6952 /* node positioning procedure */
positioning(int apex)6953 void graphe::walker::positioning(int apex) {
6954 G->unset_all_ancestors();
6955 G->unvisit_all_nodes();
6956 walk(apex,1); // first walk: determine tree depth and set node ancestors
6957 /* allocate memory for level lists */
6958 levels.resize(depth);
6959 gap_counters.resize(depth,0);
6960 for (int i=0;i<depth;++i) {
6961 levels[i].resize(node_counters[i]);
6962 node_counters[i]=0;
6963 }
6964 G->unvisit_all_nodes();
6965 walk(apex,2); // second walk: create levels
6966 /* do node positioning for each level (except the top one) in a single sweep */
6967 for (int level=depth;level-->1;) {
6968 process_level(level);
6969 }
6970 G->unvisit_all_nodes();
6971 walk(apex,3); // third walk: sum up the modifiers (i.e. move subtrees)
6972 }
6973
walker(graphe * gr,layout * ly,double hs,double vs)6974 graphe::walker::walker(graphe *gr,layout *ly,double hs,double vs) {
6975 G=gr;
6976 x=ly;
6977 hsep=hs;
6978 vsep=vs;
6979 depth=0;
6980 int n=G->node_count();
6981 node_counters.resize(n,0);
6982 position.resize(n,0);
6983 prelim.resize(n,0);
6984 modifier.resize(n,0);
6985 gaps.resize(n,0);
6986 children.resize(n,0);
6987 }
6988
6989 /*
6990 * END OF TREE NODE POSITIONING ALGORITHM
6991 */
6992
6993 /* calculate node positions and store them to the specified layout */
make_tree_layout(layout & x,double sep,int apex)6994 void graphe::make_tree_layout(layout &x,double sep,int apex) {
6995 int n=node_count();
6996 x.resize(n);
6997 if (n==0) return;
6998 /* layout the tree */
6999 double hsep=sep,vsep=sep*1.5;
7000 walker P(this,&x,hsep,vsep);
7001 P.positioning(apex);
7002 }
7003
7004 /* compute the number of rooted trees on 1,..,n vertices, output as t[1],..,t[n] */
compute_rutcounts(int n,vecteur & t)7005 void graphe::compute_rutcounts(int n,vecteur &t) {
7006 t.resize(n+1);
7007 t[1]=1;
7008 gen sum,td;
7009 int nlast=1,i;
7010 while (n>nlast) {
7011 sum=0;
7012 for (int d=1;d<=nlast;++d) {
7013 i=nlast+1;
7014 td=t[d]*gen(d);
7015 for (int j=1;j<=nlast;++j) {
7016 i-=d;
7017 if (i<=0) break;
7018 sum+=t[i]*td;
7019 }
7020 }
7021 ++nlast;
7022 t[nlast]=sum/gen(nlast-1);
7023 }
7024 }
7025
7026 /* Wilf's RANRUT algorithm - the original implementation: creates a random
7027 * rooted tree on n vertices, the numbers t[k] may be passed as pt if already computed */
ranrut(int n,ivector & tree,const vecteur & pt)7028 void graphe::ranrut(int n,ivector &tree,const vecteur &pt) {
7029 int l=0,d,j,i,k=n,is1=0,is2=0,m,ll,ls;
7030 tree.resize(n+1);
7031 ipairs jd(n+1);
7032 gen td,z;
7033 if (k<3) {
7034 tree[1]=0;
7035 if (k>1) tree[2]=1;
7036 return;
7037 }
7038 vecteur t;
7039 if (int(pt.size())>=n+1)
7040 t=vecteur(pt.begin(),pt.begin()+n+1);
7041 else
7042 compute_rutcounts(n,t);
7043 label12:
7044 if (k<=2) goto label70;
7045 z=t[k]*exact((k-1)*rand_uniform(),ctx);
7046 d=0;
7047 label30:
7048 ++d;
7049 td=t[d]*gen(d);
7050 m=k;
7051 j=0;
7052 label40:
7053 ++j;
7054 m-=d;
7055 if (m<1) goto label30;
7056 z-=t[m]*td;
7057 if (is_positive(z,ctx)) goto label40;
7058 jd[++is1]=make_pair(j,d);
7059 k=m;
7060 goto label12;
7061 label70:
7062 tree[is2+1]=l;
7063 l=is2+1;
7064 is2+=k;
7065 if (k>1) tree[is2]=is2-1;
7066 label80:
7067 k=jd[is1].second;
7068 if (k==0) goto label90;
7069 jd[is1].second=0;
7070 goto label12;
7071 label90:
7072 j=jd[is1--].first;
7073 m=is2-l+1;
7074 ll=tree[l];
7075 ls=l+(j-1)*m-1;
7076 if (j==1) goto label105;
7077 for (i=l;i<=ls;++i) {
7078 tree[i+m]=tree[i]+m;
7079 if ((i-l)%m==0) tree[i+m]=ll;
7080 }
7081 label105:
7082 is2=ls+m;
7083 if (is2==n) return;
7084 l=ll;
7085 goto label80;
7086 }
7087
ranrut_forest(int m,ivectors & trees,const vecteur & alpha,const vecteur & a)7088 void graphe::ranrut_forest(int m,ivectors &trees,const vecteur &alpha,const vecteur &a) {
7089 if (m==0)
7090 return;
7091 gen z=alpha[m]*exact(m*rand_uniform(),ctx),alphad;
7092 int d=0,i,j;
7093 label30:
7094 ++d;
7095 alphad=a[d]*gen(d);
7096 i=m;
7097 j=0;
7098 label40:
7099 ++j;
7100 i-=d;
7101 if (i<0) goto label30;
7102 z-=alpha[i]*alphad;
7103 if (is_positive(z,ctx)) goto label40;
7104 ranrut_forest(m-j*d,trees,alpha,a);
7105 ivector tree;
7106 ranrut(d,tree,a);
7107 tree[0]=j; // number of copies
7108 trees.push_back(tree);
7109 }
7110
7111 /* insert a tree rooted at vertex 'root' */
insert_tree(const ivector & tree,int root)7112 void graphe::insert_tree(const ivector &tree,int root) {
7113 for (ivector_iter it=tree.begin()+2;it!=tree.end();++it) {
7114 add_edge(it-tree.begin()-1+root,*it-1+root);
7115 }
7116 }
7117
7118 /* create random tree on n vertices with degree not larger than maxd */
make_random_tree(int maxd)7119 void graphe::make_random_tree(int maxd) {
7120 /* add one edge at a time to the tree */
7121 int ofs=array_start(ctx),n=node_count();
7122 ivector src,labels=vecteur_2_vector_int(*_randperm(n,ctx)._VECTptr);
7123 for (ivector::iterator it=labels.begin();it!=labels.end();++it) *it-=ofs;
7124 src.push_back(labels.back());
7125 labels.pop_back();
7126 int v,w;
7127 while (!labels.empty()) {
7128 v=src[rand_integer(src.size())];
7129 w=labels.back();
7130 labels.pop_back();
7131 add_edge(v,w);
7132 src.push_back(w);
7133 if (degree(node_index(v))==maxd) {
7134 ivector::iterator it=find(src.begin(),src.end(),v);
7135 assert(it!=src.end());
7136 src.erase(it);
7137 }
7138 }
7139 }
7140
7141 /* create a rooted tree on vertex set V uniformly at random (|V|<=500) */
make_random_rooted_tree()7142 void graphe::make_random_rooted_tree() {
7143 ivector tree;
7144 ranrut(node_count(),tree,vecteur(0));
7145 insert_tree(tree,0);
7146 }
7147
7148 /* create a free tree on vertex set V uniformly at random */
make_random_free_tree()7149 void graphe::make_random_free_tree() {
7150 int n=node_count();
7151 vecteur a;
7152 compute_rutcounts(n,a);
7153 /* the following is a correction of Wilf's algorithm:
7154 * a_n in step (T1) on page 207 should be T_n, the number of unrooted trees
7155 * on n vertices.
7156 * This number is correctly computed from a_1,a_2,..,a_n using the formula in:
7157 * Otter, "Number of trees" (1948), pp. 589 (http://users.math.msu.edu/users/magyar/Math482/Otter-Trees.pdf)
7158 */
7159 gen Tn=a[n];
7160 for (int i=1;i<n;++i) {
7161 Tn-=a[i]*a[n-i]/2;
7162 }
7163 if (n%2==0)
7164 Tn+=a[n/2]/2;
7165 if (n%2==0 && is_strictly_greater(a[n/2]*(1+a[n/2])/(2*Tn),exact(rand_uniform(),ctx),ctx)) {
7166 /* the output tree will have two centroids */
7167 ivector tree;
7168 ranrut(n/2,tree,a);
7169 insert_tree(tree,0);
7170 if (is_positive(exact(rand_uniform(),ctx)*(a[n/2]+1)-1,ctx))
7171 ranrut(n/2,tree,a);
7172 insert_tree(tree,n/2);
7173 add_edge(0,n/2);
7174 } else {
7175 /* the output tree will have one centroid */
7176 vecteur alpha(n);
7177 alpha[0]=1;
7178 gen sum,alphad;
7179 int m=0,i;
7180 while (n-1>m) {
7181 sum=0;
7182 for (int d=1;2*d<=n-1;++d) {
7183 i=m+1;
7184 alphad=a[d]*gen(d);
7185 for (int j=1;;++j) {
7186 i-=d;
7187 if (i<0) break;
7188 sum+=alpha[i]*alphad;
7189 }
7190 }
7191 ++m;
7192 alpha[m]=sum/gen(m);
7193 }
7194 ivectors trees;
7195 ivector roots;
7196 ranrut_forest(n-1,trees,alpha,a);
7197 m=1;
7198 for (ivectors_iter it=trees.begin();it!=trees.end();++it) {
7199 for (int j=0;j<it->front();++j) {
7200 insert_tree(*it,m);
7201 roots.push_back(m);
7202 m+=it->size()-1;
7203 }
7204 }
7205 for (ivector_iter it=roots.begin();it!=roots.end();++it) {
7206 add_edge(0,*it);
7207 }
7208 }
7209 }
7210
7211 /* use DFS traversal to compute tree depth */
tree_height_dfs(int i,int level,int & depth)7212 void graphe::tree_height_dfs(int i,int level,int &depth) {
7213 vertex &v=node(i);
7214 v.set_visited(true);
7215 depth=std::max(depth,level);
7216 int j;
7217 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
7218 j=*it;
7219 vertex &w=node(j);
7220 if (!w.is_visited())
7221 tree_height_dfs(j,level+1,depth);
7222 }
7223 }
7224
7225 /* return the height of this tree (no check is made) */
tree_height(int root)7226 int graphe::tree_height(int root) {
7227 /* assuming that this is a tree */
7228 if (node_count()==1)
7229 return 0;
7230 unvisit_all_nodes();
7231 int depth=0;
7232 tree_height_dfs(root,0,depth);
7233 return depth;
7234 }
7235
7236
7237 /* create a random biconnected planar graph with n vertices */
make_random_planar(double p,int connectivity)7238 void graphe::make_random_planar(double p,int connectivity) {
7239 /* connectivity is 0 (any), 1 (connected), 2 (biconnected) or 3 (triconnected) */
7240 assert(p>=0 && p<1 && connectivity>=0 && connectivity<4);
7241 set_directed(false);
7242 /* start with a random maximal planar graph with n vertices */
7243 int n=node_count();
7244 if (n==1)
7245 return;
7246 if (n==2) {
7247 add_edge(0,1);
7248 return;
7249 }
7250 ivectors faces;
7251 ivector face(3),old_face;
7252 for (int i=0;i<3;++i) {
7253 face[i]=i;
7254 add_edge(i,(i+1)%3);
7255 }
7256 faces.push_back(face);
7257 ivector outer_face(face.begin(),face.end());
7258 std::reverse(outer_face.begin(),outer_face.end());
7259 faces.push_back(outer_face);
7260 int k;
7261 /* create a random triangulated graph on n vertices */
7262 for (int i=3;i<n;++i) {
7263 k=rand_integer(faces.size());
7264 ivector &face_k=faces[k];
7265 old_face.assign(face_k.begin(),face_k.end());
7266 face[0]=i;
7267 for (int j=0;j<3;++j) {
7268 face[1]=old_face[j];
7269 face[2]=old_face[(j+1)%3];
7270 add_edge(i,old_face[j]);
7271 faces.push_back(face);
7272 }
7273 faces.erase(faces.begin()+k);
7274 }
7275 if (p==0)
7276 return;
7277 int mindeg=std::max(2,connectivity+1);
7278 ipairs E;
7279 get_edges_as_pairs(E);
7280 ivector indices=rand_permu(E.size());
7281 /* try to remove each edge with probability 0<p<1 */
7282 for (ivector_iter it=indices.begin();it!=indices.end();++it) {
7283 ipair &e=E[*it];
7284 if (degree(e.first)<mindeg || degree(e.second)<mindeg)
7285 continue;
7286 if (rand_uniform()<p)
7287 remove_edge(e);
7288 switch (connectivity) {
7289 case 0:
7290 break;
7291 case 1:
7292 if (!is_connected())
7293 add_edge(e);
7294 break;
7295 case 2:
7296 if (!is_biconnected())
7297 add_edge(e);
7298 break;
7299 case 3:
7300 if (!is_triconnected())
7301 add_edge(e);
7302 break;
7303 default:
7304 assert(false); // unreachable
7305 }
7306 }
7307 }
7308
7309 /* generate edges in this graph */
erdos_renyi(double p)7310 void graphe::erdos_renyi(double p) {
7311 int n=node_count(),m=std::floor(p),i,j;
7312 bool isdir=is_directed();
7313 if (m==0) {
7314 /* each edge is chosen with probability p */
7315 for (int k=0;k<(isdir?2:1);++k) {
7316 i=1; j=-1;
7317 while (i<n) {
7318 j+=1+std::floor(std::log(1-rand_uniform())/std::log(1-p));
7319 while (j>=i && i<n) {
7320 j-=i;
7321 ++i;
7322 }
7323 if (i<n) add_edge(k==0?i:j,k==0?j:i);
7324 }
7325 }
7326 } else {
7327 int N=(n*(n-1))/(isdir?1:2),i,j,r;
7328 bool islarge=m>N/2;
7329 if (islarge) { // first generate a complete graph
7330 for (i=0;i<n;++i)
7331 for (j=isdir?0:i+1;j<n;++j)
7332 if (i!=j) add_edge(i,j);
7333 }
7334 for (int k=0;k<(islarge?N-m:m);++k) {
7335 while (true) {
7336 r=rand_integer(N);
7337 if (isdir) {
7338 i=r/(n-1); j=r%(n-1);
7339 if (j>=i) ++j;
7340 } else {
7341 i=std::floor((1.0+std::sqrt(1.0+8.0*r))/2.0);
7342 j=r-i*(i-1)/2;
7343 }
7344 if (i>=n || j>=n) continue;
7345 if (islarge && has_edge(i,j)) {
7346 remove_edge(i,j);
7347 break;
7348 }
7349 if (!islarge && !has_edge(i,j)) {
7350 add_edge(i,j);
7351 break;
7352 }
7353 }
7354 }
7355 }
7356 }
7357
7358 /* generate edges of this graph according to preferential attachment rule */
preferential_attachment(int d,int o)7359 void graphe::preferential_attachment(int d,int o) {
7360 assert(!is_directed());
7361 int n=node_count();
7362 if (n<2) return;
7363 add_edge(0,1);
7364 int j,k;
7365 bucketsampler sampler(ivector(2,1),ctx);
7366 for (int i=2;i<n;++i) {
7367 for (int count=std::min(i,d);count-->0;) {
7368 do {
7369 j=sampler.generate();
7370 } while (has_edge(i,j));
7371 add_edge(i,j);
7372 sampler.increment(j);
7373 }
7374 for (int count=0;count<o;++count) {
7375 const ivector &ngh=node(i).neighbors();
7376 if (ngh.size()<2) break;
7377 j=rand_integer(ngh.size());
7378 do k=rand_integer(ngh.size()); while (k==j);
7379 j=ngh[j];
7380 k=ngh[k];
7381 if (!has_edge(j,k)) {
7382 add_edge(j,k);
7383 sampler.increment(j);
7384 sampler.increment(k);
7385 }
7386 }
7387 sampler.insert(std::min(i,d));
7388 }
7389 }
7390
7391 /* return true iff s is a graphic sequence */
is_graphic_sequence(const ivector & s_orig)7392 bool graphe::is_graphic_sequence(const ivector &s_orig) {
7393 ivector s=s_orig;
7394 std::sort(s.begin(),s.end());
7395 std::reverse(s.begin(),s.end());
7396 long sum=0;
7397 for (ivector_iter it=s.begin();it!=s.end();++it) sum+=*it;
7398 if (sum%2!=0) return false;
7399 int k=1,m,n=s.size();
7400 sum=0;
7401 for (ivector_iter it=s.begin();it!=s.end();++it,++k) {
7402 sum+=*it;
7403 m=0;
7404 for (int i=k;i<n;++i) m+=std::min(s[i],k);
7405 if (sum>k*(k-1)+m)
7406 return false;
7407 }
7408 return true;
7409 }
7410
7411 /* generate edges according to the given degree distribution */
molloy_reed(const vecteur & p)7412 void graphe::molloy_reed(const vecteur &p) {
7413 int n=node_count(),k,i;
7414 long sum;
7415 ivector stubs(n);
7416 ransampl rs(p,ctx);
7417 do {
7418 i=0; sum=0;
7419 bool done=false;
7420 while (true) {
7421 sum+=(stubs[i]=rs.generate());
7422 if (!done && i<n-1) ++i;
7423 else if (sum%2!=0) {
7424 sum-=stubs[(i=rand_integer(n))];
7425 done=true;
7426 } else break;
7427 }
7428 } while (!is_graphic_sequence(stubs));
7429 assert(hakimi(stubs));
7430 ipairs E;
7431 get_edges_as_pairs(E);
7432 int m=E.size();
7433 if (m<2) return;
7434 int iters=1+std::floor(M_LN2/std::log(double(m)/double(m-1))),tmp,at1,at2;
7435 ipair *e,*f;
7436 for (k=0;k<iters;++k) {
7437 at1=0;
7438 do {
7439 ++at1;
7440 at2=0;
7441 e=&E[rand_integer(m)];
7442 do {
7443 ++at2;
7444 f=&E[rand_integer(m)];
7445 } while (at2<10 && (e==f || edges_incident(*e,*f) ||
7446 (has_edge(e->first,f->first) && has_edge(e->first,f->second)) ||
7447 (has_edge(e->first,f->first) && has_edge(f->first,e->second)) ||
7448 (has_edge(f->first,e->second) && has_edge(e->second,f->second)) ||
7449 (has_edge(e->first,f->second) && has_edge(e->second,f->second))));
7450 if (at2<10) break;
7451 } while (at1<10);
7452 if (at1>=10) break;
7453 remove_edge(*e);
7454 remove_edge(*f);
7455 if (!has_edge(e->first,f->second) && !has_edge(f->first,e->second)) {
7456 tmp=e->second;
7457 e->second=f->second;
7458 f->second=tmp;
7459 } else {
7460 tmp=e->second;
7461 e->second=f->first;
7462 f->first=tmp;
7463 }
7464 add_edge(*e);
7465 add_edge(*f);
7466 }
7467 }
7468
7469 /* create a random graph with the given degree sequence d */
make_random_sequential(const ivector & d)7470 void graphe::make_random_sequential(const ivector &d) {
7471 /* assuming that d is graphical */
7472 assert(int(d.size())==node_count() && d.size()>0);
7473 int s=0;
7474 for (ivector_iter it=d.begin();it!=d.end();++it) {
7475 s+=*it;
7476 }
7477 assert((s%2)==0);
7478 int m=s/2,n=d.size(),sz,cnt;
7479 double p,r;
7480 map<ipair,bool> used;
7481 vector<pair<ipair,double> > emap((n*(n-1))/2);
7482 ivector D;
7483 ipair e;
7484 do {
7485 D=d;
7486 used.clear();
7487 cnt=0;
7488 while(true) {
7489 p=0;
7490 sz=0;
7491 int &i=e.first,&j=e.second;
7492 for (i=0;i<n;++i) {
7493 for (j=i+1;j<n;++j) {
7494 if (used[e])
7495 continue;
7496 p+=D[i]*D[j]*(1-d[i]*d[j]/(4*m));
7497 emap[sz++]=make_pair(e,p);
7498 }
7499 }
7500 if (p==0)
7501 break;
7502 r=rand_uniform()*p;
7503 for (int k=0;k<sz;++k) {
7504 pair<ipair,double> &elm=emap[k];
7505 if (r<=elm.second) {
7506 const ipair &edge=elm.first;
7507 used[edge]=true;
7508 ++cnt;
7509 --D[edge.first];
7510 --D[edge.second];
7511 break;
7512 }
7513 }
7514 }
7515 } while (cnt<m);
7516 for (map<ipair,bool>::const_iterator it=used.begin();it!=used.end();++it) {
7517 if (it->second)
7518 add_edge(it->first);
7519 }
7520 }
7521
7522 /* create a random bipartite graph with partition A,B */
make_random_bipartite(int a,int b,double p)7523 void graphe::make_random_bipartite(int a,int b,double p) {
7524 assert(!is_directed());
7525 int m=std::floor(p),ec=0,n=node_count(),M=std::min(m,a*b);
7526 assert(a+b==n);
7527 for (int i=0;i<a;++i) {
7528 for (int j=a;j<a+b;++j) {
7529 if ((m==0 && rand_uniform()<p) ||
7530 (m>0 && rand_uniform()<M/double(a*b))) {
7531 add_edge(i,j);
7532 ++ec;
7533 }
7534 }
7535 }
7536 if (m>0) {
7537 int d=ec-M,i,j;
7538 if (d>0) { // remove d edges at random
7539 for (int k=0;k<d;++k) {
7540 i=rand_integer(n);
7541 const vertex &v=node(i);
7542 j=v.neighbors().at(rand_integer(v.degree()));
7543 remove_edge(i,j);
7544 }
7545 } else if (d<0) { // add d edges at random
7546 for (int k=0;k<-d;++k) {
7547 i=rand_integer(a);
7548 do j=a+rand_integer(b); while (i==j || has_edge(i,j));
7549 add_edge(i,j);
7550 }
7551 }
7552 }
7553 assert(m==0 || ec==M);
7554 }
7555
7556 /* create a random d-regular graph with vertices fromm V */
make_random_regular(int d,bool connected)7557 void graphe::make_random_regular(int d,bool connected) {
7558 assert(!is_directed());
7559 ipairs E;
7560 int n=node_count();
7561 ivector prob,degrees(n);
7562 int prob_total,k,dd;
7563 double r;
7564 ipair edge;
7565 do {
7566 if (connected)
7567 make_random_tree(d);
7568 else {
7569 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
7570 it->clear_neighbors();
7571 }
7572 }
7573 for (int i=0;i<n;++i) {
7574 degrees[i]=degree(i);
7575 }
7576 E.clear();
7577 for (int i=0;i<n;++i) {
7578 if ((dd=degrees[i])<d) {
7579 for (int j=i+1;j<n;++j) {
7580 if (!nodes_are_adjacent(i,j) && degrees[j]<d)
7581 E.push_back(make_pair(i,j));
7582 }
7583 }
7584 }
7585 while (!E.empty()) {
7586 prob.resize(E.size());
7587 prob_total=0;
7588 for (ipairs_iter it=E.begin();it!=E.end();++it) {
7589 prob_total+=(d-degrees[it->first])*(d-degrees[it->second]);
7590 prob[it-E.begin()]=prob_total;
7591 }
7592 k=0;
7593 if (prob_total>0) {
7594 r=rand_uniform()*prob_total;
7595 for (ivector_iter it=prob.begin();it!=prob.end();++it) {
7596 if (r<=*it)
7597 break;
7598 ++k;
7599 }
7600 }
7601 edge=E[k];
7602 E.erase(E.begin()+k);
7603 ++degrees[edge.first];
7604 ++degrees[edge.second];
7605 add_edge(edge);
7606 for (k=E.size();k-->0;) {
7607 ipair &e=E[k];
7608 if (degrees[e.first]==d || degrees[e.second]==d)
7609 E.erase(E.begin()+k);
7610 }
7611 }
7612 } while (is_regular(d)<0);
7613 }
7614
7615 /* return -1 iff the graph is not (d-)regular, else return >=0 */
is_regular(int d) const7616 int graphe::is_regular(int d) const {
7617 int n=node_count();
7618 int deg=d;
7619 bool isdir=is_directed();
7620 for (int i=0;i<n;++i) {
7621 if (deg<0) {
7622 deg=degree(i);
7623 if (isdir && out_degree(i)!=in_degree(i))
7624 return -1;
7625 } else {
7626 if (degree(i)!=deg || (isdir && in_degree(i)!=out_degree(i)))
7627 return -1;
7628 }
7629 }
7630 return deg;
7631 }
7632
7633 /* return true iff the graph is strongly regular with sig = (lambda,mu) */
is_strongly_regular(ipair & sig)7634 bool graphe::is_strongly_regular(ipair &sig) {
7635 assert(!is_null());
7636 if (!is_regular(-1))
7637 return false;
7638 int n=node_count();
7639 int lambda=-1,mu=-1,m;
7640 for (int i=0;i<n;++i) {
7641 const ivector &Nv=node(i).neighbors();
7642 for (int j=0;j<n;++j) {
7643 if (i==j)
7644 continue;
7645 const ivector &Nw=node(j).neighbors();
7646 m=intersect_linear(Nv.begin(),Nv.end(),Nw.begin(),Nw.end());
7647 if (has_edge(i,j)) {
7648 if (lambda<0)
7649 lambda=m;
7650 else if (lambda!=m)
7651 return false;
7652 } else {
7653 if (mu<0)
7654 mu=m;
7655 else if (mu!=m)
7656 return false;
7657 }
7658 }
7659 }
7660 sig.first=lambda;
7661 sig.second=mu;
7662 return true;
7663 }
7664
7665 /* return true iff this graph is equal to G */
is_equal(const graphe & G) const7666 bool graphe::is_equal(const graphe &G) const {
7667 if (is_directed()!=G.is_directed() || is_weighted()!=G.is_weighted())
7668 return false;
7669 vecteur V1=vertices(),V2=G.vertices();
7670 if (V1!=V2)
7671 return false;
7672 ipairs E1,E2;
7673 edgeset edg,edG;
7674 get_edges_as_pairs(E1);
7675 G.get_edges_as_pairs(E2);
7676 ipairs2edgeset(E1,edg);
7677 ipairs2edgeset(E2,edG);
7678 if (edg!=edG)
7679 return false;
7680 if (is_weighted()) {
7681 for (edgeset_iter it=edg.begin();it!=edg.end();++it) {
7682 if (weight(*it)!=G.weight(*it))
7683 return false;
7684 }
7685 }
7686 return true;
7687 }
7688
7689 /* sort rectangles by height */
sort_rectangles(vector<rectangle> & rectangles)7690 void graphe::sort_rectangles(vector<rectangle> &rectangles) {
7691 rectangle::comparator comp;
7692 sort(rectangles.begin(),rectangles.end(),comp);
7693 }
7694
7695 /* packing rectangles (sorted by height) into an enclosing rectangle with specified dimensions,
7696 * returns true if embedding has changed */
embed_rectangles(vector<rectangle> & rectangles,double maxheight)7697 bool graphe::embed_rectangles(vector<rectangle> &rectangles,double maxheight) {
7698 bool embedding_changed=false;
7699 double old_x,old_y;
7700 dpair old_anchor;
7701 rectangle *old_rect;
7702 int lock_type;
7703 for (vector<rectangle>::iterator it=rectangles.begin()+1;it!=rectangles.end();++it) {
7704 rectangle &r=*it;
7705 old_x=r.x();
7706 old_y=r.y();
7707 r.set_anchor(DBL_MAX,-1);
7708 old_rect=NULL;
7709 for (vector<rectangle>::iterator jt=rectangles.begin();jt!=it;++jt) {
7710 rectangle &s=*jt;
7711 if (s.x()>r.x())
7712 continue;
7713 old_anchor.first=r.x();
7714 old_anchor.second=r.y();
7715 if (!s.is_locked_above()) {
7716 r.set_anchor(s.x(),s.y()+s.height());
7717 if (r.y()+r.height()<=maxheight && !r.intersects(rectangles.begin(),it)) {
7718 s.set_locked_above(true);
7719 if (old_rect!=NULL) {
7720 if (lock_type==1)
7721 old_rect->set_locked_above(false);
7722 else if (lock_type==2)
7723 old_rect->set_locked_right(false);
7724 }
7725 old_rect=&s;
7726 lock_type=1;
7727 continue;
7728 }
7729 }
7730 if (!s.is_locked_right()) {
7731 r.set_anchor(s.x()+s.width(),s.y());
7732 if (r.x()<old_anchor.first && r.y()+r.height()<=maxheight && !r.intersects(rectangles.begin(),it)) {
7733 s.set_locked_right(true);
7734 if (old_rect!=NULL) {
7735 if (lock_type==1)
7736 old_rect->set_locked_above(false);
7737 else if (lock_type==2)
7738 old_rect->set_locked_right(false);
7739 }
7740 old_rect=&s;
7741 lock_type=2;
7742 continue;
7743 }
7744 }
7745 r.set_anchor(old_anchor.first,old_anchor.second);
7746 }
7747 assert(r.y()>=0);
7748 if (old_x!=r.x() || old_y!=r.y())
7749 embedding_changed=true;
7750 }
7751 return embedding_changed;
7752 }
7753
7754 /* pack rectangles (sorted by height) to an enclosing rectangle with minimal perimeter and wasted space */
pack_rectangles(vector<rectangle> & rectangles)7755 void graphe::pack_rectangles(vector<rectangle> &rectangles) {
7756 /* compute total area occupied by the rectangles */
7757 double total_area=0;
7758 for (vector<rectangle>::const_iterator it=rectangles.begin();it!=rectangles.end();++it) {
7759 total_area+=it->width()*it->height();
7760 }
7761 /* step = the length of a negligible part of the shorter side of the smallest rectangle */
7762 double maxwidth=0,minwidth=DBL_MAX,minheight=rectangles.back().height();
7763 for (vector<rectangle>::const_iterator it=rectangles.begin();it!=rectangles.end();++it) {
7764 if (it->width()>maxwidth)
7765 maxwidth=it->width();
7766 if (it->width()<minwidth)
7767 minwidth=it->width();
7768 }
7769 double step=std::min(minwidth,minheight)*MARGIN_FACTOR;
7770 double bw=DBL_MAX,bh=rectangles.front().height(); // initial enclosing rectangle has an "unlimited" width
7771 double perim,best_perim=DBL_MAX,d;
7772 double xpos=0;
7773 dpairs best_embedding(rectangles.size());
7774 for (vector<rectangle>::iterator it=rectangles.begin();it!=rectangles.end();++it) {
7775 it->set_anchor(xpos,0);
7776 xpos+=it->width();
7777 }
7778 if (rectangles.size()<2)
7779 return;
7780 bool firstpass=true;
7781 clock_t start=clock();
7782 while (bw>maxwidth+step) { // loop breaks after a stacked embedding is obtained
7783 for (vector<rectangle>::iterator it=rectangles.begin();it!=rectangles.end();++it) {
7784 it->set_locked_above(false);
7785 it->set_locked_right(false);
7786 }
7787 if (firstpass || embed_rectangles(rectangles,bh)) {
7788 bw=bh=0;
7789 /* find the smallest enclosing rectangle containing the embedding */
7790 for (vector<rectangle>::const_iterator it=rectangles.begin();it!=rectangles.end();++it) {
7791 if ((d=it->x()+it->width())>bw)
7792 bw=d;
7793 if ((d=it->y()+it->height())>bh)
7794 bh=d;
7795 }
7796 /* find the embedding with the smallest perimeter (when scaled by the wasted ratio) */
7797 if ((perim=(bw+PLASTIC_NUMBER_2*bh)*std::sqrt(bw*bh/total_area))<best_perim) {
7798 best_perim=perim;
7799 for (vector<rectangle>::const_iterator it=rectangles.begin();it!=rectangles.end();++it) {
7800 dpair &p=best_embedding[it-rectangles.begin()];
7801 p.first=it->x();
7802 p.second=it->y();
7803 }
7804 }
7805 }
7806 /* increase enclosing rectangle height (rectangles will end up stacked eventually) */
7807 bh+=step;
7808 firstpass=false;
7809 if (double(clock()-start)/CLOCKS_PER_SEC>1.5)
7810 break;
7811 }
7812 for (vector<rectangle>::iterator it=rectangles.begin();it!=rectangles.end();++it) {
7813 dpair &p=best_embedding[it-rectangles.begin()];
7814 it->set_anchor(p.first,p.second);
7815 }
7816 }
7817
7818 /* return true iff an isomorphic copy with vertices permuted according to sigma is constructed */
isomorphic_copy(graphe & G,const ivector & sigma,bool strip_attributes)7819 bool graphe::isomorphic_copy(graphe &G,const ivector &sigma,bool strip_attributes) {
7820 assert(supports_attributes() || !G.supports_attributes());
7821 int n=node_count();
7822 assert(int(sigma.size())==n);
7823 G.clear();
7824 G.set_name(name());
7825 G.register_user_tags(user_tags);
7826 G.set_graph_attributes(attributes);
7827 /* add vertices */
7828 G.reserve_nodes(n);
7829 if (!G.supports_attributes())
7830 G.add_nodes(n);
7831 else {
7832 for (ivector_iter it=sigma.begin();it!=sigma.end();++it) {
7833 if (strip_attributes)
7834 G.add_node(node_label(*it));
7835 else G.add_node(node_label(*it),node(*it).attributes());
7836 }
7837 }
7838 if (G.node_count()!=n)
7839 return false;
7840 /* add edges */
7841 ipairs E,sigma_inv(n);
7842 get_edges_as_pairs(E);
7843 /* obtain the inverse of sigma */
7844 for (ivector_iter it=sigma.begin();it!=sigma.end();++it) {
7845 ipair &p=sigma_inv[it-sigma.begin()];
7846 p.first=*it;
7847 p.second=it-sigma.begin();
7848 }
7849 sort(sigma_inv.begin(),sigma_inv.end());
7850 ipair f;
7851 for (ipairs_iter it=E.begin();it!=E.end();++it) {
7852 const ipair &e=*it;
7853 f=make_pair(sigma_inv[e.first].second,sigma_inv[e.second].second);
7854 if (G.supports_attributes() && !strip_attributes)
7855 G.add_edge(f,edge_attributes(e));
7856 else G.add_edge(f);
7857 G.set_multiedge(f,multiedges(e));
7858 }
7859 return true;
7860 }
7861
7862 /* return true iff the vertices were successfully relabeled with 'labels' */
relabel_nodes(const vecteur & labels)7863 bool graphe::relabel_nodes(const vecteur &labels) {
7864 int n=node_count();
7865 if (int(labels.size())<n)
7866 return false;
7867 int i=0;
7868 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
7869 it->set_label(labels[i++]);
7870 }
7871 return true;
7872 }
7873
7874 /* return true iff the segments from p to p+r and from q to q+s intersect (compute the intersection point) */
segments_crossing(const point & p,const point & r,const point & q,const point & s,point & crossing)7875 bool graphe::segments_crossing(const point &p,const point &r,const point &q,const point &s,point &crossing) {
7876 point qq(2),pp(2),rr(2);
7877 copy_point(p,pp);
7878 copy_point(q,qq);
7879 copy_point(r,rr);
7880 subtract_point(qq,p);
7881 double vp1=point_vecprod2d(qq,r),vp2=point_vecprod2d(r,s);
7882 if (vp1==0 && vp2==0) // collinear edges
7883 return false;
7884 if (vp1!=0 && vp2==0) // parallel and non-intersecting edges
7885 return false;
7886 if (vp2!=0) {
7887 double t=point_vecprod2d(qq,s)/vp2,u=vp1/vp2;
7888 if (t>=0 && u>=0 && t<=1 && u<=1) {
7889 /* edges intersect each other, obtain the intersection point */
7890 scale_point(rr,t);
7891 add_point(pp,rr);
7892 crossing.resize(2);
7893 crossing.front()=pp[0];
7894 crossing.back()=pp[1];
7895 return true;
7896 }
7897 }
7898 /* edges are non-intersecting */
7899 return false;
7900 }
7901
7902 /* return true iff the point p can be projected onto a segment [q,r] (also compute the projection) */
point2segment_projection(const point & p,const point & q,const point & r,point & proj)7903 bool graphe::point2segment_projection(const point &p,const point &q,const point &r,point &proj) {
7904 assert(p.size()==2 && q.size()==2 && r.size()==2);
7905 proj.resize(2);
7906 point a(2),b(2),c(2);
7907 copy_point(p,a);
7908 subtract_point(a,q);
7909 copy_point(r,b);
7910 subtract_point(b,q);
7911 copy_point(r,c);
7912 subtract_point(c,p);
7913 double ab;
7914 if ((ab=point_dotprod(a,b))*point_dotprod(b,c)<=0)
7915 return false;
7916 copy_point(b,proj);
7917 double bn2=point_displacement(b,false);
7918 if (bn2==0)
7919 return false;
7920 scale_point(proj,ab/bn2);
7921 add_point(proj,q);
7922 return true;
7923 }
7924
7925 /* return the value of the largest integer node label */
largest_integer_label() const7926 int graphe::largest_integer_label() const {
7927 assert(supports_attributes());
7928 int n,m=array_start(ctx)-1;
7929 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
7930 if (it->label().is_integer() && (n=it->label().val)>m)
7931 m=n;
7932 }
7933 return m;
7934 }
7935
7936 /* return true iff two edges are incident to each other */
edges_incident(const ipair & e1,const ipair & e2)7937 bool graphe::edges_incident(const ipair &e1,const ipair &e2) {
7938 return e1.first==e2.first || e1.first==e2.second || e1.second==e2.first || e1.second==e2.second;
7939 }
7940
7941 /* return true iff two edges cross each other (also compute the crossing point) */
edges_crossing(const ipair & e1,const ipair & e2,const layout & x,point & crossing) const7942 bool graphe::edges_crossing(const ipair &e1,const ipair &e2,const layout &x,point &crossing) const {
7943 if (edges_incident(e1,e2))
7944 return false;
7945 point p(2),q(2),r(2),s(2);
7946 copy_point(x[e1.first],p);
7947 copy_point(x[e2.first],q);
7948 copy_point(x[e1.second],r);
7949 copy_point(x[e2.second],s);
7950 subtract_point(r,p);
7951 subtract_point(s,q);
7952 return segments_crossing(p,r,q,s,crossing);
7953 }
7954
7955 /* convert point to vecteur */
point2vecteur(const point & p)7956 vecteur graphe::point2vecteur(const point &p) {
7957 vecteur res;
7958 for (point::const_iterator it=p.begin();it!=p.end();++it) {
7959 res.push_back(*it);
7960 }
7961 return res;
7962 }
7963
7964 /* return true iff the points p and q coincide with each other within the given tolerance radius */
points_coincide(const point & p,const point & q,double tol)7965 bool graphe::points_coincide(const point &p,const point &q,double tol) {
7966 assert(q.size()==p.size());
7967 point r(p.size());
7968 return point_distance(p,q,r)<=tol;
7969 }
7970
7971 /*
7972 * IMPLEMENTATION OF RANDOM SAMPLING CLASSES
7973 *
7974 * RANSAMPL:
7975 * drawing samples from a given probability distribution
7976 * adapted from: ransampl.c by Joachim Wuttke, Forschungszentrum Juelich GmbH (2013)
7977 * see the original code at: apps.jcns.fz-juelich.de/ransampl
7978 *
7979 * Description:
7980 * Random-number sampling using the Walker-Vose alias
7981 * method, as described by Keith Schwarz (2011)
7982 */
7983
ransampl(const vecteur & p,GIAC_CONTEXT)7984 graphe::ransampl::ransampl(const vecteur &p,GIAC_CONTEXT) {
7985 ctx=contextptr;
7986 n=p.size();
7987 alias.resize(n);
7988 prob.resize(n);
7989 vecteur P(n);
7990 ivector S(n),L(n);
7991 gen norm_factor=gen(n)/_sum(p,ctx);
7992 for (int i=0;i<n;++i) P[i]=_evalf(p[i]*norm_factor,ctx);
7993 int nS=0,nL=0,a,g;
7994 for (int i=n-1;i>=0;--i) {
7995 if (is_strictly_greater(1,P[i],ctx)) S[nS++]=i; else L[nL++]=i;
7996 }
7997 while (nS!=0 && nL!=0) {
7998 a=S[--nS];
7999 g=L[--nL];
8000 prob[a]=P[a];
8001 alias[a]=g;
8002 P[g]+=P[a]-1;
8003 if (is_strictly_greater(1,P[g],ctx)) S[nS++]=g; else L[nL++]=g;
8004 }
8005 while (nL!=0) prob[L[--nL]]=1;
8006 while (nS!=0) prob[S[--nS]]=1;
8007 }
8008
data() const8009 gen graphe::ransampl::data() const {
8010 vecteur ret(1,n);
8011 ret=mergevecteur(ret,prob);
8012 return mergevecteur(ret,vector_int_2_vecteur(alias));
8013 }
8014
generate() const8015 int graphe::ransampl::generate() const {
8016 double ran1=giac_rand(ctx)/(RAND_MAX+1.0);
8017 double ran2=giac_rand(ctx)/(RAND_MAX+1.0);
8018 int i=std::floor(n*ran1);
8019 return is_strictly_greater(prob[i],ran2,ctx)?i:alias[i];
8020 }
8021
8022 /*
8023 * BUCKETSAMPLER:
8024 * draw samples from a given dynamic probability distribution,
8025 * supports updating the weights
8026 */
8027
bucketsampler(const ivector & W,GIAC_CONTEXT)8028 graphe::bucketsampler::bucketsampler(const ivector &W,GIAC_CONTEXT) {
8029 ctx=contextptr;
8030 int n=(weights=W).size(),k,w;
8031 total_weight=0;
8032 positions.resize(n);
8033 for (int i=0;i<n;++i) {
8034 if ((w=weights[i])==0)
8035 continue;
8036 k=nearest_pow2(w);
8037 max_weight[k]=std::max(max_weight[k],w);
8038 level_weight[k]+=w;
8039 positions[i]=make_pair(k,levels[k].size());
8040 levels[k].push_back(i);
8041 total_weight+=w;
8042 }
8043 }
8044
generate()8045 int graphe::bucketsampler::generate() {
8046 int u=giac_rand(ctx)/(RAND_MAX+1.0)*double(total_weight),i;
8047 long cweight=0;
8048 for (map<int,ivector>::const_reverse_iterator it=levels.rbegin();it!=levels.rend();++it) {
8049 cweight+=level_weight[it->first];
8050 i=it->first;
8051 if (cweight>u)
8052 break;
8053 }
8054 ivector &level=levels[i];
8055 int lmax=max_weight[i];
8056 double r,frac;
8057 int idx_in_level,idx,sz=level.size();
8058 do {
8059 r=giac_rand(ctx)/(RAND_MAX+1.0)*double(sz);
8060 idx_in_level=std::floor(r);
8061 frac=r-idx_in_level;
8062 idx=level[idx_in_level];
8063 } while (weights[idx]<frac*lmax);
8064 return idx;
8065 }
8066
insert(int w)8067 void graphe::bucketsampler::insert(int w) {
8068 int k=nearest_pow2(w);
8069 positions.push_back(make_pair(k,levels[k].size()));
8070 levels[k].push_back(weights.size());
8071 weights.push_back(w);
8072 max_weight[k]=std::max(max_weight[k],w);
8073 level_weight[k]+=w;
8074 total_weight+=w;
8075 }
8076
update(int i,int w)8077 void graphe::bucketsampler::update(int i,int w) {
8078 int old_w=weights[i];
8079 ipair &pos=positions[i];
8080 int old_k=pos.first,index=pos.second,k=nearest_pow2(w),last;
8081 if (k!=old_k) {
8082 ivector &old_level=levels[old_k];
8083 ivector &level=levels[k];
8084 last=old_level.back();
8085 ipair &last_pos=positions[last];
8086 last_pos.second=index;
8087 old_level[index]=last;
8088 old_level.pop_back();
8089 pos=make_pair(k,level.size());
8090 level.push_back(i);
8091 if (w>=max_weight[old_k]) {
8092 int &mw=max_weight[old_k];
8093 mw=0;
8094 for (ivector_iter it=old_level.begin();it!=old_level.end();++it) {
8095 if (weights[*it]>mw)
8096 mw=weights[*it];
8097 }
8098 }
8099 }
8100 weights[i]=w;
8101 level_weight[old_k]-=old_w;
8102 level_weight[k]+=w;
8103 max_weight[k]=std::max(max_weight[k],w);
8104 total_weight+=w-old_w;
8105 }
8106
8107 /*
8108 * END OF RANDOM SAMPLING CLASSES
8109 */
8110
8111 /*
8112 * IMPLEMENTATION OF THE DISJOINT SET DATA STRUCTURE
8113 */
8114
is_stored(int id)8115 bool graphe::unionfind::is_stored(int id) {
8116 for (int i=0;i<sz;++i) {
8117 if (elements[i].id==id)
8118 return true;
8119 }
8120 return false;
8121 }
8122
make_set(int id)8123 void graphe::unionfind::make_set(int id) {
8124 if (is_stored(id))
8125 return;
8126 element &e=elements[id];
8127 e.id=id;
8128 e.parent=id;
8129 e.rank=1;
8130 }
8131
find(int id)8132 int graphe::unionfind::find(int id) {
8133 element &e=elements[id];
8134 if (e.parent!=id)
8135 e.parent=find(e.parent);
8136 return e.parent;
8137 }
8138
unite(int id1,int id2)8139 void graphe::unionfind::unite(int id1,int id2) {
8140 int p1=find(id1),p2=find(id2);
8141 element &x=elements[p1],&y=elements[p2];
8142 if (x.rank>y.rank)
8143 y.parent=x.id;
8144 else if (x.rank<y.rank)
8145 x.parent=y.id;
8146 else {
8147 y.parent=x.id;
8148 ++x.rank;
8149 }
8150 }
8151
8152 /*
8153 * END OF DISJOINT_SET CLASS
8154 */
8155
8156 /* make planar layout */
make_planar_layout(layout & x)8157 bool graphe::make_planar_layout(layout &x) {
8158 int n=node_count(),of,m;
8159 ivectors faces;
8160 faces.clear();
8161 /* create the faces (adding temporary edges if necessary),
8162 * return the index of the outer face */
8163 of=planar_embedding(faces);
8164 if (of<0)
8165 return false; // the graph is not planar
8166 /* subdivide the concave faces */
8167 augment(faces,of,false);
8168 ivector &outer_face=faces[of];
8169 m=outer_face.size();
8170 /* create a fake outer face */
8171 ivector fake_outer_face(m);
8172 int label=largest_integer_label();
8173 for (ivector_iter it=outer_face.begin();it!=outer_face.end();++it) {
8174 add_temporary_edge(*it,fake_outer_face[it-outer_face.begin()]=add_node(++label));
8175 }
8176 make_tutte_layout(x,fake_outer_face); // create the layout
8177 /* remove temporary vertices and edges */
8178 remove_temporary_edges();
8179 while (node_count()>n) nodes.pop_back();
8180 x.resize(n);
8181 return true;
8182 }
8183
8184 /* get the convex hull of 2D graph layout */
convex_hull(const layout & x,layout & hull)8185 void graphe::convex_hull(const layout &x,layout &hull) {
8186 vecteur v(x.size());
8187 for (iterateur it=v.begin();it!=v.end();++it) {
8188 const point &p=x[it-v.begin()];
8189 *it=makecomplex(p.front(),p.back());
8190 }
8191 vecteur h=*_convexhull(v,ctx)._VECTptr;
8192 hull.resize(h.size());
8193 for (const_iterateur it=h.begin();it!=h.end();++it) {
8194 point &p=hull[it-h.begin()];
8195 p.resize(2);
8196 p.front()=it->_CPLXptr->DOUBLE_val();
8197 p.back()=(it->_CPLXptr+1)->DOUBLE_val();
8198 }
8199 }
8200
8201 /* rotate layout x such that left to right symmetry is exposed */
layout_best_rotation(layout & x)8202 void graphe::layout_best_rotation(layout &x) {
8203 /* center layout in the origin */
8204 point center=layout_center(x);
8205 scale_point(center,-1);
8206 translate_layout(x,center);
8207 layout hull;
8208 convex_hull(x,hull);
8209 int n=hull.size();
8210 /* compute the hull perimeter */
8211 double perim=0,score,maxscore=-1;
8212 point tmp(2),mp(2),rp(2),rq(2),origin(2,0.0),proj(2);
8213 for (int i=0;i<n;++i) {
8214 const point &p=hull[i],&q=hull[(i+1)%n];
8215 perim+=point_distance(p,q,tmp);
8216 }
8217 double a,b,c,d,tol,angle=0,half_perim=perim/2.0;
8218 vector<bool> matched(hull.size());
8219 for (int i=0;i<n;++i) {
8220 const point &p=hull[i];
8221 for (int j=i+1;j<n;++j) {
8222 const point &q=hull[j];
8223 if (!point2segment_projection(origin,p,q,proj))
8224 continue;
8225 /* obtain the perpendicular bisector ax+by+c=0 of the segment pq */
8226 copy_point(p,mp);
8227 add_point(mp,q);
8228 scale_point(mp,0.5);
8229 if (p.front()==q.front()) {
8230 a=1;
8231 c=-mp.front();
8232 b=0;
8233 } else {
8234 a=(p.back()-q.back())/(p.front()-q.front());
8235 b=-1;
8236 c=mp.back()-a*mp.front();
8237 }
8238 /* try to match hull edges that are reflections of each other */
8239 score=0;
8240 std::fill(matched.begin(),matched.end(),false);
8241 for (layout_iter it=hull.begin();it!=hull.end();++it) {
8242 if (matched[it-hull.begin()])
8243 continue;
8244 const point &p1=*it,&q1=it+1==hull.end()?hull.front():*(it+1);
8245 tol=(d=point_distance(p1,q1,tmp))*MARGIN_FACTOR/2.0;
8246 point_mirror(a,b,c,p1,rp);
8247 point_mirror(a,b,c,q1,rq);
8248 for (layout_iter jt=it;jt!=hull.end();++jt) {
8249 if (matched[jt-hull.begin()])
8250 continue;
8251 const point &p2=*jt,&q2=jt+1==hull.end()?hull.front():*(jt+1);
8252 if ((points_coincide(rp,p2,tol) && points_coincide(rq,q2,tol)) ||
8253 (points_coincide(rp,q2,tol) && points_coincide(rq,p2,tol))) {
8254 score+=d;
8255 matched[it-hull.begin()]=true;
8256 matched[jt-hull.begin()]=true;
8257 }
8258 }
8259 }
8260 score/=half_perim;
8261 double bigpart=std::pow(PLASTIC_NUMBER,4); // hull symmetry is more important
8262 score*=bigpart;
8263 score+=1.0-point_distance(proj,mp,tmp)/point_distance(p,q,tmp);
8264 score/=bigpart+1;
8265 if (score>maxscore) {
8266 maxscore=score;
8267 angle=a==0?M_PI_2:std::atan(b/a);
8268 }
8269 }
8270 }
8271 rotate_layout(x,M_PI_2-angle);
8272 rectangle rect=layout_bounding_rect(x);
8273 if (rect.y()+rect.height()/2.0<0)
8274 rotate_layout(x,M_PI);
8275 }
8276
8277 /* return true iff the degrees of vertices in v all coincide */
degrees_equal(const ivector & v,int deg) const8278 bool graphe::degrees_equal(const ivector &v,int deg) const {
8279 int D=deg,d;
8280 for (ivector_iter it=v.begin();it!=v.end();++it) {
8281 d=degree(*it);
8282 if (D==0)
8283 D=d;
8284 else if (d!=D)
8285 return false;
8286 }
8287
8288 return true;
8289 }
8290
8291 /* customize the Giac display */
customize_display(int options)8292 gen customize_display(int options) {
8293 return symbolic(at_equal,makesequence(at_display,change_subtype(options,_INT_COLOR)));
8294 }
8295
8296 /* append the line segment [p,q] to vecteur v */
append_segment(vecteur & drawing,const point & p,const point & q,int color,int width,int style,bool arrow) const8297 void graphe::append_segment(vecteur &drawing,const point &p,const point &q,int color,int width,int style,bool arrow) const {
8298 vecteur attributs(1,color | width | style);
8299 vecteur seg=p.size()==2?
8300 makevecteur(makecomplex(p[0],p[1]),makecomplex(q[0],q[1]))
8301 : makevecteur(gen(makevecteur(p[0],p[1],p[2]),_POINT__VECT),gen(makevecteur(q[0],q[1],q[2]),_POINT__VECT));
8302 drawing.push_back(pnt_attrib(gen(seg,arrow?_VECTOR__VECT:_GROUP__VECT),attributs,ctx));
8303 }
8304
8305 /* append the vertex (as a circle) to vecteur v */
append_node(vecteur & drawing,const point & p,int color,int width,int shape) const8306 void graphe::append_node(vecteur &drawing,const point &p,int color,int width,int shape) const {
8307 gen P=point2gen(p,true),args;
8308 args=makesequence(P,customize_display(color | width | shape));
8309 drawing.push_back(_point(args,ctx));
8310 }
8311
8312 /* append label to vecteur v at the specified quadrant */
append_label(vecteur & drawing,const point & p,const gen & label,int quadrant,int color) const8313 void graphe::append_label(vecteur &drawing,const point &p,const gen &label,int quadrant,int color) const {
8314 gen P=point2gen(p),args=makesequence(P,label,customize_display(quadrant | color));
8315 drawing.push_back(_legende(args,ctx));
8316 }
8317
8318 /* convert gen to point coordinates */
gen2point(const gen & g,point & p)8319 bool graphe::gen2point(const gen &g,point &p) {
8320 if (g.type==_VECT || g.is_symb_of_sommet(at_point)) {
8321 vecteur &v=g.type==_VECT?*g._VECTptr:*g._SYMBptr->feuille._VECTptr;
8322 p.resize(v.size());
8323 for (const_iterateur it=v.begin();it!=v.end();++it) {
8324 if (!is_real_number(*it))
8325 return false;
8326 p[it-v.begin()]=it->DOUBLE_val();
8327 }
8328 } else { /* assuming that pos is a complex number */
8329 p.resize(2);
8330 if (g.type==_CPLX) {
8331 gen &real=*g._CPLXptr,&imag=*(g._CPLXptr+1);
8332 if (!is_real_number(real) || !is_real_number(imag))
8333 return false;
8334 p.front()=real.DOUBLE_val();
8335 p.back()=imag.DOUBLE_val();
8336 } else {
8337 if (!is_real_number(g))
8338 return false;
8339 p.front()=g.DOUBLE_val();
8340 p.back()=0;
8341 }
8342 }
8343 return true;
8344 }
8345
8346 /* extract position attribute from attr */
get_node_position(const attrib & attr,point & p)8347 bool graphe::get_node_position(const attrib &attr,point &p) {
8348 attrib_iter it=attr.find(_GT_ATTRIB_POSITION);
8349 if (it==attr.end())
8350 return false;
8351 return gen2point(it->second,p);
8352 }
8353
8354 /* append line segments representing edges (arcs) of the graph to vecteur v */
draw_edges(vecteur & drawing,const layout & x)8355 void graphe::draw_edges(vecteur &drawing,const layout &x) {
8356 if (x.empty())
8357 return;
8358 int i,j,color,width,style;
8359 bool isdir=is_directed();
8360 double d;
8361 point r(x.front().size());
8362 attrib_iter ait;
8363 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
8364 i=it-nodes.begin();
8365 const point &p=x[i];
8366 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
8367 j=*jt;
8368 if (!isdir && j<i)
8369 continue;
8370 const point &q=x[j];
8371 const attrib &attr=it->neighbor_attributes(j);
8372 color=default_edge_color;
8373 if ((ait=attr.find(_GT_ATTRIB_COLOR))!=attr.end() && ait->second.is_integer()) {
8374 color=ait->second.val;
8375 if (color==7)
8376 color=0; /* draw white (invisible) edges as black */
8377 } else if ((ait=attr.find(_GT_ATTRIB_TEMPORARY))!=attr.end() && is_one(ait->second))
8378 color=29; // gray
8379 style=0;
8380 width=default_edge_width;
8381 if ((ait=attr.find(_GT_ATTRIB_STYLE))!=attr.end()) {
8382 const gen &val=ait->second;
8383 string s=val.type==_STRNG?genstring2str(val):gen2str(val);
8384 if (s=="dashed")
8385 style=_DASH_LINE;
8386 else if (s=="dotted")
8387 style=_DOT_LINE;
8388 else if (s=="bold")
8389 width=bold_edge_width;
8390 }
8391 if (isdir) {
8392 assert((ait=attr.find(_GT_ATTRIB_POSITION))!=attr.end());
8393 d=ait->second.DOUBLE_val();
8394 point_lincomb(p,q,d,1-d,r);
8395 append_segment(drawing,p,r,color,width,style,true);
8396 append_segment(drawing,r,q,color,width,style,false);
8397 } else
8398 append_segment(drawing,p,q,color,style,width);
8399 }
8400 }
8401 }
8402
8403 /* append points representing vertices of the graph to vecteur v */
draw_nodes(vecteur & drawing,const layout & x) const8404 void graphe::draw_nodes(vecteur &drawing,const layout &x) const {
8405 if (x.empty())
8406 return;
8407 int color,width,n=node_count();
8408 if (n<=30)
8409 width=_POINT_WIDTH_4;
8410 else if (n<=130)
8411 width=_POINT_WIDTH_3;
8412 else if (n<=330)
8413 width=_POINT_WIDTH_2;
8414 else
8415 width=_POINT_WIDTH_1;
8416 int shape;
8417 attrib_iter ait;
8418 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
8419 const attrib &attr=it->attributes();
8420 const point &p=x[it-nodes.begin()];
8421 color=default_vertex_color;
8422 if ((ait=attr.find(_GT_ATTRIB_COLOR))!=attr.end() && ait->second.is_integer()) {
8423 color=ait->second.val;
8424 if (color==7)
8425 color=0; // draw white (invisible) nodes as black
8426 }
8427 shape=_POINT_POINT;
8428 if ((ait=attr.find(_GT_ATTRIB_SHAPE))!=attr.end()) {
8429 const gen &val=ait->second;
8430 string s=val.type==_STRNG?genstring2str(val):gen2str(val);
8431 if (s=="box" || s=="square")
8432 shape=_POINT_CARRE;
8433 else if (s=="triangle")
8434 shape=_POINT_TRIANGLE;
8435 else if (s=="diamond")
8436 shape=_POINT_LOSANGE;
8437 else if (s=="star")
8438 shape=_POINT_ETOILE;
8439 else if (s=="plus")
8440 shape=_POINT_PLUS;
8441 }
8442 append_node(drawing,p,color,width,shape);
8443 }
8444 }
8445
8446 /* return the best quadrant for the placement of the i-th vertex label
8447 * (minimize the collision with the adjacent edges) */
best_quadrant(const point & p,const layout & adj) const8448 int graphe::best_quadrant(const point &p,const layout &adj) const {
8449 int bestq,n=adj.size();
8450 if (n==0 || p.size()!=2)
8451 return _QUADRANT1;
8452 layout quad(4);
8453 quad[0]=make_point(0.7071,0.7071);
8454 quad[1]=make_point(-0.7071,0.7071);
8455 quad[2]=make_point(-0.7071,-0.7071);
8456 quad[3]=make_point(0.7071,-0.7071);
8457 vector<double> min_angular_dist(4,M_PI);
8458 point u(2);
8459 double a;
8460 for (int i=0;i<4;++i) {
8461 const point &q=quad[i];
8462 double &mindist=min_angular_dist[i];
8463 for (layout_iter it=adj.begin();it!=adj.end();++it) {
8464 scale_point(u,1/point_distance(p,*it,u));
8465 a=std::acos(point_dotprod(u,q));
8466 if (a<mindist)
8467 mindist=a;
8468 }
8469 }
8470 a=-1;
8471 for (int i=0;i<4;++i) {
8472 const double &dist=min_angular_dist[i];
8473 if (a<0 || dist>a) {
8474 a=dist;
8475 bestq=i;
8476 }
8477 }
8478 switch (bestq) {
8479 case 0: return _QUADRANT1;
8480 case 1: return _QUADRANT2;
8481 case 2: return _QUADRANT3;
8482 case 3: return _QUADRANT4;
8483 default: break;
8484 }
8485 /* unreachable */
8486 return -1;
8487 }
8488
8489 /* append labels of the nodes of this graph to vecteur v */
draw_labels(vecteur & drawing,const layout & x) const8490 void graphe::draw_labels(vecteur &drawing,const layout &x) const {
8491 if (is_null())
8492 return;
8493 assert(!x.empty());
8494 ivector adjv;
8495 layout adj(2);
8496 attrib_iter ait;
8497 double d;
8498 int color,n=node_count();
8499 point r(x.front().size());
8500 bool isdirected=is_directed(),isweighted=is_weighted();
8501 if (isweighted && x.front().size()==2) {
8502 /* draw weight labels */
8503 for (int i=0;i<n;++i) {
8504 const point &p=x[i];
8505 const vertex &v=node(i);
8506 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
8507 if (!isdirected && *it<i)
8508 continue;
8509 const point &q=x[*it];
8510 const attrib &attr=v.neighbor_attributes(*it);
8511 color=default_edge_color;
8512 if ((ait=attr.find(_GT_ATTRIB_COLOR))!=attr.end())
8513 color=ait->second.val;
8514 assert((ait=attr.find(_GT_ATTRIB_POSITION))!=attr.end());
8515 d=ait->second.DOUBLE_val();
8516 point_lincomb(p,q,d,1-d,r);
8517 adj.front()=p;
8518 adj.back()=q;
8519 assert((ait=attr.find(_GT_ATTRIB_WEIGHT))!=attr.end());
8520 append_label(drawing,r,ait->second,best_quadrant(r,adj),color);
8521 }
8522 }
8523 }
8524 /* draw vertex labels */
8525 for (int i=0;i<n;++i) {
8526 const point &p=x[i];
8527 adjacent_nodes(i,adjv);
8528 adj.resize(adjv.size());
8529 for (ivector_iter it=adjv.begin();it!=adjv.end();++it) {
8530 adj[it-adjv.begin()]=x[*it];
8531 }
8532 append_label(drawing,p,node(i).label(),best_quadrant(p,adj));
8533 }
8534 }
8535
rdfs(int i,ivector & d,bool rec,int sg,bool skip_embedded)8536 void graphe::rdfs(int i,ivector &d,bool rec,int sg,bool skip_embedded) {
8537 vertex &v=node(i);
8538 v.set_visited(true);
8539 v.set_disc(++disc_time);
8540 v.set_low(v.disc());
8541 if (rec)
8542 d.push_back(i);
8543 int j;
8544 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
8545 j=*it;
8546 vertex &w=node(j);
8547 if ((sg>=0 && w.subgraph()!=sg) || (skip_embedded && w.is_embedded()))
8548 continue;
8549 if (!w.is_visited()) {
8550 w.set_ancestor(i);
8551 rdfs(j,d,rec,sg,skip_embedded);
8552 v.set_low(std::min(v.low(),w.low()));
8553 } else if (j!=v.ancestor())
8554 v.set_low(std::min(v.low(),w.disc()));
8555 }
8556 }
8557
8558 /* depth-first graph traversal with O(n+m) time and O(m) space complexity */
dfs(int root,bool rec,bool clr,ivector * D,int sg,bool skip_embedded)8559 void graphe::dfs(int root,bool rec,bool clr,ivector *D,int sg,bool skip_embedded) {
8560 if (clr) {
8561 unvisit_all_nodes(sg);
8562 unset_all_ancestors(sg);
8563 disc_time=0;
8564 }
8565 ivector &d=D!=NULL?*D:disc_nodes;
8566 if (rec) {
8567 d.clear();
8568 d.reserve(node_count());
8569 }
8570 assert(sg<0 || node(root).subgraph()==sg);
8571 rdfs(root,d,rec,sg,skip_embedded);
8572 }
8573
8574 /* breadth-first graph traversal with O(n+m) time and O(m) space complexity */
bfs(int root,bool rec,bool clr,ivector * D,int sg,bool skip_embedded)8575 void graphe::bfs(int root,bool rec,bool clr,ivector *D,int sg,bool skip_embedded) {
8576 if (clr) {
8577 unvisit_all_nodes(sg);
8578 unset_all_ancestors(sg);
8579 disc_time=0;
8580 }
8581 ivector &d=D!=NULL?*D:disc_nodes;
8582 if (rec) {
8583 d.clear();
8584 d.reserve(node_count());
8585 }
8586 assert(node_queue.empty());
8587 node_queue.push(root);
8588 int i,j;
8589 while (!node_queue.empty()) {
8590 i=node_queue.front();
8591 node_queue.pop();
8592 vertex &v=node(i);
8593 if (!v.is_visited()) {
8594 v.set_disc(disc_time++);
8595 if (rec)
8596 d.push_back(i);
8597 v.set_visited(true);
8598 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
8599 vertex &w=node(j=*it);
8600 if ((sg>=0 && w.subgraph()!=sg) || (skip_embedded && w.is_embedded()))
8601 continue;
8602 if (!w.is_visited()) {
8603 if (w.ancestor()<0)
8604 w.set_ancestor(i);
8605 node_queue.push(j);
8606 }
8607 }
8608 }
8609 }
8610 }
8611
8612 /* return true iff the graph is connected */
is_connected(int sg)8613 bool graphe::is_connected(int sg) {
8614 assert(!is_null());
8615 if (is_directed()) {
8616 graphe G(ctx,false);
8617 underlying(G);
8618 return G.is_connected(sg);
8619 }
8620 int i=sg<0?0:first_vertex_from_subgraph(sg);
8621 assert(i>=0);
8622 dfs(i,false,true,NULL,sg);
8623 for (node_iter it=nodes.begin()+i;it!=nodes.end();++it) {
8624 if ((sg<0 || it->subgraph()==sg) && !it->is_visited())
8625 return false;
8626 }
8627 return true;
8628 }
8629
8630 /* return true iff the graph is biconnected */
is_biconnected(int sg)8631 bool graphe::is_biconnected(int sg) {
8632 assert(!is_null());
8633 if (is_directed()) {
8634 graphe G(ctx,false);
8635 underlying(G);
8636 return G.is_biconnected(sg);
8637 }
8638 return is_connected(sg) && !has_cut_vertex(sg);
8639 }
8640
8641 /* return true iff the graph is triconnected, using a simple O(n*(n+m)) algorithm */
is_triconnected(int sg)8642 bool graphe::is_triconnected(int sg) {
8643 assert(!is_null());
8644 if (is_directed()) {
8645 graphe G(ctx,false);
8646 underlying(G);
8647 return G.is_triconnected(sg);
8648 }
8649 int color=max_subgraph_index()+1;
8650 for (int i=node_count();i-->0;) {
8651 vertex &v=node(i);
8652 if (sg>=0 && v.subgraph()!=sg)
8653 continue;
8654 if (degree(i)<3)
8655 return false;
8656 v.set_subgraph(color);
8657 }
8658 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
8659 if (it->subgraph()!=color)
8660 continue;
8661 it->set_subgraph(color+1);
8662 if (!is_biconnected(color))
8663 return false;
8664 it->set_subgraph(color);
8665 }
8666 return true;
8667 }
8668
8669 /* return true iff the (sub)graph is a cycle, linear time */
is_cycle(ipairs & E,int sg)8670 bool graphe::is_cycle(ipairs &E,int sg) {
8671 int root=-1;
8672 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
8673 if (sg>=0 && it->subgraph()!=sg)
8674 continue;
8675 if (degree(it-nodes.begin(),sg)>0) {
8676 root=it-nodes.begin();
8677 break;
8678 }
8679 }
8680 if (root<0)
8681 return false;
8682 dfs(root,true,true,NULL,sg);
8683 int n=disc_nodes.size();
8684 ipairs ev;
8685 get_edges_as_pairs(ev,sg);
8686 if (n!=int(ev.size()))
8687 return false;
8688 ipair e;
8689 E.resize(n);
8690 for (int i=0;i<n;++i) {
8691 e=make_pair(disc_nodes[i],disc_nodes[(i+1)%n]);
8692 if (!has_edge(e))
8693 return false;
8694 E[i]=e;
8695 }
8696 return true;
8697 }
8698
8699 /* return true iff the graph is a forest (check that the connected components are all trees) */
is_forest()8700 bool graphe::is_forest() {
8701 assert(!is_null() && !is_directed());
8702 ivectors comp;
8703 connected_components(comp);
8704 int sg=max_subgraph_index();
8705 for (ivectors_iter it=comp.begin();it!=comp.end();++it) {
8706 set_subgraph(*it,++sg);
8707 if (edge_count(sg)+1!=int(it->size()))
8708 return false;
8709 }
8710 return true;
8711 }
8712
8713 /* return true iff the graph is a tournament */
is_tournament() const8714 bool graphe::is_tournament() const {
8715 int n=node_count();
8716 if (!is_directed() || edge_count()!=n*(n-1)/2)
8717 return false;
8718 for (int i=0;i<n;++i) {
8719 for (int j=0;j<n;++j) {
8720 if (i==j)
8721 continue;
8722 if (has_edge(i,j)==has_edge(j,i))
8723 return false;
8724 }
8725 }
8726 return true;
8727 }
8728
8729 /* return true iff the graph is planar */
is_planar()8730 bool graphe::is_planar() {
8731 ivectors comp,faces;
8732 int m,sg=max_subgraph_index();
8733 connected_components(comp);
8734 for (ivectors_iter it=comp.begin();it!=comp.end();++it) {
8735 if (it->size()<5) continue;
8736 set_subgraph(*it,++sg);
8737 m=edge_count(sg);
8738 if (m>3*int(it->size())-6) {
8739 return false;
8740 }
8741 if (m<9) continue;
8742 vector<ipairs> blocks;
8743 find_blocks(blocks,sg);
8744 for (vector<ipairs>::const_iterator jt=blocks.begin();jt!=blocks.end();++jt) {
8745 if (jt->size()<9) continue;
8746 set_subgraph(*jt,++sg);
8747 if (subgraph_size(sg)<5) continue;
8748 if (!demoucron(faces,sg)) {
8749 return false;
8750 }
8751 }
8752 }
8753 return true;
8754 }
8755
8756 /* create set of vertices for product P of this graph and graph G */
make_product_nodes(const graphe & G,graphe & P) const8757 void graphe::make_product_nodes(const graphe &G,graphe &P) const {
8758 int n=node_count(),m=G.node_count();
8759 stringstream ss;
8760 P.reserve_nodes(n*m);
8761 for (int i=0;i<n;++i) {
8762 for (int j=0;j<m;++j) {
8763 const gen &v=node_label(i),&w=G.node_label(j);
8764 ss.str("");
8765 if (v.type==_STRNG)
8766 ss << genstring2str(v);
8767 else ss << v;
8768 ss << ":";
8769 if (w.type==_STRNG)
8770 ss << genstring2str(w);
8771 else ss << w;
8772 P.add_node(str2gen(ss.str(),true));
8773 }
8774 }
8775 }
8776
8777 /* compute the cartesian product of this graph and graph G and store it in P */
cartesian_product(const graphe & G,graphe & P) const8778 void graphe::cartesian_product(const graphe &G,graphe &P) const {
8779 P.clear();
8780 make_product_nodes(G,P);
8781 int n=node_count(),m=G.node_count();
8782 for (int i=0;i<n;++i) {
8783 for (int j=0;j<m;++j) {
8784 const vertex &w=G.node(j);
8785 for (ivector_iter it=w.neighbors().begin();it!=w.neighbors().end();++it) {
8786 if (*it>j)
8787 P.add_edge(i*m+j,i*m+(*it));
8788 }
8789 }
8790 }
8791 for (int j=0;j<m;++j) {
8792 for (int i=0;i<n;++i) {
8793 const vertex &v=node(i);
8794 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
8795 if (*it>i)
8796 P.add_edge(i*m+j,(*it)*m+j);
8797 }
8798 }
8799 }
8800 }
8801
8802 /* compute tensor product of this graph and graph G and store it in P */
tensor_product(const graphe & G,graphe & P) const8803 void graphe::tensor_product(const graphe &G,graphe &P) const {
8804 P.clear();
8805 make_product_nodes(G,P);
8806 int n=node_count(),m=G.node_count();
8807 for (int i=0;i<n;++i) {
8808 const vertex &v=node(i);
8809 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
8810 for (int j=0;j<m;++j) {
8811 const vertex &w=G.node(j);
8812 for (ivector_iter jt=w.neighbors().begin();jt!=w.neighbors().end();++jt) {
8813 if (*jt>j)
8814 P.add_edge(i*m+j,(*it)*m+(*jt));
8815 }
8816 }
8817 }
8818 }
8819 }
8820
8821 /* compute the distance between i-th and J nodes using BFS and store them to dist
8822 * (also output paths if shortest_paths!=NULL) */
distance(int i,const ivector & J,ivector & dist,ivectors * shortest_paths)8823 void graphe::distance(int i,const ivector &J,ivector &dist,ivectors *shortest_paths) {
8824 bfs(i,false);
8825 int k,p,len;
8826 if (shortest_paths!=NULL) {
8827 shortest_paths->resize(J.size());
8828 }
8829 dist.resize(J.size());
8830 ivector *shortest_path=NULL;
8831 for (ivector_iter it=J.begin();it!=J.end();++it) {
8832 k=*it;
8833 len=0;
8834 if (shortest_paths!=NULL) {
8835 shortest_path=&shortest_paths->at(it-J.begin());
8836 shortest_path->clear();
8837 shortest_path->push_back(*it);
8838 }
8839 while (k!=i) {
8840 if ((p=node(k).ancestor())<0) {
8841 len=-1;
8842 break;
8843 }
8844 k=p;
8845 if (shortest_path!=NULL)
8846 shortest_path->push_back(k);
8847 ++len;
8848 }
8849 if (shortest_path!=NULL)
8850 std::reverse(shortest_path->begin(),shortest_path->end());
8851 dist[it-J.begin()]=len;
8852 }
8853 }
8854
8855 /* compute the distances between all pairs of vertices using Floyd-Warshall algorithm */
allpairs_distance(matrice & m) const8856 void graphe::allpairs_distance(matrice &m) const {
8857 int n=node_count(),i,j,k;
8858 m.reserve(n);
8859 for (i=0;i<n;++i) {
8860 m.push_back(vecteur(n,plusinf()));
8861 }
8862 gen s;
8863 bool isweighted=is_weighted();
8864 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
8865 i=it-nodes.begin();
8866 m[i]._VECTptr->at(i)=0;
8867 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
8868 j=*jt;
8869 m[i]._VECTptr->at(j)=isweighted?weight(i,j):gen(1);
8870 }
8871 }
8872 for (k=0;k<n;++k) {
8873 for (i=0;i<n;++i) {
8874 const gen &mik=m[i][k];
8875 for (j=0;j<n;++j) {
8876 s=mik+m[k][j];
8877 gen &mij=m[i]._VECTptr->at(j);
8878 if (is_strictly_greater(mij,s,ctx))
8879 mij=s;
8880 }
8881 }
8882 }
8883 }
8884
8885 /* return the length of the shortest path from src to dest in weighted
8886 * graph (Dijkstra's algorithm), also fill shortest_path with the respective vertices */
dijkstra(int src,const ivector & dest,vecteur & path_weights,ivectors * cheapest_paths,int sg)8887 void graphe::dijkstra(int src,const ivector &dest,vecteur &path_weights,ivectors *cheapest_paths,int sg) {
8888 int n=node_count();
8889 ivector Q;
8890 vecteur dist(n);
8891 bool isweighted=is_weighted();
8892 if (sg>=0) {
8893 assert(node(src).subgraph()==sg);
8894 for (ivector_iter it=dest.begin();it!=dest.end();++it) {
8895 assert(node(*it).subgraph()==sg);
8896 }
8897 }
8898 unset_all_ancestors(sg);
8899 for (int i=0;i<n;++i) {
8900 vertex &v=node(i);
8901 if (sg>=0 && v.subgraph()!=sg) continue;
8902 Q.push_back(i);
8903 dist[i]=i==src?gen(0):plusinf();
8904 }
8905 unvisit_all_nodes(sg);
8906 gen min_dist,alt;
8907 int pos,u;
8908 while (!Q.empty()) {
8909 min_dist=plusinf();
8910 pos=-1;
8911 for (ivector_iter it=Q.begin();it!=Q.end();++it) {
8912 if (is_strictly_greater(min_dist,dist[*it],ctx)) {
8913 min_dist=dist[*it];
8914 pos=it-Q.begin();
8915 u=*it;
8916 }
8917 }
8918 if (pos<0) break;
8919 Q.erase(Q.begin()+pos);
8920 vertex &v=node(u);
8921 v.set_visited(true);
8922 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
8923 vertex &w=node(*it);
8924 if ((sg>=0 && w.subgraph()!=sg) || w.is_visited())
8925 continue;
8926 alt=dist[u]+(isweighted?weight(u,*it):gen(1));
8927 if (is_strictly_greater(dist[*it],alt,ctx)) {
8928 dist[*it]=alt;
8929 w.set_ancestor(u);
8930 }
8931 }
8932 }
8933 path_weights.resize(dest.size());
8934 for (ivector_iter it=dest.begin();it!=dest.end();++it) {
8935 path_weights[it-dest.begin()]=dist[*it];
8936 }
8937 if (cheapest_paths!=NULL) {
8938 cheapest_paths->resize(dest.size());
8939 for (ivector_iter it=dest.begin();it!=dest.end();++it) {
8940 ivector &path=cheapest_paths->at(it-dest.begin());
8941 path.clear();
8942 if (is_inf(dist[*it])) continue;
8943 path.push_back(*it);
8944 int p=*it;
8945 while ((p=node(p).ancestor())>=0) path.push_back(p);
8946 std::reverse(path.begin(),path.end());
8947 }
8948 }
8949 }
8950
8951 /* return the length of the shortest path from src to dest in weighted
8952 * graph (Bellman-Ford algorithm), also fill shortest_path with the respective vertices */
bellman_ford(int src,const ivector & dest,vecteur & path_weights,ivectors * cheapest_paths)8953 bool graphe::bellman_ford(int src,const ivector &dest,vecteur &path_weights,ivectors *cheapest_paths) {
8954 int n=node_count(),u,v;
8955 ivector prev(n);
8956 vecteur dist(n);
8957 bool isweighted=is_weighted();
8958 for (int i=0;i<n;++i) {
8959 dist[i]=i==src?gen(0):plusinf();
8960 prev[i]=-1;
8961 }
8962 ipairs E;
8963 get_edges_as_pairs(E);
8964 gen w(1);
8965 for (int i=1;i<n;++i) {
8966 for (ipairs_iter it=E.begin();it!=E.end();++it) {
8967 u=it->first; v=it->second;
8968 if (isweighted)
8969 get_edge_attribute(u,v,_GT_ATTRIB_WEIGHT,w);
8970 if (is_strictly_greater(dist[v],dist[u]+w,ctx)) {
8971 dist[v]=dist[u]+w;
8972 prev[v]=u;
8973 }
8974 }
8975 }
8976 /* check for negative-weight cycles */
8977 for (ipairs_iter it=E.begin();it!=E.end();++it) {
8978 if (isweighted)
8979 get_edge_attribute(u,v,_GT_ATTRIB_WEIGHT,w);
8980 if (is_strictly_greater(dist[v],dist[u]+w,ctx))
8981 return false; // a negative-weight cycle is found
8982 }
8983 if (cheapest_paths!=NULL) {
8984 cheapest_paths->resize(dest.size());
8985 for (ivector_iter it=dest.begin();it!=dest.end();++it) {
8986 ivector &path=cheapest_paths->at(it-dest.begin());
8987 path.clear();
8988 path.push_back(*it);
8989 int p=*it;
8990 while ((p=prev[p])>=0) path.push_back(p);
8991 std::reverse(path.begin(),path.end());
8992 }
8993 }
8994 path_weights.resize(dest.size());
8995 for (ivector_iter it=dest.begin();it!=dest.end();++it) {
8996 path_weights[it-dest.begin()]=dist[*it];
8997 }
8998 return true; // success
8999 }
9000
9001 /* return true iff the graph has a topological ordering and output the indices
9002 * of thus sorted vertices in list v, use Kahn's algorithm with time complexity O(n+m) */
topologic_sort(ivector & ordering)9003 bool graphe::topologic_sort(ivector &ordering) {
9004 assert(is_directed() && node_stack.empty());
9005 int n=node_count(),v;
9006 ordering.clear();
9007 ordering.reserve(n);
9008 for (int i=0;i<n;++i) {
9009 if (in_degree(i)==0)
9010 node_stack.push(i);
9011 }
9012 graphe G(ctx,false);
9013 copy(G);
9014 while (!node_stack.empty()) {
9015 v=node_stack.top();
9016 node_stack.pop();
9017 ordering.push_back(v);
9018 vertex &vert=G.node(v);
9019 for (ivector_iter it=vert.neighbors().begin();it!=vert.neighbors().end();++it) {
9020 if (G.in_degree(*it)==1)
9021 node_stack.push(*it);
9022 }
9023 vert.clear_neighbors();
9024 }
9025 return G.edge_count()==0;
9026 }
9027
9028 /* return true iff the graph is an arborescence, i.e. a directed tree */
is_arborescence() const9029 bool graphe::is_arborescence() const {
9030 assert(is_directed());
9031 bool has_root=false;
9032 ivector deg(node_count(),0);
9033 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9034 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
9035 ++deg[*jt];
9036 }
9037 }
9038 for (ivector_iter it=deg.begin();it!=deg.end();++it) {
9039 if (*it==0) {
9040 if (has_root)
9041 return false;
9042 has_root=true;
9043 } else if (*it>1)
9044 return false;
9045 }
9046 return has_root;
9047 }
9048
9049 /* write this (directed) graph with arc directions reversed to G */
reverse(graphe & G) const9050 void graphe::reverse(graphe &G) const {
9051 assert(is_directed());
9052 G.set_directed(true);
9053 G.set_graph_attributes(attributes);
9054 G.reserve_nodes(node_count());
9055 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9056 G.add_node(it->label(),it->attributes());
9057 }
9058 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9059 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
9060 G.add_edge(*jt,it-nodes.begin(),it->neighbor_attributes(*jt));
9061 }
9062 }
9063 }
9064
9065 /* write a spanning tree of this graph with i-th node as root to T, time complexity O(n+m) */
spanning_tree(int i,graphe & T,int sg)9066 void graphe::spanning_tree(int i,graphe &T,int sg) {
9067 T.clear();
9068 vecteur V=vertices(sg);
9069 T.reserve_nodes(V.size());
9070 T.add_nodes(V);
9071 ivector indices(V.size());
9072 int v,p;
9073 if (sg>=0) {
9074 for (const_iterateur it=V.begin();it!=V.end();++it) {
9075 v=it-V.begin();
9076 indices[v]=node_index(*it);
9077 }
9078 }
9079 dfs(i,false,true,NULL,sg);
9080 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9081 if (sg>=0 && it->subgraph()!=sg)
9082 continue;
9083 if ((p=it->ancestor())>=0) {
9084 if (sg>=0)
9085 T.add_edge(indices[it-nodes.begin()],indices[p]);
9086 else
9087 T.add_edge(it-nodes.begin(),p);
9088 }
9089 }
9090 }
9091
9092 /* write the minimal spanning tree of this graph to T,
9093 * use Kruskal's algorithm with time complexity O(m*log(n)) */
minimal_spanning_tree(graphe & T,int sg)9094 void graphe::minimal_spanning_tree(graphe &T,int sg) {
9095 assert(!is_directed() && is_weighted());
9096 ipairs E,res;
9097 get_edges_as_pairs(E,sg);
9098 edges_comparator comp(this);
9099 sort(E.begin(),E.end(),comp);
9100 int v,u;
9101 unionfind ds(node_count());
9102 for (ipairs_iter it=E.begin();it!=E.end();++it) {
9103 ds.make_set(it->first);
9104 ds.make_set(it->second);
9105 }
9106 for (ipairs_iter it=E.begin();it!=E.end();++it) {
9107 u=it->first;
9108 v=it->second;
9109 if (ds.find(u)!=ds.find(v)) {
9110 res.push_back(*it);
9111 ds.unite(u,v);
9112 }
9113 }
9114 extract_subgraph(res,T);
9115 }
9116
9117 /* Tarjan's offline algorithm for the lowest common ancestor, time complexity O(n) */
lca_recursion(int u,const ipairs & p,ivector & lca,unionfind & ds)9118 void graphe::lca_recursion(int u,const ipairs &p,ivector &lca,unionfind &ds) {
9119 ds.make_set(u);
9120 vertex &U=node(u);
9121 U.set_ancestor(u);
9122 U.set_visited(true);
9123 int v;
9124 for (ivector_iter it=U.neighbors().begin();it!=U.neighbors().end();++it) {
9125 v=*it;
9126 vertex &V=node(v);
9127 if (V.is_visited())
9128 continue;
9129 lca_recursion(v,p,lca,ds);
9130 ds.unite(u,v);
9131 node(ds.find(u)).set_ancestor(u);
9132 }
9133 U.set_color(1); // black
9134 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9135 v=it-nodes.begin();
9136 if (u==v)
9137 continue;
9138 for (ipairs_iter jt=p.begin();jt!=p.end();++jt) {
9139 if ((jt->first==u && jt->second==v) || (jt->first==v && jt->second==u)) {
9140 if (it->color()==1)
9141 lca[jt-p.begin()]=node(ds.find(v)).ancestor();
9142 break;
9143 }
9144 }
9145 }
9146 }
9147
9148 /* find the lowest common ancestors for all pairs of vertices in p (this must be a tree) */
lowest_common_ancestors(int root,const ipairs & p,ivector & lca)9149 void graphe::lowest_common_ancestors(int root,const ipairs &p,ivector &lca) {
9150 unvisit_all_nodes();
9151 unset_all_ancestors();
9152 uncolor_all_nodes();
9153 lca.resize(p.size(),-1);
9154 unionfind ds(node_count());
9155 lca_recursion(root,p,lca,ds);
9156 assert(find(lca.begin(),lca.end(),-1)==lca.end());
9157 }
9158
9159 /* return the lowest common ancestor of i-th node and j-th node of this tree */
lowest_common_ancestor(int i,int j,int root)9160 int graphe::lowest_common_ancestor(int i,int j,int root) {
9161 ipairs p;
9162 p.push_back(make_pair(i,j));
9163 ivector lca;
9164 lowest_common_ancestors(root,p,lca);
9165 return lca.front();
9166 }
9167
9168 /* return true iff v is a descendant of anc wrt the last dfs traversal */
is_descendant(int v,int anc) const9169 bool graphe::is_descendant(int v,int anc) const {
9170 int i=v;
9171 while ((i=node(i).ancestor())>=0) {
9172 if (i==anc)
9173 return true;
9174 }
9175 return false;
9176 }
9177
st_numbering_dfs(int i,ivector & preorder)9178 void graphe::st_numbering_dfs(int i,ivector &preorder) {
9179 vertex &v=node(i);
9180 v.set_disc(++disc_time);
9181 v.set_low(i);
9182 int j;
9183 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
9184 vertex &w=node(j=*it);
9185 if (w.disc()==0) {
9186 st_numbering_dfs(j,preorder);
9187 w.set_ancestor(i);
9188 preorder.push_back(j);
9189 if (node(w.low()).disc()<node(v.low()).disc())
9190 v.set_low(w.low());
9191 } else if (w.disc()!=0 && w.disc()<node(v.low()).disc())
9192 v.set_low(*it);
9193 }
9194 }
9195
9196 /* find st-numbering using Tarjan's algorithm (1986), time complexity O(n+m) */
compute_st_numbering(int s,int t)9197 void graphe::compute_st_numbering(int s,int t) {
9198 /* assuming that the graph is biconnected */
9199 assert(has_edge(s,t) && node_stack.empty());
9200 int n=node_count(),i;
9201 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
9202 it->set_disc(0);
9203 }
9204 disc_time=1;
9205 node(s).set_disc(1);
9206 ivector preorder,L;
9207 st_numbering_dfs(t,preorder);
9208 L.push_back(s);
9209 L.push_back(t);
9210 vector<bool> sign(n);
9211 ivector::iterator lit;
9212 bool sign_plus=true,sign_minus=false;
9213 sign[s]=sign_minus;
9214 for (ivector::const_reverse_iterator it=preorder.rbegin();it!=preorder.rend();++it) {
9215 vertex &v=node(*it);
9216 lit=find(L.begin(),L.end(),v.ancestor());
9217 assert(lit!=L.end());
9218 if (sign[v.low()]==sign_minus) {
9219 L.insert(lit,*it);
9220 sign[v.ancestor()]=sign_plus;
9221 } else if (sign[v.low()]==sign_plus) {
9222 L.insert(lit+1,*it);
9223 sign[v.ancestor()]=sign_minus;
9224 }
9225 }
9226 i=0;
9227 for (ivector_iter it=L.begin();it!=L.end();++it) {
9228 node(*it).set_number(++i);
9229 }
9230 }
9231
9232 /* return st-numbering in form of vecteur */
get_st_numbering() const9233 vecteur graphe::get_st_numbering() const {
9234 /* assuming that st numbering has been computed */
9235 vecteur st(node_count());
9236 int ofs=1-array_start(ctx);
9237 for (iterateur it=st.begin();it!=st.end();++it) {
9238 *it=node(it-st.begin()).number()-ofs;
9239 }
9240 return st;
9241 }
9242
9243 /* assign directions to edges according to the st-numbering */
assign_edge_directions_from_st()9244 void graphe::assign_edge_directions_from_st() {
9245 bool isweighted=is_weighted();
9246 matrice W;
9247 if (isweighted)
9248 weight_matrix(W);
9249 ipairs E;
9250 get_edges_as_pairs(E);
9251 for (ipairs_iter it=E.begin();it!=E.end();++it) {
9252 discard_edge_attribute(it->first,it->second,_GT_ATTRIB_WEIGHT);
9253 }
9254 set_weighted(false);
9255 set_directed(true);
9256 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
9257 vertex &v=*it;
9258 ivector ngh=v.neighbors();
9259 for (ivector_iter jt=ngh.begin();jt!=ngh.end();++jt) {
9260 const vertex &w=node(*jt);
9261 if (v.number()>w.number())
9262 v.remove_neighbor(*jt);
9263 }
9264 }
9265 if (isweighted)
9266 make_weighted(W);
9267 }
9268
strec(int i,int t,int counter,int np,iset & Q,vecteur & timestamp,vecteur & l)9269 void graphe::strec(int i,int t,int counter,int np,iset &Q,vecteur ×tamp,vecteur &l) {
9270 bool isweighted=is_weighted();
9271 ++counter;
9272 vertex &v=node(i);
9273 v.set_number(counter);
9274 gen w(1);
9275 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
9276 if (node(*it).subgraph()!=0)
9277 continue;
9278 if (*it!=t)
9279 Q.insert(*it);
9280 if (isweighted)
9281 get_edge_attribute(i,*it,_GT_ATTRIB_WEIGHT,w);
9282 if (is_strictly_greater(l[i]+w,l[*it],ctx))
9283 l[*it]=l[i]+w;
9284 timestamp[*it]=isweighted?l[*it]:gen(counter);
9285 }
9286 Q.erase(i);
9287 v.set_subgraph(1);
9288 if (Q.empty()) {
9289 node(t).set_number(node_count());
9290 return;
9291 }
9292 /* update blocks */
9293 vector<iset> B;
9294 vector<ipairs> blocks;
9295 find_blocks(blocks,0);
9296 int nb=blocks.size();
9297 B.resize(nb);
9298 for (vector<ipairs>::const_iterator it=blocks.begin();it!=blocks.end();++it) {
9299 iset &b=B[it-blocks.begin()];
9300 for (ipairs_iter jt=it->begin();jt!=it->end();++jt) {
9301 b.insert(jt->first);
9302 b.insert(jt->second);
9303 }
9304 }
9305 iset df;
9306 bool has_root=false;
9307 if (nb>1) { // G-v is not biconnected
9308 ivector cv;
9309 find_cut_vertices(cv,0);
9310 for (int k=nb;k-->0;) {
9311 iset &b=B[k];
9312 if (!has_root && b.find(t)!=b.end()) { // root block, delete it
9313 B.erase(B.begin()+k);
9314 has_root=true;
9315 } else {
9316 sets_intersection(cv,b,df);
9317 if (df.size()!=1) // non-leaf tree node, delete it
9318 B.erase(B.begin()+k);
9319 else b.erase(*df.begin()); // b is leaf node, detach it
9320 }
9321 }
9322 }
9323 /* recurse */
9324 for (vector<iset>::const_iterator it=B.begin();it!=B.end();++it) {
9325 sets_intersection(*it,Q,df);
9326 if (df.empty()) continue;
9327 gen_map m;
9328 gen ts,max_ts(undef),min_ts(undef);
9329 for (iset_iter jt=df.begin();jt!=df.end();++jt) {
9330 ts=timestamp[*jt];
9331 max_ts=is_undef(max_ts)?ts:_max(makevecteur(max_ts,ts),ctx);
9332 min_ts=is_undef(min_ts)?ts:_min(makevecteur(min_ts,ts),ctx);
9333 if (m.find(ts)==m.end())
9334 m[ts]=vecteur(1,*jt);
9335 else m[ts]._VECTptr->push_back(*jt);
9336 }
9337 vecteur &cand=*m[counter<=np?max_ts:min_ts]._VECTptr;
9338 int choice=(cand.size()==1?cand.front():cand[rand_integer(cand.size())]).val;
9339 strec(choice,t,counter,np,Q,timestamp,l);
9340 }
9341 }
9342
9343 /* impose parametrized st-orientation on this graph with parameter p in [0,1] */
parametrized_st_orientation(int s,int t,double p)9344 void graphe::parametrized_st_orientation(int s,int t,double p) {
9345 assert(p>=0 && p<=1);
9346 int n=node_count(),counter=0,np=(int)(n*p);
9347 vecteur timestamp(n,0),l(n,0);
9348 iset Q;
9349 Q.insert(s);
9350 unset_subgraphs(0);
9351 strec(s,t,counter,np,Q,timestamp,l);
9352 unset_subgraphs();
9353 }
9354
9355 /* greedy vertex coloring algorithm due to Biggs, also records vertex inclusion time */
greedy_vertex_coloring_biggs(ivector & ordering)9356 void graphe::greedy_vertex_coloring_biggs(ivector &ordering) {
9357 uncolor_all_nodes();
9358 int n=node_count(),k=0,i,maxdeg,d,col=0;
9359 ordering.resize(n);
9360 ivector_iter jt;
9361 while (k<n) {
9362 ++col;
9363 do {
9364 maxdeg=-1;
9365 i=-1;
9366 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9367 if (it->color()>0)
9368 continue;
9369 for (jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
9370 if (node(*jt).color()==col)
9371 break;
9372 }
9373 if (jt==it->neighbors().end() && (maxdeg<0 || (d=it->neighbors().size())>maxdeg)) {
9374 maxdeg=d;
9375 i=it-nodes.begin();
9376 }
9377 }
9378 if (i>=0) {
9379 node(i).set_color(col);
9380 ordering[k++]=i;
9381 }
9382 } while (i>=0);
9383 }
9384 }
9385
9386 /* classical greedy vertex coloring algorithm, time complexity O(n+m) */
greedy_vertex_coloring(const ivector & p)9387 int graphe::greedy_vertex_coloring(const ivector &p) {
9388 if (is_directed()) {
9389 graphe G(ctx,false);
9390 underlying(G);
9391 return G.greedy_vertex_coloring(p);
9392 }
9393 uncolor_all_nodes();
9394 int c=0,k;
9395 std::set<int> used;
9396 for (ivector_iter it=p.begin();it!=p.end();++it) {
9397 vertex &v=node(*it);
9398 if (c==0) {
9399 v.set_color(++c);
9400 continue;
9401 }
9402 used.clear();
9403 for (ivector_iter jt=v.neighbors().begin();jt!=v.neighbors().end();++jt) {
9404 vertex &v=node(*jt);
9405 if (v.color()>0)
9406 used.insert(v.color());
9407 }
9408 k=1;
9409 for (std::set<int>::const_iterator jt=used.begin();jt!=used.end();++jt) {
9410 if (*jt>k)
9411 break;
9412 ++k;
9413 }
9414 v.set_color(k);
9415 if (k>c)
9416 c=k;
9417 }
9418 return c;
9419 }
9420
9421 /* extract colors of the vertices and return them in order */
get_node_colors(ivector & colors)9422 void graphe::get_node_colors(ivector &colors) {
9423 colors.resize(node_count());
9424 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9425 colors[it-nodes.begin()]=it->color();
9426 }
9427 }
9428
9429 /* return true iff the graph is bipartite, time complexity O(n+m) */
is_bipartite(ivector & V1,ivector & V2,int sg)9430 bool graphe::is_bipartite(ivector &V1,ivector &V2,int sg) {
9431 assert(node_queue.empty());
9432 if (is_directed()) {
9433 graphe G(ctx,false);
9434 underlying(G);
9435 return G.is_bipartite(V1,V2,sg);
9436 }
9437 uncolor_all_nodes(-1,sg);
9438 node(0).set_color(1);
9439 node_iter nt=nodes.begin();
9440 for (;nt!=nodes.end();++nt) {
9441 if (sg<0 || nt->subgraph()==sg)
9442 break;
9443 }
9444 assert(nt!=nodes.end());
9445 node_queue.push(nt-nodes.begin());
9446 int i;
9447 while (!node_queue.empty()) {
9448 i=node_queue.front();
9449 node_queue.pop();
9450 vertex &v=node(i);
9451 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
9452 vertex &w=node(*it);
9453 if (sg>=0 && w.subgraph()!=sg)
9454 continue;
9455 if (w.color()==-1) {
9456 w.set_color(1-v.color());
9457 node_queue.push(*it);
9458 } else if (w.color()==v.color()) {
9459 clear_node_queue();
9460 return false;
9461 }
9462 }
9463 }
9464 V1.clear();
9465 V2.clear();
9466 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9467 if (sg>=0 && it->subgraph()!=sg)
9468 continue;
9469 if (it->color()==1)
9470 V1.push_back(it-nodes.begin());
9471 else V2.push_back(it-nodes.begin());
9472 }
9473 return true;
9474 }
9475
9476 /* place vertices from partitions v1 and v2 on two parallel lines */
make_bipartite_layout(layout & x,const ivector & p1,const ivector & p2)9477 void graphe::make_bipartite_layout(layout &x,const ivector &p1,const ivector &p2) {
9478 double aspect_ratio;
9479 int n1=p1.size(),n2=p2.size(),n=std::max(n1,n2);
9480 assert(n1>1 && n2>1);
9481 if (n<3)
9482 aspect_ratio=1.0;
9483 else if (n<5)
9484 aspect_ratio=PLASTIC_NUMBER;
9485 else if (n<8)
9486 aspect_ratio=PLASTIC_NUMBER_2;
9487 else
9488 aspect_ratio=PLASTIC_NUMBER_3;
9489 double step1=aspect_ratio/(double)(n1-1),step2=aspect_ratio/(double)(n2-1),xpos=0.0,ypos=1.0;
9490 x.resize(node_count());
9491 for (ivector_iter it=p1.begin();it!=p1.end();++it) {
9492 point &p=x[*it];
9493 p.resize(2);
9494 p.front()=xpos;
9495 p.back()=ypos;
9496 xpos+=step1;
9497 }
9498 xpos=ypos=0.0;
9499 for (ivector_iter it=p2.begin();it!=p2.end();++it) {
9500 point &p=x[*it];
9501 p.resize(2);
9502 p.front()=xpos;
9503 p.back()=ypos;
9504 xpos+=step2;
9505 }
9506 }
9507
9508 /* construct the plane dual of a planar graph with the given faces with time complexity O(n),
9509 * each face must be a list of vertex indices */
make_plane_dual(const ivectors & faces)9510 void graphe::make_plane_dual(const ivectors &faces) {
9511 this->clear();
9512 set_directed(false);
9513 vecteur labels;
9514 make_default_labels(labels,faces.size());
9515 reserve_nodes(labels.size());
9516 add_nodes(labels);
9517 int nc=0;
9518 for (ivectors_iter it=faces.begin();it!=faces.end();++it) {
9519 for (ivector_iter jt=it->begin();jt!=it->end();++jt) {
9520 if (*jt>nc)
9521 nc=*jt;
9522 }
9523 }
9524 edgemap emap(++nc);
9525 map<int,int>::const_iterator et;
9526 int i,j,v,w,f,n;
9527 for (ivectors_iter it=faces.begin();it!=faces.end();++it) {
9528 f=it-faces.begin();
9529 const ivector &face=*it;
9530 n=face.size();
9531 for (int k=0;k<n;++k) {
9532 i=face[k];
9533 j=face[(k+1)%n];
9534 v=i<j?i:j;
9535 w=i<j?j:i;
9536 map<int,int> &m=emap[v];
9537 if ((et=m.find(w))==m.end())
9538 m[w]=f;
9539 else add_edge(f,et->second);
9540 }
9541 }
9542 }
9543
9544 /* return the number of different colors adjacent to the i-th vertex in a partially colored graph */
saturation_degree(const vertex & v,std::set<int> & colors) const9545 int graphe::saturation_degree(const vertex &v,std::set<int> &colors) const {
9546 int i,c;
9547 colors.clear();
9548 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
9549 i=*it;
9550 const vertex &w=node(i);
9551 if ((c=w.color())>0)
9552 colors.insert(c);
9553 }
9554 return colors.size();
9555 }
9556
9557 /* return the degree of v in the uncolored subgraph of this graph */
uncolored_degree(const vertex & v) const9558 int graphe::uncolored_degree(const vertex &v) const {
9559 int deg=0;
9560 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
9561 if (node(*it).color()==0)
9562 ++deg;
9563 }
9564 return deg;
9565 }
9566
9567 /* return true iff this graph has at least one uncolored (white) vertex */
is_partially_colored() const9568 bool graphe::is_partially_colored() const {
9569 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9570 if (it->color()==0)
9571 return true;
9572 }
9573 return false;
9574 }
9575
9576 /* a heuristic algorithm by D.Bre1az for nearly optimal vertex coloring (time complexity O(n*m)),
9577 * operates on a partially colored graph, returns the number of colors */
dsatur()9578 void graphe::dsatur() {
9579 int col,i,sat,maxsat,deg,maxdeg=0;
9580 std::set<int> colors,maxcolors;
9581 ivector indices;
9582 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9583 if (it->color()==0)
9584 indices.push_back(it-nodes.begin());
9585 }
9586 if (indices.empty())
9587 return;
9588 ivector::iterator pos;
9589 do {
9590 maxsat=-1;
9591 i=-1;
9592 for (ivector::iterator it=indices.begin();it!=indices.end();++it) {
9593 const vertex &v=node(*it);
9594 if ((sat=saturation_degree(v,colors))>maxsat ||
9595 (sat==maxsat && (deg=uncolored_degree(v))>maxdeg)) {
9596 if (sat==maxsat)
9597 maxdeg=deg;
9598 maxsat=sat;
9599 maxcolors=colors;
9600 i=*it;
9601 pos=it;
9602 }
9603 }
9604 if (i>=0) {
9605 col=1;
9606 for (std::set<int>::const_iterator it=maxcolors.begin();it!=maxcolors.end();++it) {
9607 if (*it==col)
9608 ++col;
9609 else break;
9610 }
9611 node(i).set_color(col);
9612 indices.erase(pos);
9613 }
9614 } while (i>=0);
9615 }
9616
9617 /* return the total number of different nonzero vertex colors in this graph */
color_count() const9618 int graphe::color_count() const {
9619 std::set<int> colors;
9620 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9621 colors.insert(it->color());
9622 }
9623 return colors.size();
9624 }
9625
9626 /* return true iff the vertices can be colored using at most k different colors,
9627 * the vertices will be colored after the function returns */
is_vertex_colorable(int k)9628 bool graphe::is_vertex_colorable(int k) {
9629 assert(k>=0);
9630 if (k==0) {
9631 uncolor_all_nodes();
9632 return true;
9633 }
9634 if (k>node_count()) {
9635 message("Warning: there are more colors than vertices");
9636 return false;
9637 }
9638 /* try greedy coloring first (linear time), use random order of vertices */
9639 ivector sigma=rand_permu(node_count());
9640 if (greedy_vertex_coloring(sigma)<=k)
9641 return true;
9642 /* next try dsatur algorithm (quadratic time) */
9643 uncolor_all_nodes();
9644 dsatur();
9645 if (color_count()<=k)
9646 return true;
9647 /* finally resort to solving MIP problem */
9648 return exact_vertex_coloring(k)!=0;
9649 }
9650
9651 /* return the lower and the upper bound for chromatic number (inclusive) */
chromatic_number_bounds()9652 graphe::ipair graphe::chromatic_number_bounds() {
9653 /* the lower bound is the size of maximum clique */
9654 ivector clique;
9655 ostergard ost(this,3.0); // with timeout
9656 int lb=ost.maxclique(clique);
9657 /* the upper bound is given by heuristic dsatur algorithm */
9658 uncolor_all_nodes();
9659 for (ivector_iter it=clique.begin();it!=clique.end();++it) {
9660 node(*it).set_color(it-clique.begin()+1);
9661 }
9662 dsatur();
9663 int ub=color_count();
9664 return make_pair(lb,ub);
9665 }
9666
9667 /* store custom vertex coordinates */
store_layout(const layout & x)9668 void graphe::store_layout(const layout &x) {
9669 assert(int(x.size())>=node_count());
9670 for (layout_iter it=x.begin();it!=x.end();++it) {
9671 vertex &v=node(it-x.begin());
9672 v.set_attribute(_GT_ATTRIB_POSITION,point2gen(*it));
9673 }
9674 }
9675
9676 /* retrieve the previously stored layout, return true iff successful */
has_stored_layout(layout & x) const9677 bool graphe::has_stored_layout(layout &x) const {
9678 x.resize(node_count());
9679 attrib_iter ait;
9680 int dim=0;
9681 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9682 const attrib &attr=it->attributes();
9683 point &p=x[it-nodes.begin()];
9684 if ((ait=attr.find(_GT_ATTRIB_POSITION))==attr.end() ||
9685 !gen2point(ait->second,p) || (dim>0 && int(p.size())!=dim))
9686 return false;
9687 if (dim==0)
9688 dim=p.size();
9689 }
9690 return true;
9691 }
9692
bipartite_matching_bfs(ivector & dist)9693 bool graphe::bipartite_matching_bfs(ivector &dist) {
9694 assert(node_queue.empty());
9695 int u,v;
9696 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9697 if (it->color()!=1)
9698 continue;
9699 u=it-nodes.begin();
9700 if (it->number()==0) {
9701 dist[u+1]=0;
9702 node_queue.push(u);
9703 } else dist[u+1]=RAND_MAX;
9704 }
9705 dist.front()=RAND_MAX;
9706 while (!node_queue.empty()) {
9707 u=node_queue.front();
9708 node_queue.pop();
9709 if (dist[u+1]<dist.front()) {
9710 vertex &U=node(u);
9711 for (ivector_iter it=U.neighbors().begin();it!=U.neighbors().end();++it) {
9712 v=*it;
9713 vertex &V=node(v);
9714 if (dist[V.number()]==RAND_MAX) {
9715 dist[V.number()]=dist[u+1]+1;
9716 node_queue.push(V.number()-1);
9717 }
9718 }
9719 }
9720 }
9721 return dist.front()!=RAND_MAX;
9722 }
9723
bipartite_matching_dfs(int u,ivector & dist)9724 bool graphe::bipartite_matching_dfs(int u,ivector &dist) {
9725 if (u>0) {
9726 int v;
9727 vertex &U=node(u-1);
9728 for (ivector_iter it=U.neighbors().begin();it!=U.neighbors().end();++it) {
9729 v=*it;
9730 vertex &V=node(v);
9731 if (dist[V.number()]==dist[u]+1) {
9732 if (bipartite_matching_dfs(V.number(),dist)) {
9733 V.set_number(u);
9734 U.set_number(v+1);
9735 return true;
9736 }
9737 }
9738 }
9739 dist[u]=RAND_MAX;
9740 return false;
9741 }
9742 return true;
9743 }
9744
9745 /* obtain maximum matching in bipartite graph using Hopcroft-Karp algorithm */
bipartite_matching(const ivector & p1,const ivector & p2,ipairs & matching)9746 int graphe::bipartite_matching(const ivector &p1,const ivector &p2,ipairs &matching) {
9747 for (vector<vertex>::iterator it=nodes.begin();it!=nodes.end();++it) {
9748 it->set_number(0);
9749 }
9750 for (ivector_iter it=p1.begin();it!=p1.end();++it) {
9751 set_node_color(*it,1);
9752 }
9753 for (ivector_iter it=p2.begin();it!=p2.end();++it) {
9754 set_node_color(*it,2);
9755 }
9756 ivector dist(node_count()+1);
9757 int count=0,u,v;
9758 while (bipartite_matching_bfs(dist)) {
9759 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9760 if (it->color()!=1)
9761 continue;
9762 u=it-nodes.begin();
9763 if (it->number()==0 && bipartite_matching_dfs(u+1,dist))
9764 ++count;
9765 }
9766 }
9767 /* extract matching */
9768 matching.clear();
9769 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9770 if (it->color()!=1)
9771 continue;
9772 u=it-nodes.begin();
9773 v=it->number();
9774 if (v>0)
9775 matching.push_back(make_pair(std::min(u,v-1),std::max(u,v-1)));
9776 }
9777 return count; // size of the matching
9778 }
9779
9780 /* construct the line graph of this graph */
line_graph(graphe & G,ipairs & E) const9781 void graphe::line_graph(graphe &G,ipairs &E) const {
9782 assert(supports_attributes() || !G.supports_attributes());
9783 if (E.empty())
9784 get_edges_as_pairs(E);
9785 G.clear();
9786 G.reserve_nodes(E.size());
9787 if (G.supports_attributes()) {
9788 vecteur labels;
9789 gen label;
9790 for (ipairs_iter it=E.begin();it!=E.end();++it) {
9791 label=_cat(makesequence(node_label(it->first),str2gen("-",true),node_label(it->second)),ctx);
9792 labels.push_back(label);
9793 }
9794 G.add_nodes(labels);
9795 } else G.add_nodes(E.size());
9796 int i,j;
9797 for (ipairs_iter it=E.begin();it!=E.end();++it) {
9798 i=it-E.begin();
9799 for (ipairs_iter jt=it+1;jt!=E.end();++jt) {
9800 j=jt-E.begin();
9801 if (edges_incident(*it,*jt))
9802 G.add_edge(i,j);
9803 }
9804 }
9805 }
9806
9807 /* construct the transitive closure of this graph */
transitive_closure(graphe & G,bool weighted)9808 void graphe::transitive_closure(graphe &G,bool weighted) {
9809 int n=node_count();
9810 bool isdir=is_directed(),iswei=is_weighted();
9811 G.clear();
9812 G.set_directed(isdir);
9813 G.set_weighted(weighted);
9814 G.reserve_nodes(n);
9815 G.add_nodes(vertices());
9816 if (weighted) {
9817 matrice m;
9818 gen wgh;
9819 ivector dist,J(n-1);
9820 int cnt;
9821 if (iswei)
9822 allpairs_distance(m);
9823 for (int i=0;i<n;++i) {
9824 if (!iswei) {
9825 cnt=0;
9826 for (int k=0;k<n;++k) {
9827 if (k!=i)
9828 J[cnt++]=k;
9829 }
9830 distance(i,J,dist);
9831 }
9832 for (int j=isdir?0:i+1;j<n;++j) {
9833 if (i==j)
9834 continue;
9835 if ((iswei && !is_inf(wgh=m[i][j])) ||
9836 (!iswei && is_positive(wgh=dist[j<i?j:j-1],ctx)))
9837 G.add_edge(i,j,wgh);
9838 }
9839 }
9840 } else {
9841 for (int i=0;i<n;++i) {
9842 dfs(i,false);
9843 for (int j=isdir?0:i+1;j<n;++j) {
9844 if (i==j)
9845 continue;
9846 if (node(j).is_visited())
9847 G.add_edge(i,j);
9848 }
9849 }
9850 }
9851 }
9852
9853 /* return true iff this graph is isomorphic to other, also obtain an isomorphism */
is_isomorphic(const graphe & other,map<int,int> & isom) const9854 int graphe::is_isomorphic(const graphe &other,map<int,int> &isom) const {
9855 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
9856 assert(is_directed()==other.is_directed());
9857 int n=node_count(),sz;
9858 if (other.node_count()!=n)
9859 return 0;
9860 int *adj1=to_array(sz);
9861 int *adj2=other.to_array(sz);
9862 int *sigma=new int[n];
9863 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
9864 bool res=nautywrapper_is_isomorphic(is_directed()?1:0,n,adj1,adj2,sigma)!=0;
9865 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
9866 if (res) {
9867 /* obtain the isomorphism */
9868 isom.clear();
9869 for (int i=0;i<n;++i) {
9870 isom[i]=sigma[i];
9871 }
9872 }
9873 delete[] adj1;
9874 delete[] adj2;
9875 delete[] sigma;
9876 return res;
9877 #else
9878 return -1;
9879 #endif
9880 }
9881
9882 /* convert a sequence of nd digits to nonnegative integer */
digits2int(char * digits,int nd)9883 int digits2int(char *digits,int nd) {
9884 int n=1,res=0;
9885 for (int i=nd;i-->0;) {
9886 res+=*(digits+i)*n;
9887 n*=10;
9888 }
9889 return res;
9890 }
9891
9892 /* return the set of generators of the automorphism group of this graph */
aut_generators() const9893 gen graphe::aut_generators() const {
9894 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
9895 int n=node_count(),ofs=array_start(ctx),sz;
9896 vecteur out(0);
9897 if (n>0) {
9898 int *adj=to_array(sz);
9899 FILE *f=tmpfile();
9900 if (f==NULL) {
9901 message ("Error: failed to create temporary file");
9902 return undef;
9903 }
9904 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
9905 nautywrapper_aut_generators(is_directed()?1:0,n,adj,f);
9906 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
9907 /* parse the generators and output them as a sequence of
9908 * permutations, each in form of a list of disjoint cycles */
9909 int sz=ftell(f);
9910 rewind(f);
9911 int i=0,nd=0;
9912 char c;
9913 vecteur perm,cycle;
9914 char digits[32];
9915 for (int cnt=0;cnt<sz;++cnt) {
9916 c=fgetc(f);
9917 if (c=='(')
9918 cycle.clear();
9919 else if (c==')') {
9920 cycle.push_back(ofs+digits2int(digits,nd));
9921 perm.push_back(cycle);
9922 nd=0;
9923 } else if (c=='\n') {
9924 out.push_back(gen(perm,_LIST__VECT));
9925 perm.clear();
9926 } else if (c>47 && c<58)
9927 digits[nd++]=c-48;
9928 else if (c==32) {
9929 cycle.push_back(ofs+digits2int(digits,nd));
9930 nd=0;
9931 }
9932 ++i;
9933 }
9934 fclose(f);
9935 delete[] adj;
9936 }
9937 return gen(out,_LIST__VECT);
9938 #else
9939 return gensizeerr("nauty library is required for finding graph automorphisms");
9940 #endif
9941 }
9942
9943 /* return the canonical labeling of this graph as a permutation */
canonical_labeling(ivector & lab) const9944 bool graphe::canonical_labeling(ivector &lab) const {
9945 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
9946 int n=node_count(),sz;
9947 if (n==0)
9948 return false;
9949 int *adj=to_array(sz);
9950 int *clab=new int[n];
9951 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
9952 nautywrapper_canonical(is_directed()?1:0,n,adj,clab,NULL,NULL);
9953 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
9954 lab.resize(n);
9955 for (int i=0;i<n;++i) {
9956 lab[i]=clab[i];
9957 }
9958 delete[] adj;
9959 delete[] clab;
9960 return true;
9961 #else
9962 return false;
9963 #endif
9964 }
9965
9966 /* construct the closure of this graph and store it to G, complexity O(n^3) */
bondy_chvatal_closure(graphe & G,ivector & d)9967 bool graphe::bondy_chvatal_closure(graphe &G,ivector &d) {
9968 underlying(G);
9969 int n=node_count(),di;
9970 bool yes=false,have_pair;
9971 do {
9972 have_pair=false;
9973 for (int i=0;i<n && !have_pair;++i) {
9974 di=d[i];
9975 for (int j=i+1;j<n;++j) {
9976 if (!G.has_edge(i,j) && di+d[j]>=n) {
9977 G.add_edge(i,j);
9978 ++d[i]; ++d[j];
9979 yes=have_pair=true;
9980 break;
9981 }
9982 }
9983 }
9984 } while (have_pair);
9985 return yes;
9986 }
9987
9988 /* return 1 if the graph is Hamiltonian, 0 if it is not and -1 if inconclusive */
hamcond(bool make_closure)9989 int graphe::hamcond(bool make_closure) {
9990 /* test biconnectivity, complexity O(n) */
9991 if (!is_biconnected())
9992 return 0;
9993 int mindeg=RAND_MAX,deg,n=node_count(),m=edge_count();
9994 ivector d=vecteur_2_vector_int(degree_sequence());
9995 /* Dirac criterion, complexity O(n) */
9996 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
9997 if ((deg=d[it-nodes.begin()]=it->neighbors().size())<mindeg)
9998 mindeg=deg;
9999 }
10000 if (2*mindeg>=n)
10001 return 1;
10002 ivector V1,V2,v;
10003 /* unbalanced bipartite graph is not Hamiltonian, complexity O(n+m) */
10004 if (is_bipartite(V1,V2) && V1.size()!=V2.size())
10005 return 0;
10006 /* Ore criterion, complexity O(n^2) */
10007 bool yes=true;
10008 for (int i=0;i<n && yes;++i) {
10009 deg=d[i];
10010 for (int j=i+1;j<n;++j) {
10011 if (!has_edge(i,j) && deg+d[j]<n) {
10012 yes=false;
10013 break;
10014 }
10015 }
10016 }
10017 if (yes) return 1;
10018 if (make_closure) {
10019 /* apply the Bondy-Chvátal theorem: the graph is Hamiltonian if
10020 and only if its closure is Hamiltonian, complexity O(n^2) */
10021 graphe G(ctx);
10022 if (bondy_chvatal_closure(G,d))
10023 return G.hamcond(false);
10024 }
10025 if (double(m)/(double(n*n)>1.0-2.0/(1.0+std::exp(.0015*double(n))))) {
10026 /* Nash-Williams criterion */
10027 int inum=maximum_independent_set(v);
10028 if (3*mindeg>=std::max(n+2,3*inum))
10029 return 1;
10030 }
10031 return -1;
10032 }
10033
10034 /* return true iff the graph is Hamiltonian */
is_hamiltonian(ivector & hc)10035 bool graphe::is_hamiltonian(ivector &hc) {
10036 hc.clear();
10037 if (!is_directed()) {
10038 switch (hamcond()) {
10039 case 0: return false;
10040 case 1: return true;
10041 default: break;
10042 }
10043 } else {
10044 ivectors components;
10045 strongly_connected_components(components);
10046 if (components.size()>1) return false; // graph is not strongly connected
10047 vecteur dv=degree_sequence();
10048 bool isham=true;
10049 int n=node_count();
10050 for (const_iterateur it=dv.begin();it!=dv.end();++it) {
10051 if (it->val<n) {
10052 isham=false;
10053 break;
10054 }
10055 }
10056 if (isham) return true;
10057 isham=true;
10058 for (int i=0;isham && i<n;++i) {
10059 for (int j=0;j<n;++j) {
10060 if (i==j) continue;
10061 if (!has_edge(i,j) && !has_edge(j,i) && (dv[i]+dv[j]).val<2*n-1) {
10062 isham=false;
10063 break;
10064 }
10065 }
10066 }
10067 if (isham) return true;
10068 }
10069 return hamcycle(hc);
10070 }
10071
hamcycle_recurse(ivector & path,int pos)10072 bool graphe::hamcycle_recurse(ivector &path,int pos) {
10073 if (pos==node_count()) return has_edge(path[pos-1],path[0]);
10074 const vertex &v=node(path[pos-1]);
10075 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
10076 vertex &w=node(*it);
10077 if (w.is_visited()) continue;
10078 path[pos]=*it;
10079 w.set_visited(true);
10080 if (hamcycle_recurse(path,pos+1)) return true;
10081 w.set_visited(false);
10082 }
10083 return false;
10084 }
10085
hamcycle(ivector & path)10086 bool graphe::hamcycle(ivector &path) {
10087 int n=node_count();
10088 path.resize(n+1);
10089 unvisit_all_nodes();
10090 path[0]=0;
10091 nodes[0].set_visited(true);
10092 if (!hamcycle_recurse(path,1)) return false;
10093 path[n]=path[0];
10094 return true;
10095 }
10096
10097 /*
10098 * TSP CLASS IMPLEMENTATION
10099 */
10100
10101 #ifdef HAVE_LIBGLPK
10102
10103 /* MINIMAL CUT implementation, adapted from glpk/examples/tsp (maxflow.c, mincut.c and main.c)
10104 * Originally written by Andrew Makhorin <mao@gnu.org>
10105 */
10106
10107 /* compute maximal flow */
max_flow(int nn,int nedg,const ivector & beg,const ivector & end,const ivector & cap,int s,int t,ivector & x)10108 int graphe::tsp::max_flow(int nn,int nedg,const ivector &beg,
10109 const ivector &end,const ivector &cap,int s,int t,
10110 ivector &x) {
10111 int k;
10112 assert(nn>=2);
10113 assert(nedg>=0);
10114 assert(1<=s && s<=nn);
10115 assert(1<=t && t<=nn);
10116 assert(s!=t);
10117 for (k=0; k<nedg; k++) {
10118 assert(1<=beg[k] && beg[k]<end[k] && end[k]<=nn && cap[k]>0);
10119 }
10120 glp_prob *lp;
10121 glp_smcp smcp;
10122 int i,nz,flow,*rn,*cn;
10123 double temp,*aa;
10124 lp=glp_create_prob();
10125 glp_add_rows(lp,nn);
10126 for (i=1;i<=nn;++i) {
10127 glp_set_row_bnds(lp,i,GLP_FX,0.0,0.0);
10128 }
10129 glp_add_cols(lp,nedg+1);
10130 for (k=0; k<nedg; k++) {
10131 glp_set_col_bnds(lp,k+1,GLP_DB,-cap[k],+cap[k]);
10132 }
10133 glp_set_col_bnds(lp,nedg+1,GLP_FR,0.0,0.0);
10134 rn=new int[1+2*(nedg+1)];
10135 cn=new int[1+2*(nedg+1)];
10136 aa=new double[1+2*(nedg+1)];
10137 nz=0;
10138 for (k=0;k<nedg;k++) {
10139 rn[++nz]=beg[k]; cn[nz]=k+1; aa[nz]=-1.0;
10140 rn[++nz]=end[k]; cn[nz]=k+1; aa[nz]=+1.0;
10141 }
10142 rn[++nz]=t; cn[nz]=nedg+1; aa[nz]=-1.0;
10143 rn[++nz]=s; cn[nz]=nedg+1; aa[nz]=+1.0;
10144 assert(nz==2*(nedg+1));
10145 glp_load_matrix(lp,nz,rn,cn,aa);
10146 delete[] rn;
10147 delete[] cn;
10148 delete[] aa;
10149 glp_set_obj_dir(lp,GLP_MAX);
10150 glp_set_obj_coef(lp,nedg+1,1.0);
10151 glp_term_out(0);
10152 glp_adv_basis(lp,0);
10153 glp_term_out(1);
10154 glp_init_smcp(&smcp);
10155 smcp.msg_lev=GLP_MSG_OFF;
10156 assert(glp_simplex(lp,&smcp)==0);
10157 assert(glp_get_status(lp)==GLP_OPT);
10158 for (k=0;k<nedg;k++) {
10159 temp=glp_get_col_prim(lp,k+1);
10160 x[k]=(int)floor(temp+.5);
10161 assert(std::abs(x[k]-temp)<=1e-6);
10162 }
10163 temp=glp_get_col_prim(lp,nedg+1);
10164 flow=(int)floor(temp+.5);
10165 assert(std::abs(flow-temp)<=1e-6);
10166 glp_delete_prob(lp);
10167 return flow;
10168 }
10169
10170 /* find min (s,t)-cut for known max flow */
min_st_cut(int nn,int nedg,const ivector & beg,const ivector & end,const ivector & cap,int s,int t,const ivector & x,ivector & cut)10171 int graphe::tsp::min_st_cut(int nn,int nedg,const ivector &beg,
10172 const ivector &end,const ivector &cap,int s,int t,
10173 const ivector &x,ivector &cut) {
10174 int i,j,k,p,q,temp;
10175 ivector &head1=mincut_data[18]; if (int(head1.size())<nn) head1.resize(nn);
10176 ivector &head2=mincut_data[19]; if (int(head2.size())<nn) head2.resize(nn);
10177 ivector &next1=mincut_data[20]; if (int(next1.size())<nn) next1.resize(nn);
10178 ivector &next2=mincut_data[21]; if (int(next2.size())<nn) next2.resize(nn);
10179 for (i=0;i<nn;i++) head1[i]=head2[i]=0;
10180 for (k=0;k<nedg;k++) {
10181 i=beg[k]-1; next1[k]=head1[i]; head1[i]=k+1;
10182 j=end[k]-1; next2[k]=head2[j]; head2[j]=k+1;
10183 }
10184 ivector &list=mincut_data[4]; list.resize(nn);
10185 for (i=0;i<nn;i++) cut[i]=0;
10186 p=q=0; list[0]=s; cut[s-1]=1;
10187 while (p<=q) {
10188 i=list[p++];
10189 for (k=head1[i-1];k!=0;k=next1[k-1]) {
10190 j=end[k-1];
10191 assert(beg[k-1]==i);
10192 if (cut[j-1]==0 && x[k-1]<+cap[k-1]) {
10193 list[++q]=j; cut[j-1]=1;
10194 }
10195 }
10196 for (k=head2[i-1];k!=0;k=next2[k-1]) {
10197 j=beg[k-1];
10198 assert(end[k-1]==i);
10199 if (cut[j-1]==0 && x[k-1]>-cap[k-1]) {
10200 list[++q]=j; cut[j-1]=1;
10201 }
10202 }
10203 }
10204 assert(!cut[t-1]);
10205 temp=0;
10206 for (k=0;k<nedg;k++) {
10207 i=beg[k],j=end[k];
10208 if ((cut[i-1] && !cut[j-1]) || (!cut[i-1] && cut[j-1]))
10209 temp+=cap[k];
10210 }
10211 return temp;
10212 }
10213
10214 /* find min cut with Stoer and Wagner algorithm */
minimal_cut(int nn,int nedg,const ivector & beg,const ivector & end,const ivector & cap,ivector & cut)10215 int graphe::tsp::minimal_cut(int nn,int nedg,const ivector &beg,
10216 const ivector &end,const ivector &cap,ivector &cut) {
10217 int k;
10218 assert(nn>=2);
10219 assert(nedg>=0);
10220 for (k=0;k<nedg;k++) {
10221 assert(1<=beg[k] && beg[k]<end[k] && end[k]<=nn);
10222 assert(cap[k]>0);
10223 }
10224 int i,j,min_cut,flow,temp,I,J,K,S,T,DEG,NV,NE;
10225 ivector &head1=mincut_data[0]; if (int(head1.size())<nn) head1.resize(nn);
10226 ivector &head2=mincut_data[1]; if (int(head2.size())<nn) head2.resize(nn);
10227 ivector &next1=mincut_data[2]; if (int(next1.size())<nedg) next1.resize(nedg);
10228 ivector &next2=mincut_data[3]; if (int(next2.size())<nedg) next2.resize(nedg);
10229 for (i=0;i<nn;i++) head1[i]=head2[i]=0;
10230 for (k=0;k<nedg;k++) {
10231 i=beg[k]; next1[k]=head1[i-1]; head1[i-1]=k+1;
10232 j=end[k]; next2[k]=head2[j-1]; head2[j-1]=k+1;
10233 }
10234 NV=nn;
10235 ivector &HEAD=mincut_data[4]; if (int(HEAD.size())<nn) HEAD.resize(nn);
10236 ivector &NEXT=mincut_data[5]; if (int(NEXT.size())<nn) NEXT.resize(nn);
10237 ivector &NUMB=mincut_data[6]; if (int(NUMB.size())<nn) NUMB.resize(nn);
10238 for (i=0;i<nn;i++) {
10239 HEAD[i]=i+1; NEXT[i]=0; NUMB[i]=i+1;
10240 }
10241 ivector &BEG=mincut_data[7]; if (int(BEG.size())<nedg) BEG.resize(nedg);
10242 ivector &END=mincut_data[8]; if (int(END.size())<nedg) END.resize(nedg);
10243 ivector &CAP=mincut_data[9]; if (int(CAP.size())<nedg) CAP.resize(nedg);
10244 ivector &X=mincut_data[10]; if (int(X.size())<nedg) X.resize(nedg);
10245 ivector &ADJ=mincut_data[11]; if (int(ADJ.size())<nn) ADJ.resize(nn);
10246 ivector &SUM=mincut_data[12]; if (int(SUM.size())<nn) SUM.resize(nn);
10247 ivector &CUT=mincut_data[13]; if (int(CUT.size())<nn) CUT.resize(nn);
10248 min_cut=RAND_MAX;
10249 while (NV>1) {
10250 for (I=0;I<NV;I++) SUM[I]=0.0;
10251 for (I=1;I<=NV;I++) {
10252 DEG=0;
10253 for (i=HEAD[I-1];i!=0;i=NEXT[i-1]) {
10254 for (k=head1[i-1];k!=0;k=next1[k-1]) {
10255 j=end[k-1];
10256 J=NUMB[j-1];
10257 if (I>=J)
10258 continue;
10259 if (SUM[J-1]==0.0)
10260 ADJ[DEG++]=J;
10261 assert(cap[k-1]>0.0);
10262 SUM[J-1]+=cap[k-1];
10263 }
10264 for (k=head2[i-1];k!=0;k=next2[k-1]) {
10265 j=beg[k-1];
10266 J=NUMB[j-1];
10267 if (I>=J)
10268 continue;
10269 if (SUM[J-1]==0.0)
10270 ADJ[DEG++]=J;
10271 assert(cap[k-1]>0.0);
10272 SUM[J-1]+=cap[k-1];
10273 }
10274 }
10275 NE=0;
10276 for (K=0;K<DEG;K++) {
10277 assert(NE<nedg);
10278 J=ADJ[K];
10279 BEG[NE]=I; END[NE]=J; CAP[NE]=SUM[J-1];
10280 SUM[J-1]=0.0;
10281 ++NE;
10282 }
10283 }
10284 S=1; T=NV;
10285 flow=max_flow(NV,NE,BEG,END,CAP,S,T,X);
10286 if (min_cut>flow)
10287 { min_cut=flow;
10288 temp=min_st_cut(NV,NE,BEG,END,CAP,S,T,X,CUT);
10289 assert(flow==temp);
10290 for (i=0;i<nn;i++) cut[i]=CUT[NUMB[i]-1];
10291 if (min_cut==0)
10292 break;
10293 }
10294 assert(T==NV);
10295 for (i=HEAD[T-1];i!=0;i=NEXT[i-1]) NUMB[i-1]=S;
10296 i=HEAD[S-1];
10297 assert(i!=0);
10298 while (NEXT[i-1]!=0)
10299 i=NEXT[i-1];
10300 NEXT[i-1]=HEAD[T-1];
10301 NV--;
10302 }
10303 return min_cut;
10304 }
10305
10306 /* TSP constructor */
tsp(graphe * gr)10307 graphe::tsp::tsp(graphe *gr) {
10308 G=gr;
10309 sg=-1;
10310 isdirected=G->is_directed();
10311 isweighted=G->is_weighted();
10312 ipairs E;
10313 G->get_edges_as_pairs(E);
10314 edges_comparator comp(G);
10315 sort(E.begin(),E.end(),comp); // sort edges by weight (ascending)
10316 nv=G->node_count();
10317 ne=E.size();
10318 tour.reserve(nv);
10319 obj.resize(ne);
10320 xev.resize(ne);
10321 can_branch.resize(ne);
10322 coeff=new double[ne+1];
10323 indices=new int[ne+1];
10324 visited=new bool[nv];
10325 arcs=new arc[ne];
10326 sg_vertices=new int[nv];
10327 sg_edges=new int[ne];
10328 int i;
10329 for (ipairs_iter it=E.begin();it!=E.end();++it) {
10330 i=it-E.begin();
10331 arc &a=arcs[i];
10332 a.head=it->second;
10333 a.tail=it->first;
10334 loc_map[a.tail][a.head]=i;
10335 a.sg_index=-1;
10336 weight_map[a.tail][a.head]=_evalf(G->weight(*it),G->giac_context()).DOUBLE_val();
10337 }
10338 is_undir_weighted=!isdirected && isweighted;
10339 }
10340
10341 /* TSP destructor */
~tsp()10342 graphe::tsp::~tsp() {
10343 delete[] coeff;
10344 delete[] indices;
10345 delete[] visited;
10346 delete[] arcs;
10347 delete[] sg_vertices;
10348 delete[] sg_edges;
10349 }
10350
10351 /* create an edge or arc */
make_edge(int i,int j) const10352 graphe::ipair graphe::tsp::make_edge(int i,int j) const {
10353 if (isdirected)
10354 return make_pair(i,j);
10355 return make_pair(i<j?i:j,i<j?j:i);
10356 }
10357
10358 /* return the subgraph index of edge e */
edge_index(const ipair & e)10359 int graphe::tsp::edge_index(const ipair &e) {
10360 int i=loc_map[e.first][e.second];
10361 return sg<0?i:arcs[i].sg_index;
10362 }
10363
10364 /* return the subgraph index of vertex i */
vertex_index(int i)10365 int graphe::tsp::vertex_index(int i) {
10366 if (sg<0)
10367 return i;
10368 for (int j=0;j<sg_nv;++j) {
10369 if (sg_vertices[j]==i)
10370 return j;
10371 }
10372 return -1;
10373 }
10374
10375 /* collect indices of all edges in the subgraph of G with index sg */
make_sg_edges()10376 void graphe::tsp::make_sg_edges() {
10377 int j=0;
10378 for (int i=0;i<ne;++i) {
10379 arc &a=arcs[i];
10380 if (sg<0 || (G->node(a.head).subgraph()==sg && G->node(a.tail).subgraph()==sg)) {
10381 a.sg_index=j;
10382 sg_edges[j++]=i;
10383 } else a.sg_index=-1;
10384 }
10385 sg_ne=j;
10386 }
10387
10388 /* formulate TSP as MIP, initially without any subtour elimination constraints */
formulate_mip()10389 void graphe::tsp::formulate_mip() {
10390 ivectors rows;
10391 int n=sg<0?nv:sg_nv,m=sg<0?ne:sg_ne;
10392 int nonzeros=0,i,j,k,l,cnt=0,nrows,ncols,nrows0;
10393 for (j=0;j<m;++j) {
10394 const arc &a=arcs[sg<0?j:sg_edges[j]];
10395 obj[j]=isweighted?weight(a.tail,a.head):1.0;
10396 }
10397 for (j=0;j<n;++j) {
10398 rows.resize(rows.size()+1);
10399 ivector &row=rows.back();
10400 l=sg<0?j:sg_vertices[j];
10401 row.push_back(l);
10402 for (i=0;i<n;++i) {
10403 k=sg<0?i:sg_vertices[i];
10404 if (i!=j && G->has_edge(k,l)) {
10405 row.push_back(k);
10406 ++nonzeros;
10407 }
10408 }
10409 }
10410 if (isdirected) {
10411 nrows0=rows.size();
10412 for (i=0;i<n;++i) {
10413 rows.resize(rows.size()+1);
10414 ivector &row=rows.back();
10415 k=sg<0?i:sg_vertices[i];
10416 row.push_back(k);
10417 for (j=0;j<n;++j) {
10418 l=sg<0?j:sg_vertices[j];
10419 if (i!=j && G->has_edge(k,l)) {
10420 row.push_back(l);
10421 ++nonzeros;
10422 }
10423 }
10424 }
10425 }
10426 ncols=m;
10427 nrows=rows.size();
10428 if (is_undir_weighted)
10429 nonzeros+=m;
10430 int *ia=new int[nonzeros+1];
10431 int *ja=new int[nonzeros+1];
10432 double *ar=new double[nonzeros+1];
10433 for (ivectors_iter it=rows.begin();it!=rows.end();++it) {
10434 const ivector &row=*it;
10435 k=it-rows.begin();
10436 i=row.front();
10437 for (ivector_iter rt=row.begin()+1;rt!=row.end();++rt) {
10438 j=*rt;
10439 l=edge_index(isdirected?(k<nrows0?make_pair(j,i):make_pair(i,j)):make_edge(i,j));
10440 assert(l<m);
10441 ia[++cnt]=k+1; ja[cnt]=l+1; ar[cnt]=1;
10442 }
10443 }
10444 /* build MIP */
10445 glp_add_rows(mip,nrows);
10446 double rh=isdirected?1.0:2.0;
10447 for (i=0;i<nrows;++i) glp_set_row_bnds(mip,i+1,GLP_FX,rh,rh);
10448 if (is_undir_weighted) {
10449 int r=glp_add_rows(mip,1);
10450 double lb=lower_bound();
10451 glp_set_row_bnds(mip,r,GLP_LO,lb,DBL_MAX);
10452 for (i=0;i<m;++i) {
10453 ia[++cnt]=r; ja[cnt]=i+1; ar[cnt]=obj[i];
10454 }
10455 }
10456 glp_add_cols(mip,ncols);
10457 for (j=0;j<m;++j) {
10458 glp_set_col_kind(mip,j+1,GLP_BV);
10459 glp_set_obj_coef(mip,j+1,obj[j]);
10460 }
10461 assert(cnt<=nonzeros);
10462 glp_load_matrix(mip,cnt,ia,ja,ar);
10463 delete[] ia; delete[] ja; delete[] ar;
10464 }
10465
10466 /* compute lower bound for the objective function using minimal spanning tree */
lower_bound()10467 double graphe::tsp::lower_bound() {
10468 double cost,maxcost=0;
10469 int i;
10470 for (int k=0;k<(sg<0?nv:sg_nv);++k) {
10471 i=sg<0?k:sg_vertices[k];
10472 vertex &v=G->node(i);
10473 if (sg<0) {
10474 G->unset_subgraphs(0);
10475 v.set_subgraph(1);
10476 } else v.set_subgraph(-1);
10477 graphe T(G->giac_context());
10478 G->minimal_spanning_tree(T,sg);
10479 ipairs E;
10480 cost=0;
10481 T.get_edges_as_pairs(E);
10482 for (ipairs_iter it=E.begin();it!=E.end();++it) {
10483 cost+=_evalf(T.weight(*it),G->giac_context()).DOUBLE_val();
10484 }
10485 if (sg<0)
10486 G->unset_subgraphs();
10487 else v.set_subgraph(sg);
10488 dvector c;
10489 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
10490 if (sg>=0 && G->node(*it).subgraph()!=sg)
10491 continue;
10492 c.push_back(weight(i,*it));
10493 }
10494 assert(c.size()>1);
10495 sort(c.begin(),c.end());
10496 cost+=c[0];
10497 cost+=c[1];
10498 if (cost>maxcost)
10499 maxcost=cost;
10500 }
10501 return maxcost;
10502 }
10503
10504 /* find the subtours (sv) in the subgraph induced by vertices in v */
find_subgraph_subtours(ivectors & sv,solution_status & status)10505 bool graphe::tsp::find_subgraph_subtours(ivectors &sv,solution_status &status) {
10506 glp_erase_prob(mip);
10507 glp_set_obj_dir(mip,GLP_MIN);
10508 formulate_mip();
10509 glp_smcp lparm; // LP solver settings
10510 glp_init_smcp(&lparm);
10511 lparm.msg_lev=GLP_MSG_OFF; // do not output any messages
10512 glp_iocp parm; // MIP solver settings
10513 glp_init_iocp(&parm);
10514 parm.msg_lev=GLP_MSG_OFF; // do not output any messages
10515 parm.gmi_cuts=GLP_ON; // generate Gomory cuts
10516 parm.br_tech=GLP_BR_MFV; // choose the most fractional variable (the fallback branching rule)
10517 parm.fp_heur=GLP_ON; // enable feasibility pump heuristic
10518 parm.sr_heur=GLP_OFF; // disable simple rounding heuristic (according to A. Makhorin)
10519 parm.cb_func=&callback; // MIP callback
10520 parm.cb_info=static_cast<void*>(this);
10521 parm.tm_lim=sg>=0?5000:RAND_MAX; // time limit
10522 parm.bt_tech=sg<0?GLP_BT_BPH:GLP_BT_BLB; // backtracking technique
10523 parm.mip_gap=sg<0?0.0:1e-4; // MIP gap relative tolerance
10524 bool retval=true;
10525 int iter_count=0,res,lres,stat;
10526 is_symmetric_tsp=is_undir_weighted && G->is_clique(sg);
10527 heur_type=is_symmetric_tsp?_GT_TSP_CHRISTOFIDES_SA:
10528 (is_undir_weighted?_GT_TSP_FARTHEST_INSERTION_HEUR:
10529 _GT_TSP_NO_HEUR);
10530 do {
10531 ++iter_count;
10532 /* append subtour elimination constraints */
10533 for (set<ivector>::const_iterator it=subtours.begin();it!=subtours.end();++it) {
10534 append_sce(*it);
10535 }
10536 subtours.clear();
10537 /* solve */
10538 if ((lres=glp_simplex(mip,&lparm))==0 &&
10539 ((stat=glp_get_status(mip))==GLP_OPT || stat==GLP_FEAS))
10540 res=glp_intopt(mip,&parm);
10541 else if (lres!=0 || stat==GLP_UNDEF || stat==GLP_UNBND) {
10542 status=_GT_TSP_ERROR;
10543 break;
10544 } else {
10545 status=_GT_TSP_NOT_HAMILTONIAN;
10546 break;
10547 }
10548 if (res!=0 || (stat=glp_mip_status(mip))==GLP_UNDEF) {
10549 status=_GT_TSP_ERROR;
10550 retval=false;
10551 break;
10552 }
10553 switch (stat) {
10554 case GLP_FEAS:
10555 *logptr(G->giac_context()) << "Warning: the solution is not necessarily optimal\n";
10556 case GLP_OPT:
10557 status=_GT_TSP_OPTIMAL;
10558 break;
10559 case GLP_NOFEAS:
10560 status=_GT_TSP_NOT_HAMILTONIAN;
10561 break;
10562 }
10563 if (status==_GT_TSP_NOT_HAMILTONIAN) break;
10564 if (!get_subtours()) {
10565 status=_GT_TSP_NOT_HAMILTONIAN;
10566 break;
10567 }
10568 if (sg>=0) {
10569 lift_subtours(sv);
10570 if (iter_count>25)
10571 break;
10572 }
10573 } while (subtours.size()>1);
10574 ++num_nodes;
10575 if (sg<0 && status==_GT_TSP_OPTIMAL)
10576 lift_subtours(sv);
10577 return retval;
10578 }
10579
10580 /* lift subtours to cycles in G */
lift_subtours(ivectors & sv) const10581 void graphe::tsp::lift_subtours(ivectors &sv) const {
10582 for (set<ivector>::const_iterator it=subtours.begin();it!=subtours.end();++it) {
10583 const ivector &subtour=*it;
10584 if (sg<0)
10585 sv.push_back(subtour);
10586 else {
10587 sv.resize(sv.size()+1);
10588 ivector &lifted_subtour=sv.back();
10589 lifted_subtour.resize(subtour.size());
10590 for (ivector_iter jt=subtour.begin();jt!=subtour.end();++jt) {
10591 lifted_subtour[jt-subtour.begin()]=sg_edges[*jt];
10592 }
10593 }
10594 }
10595 }
10596
10597 /* append subtour elimination constraint to MIP */
append_sce(const ivector & subtour)10598 void graphe::tsp::append_sce(const ivector &subtour) {
10599 int i,j,r=glp_add_rows(mip,1),cnt=0,sz=subtour.size();
10600 int m=sg<0?ne:sg_ne;
10601 if (!isdirected && 3*sz>2*(sg<0?nv:sg_nv)+1) {
10602 for (int k=0;k<m;++k) {
10603 if (find(subtour.begin(),subtour.end(),k)!=subtour.end())
10604 continue;
10605 i=sg<0?k:sg_edges[k];
10606 const arc &a1=arcs[i];
10607 for (ivector_iter jt=subtour.begin();jt!=subtour.end();++jt) {
10608 j=sg<0?*jt:sg_edges[*jt];
10609 assert(i!=j);
10610 const arc &a2=arcs[j];
10611 if (a1.head==a2.head || a1.tail==a2.tail ||
10612 a1.head==a2.tail || a1.tail==a2.head) {
10613 indices[++cnt]=k+1;
10614 coeff[cnt]=1.0;
10615 break;
10616 }
10617 }
10618 }
10619 glp_set_row_bnds(mip,r,GLP_LO,2,DBL_MAX);
10620 } else {
10621 for (ivector_iter it=subtour.begin();it!=subtour.end();++it) {
10622 indices[++cnt]=*it+1;
10623 coeff[cnt]=1.0;
10624 }
10625 glp_set_row_bnds(mip,r,GLP_UP,0.0,sz-1);
10626 }
10627 glp_set_mat_row(mip,r,cnt,indices,coeff);
10628 }
10629
10630 /* append subtours from sv, converting them to conform sg_edges */
add_subtours(const ivectors & sv)10631 void graphe::tsp::add_subtours(const ivectors &sv) {
10632 ivector subtour;
10633 for (ivectors_iter it=sv.begin();it!=sv.end();++it) {
10634 if (sg<0) {
10635 subtours.insert(canonical_subtour(*it));
10636 } else {
10637 subtour.resize(it->size());
10638 for (ivector_iter jt=it->begin();jt!=it->end();++jt) {
10639 subtour[jt-it->begin()]=arcs[*jt].sg_index;
10640 }
10641 subtours.insert(canonical_subtour(subtour));
10642 }
10643 }
10644 }
10645
10646 /* collect subtours from the current best MIP integer solution */
get_subtours()10647 bool graphe::tsp::get_subtours() {
10648 ivector sol;
10649 int m=glp_get_num_cols(mip),i,j;
10650 for (i=0;i<m;++i) {
10651 if (glp_mip_col_val(mip,i+1)>0.5)
10652 sol.push_back(i);
10653 }
10654 if (sg<0) {
10655 if (sol==old_sol) return false;
10656 old_sol=sol;
10657 }
10658 vector<bool> vst(sol.size(),false);
10659 ivector subtour;
10660 subtour.reserve(sg<0?ne:sg_ne);
10661 arc a;
10662 for (ivector_iter st=sol.begin();st!=sol.end();++st) {
10663 const arc &fa=arcs[sg<0?*st:sg_edges[*st]];
10664 i=st-sol.begin();
10665 if (vst[i])
10666 continue;
10667 subtour.clear();
10668 subtour.push_back(*st);
10669 vst[i]=true;
10670 a=fa;
10671 ivector_iter it;
10672 do {
10673 for (it=sol.begin();it!=sol.end();++it) {
10674 j=it-sol.begin();
10675 const arc &aa=arcs[sg<0?*it:sg_edges[*it]];
10676 if (i==j || vst[j])
10677 continue;
10678 if (aa.tail==a.head || (!isdirected && (aa.tail==a.tail || aa.head==a.head || aa.head==a.tail))) {
10679 vst[j]=true;
10680 subtour.push_back(*it);
10681 a.head=aa.head;
10682 a.tail=aa.tail;
10683 i=j;
10684 break;
10685 }
10686 }
10687 } while (it!=sol.end());
10688 subtours.insert(canonical_subtour(subtour));
10689 }
10690 return true;
10691 }
10692
10693 /* construct hierarhical clustering forest */
make_hierarchical_clustering_forest()10694 void graphe::tsp::make_hierarchical_clustering_forest() {
10695 int k;
10696 int u=std::min(nv-1,(int)std::floor(nv*4.0*M_LN2/std::log(nv))); // max cluster cardinality
10697 clustering_forest.clear();
10698 /* create leaf nodes */
10699 for (int i=0;i<nv;++i) {
10700 ivector node(4,-1);
10701 node.back()=i;
10702 clustering_forest.push_back(node);
10703 }
10704 ipair child;
10705 /* add edges one by one, creating tree nodes from bottom up */
10706 for (int i=0;i<ne;++i) {
10707 arc &a=arcs[i];
10708 k=clustering_forest.size();
10709 for (ivectors_iter it=clustering_forest.begin();it!=clustering_forest.end();++it) {
10710 if (it->front()<0 && find(it->begin()+3,it->end(),a.tail)!=it->end())
10711 child.first=it-clustering_forest.begin();
10712 if (it->front()<0 && find(it->begin()+3,it->end(),a.head)!=it->end())
10713 child.second=it-clustering_forest.begin();
10714 }
10715 if (child.first==child.second) // e does not connect two separated components
10716 continue;
10717 ivector &c1=clustering_forest[child.first],&c2=clustering_forest[child.second];
10718 if (int(c1.size()+c2.size())>u+6) // forbid creating components with more than u vertices
10719 continue;
10720 /* merge components to parent node */
10721 c1.front()=c2.front()=k; // set parent to children
10722 ivector p(3,-1);
10723 p[1]=child.first;
10724 p[2]=child.second;
10725 /* merge the children vertex sets and sort the resulting list */
10726 p.insert(p.end(),c1.begin()+3,c1.end());
10727 p.insert(p.end(),c2.begin()+3,c2.end());
10728 sort(p.begin()+3,p.end());
10729 clustering_forest.push_back(p);
10730 }
10731 }
10732
10733 /* return canonical representation of the subtour (starting with the lowest edge index) */
canonical_subtour(const ivector & subtour)10734 graphe::ivector graphe::tsp::canonical_subtour(const ivector &subtour) {
10735 int minv=-1,pos;
10736 for (ivector_iter it=subtour.begin();it!=subtour.end();++it) {
10737 if (minv<0 || *it<minv) {
10738 minv=*it;
10739 pos=it-subtour.begin();
10740 }
10741 }
10742 ivector res(subtour.begin()+pos,subtour.end());
10743 res.insert(res.end(),subtour.begin(),subtour.begin()+pos);
10744 if (!isdirected && res.size()>2 && res[1]>res.back())
10745 std::reverse(res.begin()+1,res.end()); // canonical orientation
10746 return res;
10747 }
10748
10749 /* traverse the hierarhical clustering forest and collect all relevant SEC */
hierarchical_clustering_dfs(int i,ivectors & considered_sec,ivectors & relevant_sec)10750 void graphe::tsp::hierarchical_clustering_dfs(int i,ivectors &considered_sec,ivectors &relevant_sec) {
10751 if (i<0)
10752 return;
10753 const ivector &node=clustering_forest[i];
10754 assert(node.size()>3);
10755 int sz=node.size()-3,left_child=node[1],right_child=node[2];
10756 if (sz<3) // do not search for subtours in nodes with less than 3 vertices
10757 return;
10758 /* process the children nodes to obtain considered and relevant SEC */
10759 ivectors left_cons,right_cons,left_sec,right_sec,sv,cons;
10760 hierarchical_clustering_dfs(left_child,left_cons,left_sec);
10761 hierarchical_clustering_dfs(right_child,right_cons,right_sec);
10762 relevant_sec.insert(relevant_sec.end(),left_sec.begin(),left_sec.end());
10763 relevant_sec.insert(relevant_sec.end(),right_sec.begin(),right_sec.end());
10764 cons.insert(cons.end(),left_cons.begin(),left_cons.end());
10765 cons.insert(cons.end(),right_cons.begin(),right_cons.end());
10766 /* process this node */
10767 solution_status status;
10768 sg=G->max_subgraph_index()+1;
10769 ivector V(node.begin()+3,node.end());
10770 G->set_subgraph(V,sg);
10771 if (!G->is_biconnected(sg)) {
10772 considered_sec=cons;
10773 return;
10774 }
10775 make_sg_edges();
10776 sg_nv=sz;
10777 for (ivector_iter it=V.begin();it!=V.end();++it) {
10778 sg_vertices[it-V.begin()]=*it;
10779 }
10780 subtours.clear();
10781 add_subtours(left_sec);
10782 add_subtours(right_sec);
10783 find_subgraph_subtours(sv,status);
10784 for (ivectors::iterator it=cons.begin();it!=cons.end();++it) {
10785 *it=canonical_subtour(*it);
10786 }
10787 ivector canon_s;
10788 ivectors_iter jt;
10789 for (ivectors_iter it=sv.begin();it!=sv.end();++it) {
10790 canon_s=canonical_subtour(*it);
10791 for (jt=cons.begin();jt!=cons.end();++jt) {
10792 if (canon_s==*jt) {
10793 relevant_sec.push_back(*it);
10794 break;
10795 }
10796 }
10797 if (jt==cons.end())
10798 considered_sec.push_back(*it);
10799 }
10800 }
10801
10802 /* solve the original problem */
solve(ivector & hc,double & cost)10803 int graphe::tsp::solve(ivector &hc,double &cost) {
10804 make_hierarchical_clustering_forest();
10805 G->unset_subgraphs();
10806 ivectors cons,relevant,sec,sv;
10807 mip=glp_create_prob();
10808 num_nodes=0;
10809 for (ivectors_iter it=clustering_forest.begin();it!=clustering_forest.end();++it) {
10810 if (it->front()<0) { // we're in the root node of a tree in the HC forest
10811 hierarchical_clustering_dfs(it-clustering_forest.begin(),cons,relevant);
10812 sec.insert(sec.end(),cons.begin(),cons.end());
10813 sec.insert(sec.end(),relevant.begin(),relevant.end());
10814 }
10815 }
10816 solution_status status;
10817 sg=-1;
10818 G->unset_subgraphs();
10819 add_subtours(sec);
10820 if (!find_subgraph_subtours(sv,status))
10821 return -1;
10822 int retval;
10823 switch (status) {
10824 case _GT_TSP_OPTIMAL:
10825 if (sv.size()==1) {
10826 const ivector &t=sv.front();
10827 int n=G->node_count();
10828 assert(int(t.size())==n);
10829 hc.clear();
10830 const arc &first=arcs[t.front()],&last=arcs[t.back()];
10831 int i=first.tail,j=first.head,k;
10832 if (i==last.tail || i==last.head) {
10833 hc.push_back(i);
10834 hc.push_back(k=j);
10835 } else {
10836 hc.push_back(j);
10837 hc.push_back(k=i);
10838 }
10839 for (ivector_iter it=t.begin()+1;it!=t.end();++it) {
10840 const arc &a=arcs[*it];
10841 if (a.tail==k) hc.push_back(k=a.head);
10842 else {
10843 assert(a.head==k);
10844 hc.push_back(k=a.tail);
10845 }
10846 }
10847 improve_tour(hc);
10848 cost=tour_cost(hc);
10849 retval=1; // success
10850 } else retval=0;
10851 break;
10852 case _GT_TSP_NOT_HAMILTONIAN:
10853 retval=0; // fail
10854 break;
10855 case _GT_TSP_ERROR:
10856 retval=-1; // error
10857 break;
10858 }
10859 glp_delete_prob(mip);
10860 return retval;
10861 }
10862
10863 /* return weight of edge (i,j) */
weight(int i,int j)10864 double graphe::tsp::weight(int i,int j) {
10865 ipair e=make_edge(i,j);
10866 return weight_map[e.first][e.second];
10867 }
10868
10869 /* return the cost of the tour */
tour_cost(const ivector & hc)10870 double graphe::tsp::tour_cost(const ivector &hc) {
10871 int n=hc.size()-1,v,w;
10872 if (!isweighted)
10873 return n;
10874 double cost=0;
10875 for (int i=0;i<n;++i) {
10876 v=hc[i];
10877 w=hc[i+1];
10878 assert(G->has_edge(v,w));
10879 cost+=weight(v,w);
10880 }
10881 return cost;
10882 }
10883
10884 /* apply heuristics */
heur(glp_tree * tree)10885 void graphe::tsp::heur(glp_tree *tree) {
10886 if (heur_type==_GT_TSP_NO_HEUR)
10887 return;
10888 int n=sg<0?nv:sg_nv,m=sg<0?ne:sg_ne,i,j,k;
10889 if (heur_type==_GT_TSP_CHRISTOFIDES_SA) { // symmetric TSP
10890 christofides(tour);
10891 heur_type=_GT_TSP_FARTHEST_INSERTION_RANDOM;
10892 } else { // weighted undirected TSP
10893 /* choose the initial arc a by random such that weight(e) >= median weight,
10894 * in the first pass try to construct a tour starting from heaviest edge */
10895 int index=heur_type==_GT_TSP_FARTHEST_INSERTION_RANDOM?(m+1)/2+G->rand_integer(m/2):m-1;
10896 farthest_insertion(index,tour);
10897 heur_type=_GT_TSP_FARTHEST_INSERTION_RANDOM;
10898 if (int(tour.size())<=n)
10899 return;
10900 }
10901 assert(int(tour.size())==n+1);
10902 /* optimize the tour */
10903 //double old=tour_cost(tour);
10904 //cout << "Improving the tour... ";
10905 lin_kernighan(tour);
10906 //cout << "Done. Ratio: " << (old-tour_cost(tour))/old*100.0 << "%\n";
10907 /* construct the heuristic solution and pass it to the MIP solver */
10908 for (i=0;i<m;++i) coeff[i+1]=0.0;
10909 for (i=0;i<n;++i) {
10910 j=i+1;
10911 k=edge_index(make_edge(tour[i],tour[j]));
10912 coeff[k+1]=1.0;
10913 }
10914 glp_ios_heur_sol(tree,coeff);
10915 }
10916
10917 /* farthest insertion heuristic for obtaining a Hamiltonian tour */
farthest_insertion(int index,ivector & hc)10918 void graphe::tsp::farthest_insertion(int index,ivector &hc) {
10919 int n=sg<0?nv:sg_nv,i,j,k,f;
10920 const arc &a=arcs[index];
10921 i=a.tail;
10922 j=a.head;
10923 hc.clear();
10924 hc.push_back(i);
10925 hc.push_back(j);
10926 hc.push_back(i);
10927 ivector_iter jt;
10928 for (int vis=0;vis<nv;++vis) visited[vis]=false;
10929 visited[i]=visited[j]=true;
10930 dvector W;
10931 double w,maxw,minw;
10932 /* proceed with farthest insertion heuristic */
10933 do {
10934 maxw=0;
10935 f=-1;
10936 for (int l=0;l<n;++l) {
10937 k=sg<0?l:sg_vertices[l];
10938 if (visited[k])
10939 continue;
10940 W.clear();
10941 for (ivector_iter it=hc.begin();it!=hc.end();++it) {
10942 if (G->has_edge(k,*it))
10943 W.push_back(weight(k,*it));
10944 }
10945 minw=DBL_MAX;
10946 if (W.size()<2)
10947 continue;
10948 else for (dvector_iter wt=W.begin();wt!=W.end();++wt) {
10949 if (*wt<minw)
10950 minw=*wt;
10951 }
10952 if (minw>maxw) {
10953 maxw=minw;
10954 f=k;
10955 }
10956 }
10957 if ((k=f)<0)
10958 break;
10959 i=-1;
10960 minw=DBL_MAX;
10961 for (ivector_iter it=hc.begin();it!=hc.end();++it) {
10962 jt=it+1;
10963 if (jt!=hc.end() && G->has_edge(*it,k) && G->has_edge(k,*jt) &&
10964 minw>(w=weight(*it,k)+weight(k,*jt)-weight(*it,*jt))) {
10965 minw=w;
10966 i=it-hc.begin();
10967 }
10968 }
10969 if (i<0)
10970 break;
10971 hc.insert(hc.begin()+i+1,k);
10972 visited[k]=true;
10973 } while (int(hc.size())<=n);
10974 }
10975
10976 /* try to lower the cost of the tour hc */
perform_3opt_moves(ivector & hc)10977 void graphe::tsp::perform_3opt_moves(ivector &hc) {
10978 int n=hc.size()-1,b1,e1,b2,e2,b3,e3,i1,j1,i2,j2,i3,j3,i,j,k,var,iter_count=0,moves_count=0;
10979 double opt_timeout=5.0+25.0*std::exp(-std::pow(std::max(0,1000-n),2)/2e5);
10980 vector<bool> visited(nv);
10981 ivectors opt_moves;
10982 double sw,save,maxsave,wb1e1,wb2e2,wb3e3,wb1b2,wb1e2,we1e2;
10983 bool hb1e2,hb1b2,he1e2;
10984 /* improve the tour by making a limited number of 3-opt moves */
10985 clock_t start_time=clock();
10986 ivector ijk(3);
10987 bool triplet_found=false;
10988 bool timed_out=false;
10989 do {
10990 ++iter_count;
10991 opt_moves.clear();
10992 std::fill(visited.begin(),visited.end(),false);
10993 for (i=0;i<n;++i) {
10994 triplet_found=false;
10995 b1=hc[i]; e1=hc[i+1];
10996 if (visited[b1] || visited[e1])
10997 continue;
10998 wb1e1=weight(b1,e1);
10999 for (j=i+2;j<n;++j) {
11000 if (double(clock()-start_time)/CLOCKS_PER_SEC>opt_timeout) {
11001 timed_out=true;
11002 break;
11003 }
11004 b2=hc[j]; e2=hc[j+1];
11005 if (visited[b2] || visited[e2])
11006 continue;
11007 wb2e2=weight(b2,e2);
11008 hb1e2=G->has_edge(b1,e2);
11009 hb1b2=G->has_edge(b1,b2);
11010 he1e2=G->has_edge(e1,e2);
11011 if (hb1b2) wb1b2=weight(b1,b2);
11012 if (hb1e2) wb1e2=weight(b1,e2);
11013 if (he1e2) we1e2=weight(e1,e2);
11014 for (k=j+2;k<n;++k) {
11015 b3=hc[k]; e3=hc[k+1];
11016 if (visited[b3] || visited[e3])
11017 continue;
11018 wb3e3=weight(b3,e3);
11019 sw=wb1e1+wb2e2+wb3e3;
11020 if ((hb1e2 && G->has_edge(b3,e1) && G->has_edge(b2,e3) && sw>wb1e2+weight(b3,e1)+weight(b2,e3)) ||
11021 (hb1e2 && G->has_edge(b3,b2) && G->has_edge(e1,e3) && sw>wb1e2+weight(b3,b2)+weight(e1,e3)) ||
11022 (hb1b2 && G->has_edge(b3,e1) && G->has_edge(e2,e3) && sw>wb1b2+weight(b3,e1)+weight(e2,e3)) ||
11023 (G->has_edge(b1,b3) && he1e2 && G->has_edge(b2,e3) && sw>weight(b1,b3)+we1e2+weight(b2,e3)))
11024 {
11025 ivector opt_move(6);
11026 opt_move[0]=b1; opt_move[1]=b2; opt_move[2]=b3;
11027 opt_move[3]=e1; opt_move[4]=e2; opt_move[5]=e3;
11028 opt_moves.push_back(opt_move);
11029 visited[b1]=visited[b2]=visited[b3]=true;
11030 visited[e1]=visited[e2]=visited[e3]=true;
11031 triplet_found=true;
11032 break;
11033 }
11034 }
11035 if (triplet_found)
11036 break;
11037 }
11038 if (timed_out)
11039 break;
11040 }
11041 if (opt_moves.empty()) break;
11042 for (ivectors_iter it=opt_moves.begin(); it!=opt_moves.end();++it) {
11043 const ivector &opt_move=*it;
11044 i1=find(hc.begin(),hc.end(),opt_move[0])-hc.begin();
11045 i2=find(hc.begin(),hc.end(),opt_move[1])-hc.begin();
11046 i3=find(hc.begin(),hc.end(),opt_move[2])-hc.begin();
11047 j1=find(hc.begin(),hc.end(),opt_move[3])-hc.begin();
11048 j2=find(hc.begin(),hc.end(),opt_move[4])-hc.begin();
11049 j3=find(hc.begin(),hc.end(),opt_move[5])-hc.begin();
11050 if (std::abs(i1-j1)!=1) {
11051 if (i1==0) i1=n;
11052 else if (j1==0) j1=n;
11053 else assert(false);
11054 }
11055 if (std::abs(i2-j2)!=1) {
11056 if (i2==0) i2=n;
11057 else if (j2==0) j2=n;
11058 else assert(false);
11059 }
11060 if (std::abs(i3-j3)!=1) {
11061 if (i3==0) i3=n;
11062 else if (j3==0) j3=n;
11063 else assert(false);
11064 }
11065 assert(std::abs(i1-j1)==1 && std::abs(i2-j2)==1 && std::abs(i3-j3)==1);
11066 ijk[0]=std::min(i1,j1);
11067 ijk[1]=std::min(i2,j2);
11068 ijk[2]=std::min(i3,j3);
11069 sort(ijk.begin(),ijk.end());
11070 i=ijk[0]; j=ijk[1]; k=ijk[2];
11071 b1=hc[i]; b2=hc[j]; b3=hc[k];
11072 e1=hc[i+1]; e2=hc[j+1]; e3=hc[k+1];
11073 sw=weight(b1,e1)+weight(b2,e2)+weight(b3,e3);
11074 maxsave=0.0;
11075 if (G->has_edge(b1,e2) && G->has_edge(b3,e1) && G->has_edge(b2,e3) &&
11076 (save=sw-weight(b1,e2)-weight(b3,e1)-weight(b2,e3))>maxsave) {
11077 var=0; maxsave=save;
11078 }
11079 if (G->has_edge(b1,e2) && G->has_edge(b3,b2) && G->has_edge(e1,e3) &&
11080 (save=sw-weight(b1,e2)-weight(b3,b2)-weight(e1,e3))>maxsave) {
11081 var=1; maxsave=save;
11082 }
11083 if (G->has_edge(b1,b2) && G->has_edge(b3,e1) && G->has_edge(e2,e3) &&
11084 (save=sw-weight(b1,b2)-weight(b3,e1)-weight(e2,e3))>maxsave) {
11085 var=2; maxsave=save;
11086 }
11087 if (G->has_edge(b1,b3) && G->has_edge(e1,e2) && G->has_edge(b2,e3) &&
11088 (save=sw-weight(b1,b3)-weight(e1,e2)-weight(b2,e3))>maxsave) {
11089 var=3; maxsave=save;
11090 }
11091 if (maxsave>.001) {
11092 ivector part(hc.begin()+j+1,hc.begin()+k+1);
11093 switch (var) {
11094 case 1:
11095 std::reverse(hc.begin()+i+1,hc.begin()+j+1);
11096 case 3:
11097 if (var==3) std::reverse(part.begin(),part.end());
11098 case 0:
11099 hc.erase(hc.begin()+j+1,hc.begin()+k+1);
11100 hc.insert(hc.begin()+i+1,part.begin(),part.end());
11101 break;
11102 case 2:
11103 std::reverse(hc.begin()+i+1,hc.begin()+j+1);
11104 std::reverse(hc.begin()+j+1,hc.begin()+k+1);
11105 break;
11106 default:
11107 assert(false);
11108 }
11109 ++moves_count;
11110 }
11111 }
11112 } while (!timed_out);
11113 }
11114
straighten(ivector & hc)11115 void graphe::tsp::straighten(ivector &hc) {
11116 ivectors opt_moves;
11117 int i,j,k,l,b1,b2,e1,e2,n=hc.size()-1,iter_count=0,moves_count=0;
11118 double w0;
11119 vector<bool> visited(n+1);
11120 ivector opt_move(4);
11121 while (true) {
11122 ++iter_count;
11123 opt_moves.clear();
11124 std::fill(visited.begin(),visited.end(),false);
11125 for (i=0;i<n;++i) {
11126 if (visited[i] && visited[i+1]) continue;
11127 b1=hc[i]; e1=hc[i+1];
11128 w0=weight(b1,e1);
11129 for (j=i+2;j<n;++j) {
11130 if ((i==0 && j==n-1) || (visited[j] && visited[j+1])) continue;
11131 b2=hc[j]; e2=hc[j+1];
11132 if (G->has_edge(b1,b2) && G->has_edge(e1,e2) &&
11133 w0+weight(b2,e2)-weight(b1,b2)-weight(e1,e2)>.001) {
11134 opt_move[0]=b1; opt_move[1]=b2; opt_move[2]=e1; opt_move[3]=e2;
11135 opt_moves.push_back(opt_move);
11136 visited[i]=visited[i+1]=visited[j]=visited[j+1]=true;
11137 break;
11138 }
11139 }
11140 }
11141 if (opt_moves.empty()) break;
11142 for (ivectors_iter it=opt_moves.begin();it!=opt_moves.end();++it) {
11143 const ivector &opt_move=*it;
11144 b1=opt_move[0]; b2=opt_move[1]; e1=opt_move[2]; e2=opt_move[3];
11145 i=find(hc.begin(),hc.end(),b1)-hc.begin(); j=find(hc.begin(),hc.end(),e1)-hc.begin();
11146 k=find(hc.begin(),hc.end(),b2)-hc.begin(); l=find(hc.begin(),hc.end(),e2)-hc.begin();
11147 if (std::abs(i-j)!=1) {
11148 if (i==0) i=n;
11149 else if (j==0) j=n;
11150 else assert(false);
11151 }
11152 if (std::abs(k-l)!=1) {
11153 if (k==0) k=n;
11154 else if (l==0) l=n;
11155 else assert(false);
11156 }
11157 assert(std::abs(i-j)==1 && std::abs(k-l)==1);
11158 i=std::min(i,j);
11159 j=std::min(k,l);
11160 std::reverse(hc.begin()+(i<j?i:j)+1,hc.begin()+(i<j?j:i)+1);
11161 ++moves_count;
11162 }
11163 }
11164 }
11165
11166 /* Helsgaun criterion for k-opt move feasibility */
is_move_feasible(int k,const ivector & t,const ipairs & x)11167 bool graphe::tsp::is_move_feasible(int k,const ivector &t,const ipairs &x) {
11168 ivector incl(2*k+1,0);
11169 int i,j,pi,count;
11170 for (int c=0;c<k;++c) {
11171 i=2*c+1;
11172 j=(i+1)%(2*k);
11173 incl[i+1]=j+1;
11174 incl[j+1]=i+1;
11175 }
11176 ivector p,q;
11177 ipairs xs(x.begin()+1,x.begin()+k+1);
11178 sort(xs.begin(),xs.end());
11179 for (ipairs_iter it=xs.begin();it!=xs.end();++it) {
11180 p.push_back(find(t.begin()+1,t.begin()+2*k+1,it->first)-t.begin());
11181 }
11182 for (i=k;i-->0;) {
11183 p.insert(p.begin()+i+1,((pi=p[i])%2)==0?pi-1:pi+1);
11184 }
11185 q.resize(p.size()+1);
11186 for (i=p.size();i-->0;) {
11187 assert((pi=p[i])<=2*k);
11188 q[pi]=i+1;
11189 }
11190 for (i=2*k,count=1;(i=q[incl[p[i-1]]]^1)!=0;count++);
11191 return count==k;
11192 }
11193
11194 /* Lin-Kernighan backtracking k-opt heuristic for tour improvement */
lin_kernighan(ivector & hc)11195 void graphe::tsp::lin_kernighan(ivector &hc) {
11196 int n=hc.size()-1;
11197 int i,choice,j,j0,j_next,pos,ypos,t1,t2,t3,t4,t5,t2i,t2ip,dir;
11198 static ipairs x,y,y_tmp;
11199 static dvector wx,wy;
11200 static ivector t,t1_alt,y1_alt,y2_alt,cheaper_hc;
11201 x.resize(n+1); y.resize(n+1);
11202 wx.resize(n+1); wy.resize(n+1);
11203 t.resize(2*n+1);
11204 cheaper_hc.resize(n+1);
11205 t1_alt.clear();
11206 double w,wi;
11207 for (int k=0;k<n;++k) t1_alt.push_back(k); // initialize alternatives for t1
11208 lk2:
11209 /* Let i:=1. Choose t[1] and let x1:=(t[1],t[2]=succ(t[1])) in hc.
11210 * Initialize alternatives for y1. */
11211 i=1;
11212 if (t1_alt.empty()) return; // no more alternatives for t[1]
11213 choice=t1_alt.size()==1?0:G->rand_integer(t1_alt.size());
11214 t1=t[1]=t1_alt[choice]; t1_alt.erase(t1_alt.begin()+choice);
11215 x[1]=make_pair(t1,t2=t[2]=(t1+1)%n);
11216 w=wx[1]=weight(hc[t1],hc[t2]);
11217 y1_alt.clear();
11218 for (int k=0;k<n;++k) {
11219 if (k!=t1 && k!=t2 && k!=(t1-1+n)%n && k!=(t2+1)%n &&
11220 G->has_edge(hc[t2],hc[k]) && w>weight(hc[t2],hc[k]))
11221 y1_alt.push_back(k);
11222 }
11223 lk4:
11224 /* Choose y1:=(t[2],t[3]) not in hc such that G1>0. Else, go to lk2. */
11225 if (y1_alt.empty()) goto lk2;
11226 choice=y1_alt.size()==1?0:G->rand_integer(y1_alt.size());
11227 t3=t[3]=y1_alt[choice]; y1_alt.erase(y1_alt.begin()+choice);
11228 y[1]=make_pair(t2=t[2],t3);
11229 wy[1]=weight(hc[t2],hc[t3]);
11230 lk5:
11231 /* Let i:=i+1 and let xi=(t[2i-1],t[2i]) in hc.
11232 * Update the tour if possible. If i=1 initialize alternatives for y2. */
11233 ++i;
11234 t2ip=t[2*i-1];
11235 x[i]=make_pair(t2ip,t2i=t[2*i]=(t2ip+1)%n);
11236 wx[i]=weight(hc[t2ip],hc[t2i]);
11237 w=0.0;
11238 for (int k=1;k<=i;++k) w+=wx[k]-(k==i?0.0:wy[k]);
11239 if (t2i!=(t1-1+n)%n && G->has_edge(hc[t2i],hc[t1]) &&
11240 w-weight(hc[t2i],hc[t1])>.001 && is_move_feasible(i,t,x)) {
11241 /* update hc with the new cheaper tour starting from t[2] */
11242 y[i]=make_pair(t2i,t1); // temporary yi
11243 y_tmp=ipairs(y.begin()+1,y.begin()+i+1);
11244 j=j0=t[2]; j_next=t[3];
11245 pos=ypos=dir=0;
11246 while (true) {
11247 if (ypos>=0)
11248 y_tmp.erase(y_tmp.begin()+ypos);
11249 cheaper_hc[pos++]=hc[j];
11250 j=j_next;
11251 if (j==j0) break;
11252 ypos=-1;
11253 for (int k=y_tmp.size();k-->0;) {
11254 const ipair &yk=y_tmp[k];
11255 if (yk.first==j || yk.second==j) {
11256 j_next=yk.first==j?yk.second:yk.first;
11257 ypos=k;
11258 dir=0;
11259 break;
11260 }
11261 }
11262 if (ypos<0) {
11263 if (dir==0)
11264 dir=find(x.begin()+1,x.begin()+i+1,make_pair(j,(j+1)%n))==x.begin()+i+1?1:-1;
11265 j_next=(j+dir+n)%n;
11266 }
11267 }
11268 assert(pos==n);
11269 cheaper_hc.back()=hc[j0];
11270 hc=cheaper_hc;
11271 t1_alt.clear();
11272 for (int k=0;k<n;++k) t1_alt.push_back(k); // initialize alternatives for t1
11273 goto lk2;
11274 } else if (i==2) { // initialize alternatives for y2
11275 y2_alt.clear();
11276 t1=t[1]; t4=t[4];
11277 for (int k=0;k<n;++k) {
11278 if (find(t.begin()+1,t.begin()+5,k)==t.begin()+5 &&
11279 find(t.begin()+1,t.begin()+5,(k+1)%n)==t.begin()+5 &&
11280 G->has_edge(hc[t4],hc[k]) && w-weight(hc[t4],hc[k])>.001)
11281 y2_alt.push_back(k);
11282 }
11283 }
11284 lk7:
11285 /* Choose yi:=(t[2i],t[2i+1]) not in hc such that Gi>0. If successful, go to lk5. */
11286 if (i==2) {
11287 if (y2_alt.empty()) { i=1; goto lk4; }
11288 choice=y2_alt.size()==1?0:G->rand_integer(y2_alt.size());
11289 y[2]=make_pair(t4=t[4],t5=t[5]=y2_alt[choice]); y2_alt.erase(y2_alt.begin()+choice);
11290 wy[2]=weight(hc[t4],hc[t5]);
11291 goto lk5;
11292 } else {
11293 int k;
11294 t2i=t[2*i]; t1=t[1];
11295 for (k=0;k<n;++k) {
11296 if (find(t.begin()+1,t.begin()+2*i+1,k)==t.begin()+2*i+1 &&
11297 find(t.begin()+1,t.begin()+2*i+1,(k+1)%n)==t.begin()+2*i+1 &&
11298 G->has_edge(hc[t2i],hc[k]) && w-(wi=weight(hc[t2i],hc[k]))>.001) {
11299 y[i]=make_pair(t2i,t[2*i+1]=k);
11300 wy[i]=wi;
11301 break;
11302 }
11303 }
11304 if (k<n) goto lk5;
11305 }
11306 i=2;
11307 goto lk7;
11308 }
11309
11310 /* find minimum weight perfect matching in an undirected bipartite graph with
11311 * even number of vertices, edge set E and edge weights W */
min_weight_matching_bipartite(const ivector & eind,const dvector & weights,ivector & matched_arcs)11312 void graphe::tsp::min_weight_matching_bipartite(const ivector &eind,const dvector &weights,ivector &matched_arcs) {
11313 set<int> Vset; // set of vertices
11314 for (ivector_iter it=eind.begin();it!=eind.end();++it) {
11315 const arc &a=arcs[*it];
11316 Vset.insert(a.head);
11317 Vset.insert(a.tail);
11318 }
11319 ivector V;
11320 for (set<int>::const_iterator it=Vset.begin();it!=Vset.end();++it) {
11321 V.push_back(*it);
11322 }
11323 int m=eind.size(),n=V.size(),nz=2*m,cnt=0,v;
11324 assert((n%2)==0);
11325 glp_prob *wp=glp_create_prob();
11326 glp_add_rows(wp,n);
11327 glp_add_cols(wp,m);
11328 glp_set_obj_dir(wp,GLP_MIN);
11329 int *ia=new int[nz+1];
11330 int *ja=new int[nz+1];
11331 double *ar=new double[nz+1];
11332 for (int i=0;i<n;++i) {
11333 v=V[i];
11334 for (int j=0;j<m;++j) {
11335 const arc &a=arcs[eind[j]];
11336 if (a.head==v || a.tail==v) {
11337 ia[++cnt]=i+1; ja[cnt]=j+1;
11338 ar[cnt]=1.0;
11339 }
11340 }
11341 }
11342 assert(cnt==nz);
11343 for (int i=0;i<n;++i) glp_set_row_bnds(wp,i+1,GLP_FX,1.0,1.0);
11344 for (int j=0;j<m;++j) {
11345 glp_set_col_kind(wp,j+1,GLP_BV);
11346 glp_set_obj_coef(wp,j+1,weights[j]);
11347 }
11348 glp_load_matrix(wp,nz,ia,ja,ar);
11349 delete[] ia; delete[] ja;
11350 delete[] ar;
11351 glp_smcp lparm;
11352 glp_iocp parm;
11353 glp_init_smcp(&lparm);
11354 lparm.msg_lev=GLP_MSG_OFF;
11355 glp_init_iocp(&parm);
11356 parm.br_tech=GLP_BR_MFV;
11357 parm.bt_tech=GLP_BT_BLB;
11358 parm.gmi_cuts=GLP_ON;
11359 parm.mir_cuts=GLP_ON;
11360 parm.msg_lev=GLP_MSG_OFF;
11361 parm.fp_heur=GLP_ON;
11362 parm.sr_heur=GLP_OFF;
11363 parm.cb_func=&min_wpm_callback;
11364 pair<const ivector*,tsp*> info;
11365 info.first=&eind;
11366 info.second=this;
11367 parm.cb_info=static_cast<void*>(&info);
11368 assert(glp_simplex(wp,&lparm)==0 && glp_get_status(wp)==GLP_OPT);
11369 assert(glp_intopt(wp,&parm)==0 && glp_get_status(wp)==GLP_OPT);
11370 for (int j=0;j<m;++j) {
11371 if (glp_mip_col_val(wp,j+1)!=0)
11372 matched_arcs.push_back(j);
11373 }
11374 glp_delete_prob(wp);
11375 }
11376
min_wpm_heur(glp_tree * tree,const ivector & eind)11377 void graphe::tsp::min_wpm_heur(glp_tree *tree,const ivector &eind) {
11378 vector<bool> vertex_matched(nv,false);
11379 vector<bool> arc_matched(eind.size(),false);
11380 set<int> V;
11381 int i,j,k,n=eind.size();
11382 glp_prob *lp=glp_ios_get_prob(tree);
11383 for (i=0;i<n;++i) {
11384 if (glp_ios_can_branch(tree,i+1)==0 && glp_get_col_prim(lp,i+1)>0.9) {
11385 const arc &a=arcs[eind[i]];
11386 if (vertex_matched[a.head] || vertex_matched[a.tail])
11387 continue;
11388 arc_matched[i]=true;
11389 vertex_matched[a.head]=vertex_matched[a.tail]=true;
11390 }
11391 }
11392 for (ivector_iter it=eind.begin();it!=eind.end();++it) {
11393 k=it-eind.begin();
11394 if (arc_matched[k])
11395 continue;
11396 const arc &a=arcs[*it];
11397 i=a.tail; j=a.head;
11398 V.insert(i); V.insert(j);
11399 if (vertex_matched[i] || vertex_matched[j])
11400 continue;
11401 arc_matched[k]=true;
11402 vertex_matched[i]=vertex_matched[j]=true;
11403 }
11404 int cnt=0;
11405 for (vector<bool>::const_iterator it=arc_matched.begin();it!=arc_matched.end();++it) {
11406 if (*it) ++cnt;
11407 coeff[it-arc_matched.begin()+1]=*it?1.0:0.0;
11408 }
11409 if (int(V.size())==2*cnt)
11410 glp_ios_heur_sol(tree,coeff);
11411 }
11412
11413 /* construct a tour using the method of Christofides for symmetric TSP */
christofides(ivector & hc)11414 void graphe::tsp::christofides(ivector &hc) {
11415 hc.clear();
11416 int n=sg<0?nv:sg_nv,m=sg<0?ne:sg_ne,ei;
11417 /* create spanning tree T of the subgraph with index sg */
11418 graphe T(G->giac_context());
11419 G->minimal_spanning_tree(T,sg);
11420 ivector V;
11421 for (int i=0;i<n;++i) {
11422 if ((T.degree(i)%2)!=0)
11423 V.push_back(G->node_index(T.node_label(i)));
11424 }
11425 /* the number of odd degree vertices in T must be even */
11426 assert(V.size()>0 && (V.size()%2)==0);
11427 /* get edges in SG\T connecting the vertices from V,
11428 * these form a bipartite graph B(V,E) */
11429 ivector eind,matched_arcs;
11430 dvector weights;
11431 for (int k=0;k<m;++k) {
11432 ei=sg<0?k:sg_edges[k];
11433 const arc &a=arcs[ei];
11434 if (find(V.begin(),V.end(),a.head)!=V.end() &&
11435 find(V.begin(),V.end(),a.tail)!=V.end() &&
11436 !T.has_edge(T.node_index(G->node_label(a.tail)),
11437 T.node_index(G->node_label(a.head)))) {
11438 eind.push_back(ei);
11439 weights.push_back(weight(a.tail,a.head));
11440 }
11441 }
11442 if (eind.size()==1)
11443 matched_arcs.resize(1,0);
11444 else min_weight_matching_bipartite(eind,weights,matched_arcs);
11445 assert(2*matched_arcs.size()==V.size());
11446 /* add matched edges to T and find Eulerian circuit,
11447 * such exists because T now has all vertex degrees even */
11448 for (ivector_iter it=matched_arcs.begin();it!=matched_arcs.end();++it) {
11449 const arc &a=arcs[eind[*it]];
11450 const attrib &attr=G->edge_attributes(a.tail,a.head);
11451 T.add_edge(G->node_label(a.tail),G->node_label(a.head),attr);
11452 }
11453 ivector etrail; // eulerian trail
11454 assert(T.find_eulerian_trail(etrail) && etrail.front()==etrail.back());
11455 vector<bool> visited(n,false);
11456 for (ivector_iter it=etrail.begin();it!=etrail.end();++it) {
11457 if (visited[*it])
11458 continue;
11459 hc.push_back(G->node_index(T.node_label(*it)));
11460 visited[*it]=true;
11461 }
11462 hc.push_back(hc.front());
11463 }
11464
11465 /* improve the tour hc by making k-opt moves */
improve_tour(ivector & hc)11466 void graphe::tsp::improve_tour(ivector &hc) {
11467 lin_kernighan(hc);
11468 perform_3opt_moves(hc);
11469 straighten(hc);
11470 }
11471
11472 /* construct an approximate tour, G must be a complete graph */
approx(ivector & hc)11473 double graphe::tsp::approx(ivector &hc) {
11474 assert(is_undir_weighted);
11475 sg=-1;
11476 christofides(hc);
11477 double old_cost=tour_cost(hc),imp_cost;
11478 improve_tour(hc);
11479 imp_cost=tour_cost(hc);
11480 return (1.5*imp_cost/old_cost);
11481 }
11482
11483 /* compute the mean and the standard deviation of the given sample */
sample_mean_stddev(const dvector & sample,double & mean,double & stddev)11484 void graphe::tsp::sample_mean_stddev(const dvector &sample,double &mean,double &stddev) {
11485 assert(!sample.empty());
11486 /* compute the mean */
11487 double sum=0;
11488 for (dvector_iter it=sample.begin();it!=sample.end();++it) {
11489 sum+=*it;
11490 }
11491 mean=sum/double(sample.size());
11492 if (sample.size()==1)
11493 stddev=0;
11494 else {
11495 double d;
11496 sum=0;
11497 for (dvector_iter it=sample.begin();it!=sample.end();++it) {
11498 d=*it-mean;
11499 sum+=d*d;
11500 }
11501 stddev=std::sqrt(sum/double(sample.size()-1));
11502 }
11503 }
11504
11505 /* branching variable selection technique proposed by Padberg & Rinaldi */
select_branching_variable(glp_tree * tree)11506 void graphe::tsp::select_branching_variable(glp_tree *tree) {
11507 glp_prob *lp=glp_ios_get_prob(tree);
11508 int n=glp_get_num_cols(lp),b=-1;
11509 double x0=0.0,x1=1.0,xe;
11510 double par=0.5,rho=3.5,bctol=0.05; // constants
11511 for (int i=0;i<n;++i) {
11512 can_branch[i]=glp_ios_can_branch(tree,i+1)!=0;
11513 xe=xev[i]=glp_get_col_prim(lp,i+1);
11514 if (xe-0.5>=0 && xe<x1) x1=xe;
11515 if (xe-0.5<=0 && xe>x0) x0=xe;
11516 obj[i]=glp_get_obj_coef(lp,i+1);
11517 }
11518 ivector I;
11519 for (int i=0;i<n;++i) {
11520 xe=xev[i];
11521 if (can_branch[i] && (1-par)*x0<=xe && xe<=x1+par*(1-x1))
11522 I.push_back(i);
11523 }
11524 assert(!I.empty());
11525 if (I.size()==1)
11526 b=I.front();
11527 else {
11528 int N=I.size();
11529 vector<pair<double,int> > sorted_by_obj_coeff;
11530 ivector ind(N);
11531 for (ivector_iter it=I.begin();it!=I.end();++it) {
11532 sorted_by_obj_coeff.push_back(make_pair(obj[*it],*it));
11533 }
11534 sort(sorted_by_obj_coeff.begin(),sorted_by_obj_coeff.end());
11535 dvector data2(N),data1(0);
11536 for (int i=0;i<N;++i) {
11537 ind[i]=sorted_by_obj_coeff[i].second;
11538 data2[i]=sorted_by_obj_coeff[i].first;
11539 }
11540 std::reverse(data2.begin(),data2.end());
11541 double mu1,mu2,sigma1,sigma2;
11542 int i=1;
11543 for (;i<N;++i) {
11544 data1.push_back(data2.back());
11545 data2.pop_back();
11546 sample_mean_stddev(data1,mu1,sigma1);
11547 sample_mean_stddev(data2,mu2,sigma2);
11548 if (mu1+rho*sigma1<mu2-rho*sigma2)
11549 break;
11550 }
11551 if (i==N) i=0;
11552 /* the set I2 starts from i in ind */
11553 ivector I2(ind.begin()+i,ind.end());
11554 assert(!I2.empty());
11555 N=I2.size();
11556 double dist,mindist=DBL_MAX;
11557 int j0;
11558 for (int j=0;j<N;++j) {
11559 if ((dist=std::abs(0.5-xev[I2[j]]))<mindist) {
11560 mindist=dist;
11561 j0=j;
11562 }
11563 }
11564 x0=xev[I2[j0]];
11565 double c,maxc=0.0;
11566 for (ivector_iter it=I2.begin();it!=I2.end();++it) {
11567 xe=xev[*it];
11568 if (xe>=x0-bctol && xe<=x0+bctol && (c=obj[*it])>maxc) {
11569 maxc=c;
11570 b=*it;
11571 }
11572 }
11573 }
11574 assert(b>=0);
11575 /* Padberg & Rinaldi suggest exploring the upper branch first */
11576 glp_ios_branch_upon(tree,b+1,GLP_UP_BRNCH);
11577 }
11578
11579 /* row generation (originally written by Andrew Makhorin) */
rowgen(glp_tree * tree)11580 void graphe::tsp::rowgen(glp_tree *tree) {
11581 if (mincut_data.empty())
11582 mincut_data.resize(22);
11583 glp_prob *prob=glp_ios_get_prob(tree);
11584 int i,j,k,m=sg<0?ne:sg_ne,n=sg<0?nv:sg_nv,nedg=0,nz;
11585 double sum,xk;
11586 for (k=0;k<m;k++) {
11587 if (glp_get_col_prim(prob,k+1)>=.001)
11588 nedg++;
11589 }
11590 /* build the capacitated network */
11591 assert(nedg<=m);
11592 ivector &beg=mincut_data[14]; if (int(beg.size())<nedg) beg.resize(nedg);
11593 ivector &end=mincut_data[15]; if (int(end.size())<nedg) end.resize(nedg);
11594 ivector &cap=mincut_data[16]; if (int(cap.size())<nedg) cap.resize(nedg);
11595 nz=0;
11596 for (k=0;k<m;k++) {
11597 if ((xk=glp_get_col_prim(prob,k+1))>=.001) {
11598 const arc &a=arcs[sg<0?k:sg_edges[k]];
11599 beg[nz]=vertex_index(a.tail)+1; end[nz]=vertex_index(a.head)+1;
11600 rlx_sol_map[a.tail][a.head]=xk;
11601 cap[nz++]=std::ceil(1000*xk); // scale edge capacities to make them integral
11602 }
11603 }
11604 assert(nz==nedg);
11605 ivector &cut=mincut_data[17]; if (int(cut.size())<n) cut.resize(n);
11606 minimal_cut(n,nedg,beg,end,cap,cut); // find minimal cut in the capacitated network
11607 nedg=0; sum=0;
11608 for (i=0;i<n;i++) {
11609 for (j=i+1;j<n;j++) {
11610 if ((cut[i] && !cut[j]) || (!cut[i] && cut[j])) {
11611 nedg++;
11612 sum+=rlx_sol_map[sg<0?i:sg_vertices[i]][sg<0?j:sg_vertices[j]];
11613 }
11614 }
11615 }
11616 /* if the (unscaled) capacity of min cut is less than 2, the
11617 * corresponding subtour elimination constraint is violated */
11618 if (sum<=1.999) {
11619 nz=0;
11620 for (i=0;i<n;i++) {
11621 for (j=i+1;j<n;j++) {
11622 if ((cut[i] && !cut[j]) || (!cut[i] && cut[j])) {
11623 nz++;
11624 assert(nz<=nedg);
11625 indices[nz]=edge_index(make_pair(sg<0?i:sg_vertices[i],sg<0?j:sg_vertices[j]))+1;
11626 coeff[nz]=1.0;
11627 }
11628 }
11629 }
11630 assert(nz==nedg);
11631 i=glp_add_rows(prob,1);
11632 glp_set_row_bnds(prob,i,GLP_LO,2.0,0.0);
11633 glp_set_mat_row(prob,i,nz,indices,coeff);
11634 }
11635 }
11636
11637 /* MIP callback routine */
callback(glp_tree * tree,void * info)11638 void graphe::tsp::callback(glp_tree *tree,void *info) {
11639 tsp *tsprob=static_cast<tsp*>(info);
11640 switch (glp_ios_reason(tree)) {
11641 case GLP_IHEUR:
11642 tsprob->heur(tree);
11643 break;
11644 case GLP_IBRANCH:
11645 if (tsprob->is_undir_weighted)
11646 tsprob->select_branching_variable(tree);
11647 break;
11648 case GLP_IROWGEN:
11649 if (tsprob->is_symmetric_tsp)
11650 tsprob->rowgen(tree);
11651 break;
11652 case GLP_IBINGO:
11653 if (tsprob->is_symmetric_tsp && tsprob->sg>=0)
11654 tsprob->get_subtours();
11655 break;
11656 default:
11657 break;
11658 }
11659 }
11660
11661 /* min weight perfect matching solver callback routine */
min_wpm_callback(glp_tree * tree,void * info)11662 void graphe::tsp::min_wpm_callback(glp_tree *tree,void *info) {
11663 pair<const ivector*,tsp*> *origin=static_cast<pair<const ivector*,tsp*>*>(info);
11664 const ivector *eind=origin->first;
11665 tsp *tsprob=origin->second;
11666 //glp_prob *lp=glp_ios_get_prob(tree);
11667 //int n=glp_get_num_cols(lp);
11668 switch (glp_ios_reason(tree)) {
11669 case GLP_IHEUR:
11670 tsprob->min_wpm_heur(tree,*eind);
11671 break;
11672 default:
11673 break;
11674 }
11675 }
11676
11677 /*
11678 * END OF TSP CLASS IMPLEMENTATION
11679 */
11680
11681 /*
11682 * ATSP CLASS (asymmetric traveling salesman problem)
11683 */
11684
atsp(graphe * gr,const ipairs & must_include_arcs)11685 graphe::atsp::atsp(graphe *gr,const ipairs &must_include_arcs) {
11686 G=gr;
11687 mia=must_include_arcs;
11688 mip=NULL;
11689 isweighted=G->is_weighted();
11690 }
11691
~atsp()11692 graphe::atsp::~atsp() {
11693 if (mip!=NULL) glp_delete_prob(mip);
11694 }
11695
solve(ivector & hc,double & cost)11696 bool graphe::atsp::solve(ivector &hc,double &cost) {
11697 if (mip!=NULL) glp_erase_prob(mip);
11698 else mip=glp_create_prob();
11699 glp_set_obj_dir(mip,GLP_MIN);
11700 int n=G->node_count(),nz=8+8*n*(n-2)+n*ft.size(),i,j,r,c=0;
11701 int *u=new int[n];
11702 int **x=new int*[n];
11703 for (i=0;i<n;++i) x[i]=new int[n];
11704 int *ia=new int[nz+1];
11705 int *ja=new int[nz+1];
11706 double *ar=new double[nz+1];
11707 double w;
11708 gen e;
11709 ipairs E;
11710 G->get_edges_as_pairs(E);
11711 /* add variables */
11712 for (ipairs_iter it=E.begin();it!=E.end();++it) {
11713 i=it->first; j=it->second;
11714 x[i][j]=glp_add_cols(mip,1);
11715 if (find(mia.begin(),mia.end(),*it)!=mia.end())
11716 glp_set_col_bnds(mip,x[i][j],GLP_FX,1,1);
11717 else glp_set_col_kind(mip,x[i][j],GLP_BV);
11718 if (isweighted) {
11719 e=_evalf(G->weight(i,j),G->giac_context());
11720 if (e.type!=_DOUBLE_) {
11721 *logptr(G->giac_context()) << "Warning: arc weight " << e
11722 << " is not numeric, replacing by 1\n";
11723 w=1;
11724 } else w=e.DOUBLE_val();
11725 } else w=1;
11726 glp_set_obj_coef(mip,x[i][j],w);
11727 }
11728 for (i=1;i<n;++i) {
11729 u[i]=glp_add_cols(mip,1);
11730 glp_set_col_bnds(mip,u[i],GLP_DB,2,n);
11731 }
11732 /* create the basic constraints */
11733 for (i=0;i<n;++i) {
11734 r=glp_add_rows(mip,2);
11735 glp_set_row_bnds(mip,r,GLP_FX,1,1);
11736 glp_set_row_bnds(mip,r+1,GLP_FX,1,1);
11737 for (j=0;j<n;++j) {
11738 if (i==j) continue;
11739 if (G->has_edge(i,j)) { ia[++c]=x[i][j]; ja[c]=r; ar[c]=1; }
11740 if (G->has_edge(j,i)) { ia[++c]=x[j][i]; ja[c]=r+1; ar[c]=1; }
11741 }
11742 }
11743 /* SEC: an enhanced formulation of Miller et al. */
11744 for (i=1;i<n;++i) {
11745 for (j=1;j<n;++j) {
11746 if (i==j) continue;
11747 r=glp_add_rows(mip,1);
11748 glp_set_row_bnds(mip,r,GLP_UP,0,n-1);
11749 ia[++c]=u[i]; ja[c]=r; ar[c]=1;
11750 ia[++c]=u[j]; ja[c]=r; ar[c]=-1;
11751 if (G->has_edge(i,j)) { ia[++c]=x[i][j]; ja[c]=r; ar[c]=n; }
11752 if (G->has_edge(j,i)) { ia[++c]=x[j][i]; ja[c]=r; ar[c]=n-2; }
11753 }
11754 }
11755 /* forbid the specified tours */
11756 for (ivectors_iter it=ft.begin();it!=ft.end();++it) {
11757 r=glp_add_rows(mip,1);
11758 glp_set_row_bnds(mip,r,GLP_UP,0,n-1);
11759 for (int k=0;k<n;++k) {
11760 i=it->at(k); j=it->at(k+1);
11761 assert(G->has_edge(i,j));
11762 ia[++c]=x[i][j]; ja[c]=r; ar[c]=1;
11763 }
11764 }
11765 assert(c<=nz);
11766 glp_load_matrix(mip,c,ja,ia,ar);
11767 delete[] ia; delete[] ja; delete[] ar; delete[] u;
11768 /* solve the problem */
11769 glp_iocp parm;
11770 glp_init_iocp(&parm);
11771 parm.msg_lev=GLP_OFF;
11772 parm.br_tech=GLP_BR_FFV;
11773 parm.presolve=GLP_ON;
11774 parm.gmi_cuts=GLP_ON;
11775 parm.mir_cuts=GLP_ON;
11776 parm.fp_heur=GLP_ON;
11777 bool ret=false;
11778 if (glp_intopt(mip,&parm)==0) {
11779 ret=true;
11780 switch(glp_mip_status(mip)) {
11781 case GLP_FEAS:
11782 *logptr(G->giac_context()) << "Warning: the solution is not necessarily optimal\n";
11783 case GLP_OPT:
11784 break;
11785 case GLP_UNDEF:
11786 *logptr(G->giac_context()) << "Warning: obtained an undefined solution\n";
11787 case GLP_NOFEAS:
11788 ret=false;
11789 break;
11790 }
11791 if (ret) {
11792 cost=glp_mip_obj_val(mip);
11793 int n=G->node_count(),i,j,pos=0;
11794 hc.resize(n+1,0);
11795 while (pos<n) {
11796 i=hc[pos];
11797 for (j=0;j<n;++j) {
11798 if (i==j || !G->has_edge(i,j)) continue;
11799 if (glp_mip_col_val(mip,x[i][j])>0.5) {
11800 hc[++pos]=j;
11801 break;
11802 }
11803 }
11804 assert(j<n);
11805 }
11806 assert(hc.back()==hc.front());
11807 }
11808 }
11809 for (i=0;i<n;++i) delete[] x[i];
11810 delete[] x;
11811 return ret;
11812 }
11813
ksolve(int k,ivectors & hcv,dvector & costs)11814 void graphe::atsp::ksolve(int k,ivectors &hcv,dvector &costs) {
11815 hcv.clear();
11816 costs.clear();
11817 ft.clear();
11818 hcv.reserve(k);
11819 costs.reserve(k);
11820 ft.reserve(k-1);
11821 ivector hc;
11822 double cost;
11823 for (int cnt=0;cnt<k;++cnt) {
11824 if (!solve(hc,cost)) break;
11825 hcv.push_back(hc);
11826 costs.push_back(cost);
11827 if (cnt<k-1) ft.push_back(hc);
11828 }
11829 }
11830
11831 /*
11832 * END OF ATSP CLASS IMPLEMENTATION
11833 */
11834
11835 #endif
11836
11837 /* Try to find an optimal Hamiltonian cycle.
11838 * Return 0 if the graph is not Hamiltonian, else store the circuit in h
11839 * and return 1, if unable to solve return -1 */
traveling_salesman(ivector & h,double & cost,bool approximate)11840 int graphe::traveling_salesman(ivector &h,double &cost,bool approximate) {
11841 #ifdef HAVE_LIBGLPK
11842 tsp t(this);
11843 if (approximate) {
11844 double ratio=t.approx(h);
11845 message("The tour cost is within %d%% of the optimal value",
11846 std::floor((ratio-1.0)*100.0+.5));
11847 cost=t.tour_cost(h);
11848 return 1;
11849 }
11850 return t.solve(h,cost);
11851 #else
11852 message("Error: GLPK library is required for solving traveling salesman problem");
11853 return -1;
11854 #endif
11855 }
11856
11857 /* find first k optimal tours in directed graph */
find_directed_tours(int k,ivectors & hcv,dvector & costs,const ipairs & incl)11858 bool graphe::find_directed_tours(int k,ivectors &hcv,dvector &costs,const ipairs &incl) {
11859 assert(is_directed());
11860 #ifdef HAVE_LIBGLPK
11861 atsp t(this,incl);
11862 t.ksolve(k,hcv,costs);
11863 return true;
11864 #else
11865 message("Error: GLPK library is required for solving traveling salesman problem");
11866 return false;
11867 #endif
11868 }
11869
11870 /* for each edge of the graph, assign the distance between endpoints as a weight */
make_euclidean_distances()11871 bool graphe::make_euclidean_distances() {
11872 assert(!is_weighted() && !is_directed());
11873 layout x;
11874 if (!has_stored_layout(x))
11875 return false;
11876 if (!x.empty()) {
11877 int n=node_count();
11878 set_weighted(true);
11879 point pq(x.front().size());
11880 for (int i=0;i<n;++i) {
11881 const point &p=x[i];
11882 for (int j=i+1;j<n;++j) {
11883 const point &q=x[j];
11884 set_edge_attribute(i,j,_GT_ATTRIB_WEIGHT,gen(point_distance(p,q,pq)));
11885 }
11886 }
11887 }
11888 return true;
11889 }
11890
11891 /* find the maximum flow using Edmonds-Karp algorithm (exact computation) */
maxflow_edmonds_karp(int s,int t,vector<map<int,gen>> & flow,const gen & limit)11892 gen graphe::maxflow_edmonds_karp(int s,int t,vector<map<int,gen> > &flow,const gen &limit) {
11893 assert(is_directed() && node_queue.empty());
11894 gen mf(0),df; // the value of maximum flow
11895 int n=node_count(),i,j;
11896 vector<map<int,gen> > cap(n);
11897 /* initialize arc capacities and flows */
11898 flow.resize(n);
11899 bool isweighted=is_weighted();
11900 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
11901 i=it-nodes.begin();
11902 map<int,gen> &c=cap[i];
11903 flow[i].clear();
11904 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
11905 j=*jt;
11906 c[j]=isweighted?weight(i,j):gen(1); // all capacities are set to 1 in unweighted graphs
11907 }
11908 }
11909 ipairs pred(n);
11910 ipair nullpair=make_pair(-1,-1);
11911 while (true) {
11912 /* run BFS */
11913 node_queue.push(s);
11914 std::fill(pred.begin(),pred.end(),nullpair);
11915 while (!node_queue.empty()) {
11916 i=node_queue.front();
11917 node_queue.pop();
11918 const vertex &v=node(i);
11919 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
11920 j=*it;
11921 if (j!=s && pred[j]==nullpair && is_strictly_greater(cap[i][j],flow[i][j],ctx)) {
11922 pred[j]=make_pair(i,j);
11923 node_queue.push(j);
11924 }
11925 }
11926 }
11927 if (pred[t]!=nullpair) {
11928 /* found an augmenting path */
11929 df=plusinf();
11930 /* compute df = how much flow can we send ... */
11931 for (ipair e=pred[t];e.first>=0;e=pred[e.first]) {
11932 df=min(df,cap[e.first][e.second]-flow[e.first][e.second],ctx);
11933 }
11934 /* ... and increase edge flows by df */
11935 for (ipair e=pred[t];e.first>=0;e=pred[e.first]) {
11936 flow[e.first][e.second]+=df;
11937 flow[e.second][e.first]-=df;
11938 }
11939 mf+=df;
11940 if (is_greater(mf,limit,ctx))
11941 break;
11942 } else break;
11943 }
11944 return mf; // return the maximum flow
11945 }
11946
11947 /* obtain a minimum cut from maximum flow */
minimum_cut(int s,const vector<map<int,gen>> & flow,ipairs & cut)11948 void graphe::minimum_cut(int s,const vector<map<int,gen> > &flow,ipairs &cut) {
11949 /* create the residual network */
11950 graphe G(ctx,false);
11951 G.add_nodes(node_count());
11952 G.make_directed();
11953 cut.clear();
11954 int i,j;
11955 gen c,f;
11956 bool isweighted=is_weighted();
11957 map<int,gen>::const_iterator mit;
11958 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
11959 i=it-nodes.begin();
11960 const map<int,gen> &flowi=flow[i];
11961 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
11962 j=*jt;
11963 f=max(0,(mit=flowi.find(j))!=flowi.end()?mit->second:gen(0),ctx);
11964 c=isweighted?weight(i,j):gen(1);
11965 if (!is_zero(_ratnormal(c-f,ctx),ctx))
11966 G.add_edge(i,j);
11967 }
11968 }
11969 /* run DFS on the residual network, store all discovered nodes */
11970 ivector disc;
11971 G.dfs(s,true,true,&disc);
11972 unvisit_all_nodes();
11973 for (ivector_iter it=disc.begin();it!=disc.end();++it) {
11974 node(*it).set_visited(true);
11975 }
11976 /* if, for an edge (u,v), u is discovered and v is not
11977 * or vice versa, (u,v) belongs to the cut */
11978 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
11979 for (ivector_iter jt=it->neighbors().begin();jt!=it->neighbors().end();++jt) {
11980 if (it->is_visited() && !node(*jt).is_visited())
11981 cut.push_back(make_pair(it-nodes.begin(),*jt));
11982 }
11983 }
11984 }
11985
make_colon_label(const ivector & v)11986 gen graphe::make_colon_label(const ivector &v) {
11987 stringstream ss;
11988 for (ivector_iter it=v.begin();it!=v.end();++it) {
11989 ss << *it;
11990 if (it+1!=v.end())
11991 ss << ":";
11992 }
11993 return graphe::str2gen(ss.str(),true);
11994 }
11995
colon_label(int i,int j)11996 gen graphe::colon_label(int i, int j) {
11997 ivector v(2);
11998 v[0]=i; v[1]=j;
11999 return make_colon_label(v);
12000 }
12001
colon_label(int i,int j,int k)12002 gen graphe::colon_label(int i, int j,int k) {
12003 ivector v(3);
12004 v[0]=i; v[1]=j; v[2]=k;
12005 return make_colon_label(v);
12006 }
12007
12008 /* convert this multigraph to simple graph by adding new colored vertices */
simplify(graphe & G,bool color_temp_vertices) const12009 void graphe::simplify(graphe &G,bool color_temp_vertices) const {
12010 assert(!is_directed() && (supports_attributes() || !G.supports_attributes()));
12011 ipairs E;
12012 int lab,k,i,hcol=default_highlighted_vertex_color;
12013 get_edges_as_pairs(E);
12014 G.clear();
12015 if (G.supports_attributes()) {
12016 G.add_nodes(vertices());
12017 lab=G.largest_integer_label();
12018 } else G.add_nodes(node_count());
12019 for (ipairs_iter it=E.begin();it!=E.end();++it) {
12020 const ipair &e=*it;
12021 k=multiedges(e);
12022 if (k>0) {
12023 for (int c=0;c<=k;++c) {
12024 i=G.supports_attributes()?G.add_node(++lab):G.add_node();
12025 if (color_temp_vertices) {
12026 if (G.supports_attributes())
12027 G.set_node_attribute(i,_GT_ATTRIB_COLOR,hcol);
12028 else G.set_node_color(i,hcol);
12029 }
12030 G.add_edge(e.first,i);
12031 G.add_edge(e.second,i);
12032 }
12033 } else G.add_edge(e);
12034 }
12035 }
12036
12037 /* permute vertices according to SHARC ordering by Michael Monagan */
sharc_order()12038 void graphe::sharc_order() {
12039 /* assuming that the graph is connected */
12040 assert(!is_null() && node_queue.empty());
12041 int n=node_count(),i,j;
12042 unset_subgraphs(0);
12043 node(0).set_subgraph(1); // the set S has subgraph=1
12044 node(0).set_visited(true);
12045 ivector order(1,0); // vertices in S
12046 order.reserve(n);
12047 set<int> adj;
12048 bool has_path;
12049 while (subgraph_size(1)<n) {
12050 /* collect vertices adjacent to S */
12051 adj.clear();
12052 for (ivector_iter it=order.begin();it!=order.end();++it) {
12053 const vertex &v=node(*it);
12054 for (ivector_iter jt=v.neighbors().begin();jt!=v.neighbors().end();++jt) {
12055 if (node(*jt).subgraph()==0)
12056 adj.insert(*jt);
12057 }
12058 }
12059 /* add vertices from S to queue */
12060 for (set<int>::const_iterator it=adj.begin();it!=adj.end();++it) {
12061 node_queue.push(*it);
12062 }
12063 unvisit_all_nodes(0);
12064 unset_all_ancestors(0);
12065 has_path=false;
12066 while (!node_queue.empty()) {
12067 i=node_queue.front();
12068 node_queue.pop();
12069 vertex &v=node(i);
12070 if (!v.is_visited()) {
12071 v.set_visited(true);
12072 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
12073 vertex &w=node(j=*it);
12074 if (w.is_visited())
12075 continue;
12076 if (adj.find(j)!=adj.end()) {
12077 /* path found */
12078 w.set_ancestor(i);
12079 do {
12080 order.push_back(j);
12081 node(j).set_subgraph(1);
12082 } while ((j=node(j).ancestor())>=0);
12083 clear_node_queue();
12084 has_path=true;
12085 break;
12086 }
12087 if (w.subgraph()==0) {
12088 w.set_ancestor(i);
12089 node_queue.push(j);
12090 }
12091 }
12092 }
12093 }
12094 if (!has_path) {
12095 i=*adj.begin();
12096 node(i).set_subgraph(1);
12097 order.push_back(i);
12098 }
12099 }
12100 graphe G(*this);
12101 G.isomorphic_copy(*this,order);
12102 }
12103
12104 map<graphe::ivector,vector<graphe::cpol> > graphe::cache;
12105
12106 /* implementation of cpol class */
12107
assign(const cpol & other)12108 void graphe::cpol::assign(const cpol &other) {
12109 nv=other.nv;
12110 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
12111 cg=other.cg;
12112 col=other.col;
12113 #else
12114 adj=other.adj;
12115 #endif
12116 sz=other.sz;
12117 frq=other.frq;
12118 poly=other.poly;
12119 }
12120
cpol(const cpol & other)12121 graphe::cpol::cpol(const cpol &other) {
12122 assign(other);
12123 }
12124
12125 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
cpol(int n,ulong * g,int * c,size_t s,const intpoly & p)12126 graphe::cpol::cpol(int n,ulong *g,int *c,size_t s,const intpoly &p) {
12127 nv=n;
12128 cg=g;
12129 col=c;
12130 sz=s;
12131 frq=0;
12132 poly=p;
12133 }
12134 #else
cpol(int n,int * a,size_t s,const intpoly & p)12135 graphe::cpol::cpol(int n,int *a,size_t s,const intpoly &p) {
12136 nv=n;
12137 adj=a;
12138 sz=s;
12139 frq=0;
12140 poly=p;
12141 }
12142 #endif
12143
operator =(const cpol & other)12144 graphe::cpol &graphe::cpol::operator =(const cpol &other) {
12145 assign(other);
12146 return *this;
12147 }
12148
12149 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
match(int n,ulong * g,int * c) const12150 bool graphe::cpol::match(int n,ulong *g,int *c) const {
12151 if (nv!=n)
12152 return false;
12153 for (int i=0;i<n;++i) {
12154 if (c[i]!=col[i])
12155 return false;
12156 }
12157 size_t cnt=0;
12158 for (;cnt<sz;++cnt) {
12159 if (g[cnt]!=cg[cnt])
12160 return false;
12161 }
12162 return true;
12163 }
12164 #else
match(int n,int * a,int adj_sz) const12165 bool graphe::cpol::match(int n,int *a,int adj_sz) const {
12166 if (nv!=n || sz!=adj_sz)
12167 return false;
12168 for (int i=0;i<sz;++i) {
12169 if (adj[i]!=a[i])
12170 return false;
12171 }
12172 return true;
12173 }
12174 #endif
12175
12176 /* end of cpol class implementation */
12177
12178 /* add the polynomial b to a (a is changed in place) */
poly_add(intpoly & a,const intpoly & b)12179 void graphe::poly_add(intpoly &a,const intpoly &b) {
12180 for (intpoly_iter it=b.begin();it!=b.end();++it) {
12181 a[it->first]+=it->second;
12182 }
12183 }
12184
12185 /* multiply the polynomial a with b (a is changed in place) */
poly_mult(intpoly & a,const intpoly & b)12186 void graphe::poly_mult(intpoly &a,const intpoly &b) {
12187 intpoly c(a);
12188 a.clear();
12189 for (intpoly_iter it=b.begin();it!=b.end();++it) {
12190 const ipair &p=it->first;
12191 for (intpoly_iter jt=c.begin();jt!=c.end();++jt) {
12192 const ipair &q=jt->first;
12193 a[make_pair(p.first+q.first,p.second+q.second)]+=it->second*jt->second;
12194 }
12195 }
12196 }
12197
12198 /* return the geometric sequence in variable var (1 or 2) of length k */
poly_geom(int var,int k,bool leading_one,bool add_other_var)12199 graphe::intpoly graphe::poly_geom(int var,int k,bool leading_one,bool add_other_var) {
12200 assert((var==1 || var==2) && k>0);
12201 intpoly res;
12202 for (int i=leading_one?0:1;i<k;++i) {
12203 res[make_pair(var==1?i:0,var==2?i:0)]=1;
12204 }
12205 if (add_other_var)
12206 res[make_pair(var==2?1:0,var==1?1:0)]=1;
12207 return res;
12208 }
12209
12210 /* return 1 as polynom */
poly_one()12211 graphe::intpoly graphe::poly_one() {
12212 intpoly res;
12213 res[make_pair(0,0)]=1;
12214 return res;
12215 }
12216
12217 /* convert list of integers to a 2-variable polynomial with integral coefficients */
intpoly2gen(const intpoly & v,const gen & x,const gen & y)12218 gen graphe::intpoly2gen(const intpoly &v,const gen &x,const gen &y) {
12219 int pwx,pwy,cf;
12220 gen p(0);
12221 for (intpoly_iter it=v.begin();it!=v.end();++it) {
12222 pwx=it->first.first;
12223 pwy=it->first.second;
12224 cf=it->second;
12225 p+=gen(cf)*(pwx==0?gen(1):pow(x,pwx))*(pwy==0?gen(1):pow(y,pwy));
12226 }
12227 return p;
12228 }
12229
12230 static int tutte_iter_count;
12231 static int tutte_hits;
12232 static clock_t tutte_time_start;
12233 static double tutte_matching_time;
12234
12235 /* compute the Tutte polynomial for this graph, using vorder-push heuristic */
tutte_poly_recurse(int vc)12236 graphe::intpoly graphe::tutte_poly_recurse(int vc) {
12237 ++tutte_iter_count;
12238 intpoly p=poly_one(),fac;
12239 int n=node_count(),adj_sz,snv;
12240 bool isom;
12241 ipair e;
12242 vector<ipairs> blocks;
12243 ipairs E;
12244 graphe G(ctx,false),Gd(ctx,false),Gc(ctx,false);
12245 matrice L;
12246 ivector L_cp;
12247 map<ivector,vector<cpol> >::iterator ct;
12248 int *adj,*col;
12249 ulong *cg;
12250 size_t cg_sz;
12251 switch (vc) {
12252 case 2:
12253 assert(n>2);
12254 /* process cycles with multiedges */
12255 if (is_cycle(E)) {
12256 p=poly_geom(2,multiedges(E[n-1])+multiedges(E[n-2])+2,false,true);
12257 for (int i=1;i<=n-2;++i) {
12258 poly_mult(p,poly_geom(2,1+multiedges(E[i-1]),true));
12259 }
12260 for (int i=1;i<=n-2;++i) {
12261 intpoly q=poly_one();
12262 q[make_pair(0,0)]=1;
12263 for (int j=i+1;j<=n;++j) {
12264 poly_mult(q,poly_geom(2,1+multiedges(E[j-1]),false,true));
12265 }
12266 for (int j=1;j<=i-1;++j) {
12267 poly_mult(q,poly_geom(2,1+multiedges(E[j-1]),true));
12268 }
12269 poly_add(p,q);
12270 }
12271 break;
12272 }
12273 /* check for cached isomorphic graph, record the time */
12274 isom=false;
12275 tutte_time_start=clock();
12276 simplify(G,true);
12277 G.laplacian_matrix(L);
12278 L_cp=vecteur_2_vector_int(*_eval(symbolic(at_charpoly,L),ctx)._VECTptr); // charpoly of the Laplacian
12279 adj=G.to_array(adj_sz,true);
12280 snv=G.node_count();
12281 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
12282 cg_sz=nautywrapper_words_needed(snv)*(size_t)snv;
12283 cg=new ulong[cg_sz];
12284 col=new int[snv];
12285 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
12286 nautywrapper_canonical(0,snv,adj,NULL,cg,col);
12287 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
12288 delete[] adj;
12289 #endif
12290 if ((ct=cache.find(L_cp))!=cache.end()) {
12291 for (vector<cpol>::iterator it=ct->second.begin();it!=ct->second.end();++it) {
12292 cpol &cp=*it;
12293 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
12294 if (cp.match(snv,cg,col)) {
12295 ++cp.frq;
12296 ++tutte_hits;
12297 delete[] cg;
12298 delete[] col;
12299 p=cp.poly;
12300 isom=true;
12301 break;
12302 }
12303 #else
12304 if (cp.match(snv,adj,adj_sz)) {
12305 ++cp.frq;
12306 ++tutte_hits;
12307 delete[] adj;
12308 p=cp.poly;
12309 isom=true;
12310 break;
12311 }
12312 #endif
12313 }
12314 }
12315 tutte_matching_time+=double(clock()-tutte_time_start)/CLOCKS_PER_SEC;
12316 if (isom) break;
12317 /* no luck, perform the delete-contract step */
12318 get_edges_as_pairs(E);
12319 e=E.front();
12320 for (ipairs_iter it=E.begin()+1;it!=E.end();++it) {
12321 if (*it<e) e=*it;
12322 }
12323 fac=poly_geom(2,1+multiedges(e),true);
12324 set_multiedge(e,0);
12325 copy(Gd); copy(Gc); // copies to perform deletion-contraction on
12326 Gd.remove_edge(e);
12327 Gc.contract_edge(e.second,e.first,false);
12328 p=Gd.tutte_poly_recurse(1);
12329 poly_mult(fac,Gc.tutte_poly_recurse(1));
12330 poly_add(p,fac);
12331 /* cache the graph and its polynomial for future use */
12332 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
12333 cache[L_cp].push_back(cpol(snv,cg,col,cg_sz,p));
12334 #else
12335 cache[L_cp].push_back(cpol(snv,adj,adj_sz,p));
12336 #endif
12337 break;
12338 case 1:
12339 find_blocks(blocks);
12340 for (vector<ipairs>::iterator it=blocks.begin();it!=blocks.end();++it) {
12341 ipairs &block=*it;
12342 assert(!block.empty());
12343 if (block.size()==1) { // bridge
12344 poly_mult(p,poly_geom(2,1+multiedges(block.front()),false,true));
12345 } else { // non-trivial biconnected subgraph
12346 sort(block.begin(),block.end());
12347 extract_subgraph(block,G);
12348 poly_mult(p,G.tutte_poly_recurse(2));
12349 }
12350 }
12351 break;
12352 default:
12353 assert(false);
12354 }
12355 return p;
12356 }
12357
12358 /* return the Tutte polynomial of this graph */
tutte_polynomial(const gen & x,const gen & y)12359 gen graphe::tutte_polynomial(const gen &x,const gen &y) {
12360 assert(cache.empty() && !is_directed());
12361 tutte_iter_count=tutte_hits=0;
12362 tutte_matching_time=0;
12363 intpoly p;
12364 graphe G(ctx,false);
12365 if (is_connected()) {
12366 copy(G);
12367 G.sort_by_degrees();
12368 G.sharc_order();
12369 p=G.tutte_poly_recurse(1);
12370 } else {
12371 p=poly_one();
12372 ivectors comp;
12373 connected_components(comp);
12374 for (ivectors::iterator it=comp.begin();it!=comp.end();++it) {
12375 if (it->size()<2)
12376 continue;
12377 sort(it->begin(),it->end());
12378 induce_subgraph(*it,G);
12379 G.sort_by_degrees();
12380 G.sharc_order();
12381 poly_mult(p,G.tutte_poly_recurse(1));
12382 }
12383 }
12384 /* clear the cache and return the Tutte polynomial p */
12385 for (map<ivector,vector<cpol> >::iterator it=cache.begin();it!=cache.end();++it) {
12386 for (vector<cpol>::const_iterator jt=it->second.begin();jt!=it->second.end();++jt) {
12387 #if defined HAVE_LIBNAUTY && defined HAVE_NAUTY_NAUTUTIL_H
12388 delete[] jt->cg;
12389 delete[] jt->col;
12390 #else
12391 delete[] jt->adj;
12392 #endif
12393 }
12394 it->second.clear();
12395 }
12396 cache.clear();
12397 return intpoly2gen(p,x,y);
12398 }
12399
12400 /* find all fundamental cycles in this graph */
fundamental_cycles(ivectors & cycles,int sg,bool check)12401 void graphe::fundamental_cycles(ivectors &cycles,int sg,bool check) {
12402 assert(!is_directed());
12403 ivectors comp;
12404 if (check) {
12405 connected_components(comp,sg);
12406 if (comp.size()>1) {
12407 int nsg=max_subgraph_index();
12408 for (ivectors_iter it=comp.begin();it!=comp.end();++it) {
12409 set_subgraph(*it,++nsg);
12410 fundamental_cycles(cycles,nsg,false);
12411 }
12412 return;
12413 }
12414 }
12415 ipairs E,nte;
12416 get_edges_as_pairs(E,sg);
12417 int root=sg<0?0:first_vertex_from_subgraph(sg),i,j;
12418 dfs(root,true,true,NULL,sg);
12419 for (ipairs_iter it=E.begin();it!=E.end();++it) {
12420 i=it->first; j=it->second;
12421 if (node(i).ancestor()!=j && node(j).ancestor()!=i)
12422 nte.push_back(*it);
12423 }
12424 for (ipairs_iter it=nte.begin();it!=nte.end();++it) {
12425 const vertex &v=node(it->first),&w=node(it->second);
12426 i=v.disc()>w.disc()?it->first:it->second;
12427 j=v.disc()<w.disc()?it->first:it->second;
12428 ivector c;
12429 while (i!=j) {
12430 c.push_back(i);
12431 i=node(i).ancestor();
12432 assert(i>=0);
12433 }
12434 c.push_back(j);
12435 cycles.push_back(c);
12436 }
12437 }
12438
12439 /* construct Mycielski graph with 2n+1 vertices and 3m+n edges */
mycielskian(graphe & G) const12440 void graphe::mycielskian(graphe &G) const {
12441 assert(!is_directed());
12442 ipairs E;
12443 get_edges_as_pairs(E);
12444 int lab=largest_integer_label(),n=node_count(),m=E.size();
12445 copy(G);
12446 ivector u(n);
12447 for (int i=0;i<n;++i) {
12448 u[i]=G.add_node(++lab);
12449 }
12450 int w=G.add_node(++lab);
12451 for (ipairs_iter it=E.begin();it!=E.end();++it) {
12452 G.add_edge(it->first,u[it->second]);
12453 G.add_edge(it->second,u[it->first]);
12454 }
12455 for (int i=0;i<n;++i) {
12456 G.add_edge(w,u[i]);
12457 }
12458 assert(G.node_count()==2*n+1 && G.edge_count()==3*m+n);
12459 }
12460
12461 /* return the local clustering coefficient of the i-th vertex */
local_clustering_coeff(int i) const12462 gen graphe::local_clustering_coeff(int i) const {
12463 assert(!is_directed());
12464 const vertex &v=node(i);
12465 const ivector &vn=v.neighbors();
12466 int d=vn.size(),cnt=0;
12467 for (ivector_iter it=vn.begin();it!=vn.end();++it) {
12468 const ivector &wn=node(*it).neighbors();
12469 cnt+=intersect_linear(vn.begin(),vn.end(),wn.begin(),wn.end());
12470 }
12471 return _ratnormal(fraction(cnt,d*(d-1)),ctx);
12472 }
12473
12474 /* return the clustering coefficient of this graph */
clustering_coeff(bool approx,bool exact)12475 gen graphe::clustering_coeff(bool approx,bool exact) {
12476 assert(!is_directed());
12477 int i,j,n=node_count();
12478 if (n<3) return 0;
12479 if (approx) {
12480 /* approximate within +-1/2*1e-2 with probability 0.9999 */
12481 int k=184207,l=0,u,v;
12482 for (i=0;i<k;++i) {
12483 j=rand_integer(n);
12484 const ivector &ngh=node(j).neighbors();
12485 u=ngh[rand_integer(ngh.size())];
12486 while (u==(v=ngh[rand_integer(ngh.size())]));
12487 if (has_edge(u,v)) ++l;
12488 }
12489 return _evalf(fraction(l,k),ctx);
12490 }
12491 return triangle_count(NULL,true,exact);
12492 }
12493
12494 /* return the triangle density (transitivity) of this graph */
transitivity()12495 gen graphe::transitivity() {
12496 gen num_triangles(0),num_triplets(0);
12497 if (!is_directed()) {
12498 num_triangles=gen(3)*triangle_count();
12499 for (node_iter it=nodes.begin();it!=nodes.end();++it) {
12500 num_triplets+=comb(it->neighbors().size(),2);
12501 }
12502 } else {
12503 ipairs E;
12504 get_edges_as_pairs(E);
12505 int i,j;
12506 for (ipairs_iter it=E.begin();it!=E.end();++it) {
12507 i=it->first; j=it->second;
12508 const vertex &v=node(i),&w=node(j);
12509 const ivector &vn=v.neighbors(),&wn=w.neighbors();
12510 num_triangles+=intersect_linear(vn.begin(),vn.end(),wn.begin(),wn.end());
12511 num_triplets+=wn.size()-(w.has_neighbor(i)?1:0);
12512 }
12513 }
12514 if (is_zero(num_triplets))
12515 return 0;
12516 return _ratnormal(fraction(num_triangles,num_triplets),ctx);
12517 }
12518
12519 /* return the edge connectivity of this graph using Matula's algorithm */
edge_connectivity()12520 int graphe::edge_connectivity() {
12521 int n=node_count();
12522 assert(n>=2 && !is_directed());
12523 set<int> D,A;
12524 vector<map<int,gen> > flow;
12525 int p,lambda=RAND_MAX,d,v,w,lambda_vw,maxdeg,i;
12526 /* set lambda to its upper bound */
12527 for (i=0;i<n;++i) {
12528 if ((d=degree(i))<lambda) {
12529 p=i;
12530 lambda=d;
12531 }
12532 }
12533 /* construct a dominating set D */
12534 v=p; maxdeg=lambda;
12535 for (i=0;i<n;++i) {
12536 A.insert(i);
12537 if (i!=v && (d=degree(i))>maxdeg) {
12538 maxdeg=d;
12539 v=i;
12540 }
12541 }
12542 set<int>::iterator sit;
12543 while (true) {
12544 D.insert(v);
12545 A.erase(A.find(v));
12546 const vertex &vv=node(v);
12547 for (ivector_iter it=vv.neighbors().begin();it!=vv.neighbors().end();++it) {
12548 sit=A.find(*it);
12549 if (sit!=A.end())
12550 A.erase(sit);
12551 }
12552 if (A.empty()) break;
12553 v=*A.begin();
12554 }
12555 /* find lambda(G) */
12556 v=*D.begin();
12557 D.erase(D.begin());
12558 set_directed(true);
12559 for (set<int>::const_iterator it=D.begin();it!=D.end();++it) {
12560 w=*it;
12561 lambda_vw=maxflow_edmonds_karp(v,w,flow).val;
12562 if (lambda_vw<lambda)
12563 lambda=lambda_vw;
12564 }
12565 set_directed(false);
12566 return lambda;
12567 }
12568
vertex_pair_connectivity(int v,int w)12569 int graphe::vertex_pair_connectivity(int v,int w) {
12570 int n=node_count();
12571 graphe D(ctx,false);
12572 D.set_directed(true);
12573 D.add_nodes(2*n);
12574 int u1,u2;
12575 for (int i=0;i<n;++i) {
12576 u1=2*i; u2=2*i+1;
12577 if (i!=v || i!=w)
12578 D.add_edge(u1,u2);
12579 const vertex &u=node(i);
12580 for (ivector_iter it=u.neighbors().begin();it!=u.neighbors().end();++it) {
12581 if (i!=v) D.add_edge(*it,u1);
12582 if (i!=w) D.add_edge(u2,*it);
12583 }
12584 }
12585 vector<map<int,gen> > flow;
12586 return D.maxflow_edmonds_karp(2*v+1,2*w,flow).val;
12587 }
12588
12589 /* return the vertex connectivity of an undirected graph */
vertex_connectivity()12590 int graphe::vertex_connectivity() {
12591 int n=node_count(),k=RAND_MAX,mindeg=RAND_MAX,deg,v;
12592 for (int i=0;i<n;++i) {
12593 if ((deg=degree(i))<mindeg) {
12594 v=i;
12595 mindeg=deg;
12596 }
12597 }
12598 for (int i=0;i<n;++i) {
12599 if (i==v || has_edge(i,v))
12600 continue;
12601 k=std::min(k,vertex_pair_connectivity(v,i));
12602 }
12603 ivector adj;
12604 adjacent_nodes(v,adj);
12605 for (ivector_iter it=adj.begin();it!=adj.end();++it) {
12606 for (ivector_iter jt=it+1;jt!=adj.end();++jt) {
12607 if (has_edge(*it,*jt)) continue;
12608 k=std::min(k,vertex_pair_connectivity(*it,*jt));
12609 }
12610 }
12611 return k;
12612 }
12613
12614 /* truncate the graph, assuming that it is planar */
truncate(graphe & dest,const ivectors & faces)12615 void graphe::truncate(graphe &dest,const ivectors &faces) {
12616 set_embedding(faces);
12617 dest.clear();
12618 int nv=node_count(),ne=edge_count(),n;
12619 if (dest.supports_attributes()) {
12620 vecteur V;
12621 dest.make_default_labels(V,2*ne);
12622 dest.add_nodes(V);
12623 } else dest.add_nodes(2*ne);
12624 int cnt=0,f;
12625 ivector adj;
12626 map<ipair,ivector> p;
12627 for (int i=0;i<nv;++i) {
12628 vertex &v=node(i);
12629 n=v.neighbors().size();
12630 ivector ngh;
12631 adjacent_nodes(i,adj);
12632 ngh.push_back(adj.back());
12633 adj.pop_back();
12634 while (!adj.empty()) {
12635 f=v.edge_face(ngh.back());
12636 ivector::iterator it=adj.begin();
12637 for (;it!=adj.end() && f!=node(*it).edge_face(i);++it);
12638 assert(it!=adj.end());
12639 ngh.push_back(*it);
12640 adj.erase(it);
12641 }
12642 for (int j=0;j<n;++j) {
12643 p[make_pair(i<ngh[j]?i:ngh[j],i<ngh[j]?ngh[j]:i)].push_back(cnt+j);
12644 dest.add_edge(cnt+j,cnt+(j+1)%n);
12645 }
12646 cnt+=n;
12647 }
12648 ipairs E;
12649 get_edges_as_pairs(E);
12650 for (ipairs_iter it=E.begin();it!=E.end();++it) {
12651 const ivector &iv=p[*it];
12652 assert(iv.size()==2);
12653 dest.add_edge(iv.front(),iv.back());
12654 }
12655 }
12656
12657 /*
12658 * CIRC_ENUM CLASS IMPLEMENTATION
12659 *
12660 * Implementation of Tarjan's algorithm published in SIAM J. Comp. 2(3), 1973
12661 */
12662
circ_enum(graphe * gr,int lo,int hi)12663 graphe::circ_enum::circ_enum(graphe *gr,int lo,int hi) {
12664 G=gr;
12665 lb=lo; ub=hi;
12666 int n=G->node_count();
12667 A.resize(n);
12668 for (int i=0;i<n;++i) {
12669 const vertex &v=G->node(i);
12670 for (ivector_iter it=v.neighbors().begin();it!=v.neighbors().end();++it) {
12671 A[i].push_back(*it);
12672 }
12673 }
12674 }
12675
backtrack(int v,bool & f)12676 void graphe::circ_enum::backtrack(int v,bool &f) {
12677 bool g;
12678 f=false;
12679 point_stack.push_back(v);
12680 mark[v]=true;
12681 marked_stack.push(v);
12682 int w,u,len;
12683 for (int i=A[v].size();i-->0;) {
12684 w=A[v][i];
12685 if (w<s) A[v].erase(A[v].begin()+i);
12686 else if (w==s) {
12687 len=point_stack.size();
12688 if ((lb<0 || len>=lb) && (ub<0 || len<=ub))
12689 res.push_back(point_stack);
12690 f=true;
12691 } else if (!mark[w]) {
12692 backtrack(w,g);
12693 f=f||g;
12694 }
12695 }
12696 /* f is true if an elementary circuit containing
12697 * the partial path has been found */
12698 if (f) {
12699 while (marked_stack.top()!=v) {
12700 u=marked_stack.top();
12701 marked_stack.pop();
12702 mark[u]=false;
12703 }
12704 marked_stack.pop();
12705 mark[v]=false;
12706 }
12707 point_stack.pop_back();
12708 }
12709
12710 /* return the list of all elementary cycles in the given digraph */
find_cycles()12711 graphe::ivectors graphe::circ_enum::find_cycles() {
12712 int n=G->node_count(),u;
12713 bool flag;
12714 mark.resize(n,false);
12715 for (s=0;s<n;++s) {
12716 backtrack(s,flag);
12717 while (!marked_stack.empty()) {
12718 u=marked_stack.top();
12719 mark[u]=false;
12720 marked_stack.pop();
12721 }
12722 }
12723 return res;
12724 }
12725
12726 /*
12727 * END OF CIRC_ENUM CLASS IMPLEMENTATION
12728 */
12729
elementary_cycles(ivectors & cyc,int lo,int hi)12730 void graphe::elementary_cycles(ivectors &cyc,int lo,int hi) {
12731 assert(is_directed());
12732 circ_enum ce(this,lo,hi);
12733 cyc=ce.find_cycles();
12734 }
12735
12736 /*
12737 * YEN CLASS IMPLEMENTATION
12738 */
12739
delete_children(tree_node * r)12740 void graphe::yen::delete_children(tree_node *r) {
12741 for (vector<tree_node*>::const_iterator it=r->children.begin();it!=r->children.end();++it) {
12742 delete_children(*it);
12743 delete *it;
12744 }
12745 }
12746
add_tree_node(tree_node * p)12747 graphe::yen::tree_node *graphe::yen::add_tree_node(tree_node *p) {
12748 if (p==NULL) {
12749 root=new tree_node;
12750 root->parent=NULL;
12751 root->i=src;
12752 return root;
12753 }
12754 tree_node *t;
12755 p->children.push_back(t=new tree_node);
12756 t->parent=p;
12757 return t;
12758 }
12759
~yen()12760 graphe::yen::~yen() {
12761 if (root!=NULL) {
12762 delete_children(root);
12763 delete root;
12764 }
12765 }
12766
store_path(const ivector & path,tree_node * r)12767 graphe::yen::tree_node *graphe::yen::store_path(const ivector &path,tree_node *r) {
12768 tree_node *t=r,*next;
12769 int i,j,n=path.size();
12770 for (i=1;i<n;++i) {
12771 next=NULL;
12772 for (vector<tree_node*>::const_iterator it=t->children.begin();it!=t->children.end();++it) {
12773 if ((*it)->i==path[i]) {
12774 next=*it;
12775 break;
12776 }
12777 }
12778 if (next!=NULL) {
12779 t=next;
12780 continue;
12781 }
12782 t=add_tree_node(t);
12783 t->i=path[i];
12784 t->selected=false;
12785 }
12786 return t;
12787 }
12788
select_path(tree_node * p)12789 void graphe::yen::select_path(tree_node *p) {
12790 kspaths.push_back(p);
12791 tree_node *t=p;
12792 while (t!=NULL) {
12793 if (t->selected) break;
12794 t->selected=true;
12795 t=t->parent;
12796 }
12797 }
12798
restore_path(tree_node * p,ivector & path)12799 void graphe::yen::restore_path(tree_node *p,ivector &path) {
12800 tree_node *t=p;
12801 path.clear();
12802 while (t!=NULL) {
12803 path.push_back(t->i);
12804 t=t->parent;
12805 }
12806 std::reverse(path.begin(),path.end());
12807 }
12808
find_kspaths(ivectors & paths)12809 void graphe::yen::find_kspaths(ivectors &paths) {
12810 assert(G->supports_attributes());
12811 ivectors cp;
12812 vecteur pw;
12813 matrice W;
12814 if (!G->is_weighted()) {
12815 G->adjacency_matrix(W);
12816 G->make_weighted(W);
12817 }
12818 G->weight_matrix(W);
12819 paths.clear();
12820 G->dijkstra(src,ivector(1,dest),pw,&cp);
12821 if (cp.front().empty()) return;
12822 kspaths.clear();
12823 tree_node *p=store_path(cp.front(),add_tree_node(NULL)),*t,*next;
12824 select_path(p);
12825 stack<ipair> removed_edges;
12826 gen wg;
12827 int i,j,spur_node,tail,head;
12828 set<pair<gen,tree_node*>,kspaths_comparator> candidates;
12829 set<pair<gen,tree_node*>,kspaths_comparator>::const_iterator cit;
12830 ivector path;
12831 path.reserve(G->node_count());
12832 G->save_subgraphs();
12833 G->unset_subgraphs(1);
12834 for (int k=1;k<K;++k) {
12835 restore_path(p,path);
12836 t=root;
12837 for (i=0;i+1<(int)path.size();++i) {
12838 spur_node=path[i];
12839 for (vector<tree_node*>::const_iterator it=t->children.begin();it!=t->children.end();++it) {
12840 if ((*it)->selected) {
12841 head=(*it)->i; tail=(*it)->parent->i;
12842 G->set_edge_attribute(tail,head,_GT_ATTRIB_WEIGHT,plusinf());
12843 removed_edges.push(make_pair(tail,head));
12844 if (head==path[i+1]) next=*it;
12845 }
12846 }
12847 G->dijkstra(spur_node,ivector(1,dest),pw,&cp,1);
12848 if (!cp.front().empty()) {
12849 wg=pw.front();
12850 for (j=0;j<i;++j) wg+=W[path[j]][path[j+1]];
12851 candidates.insert(make_pair(wg,store_path(cp.front(),t)));
12852 }
12853 G->node(spur_node).set_subgraph(0);
12854 t=next;
12855 }
12856 for (ivector_iter it=path.begin();it+1!=path.end();++it) {
12857 G->node(*it).set_subgraph(1);
12858 }
12859 while (!removed_edges.empty()) {
12860 i=removed_edges.top().first; j=removed_edges.top().second;
12861 G->set_edge_attribute(i,j,_GT_ATTRIB_WEIGHT,W[i][j]);
12862 removed_edges.pop();
12863 }
12864 if (candidates.empty()) break;
12865 cit=candidates.begin();
12866 p=cit->second;
12867 select_path(p);
12868 candidates.erase(cit);
12869 }
12870 G->restore_subgraphs();
12871 for (vector<tree_node*>::const_iterator it=kspaths.begin();it!=kspaths.end();++it) {
12872 restore_path(*it,path);
12873 paths.push_back(path);
12874 }
12875 }
12876
12877 /*
12878 * END OF YEN CLASS
12879 */
12880
yen_ksp(int K,int src,int dest,ivectors & paths)12881 void graphe::yen_ksp(int K,int src,int dest,ivectors &paths) {
12882 yen Y(this,src,dest,K);
12883 Y.find_kspaths(paths);
12884 }
12885
12886 #ifndef NO_NAMESPACE_GIAC
12887 }
12888 #endif // ndef NO_NAMESPACE_GIAC
12889