/* Copyright (c) 1997-2006
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
*/

#ident "$Project: polymake $$Id: graph_compare.cc 7327 2006-04-04 19:39:56Z gawrilow $"

#define graph nauty_graph
#define set nauty_set
#define permutation nauty_permutation

#include <nauty.h>

namespace {
   inline nauty_set* graph_row(nauty_graph *g, int v, int m) { return GRAPHROW(g,v,m); }

   int *_suppress_unused_bytecount=bytecount, *suppress_unused_leftbit=leftbit;
}

#undef GRAPHROW
#undef graph
#undef set
#undef permutation

#include <graph_compare.h>

namespace polymake { namespace graph {

namespace {
   DEFAULTOPTIONS_GRAPH(default_options);

   NautyGraph *in_processing=0;
}

   struct NautyGraph::impl {
      int n, m;
      nauty_graph *src_graph, *canon_graph;
      int *orbits, *canon_labels, *partitions;
      optionblk options;

      explicit impl(int n_arg)
	 : n(n_arg), m((n + WORDSIZE - 1) / WORDSIZE),
	   src_graph(0), canon_graph(0),
	   orbits(0), canon_labels(0), partitions(0)
      {
	 src_graph=new nauty_graph[n*m];
	 EMPTYSET(src_graph,n*m);
	 canon_graph=new nauty_graph[n*m];
	 orbits=new int[n];
	 canon_labels=new int[n];
	 partitions=new int[n];
	 options=default_options;
      }

      ~impl()
      {
	 delete[] partitions;
	 delete[] canon_labels;
	 delete[] orbits;
	 delete[] canon_graph;
	 delete[] src_graph;
      }

      static void store_autom(int n_autom, nauty_permutation *perm, int*, int, int, int n)
      {
	 in_processing->n_autom=n_autom;
	 in_processing->autom.push_back( Array<int>(n, perm) );
      }
   };

   NautyGraph::impl* NautyGraph::alloc_impl(int n, bool dir)
   {
      impl* i=new impl(n);
      i->options.digraph=dir;
      i->options.getcanon=true;
      return i;
   }

   NautyGraph::~NautyGraph() { delete p_impl; }

   void NautyGraph::add_edge(int from, int to)
   {
      nauty_set *gv=graph_row(p_impl->src_graph, from, p_impl->m);
      ADDELEMENT(gv, to);
   }

   void NautyGraph::partition(int at)
   {
      p_impl->options.defaultptn=false;
      std::fill(p_impl->partitions, p_impl->partitions+p_impl->n-1, 1);
      std::copy(entire(sequence(0,p_impl->n)), p_impl->canon_labels);
      p_impl->partitions[at-1]=0;
      p_impl->partitions[p_impl->n-1]=0;
   }

   int* NautyGraph::partitions()
   {
      p_impl->options.defaultptn=false;
      return p_impl->partitions;
   }

   int* NautyGraph::labels()
   {
      return p_impl->canon_labels;
   }

   void NautyGraph::finalize(bool gather_automorphisms)
   {
      statsblk stats;
      const int worksize=100*1024*1024;	// 100MB
      nauty_set *workspace=new nauty_set[worksize];
      if (gather_automorphisms) {
	 p_impl->options.userautomproc=&impl::store_autom;
	 in_processing=this;
      }
      nauty(p_impl->src_graph, p_impl->canon_labels, p_impl->partitions, 0, p_impl->orbits,
	    &p_impl->options, &stats, workspace, worksize, p_impl->m, p_impl->n, p_impl->canon_graph);
      delete[] workspace;
   }

   bool NautyGraph::operator== (const NautyGraph& g2) const
   {
      if (p_impl->n != g2.p_impl->n) return false;
      nauty_set *cg1=p_impl->canon_graph, *cg1_end=cg1+p_impl->n*p_impl->m, *cg2=g2.p_impl->canon_graph;
      return std::equal(cg1, cg1_end, cg2);
   }

   Array<int> NautyGraph::find_permutation(const NautyGraph& g2) const
   {
      if (*this != g2)
	 throw pm::no_match("not isomorphic");

      Array<int> perm(p_impl->n);
      for (int *dst=perm.begin(), *lab1=p_impl->canon_labels, *lab1_end=lab1+p_impl->n, *lab2=g2.p_impl->canon_labels;
	   lab1<lab1_end; ++lab1, ++lab2)
	 dst[*lab1]=*lab2;
      return perm;
   }

   std::pair< Array<int>, Array<int> >
   NautyGraph::find_permutations(const NautyGraph& g2, int n_cols) const
   {
      if (*this != g2)
	 throw pm::no_match("not isomorphic");

      Array<int> row_perm(p_impl->n-n_cols), col_perm(n_cols);

      int *lab1=p_impl->canon_labels, *lab1_end=lab1+n_cols, *lab2=g2.p_impl->canon_labels;
      for (int *dst=col_perm.begin(); lab1<lab1_end; ++lab1, ++lab2)
	 dst[*lab1]=*lab2;

      lab1_end=p_impl->canon_labels+p_impl->n;
      for (int *dst=row_perm.begin(); lab1<lab1_end; ++lab1, ++lab2)
	 dst[*lab1-n_cols]=*lab2-n_cols;

      return std::make_pair(row_perm, col_perm);
   }

} }

// Local Variables:
// c-basic-offset:3
// End:


syntax highlighted by Code2HTML, v. 0.9.1