~ubuntu-branches/ubuntu/precise/igraph/precise

« back to all changes in this revision

Viewing changes to src/bliss.cc

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Malaterre
  • Date: 2009-11-16 18:12:42 UTC
  • Revision ID: james.westby@ubuntu.com-20091116181242-mzv9p5fz9uj57xd1
Tags: upstream-0.5.3
ImportĀ upstreamĀ versionĀ 0.5.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 Copyright (C) 2003-2006 Tommi Junttila
 
3
 
 
4
 This program is free software; you can redistribute it and/or modify
 
5
 it under the terms of the GNU General Public License version 2
 
6
 as published by the Free Software Foundation.
 
7
 
 
8
 This program is distributed in the hope that it will be useful,
 
9
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 GNU General Public License for more details.
 
12
 
 
13
 You should have received a copy of the GNU General Public License
 
14
 along with this program; if not, write to the Free Software
 
15
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
16
*/
 
17
 
 
18
/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
 
19
 
 
20
#include "bliss_timer.hh"
 
21
#include "bliss_graph.hh"
 
22
#include "bliss_kqueue.hh"
 
23
#include "bliss_utils.hh"
 
24
 
 
25
#include "types.h"
 
26
 
 
27
#include <cstring>
 
28
 
 
29
using namespace igraph;
 
30
 
 
31
/**
 
32
 * \function igraph_canonical_permutation
 
33
 * Canonical permutation using BLISS
 
34
 * 
 
35
 * This function computes the canonical permutation which transforms
 
36
 * the graph into a canonical form by using the BLISS algorithm.
 
37
 * 
 
38
 * \param graph The input graph, it is treated as undirected and the
 
39
 *    multiple edges are ignored.
 
40
 * \param labeling Pointer to a vector, the result is stored here. The
 
41
 *    permutation takes vertex 0 to the first element of the vector,
 
42
 *    vertex 1 to the second, etc. The vector will be resized as
 
43
 *    needed.
 
44
 * \param sh The split heuristics to be used in BLISS. See \ref
 
45
 *    igraph_bliss_sh_t.
 
46
 * \param info If not \c NULL then information on BLISS internals is
 
47
 *    stored here. See \ref igraph_bliss_info_t.
 
48
 * \return Error code.
 
49
 * 
 
50
 * Time complexity: exponential, in practice it is fast for many graphs.
 
51
 */
 
52
int igraph_canonical_permutation(const igraph_t *graph, igraph_vector_t *labeling,
 
53
                                 igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {
 
54
  Graph *g = Graph::from_igraph(graph);
 
55
  Stats stats;
 
56
  const unsigned int N=g->get_nof_vertices();
 
57
  unsigned int gsh=Graph::sh_flm;
 
58
 
 
59
  switch (sh) { 
 
60
  case IGRAPH_BLISS_F:    gsh= Graph::sh_f;   break;
 
61
  case IGRAPH_BLISS_FL:   gsh= Graph::sh_fl;  break;
 
62
  case IGRAPH_BLISS_FS:   gsh= Graph::sh_fs;  break;
 
63
  case IGRAPH_BLISS_FM:   gsh= Graph::sh_fm;  break;
 
64
  case IGRAPH_BLISS_FLM:  gsh= Graph::sh_flm; break;
 
65
  case IGRAPH_BLISS_FSM:  gsh= Graph::sh_fsm; break;
 
66
  }
 
67
 
 
68
  g->set_splitting_heuristics(gsh);
 
69
  const unsigned int *cl = g->canonical_form(stats);
 
70
  IGRAPH_CHECK(igraph_vector_resize(labeling, N));
 
71
  for (unsigned int i=0; i<N; i++) {
 
72
    VECTOR(*labeling)[i] = cl[i];
 
73
  }
 
74
  delete g;
 
75
 
 
76
  if (info) { 
 
77
    info->nof_nodes      = stats.nof_nodes;
 
78
    info->nof_leaf_nodes = stats.nof_leaf_nodes;
 
79
    info->nof_bad_nodes  = stats.nof_bad_nodes;
 
80
    info->nof_canupdates = stats.nof_canupdates;
 
81
    info->max_level      = stats.max_level;
 
82
    stats.group_size.tostring(&info->group_size);
 
83
  }
 
84
  
 
85
  return 0;
 
86
}
 
87
 
 
88
/**
 
89
 * \function igraph_automorphisms
 
90
 * Number of automorphisms using BLISS
 
91
 * 
 
92
 * The number of automorphisms of a graph is computed using BLISS. The
 
93
 * result is returned as part of the \p info structure, in tag \c
 
94
 * group_size. It is returned as a string, as it can be very high even
 
95
 * for relatively small graphs. If the GNU MP library is used then
 
96
 * this number is exact, otherwise a <type>long double</type> is used
 
97
 * and it is only approximate. See also \ref igraph_bliss_info_t.
 
98
 * 
 
99
 * \param graph The input graph, it is treated as undirected and the
 
100
 *    multiple edges are ignored.
 
101
 * \param sh The split heuristics to be used in BLISS. See \ref
 
102
 *    igraph_bliss_sh_t.
 
103
 * \param info The result is stored here, in particular in the \c
 
104
 *    group_size tag of \p info.
 
105
 * \return Error code.
 
106
 * 
 
107
 * Time complexity: exponential, in practice it is fast for many graphs.
 
108
 */
 
109
int igraph_automorphisms(const igraph_t *graph,
 
110
                         igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {
 
111
  
 
112
  Graph *g = Graph::from_igraph(graph);
 
113
  Stats stats;
 
114
  unsigned int gsh=Graph::sh_flm;
 
115
 
 
116
  switch (sh) { 
 
117
  case IGRAPH_BLISS_F:    gsh= Graph::sh_f;   break;
 
118
  case IGRAPH_BLISS_FL:   gsh= Graph::sh_fl;  break;
 
119
  case IGRAPH_BLISS_FS:   gsh= Graph::sh_fs;  break;
 
120
  case IGRAPH_BLISS_FM:   gsh= Graph::sh_fm;  break;
 
121
  case IGRAPH_BLISS_FLM:  gsh= Graph::sh_flm; break;
 
122
  case IGRAPH_BLISS_FSM:  gsh= Graph::sh_fsm; break;
 
123
  }
 
124
 
 
125
  g->set_splitting_heuristics(gsh);
 
126
  g->find_automorphisms(stats);
 
127
 
 
128
  if (info) { 
 
129
    info->nof_nodes      = stats.nof_nodes;
 
130
    info->nof_leaf_nodes = stats.nof_leaf_nodes;
 
131
    info->nof_bad_nodes  = stats.nof_bad_nodes;
 
132
    info->nof_canupdates = stats.nof_canupdates;
 
133
    info->max_level      = stats.max_level;
 
134
    stats.group_size.tostring(&info->group_size);
 
135
  }
 
136
  delete g;
 
137
  
 
138
  return 0;
 
139
}
 
140
 
 
141
bool bliss_verbose = false;
 
142
FILE *bliss_verbstr = stdout;
 
143
 
 
144
namespace igraph {
 
145
 
 
146
typedef enum {FORMAT_BIN = 0, FORMAT_ADJ} Format;
 
147
// static Format input_format;
 
148
 
 
149
// static char *infilename = 0;
 
150
 
 
151
// static bool opt_canonize = false;
 
152
// static char *opt_output_can_file = 0;
 
153
// static unsigned int sh = Graph::sh_fm;
 
154
 
 
155
// static void usage(FILE *fp, char *argv0)
 
156
// {
 
157
//   char *program_name;
 
158
  
 
159
//   program_name = strrchr(argv0, '/');
 
160
  
 
161
//   if(program_name) program_name++;
 
162
//   else program_name = argv0;
 
163
  
 
164
//   if(!*program_name) program_name = "bliss";
 
165
//   fprintf(fp, "bliss, version 0.35, compiled " __DATE__ "\n");
 
166
//   fprintf(fp, "Copyright 2003-2006 Tommi Junttila\n");
 
167
//   fprintf(fp,
 
168
// "%s [<graph file>]\n"
 
169
// "\n"
 
170
// "  -can        compute canonical form\n"
 
171
// "  -ocan=f     compute canonical form and output it in file f\n"
 
172
// //"  -v        switch verbose mode on\n"
 
173
// "  -sh=x       select splitting heuristics, where x is\n"
 
174
// "                f    first non-singleton cell\n"
 
175
// "                fl   first largest non-singleton cell\n"
 
176
// "                fs   first smallest non-singleton cell\n"
 
177
// "                fm   first maximally non-trivially connected non-singleton cell [default]\n"
 
178
// "                flm  first largest maximally non-trivially connected non-singleton cell\n"
 
179
// "                fsm  first smallest maximally non-trivially connected non-singleton cell\n"
 
180
//           ,program_name);
 
181
// }
 
182
 
 
183
 
 
184
// static void parse_options(int argc, char ** argv)
 
185
// {
 
186
//   for(int i = 1; i < argc; i++)
 
187
//     {
 
188
//       //if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "-verbose") == 0)
 
189
//       //bliss_verbose = true;
 
190
//       /*
 
191
//       if(strcmp(argv[i], "-bin") == 0)
 
192
//      input_format = FORMAT_BIN;
 
193
//       else if(strcmp(argv[i], "-adj") == 0)
 
194
//      input_format = FORMAT_ADJ;
 
195
//       */
 
196
//       if(strcmp(argv[i], "-can") == 0)
 
197
//      opt_canonize = true;
 
198
//       else if((strncmp(argv[i], "-ocan=", 6) == 0) && (strlen(argv[i]) > 6))
 
199
//      {
 
200
//        opt_canonize = true;
 
201
//        opt_output_can_file = argv[i]+6;
 
202
//      }
 
203
//       else if(strcmp(argv[i], "-sh=f") == 0)
 
204
//      sh = Graph::sh_f;
 
205
//       else if(strcmp(argv[i], "-sh=fs") == 0)
 
206
//      sh = Graph::sh_fs;
 
207
//       else if(strcmp(argv[i], "-sh=fl") == 0)
 
208
//      sh = Graph::sh_fl;
 
209
//       else if(strcmp(argv[i], "-sh=fm") == 0)
 
210
//      sh = Graph::sh_fm;
 
211
//       else if(strcmp(argv[i], "-sh=fsm") == 0)
 
212
//      sh = Graph::sh_fsm;
 
213
//       else if(strcmp(argv[i], "-sh=flm") == 0)
 
214
//      sh = Graph::sh_flm;
 
215
//       else if(argv[i][0] == '-') {
 
216
//      fprintf(stderr, "unknown command line argument `%s'\n", argv[i]);
 
217
//      usage(stderr, argv[0]);
 
218
//      exit(1);
 
219
//       }
 
220
//       else {
 
221
//      if(infilename) {
 
222
//        fprintf(stderr, "too many file arguments\n");
 
223
//        usage(stderr, argv[0]);
 
224
//        exit(1);
 
225
//      }
 
226
//      else {
 
227
//        infilename = argv[i];
 
228
//      }
 
229
//       }
 
230
//     }
 
231
// }                        
 
232
 
 
233
}
 
234
 
 
235
// using namespace igraph;
 
236
 
 
237
// int main(int argc, char **argv)
 
238
// {
 
239
//   Timer t;
 
240
//   t.start();
 
241
 
 
242
//   parse_options(argc, argv);
 
243
 
 
244
//   Graph *g = 0;
 
245
  
 
246
//   FILE *infile = stdin;
 
247
//   if(infilename) {
 
248
//     if(input_format == FORMAT_BIN)
 
249
//       infile = fopen(infilename, "rb");
 
250
//     else
 
251
//       infile = fopen(infilename, "r");
 
252
//     if(!infile) {
 
253
//       fprintf(stderr, "cannot not open `%s' for input\n", infilename);
 
254
//       exit(1); }
 
255
//   }
 
256
 
 
257
//   g = Graph::read_dimacs(infile);
 
258
 
 
259
//   if(infile != stdin)
 
260
//     fclose(infile);
 
261
 
 
262
//   if(!g)
 
263
//     return 0;
 
264
  
 
265
//   fprintf(stdout, "Graph read in %.2fs\n", t.get_intermediate());
 
266
  
 
267
// #ifdef DEBUG_PRINT_DOT
 
268
//   g->to_dot("debug_graph.dot");
 
269
// #endif
 
270
 
 
271
//   Stats stats;
 
272
 
 
273
//   g->set_splitting_heuristics(sh);
 
274
 
 
275
//   if(opt_canonize)
 
276
//     {
 
277
//       const unsigned int *cl = g->canonical_form(stats);
 
278
//       //fprintf(stdout, "Canonical labeling: ");
 
279
//       //print_permutation(stdout, g->get_nof_vertices(), cl);
 
280
//       //fprintf(stdout, "\n");
 
281
//       if(opt_output_can_file)
 
282
//      {
 
283
//        Graph *cf = g->permute(cl);
 
284
//        FILE *fp = fopen(opt_output_can_file, "w");
 
285
//        if(!fp)
 
286
//          {
 
287
//            fprintf(stderr, "Can not open '%s' for outputting the canonical form", opt_output_can_file);
 
288
//            exit(1);
 
289
//          }
 
290
//        cf->print_dimacs(fp);
 
291
//        fclose(fp);
 
292
//        delete cf;
 
293
//      }
 
294
//     }
 
295
//   else
 
296
//     {
 
297
//       g->find_automorphisms(stats);
 
298
//     }
 
299
 
 
300
//   printf("Nodes:\t\t%lu\n", stats.nof_nodes);
 
301
//   printf("Leaf nodes:\t%lu\n", stats.nof_leaf_nodes);
 
302
//   printf("Bad nodes:\t%lu\n", stats.nof_bad_nodes);
 
303
//   printf("Canrep updates:\t%lu\n", stats.nof_canupdates);
 
304
//   printf("Generators:\t%lu\n", stats.nof_generators);
 
305
//   printf("Max level:\t%lu\n", stats.max_level);
 
306
//   printf("|Aut|:\t\t"); stats.group_size.print(stdout); printf("\n");
 
307
 
 
308
//   t.stop();
 
309
//   printf("Total time:\t%.2fs\n", t.get_duration());
 
310
 
 
311
//   delete g;
 
312
 
 
313
//   return 0;
 
314
// }
 
315