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 &notfound) 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 &timestamp,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