/**
  * g must form a circuit
  *
  * @param g a directed graph variable
  * @return a circuit constraint
  */
 public static Constraint circuit(IDirectedGraphVar g) {
   if (g.getMandatoryNodes().getSize() == g.getNbMaxNodes()) {
     return hamiltonian_circuit(g);
   }
   return new Constraint(
       "circuit",
       new PropNodeDegree_AtLeast_Incr(g, Orientation.SUCCESSORS, 1),
       new PropNodeDegree_AtLeast_Incr(g, Orientation.PREDECESSORS, 1),
       new PropNodeDegree_AtMost_Incr(g, Orientation.SUCCESSORS, 1),
       new PropNodeDegree_AtMost_Incr(g, Orientation.PREDECESSORS, 1),
       new PropNbSCC(g, g.getSolver().ONE),
       new PropCircuit(g));
 }
 /**
  * Creates a directed tree constraint : g forms an arborescence rooted in vertex 'root' i.e. g has
  * no circuit and a path exists from the root to every node
  *
  * @param g a directed graph variable
  * @param root the (fixed) root of the tree
  * @return a directed tree constraint
  */
 public static Constraint directed_tree(IDirectedGraphVar g, int root) {
   int n = g.getNbMaxNodes();
   int[] nbPreds = new int[n];
   for (int i = 0; i < n; i++) {
     nbPreds[i] = 1;
   }
   nbPreds[root] = 0;
   return new Constraint(
       "directed_tree",
       new PropArborescence(g, root),
       new PropNodeDegree_AtMost_Coarse(g, Orientation.PREDECESSORS, nbPreds),
       new PropNodeDegree_AtLeast_Incr(g, Orientation.PREDECESSORS, nbPreds));
 }
 /**
  * Creates a path constraint : g forms a path from node 'from' to node 'to' Basic but fast
  * propagation
  *
  * @param g a directed graph variable
  * @param from an integer variable
  * @param to an integer variable
  * @return a path constraint
  */
 public static Constraint path(IDirectedGraphVar g, int from, int to) {
   int n = g.getNbMaxNodes();
   int[] succs = new int[n];
   int[] preds = new int[n];
   for (int i = 0; i < n; i++) {
     succs[i] = preds[i] = 1;
   }
   succs[to] = preds[from] = 0;
   Propagator[] props =
       new Propagator[] {
         new PropNodeDegree_AtLeast_Coarse(g, Orientation.SUCCESSORS, succs),
         new PropNodeDegree_AtMost_Incr(g, Orientation.SUCCESSORS, succs),
         new PropNodeDegree_AtLeast_Coarse(g, Orientation.PREDECESSORS, preds),
         new PropNodeDegree_AtMost_Incr(g, Orientation.PREDECESSORS, preds),
         new PropPathNoCircuit(g)
       };
   return new Constraint("path", props);
 }
 /**
  * Creates a constraint which states that d is the diameter of g i.e. d is the length (number of
  * arcs) of the largest shortest path among any pair of nodes This constraint implies that g is
  * strongly connected
  *
  * @param g a directed graph variable
  * @param d an integer variable
  * @return a constraint which states that d is the diameter of g
  */
 public static Constraint diameter(IDirectedGraphVar g, IntVar d) {
   return new Constraint("NbCliques", new PropNbSCC(g, g.getSolver().ONE), new PropDiameter(g, d));
 }
 /**
  * Creates a strong connectedness constraint which ensures that g is strongly connected
  *
  * @param g a directed graph variable
  * @return A strong connectedness constraint which ensures that g is strongly connected
  */
 public static Constraint strongly_connected(IDirectedGraphVar g) {
   return nb_strongly_connected_components(
       g, VF.bounded("nbSCC", 0, g.getNbMaxNodes(), g.getSolver()));
 }