#  Copyright (c) 1997-2009
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
#  http://www.polymake.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.
#-------------------------------------------------------------------------------
#  $Project: polymake $$Id: graph_properties.rules 9564 2010-03-14 19:43:08Z herr $

# A graph with optional node and edge attributes.
#
declare object Graph<Dir=Undirected> {

# combinatorial description of the Graph in the form of adjacency matrix
property ADJACENCY : props::Graph<Dir>;

declare permutation NodePerm {

   # Transforming this [[ADJACENCY]] into the basic object
   property PERMUTATION : Array<Int>;
}

rule ADJACENCY : NodePerm.ADJACENCY, NodePerm.PERMUTATION {
   $this->ADJACENCY=permuted_nodes($this->NodePerm->ADJACENCY, $this->NodePerm->PERMUTATION);
}
weight 1.20;

# Number of nodes of the graph.
property N_NODES : Int;

# Number of [[EDGES]] of the graph.
property N_EDGES : Int;

# Degrees of nodes in the graph.
property NODE_DEGREES : Array<Int>;

# The diameter of the graph.
property DIAMETER : Int;

# True if the graph is a connected graph.
property CONNECTED : Bool;

# The connected components, encoded as node sets.
property CONNECTED_COMPONENTS : PowerSet;

# Number of [[CONNECTED_COMPONENTS]] of the graph.
property N_CONNECTED_COMPONENTS : Int;

# Labels of the nodes of the graph.
property NODE_LABELS : Array<String>;

# @notest  Rule defined "in stock" - currently without use
rule NODE_LABELS : NodePerm.NODE_LABELS, NodePerm.PERMUTATION {
   $this->NODE_LABELS=permuted($this->NodePerm->NODE_LABELS, $this->NodePerm->PERMUTATION);
}
weight 1.10;

rule N_NODES : ADJACENCY {
   $this->N_NODES=$this->ADJACENCY->nodes;
}
weight 0.10;

rule N_EDGES : ADJACENCY {
   $this->N_EDGES=$this->ADJACENCY->edges;
}
weight 0.10;

rule NODE_DEGREES : ADJACENCY {
   $this->NODE_DEGREES(temporary)=[ map { $this->ADJACENCY->degree($_) } 0..($this->ADJACENCY->nodes-1) ];
}
weight 1.10;

rule DIAMETER : ADJACENCY {
   $this->DIAMETER=diameter($this->ADJACENCY);
}
precondition : CONNECTED;

rule CONNECTED : ADJACENCY {
   $this->CONNECTED=is_connected($this->ADJACENCY);
}
weight 1.10;

rule CONNECTED_COMPONENTS : ADJACENCY {
   $this->CONNECTED_COMPONENTS=connected_components($this->ADJACENCY);
}

rule N_CONNECTED_COMPONENTS : CONNECTED_COMPONENTS {
   $this->N_CONNECTED_COMPONENTS=@{$this->CONNECTED_COMPONENTS};
}
weight 0.10;

rule CONNECTED : N_CONNECTED_COMPONENTS {
   $this->CONNECTED = $this->N_CONNECTED_COMPONENTS <= 1;
}
weight 0.10;

# Explore the graph as a sequence of its edges.
# @param Graph G
# @return Array<Set<Int>>
user_method EDGES {
  my $g=shift;
  my $a = new Array<Set<Int> >($g->N_EDGES);
  my $i = 0;
  for ( my $e=entire(edges($g->ADJACENCY)); $e; ++$e, ++$i ) { 
     $a->[$i] = new Set<Int>([$e->from_node,$e->to_node]);
  }
  return $a;
}

}

object Graph<Undirected> {

# True if the graph is a bipartite.
property BIPARTITE : Bool;

# Difference of the black and white nodes if the graph is [[BIPARTITE]].
# Otherwise -1.
property SIGNATURE : Int;

# Determine whether the graph has triangles or not.
property TRIANGLE_FREE : Bool;

# Node connectivity of the graph, that is, the minimal number of nodes to be removed
# from the graph such that the result is disconnected.
property CONNECTIVITY : Int;

# The maximal cliques of the graph, encoded as node sets.
property MAX_CLIQUES : PowerSet;

rule BIPARTITE, SIGNATURE : ADJACENCY {
   bipartite($this);
}
precondition : N_NODES;
weight 1.10;


rule TRIANGLE_FREE : ADJACENCY {
   $this->TRIANGLE_FREE=triangle_free($this->ADJACENCY);
}

rule TRIANGLE_FREE : { $this->TRIANGLE_FREE=1 }
precondition : BIPARTITE;
weight 0.10;

rule CONNECTIVITY : ADJACENCY {
   $this->CONNECTIVITY=connectivity($this->ADJACENCY);
}

rule MAX_CLIQUES : ADJACENCY {
   $this->MAX_CLIQUES=max_cliques($this->ADJACENCY);
}

}

object Graph<Directed> {

# The number of outgoing edges of the graph nodes.
property NODE_OUT_DEGREES : Array<Int>;

# The number of incoming edges of the graph nodes.
property NODE_IN_DEGREES : Array<Int>;

rule NODE_OUT_DEGREES : ADJACENCY {
   $this->NODE_OUT_DEGREES(temporary)=[ map { $this->ADJACENCY->out_degree($_) } 0..($this->ADJACENCY->nodes-1) ];
}
weight 1.10;

rule NODE_IN_DEGREES : ADJACENCY {
   $this->NODE_IN_DEGREES(temporary)=[ map { $this->ADJACENCY->in_degree($_) } 0..($this->ADJACENCY->nodes-1) ];
}
weight 1.10;

}

############################################################################

property_type common::NodeMap {

   # ADJACENCY is the default graph to attach itself
   method construct(graph::Graph<Dir>, @) {
      my ($proto, $graph)=splice @_,0,2;
      CPlusPlus::assign_any($proto->construct->($graph->ADJACENCY), @_);
   }
}

property_type common::EdgeMap {

   # ADJACENCY is the default graph to attach itself
   method construct(graph::Graph<Dir>, @) {
      my ($proto, $graph)=splice @_,0,2;
      CPlusPlus::assign_any($proto->construct->($graph->ADJACENCY), @_);
   }
}

property_type common::NodeHashMap {

   # ADJACENCY is the default graph to attach itself
   method construct(graph::Graph<Dir>, @) {
      my ($proto, $graph)=splice @_,0,2;
      CPlusPlus::assign_any($proto->construct->($graph->ADJACENCY), @_);
   }
}

property_type common::EdgeHashMap {

   # ADJACENCY is the default graph to attach itself
   method construct(graph::Graph<Dir>, @) {
      my ($proto, $graph)=splice @_,0,2;
      CPlusPlus::assign_any($proto->construct->($graph->ADJACENCY), @_);
   }
}

############################################################################

# @category Other
# Creates a graph from a given list of //edges//.
# @param Array<Set<Int>> edges
# @return Graph
user_function graph_from_edges($) {
   my $edges = shift;
   my $max = 0;
   foreach (@$edges ) {
      ( $#$_ == 1 && $_->[0] != $_->[1] ) or croak("not a list of edges\n");
      assign_max($max, $_->[0]);
      assign_max($max, $_->[1]);
   }

   my $g = new props::Graph($max+1);
   for ( @$edges ) {
      $g->edge(@$_);
   }

   return new Graph(ADJACENCY=>$g);
}



############################################################################

function is_connected(props::Graph) : c++ (include=>["connected.h"]);

function connected_components(props::Graph) : c++ (include=>["connected.h"]);

function max_cliques(props::Graph) : c++ (include=>["max_cliques.h"]);





# Local Variables:
# mode: perl
# c-basic-offset:3
# End:
