All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.chocosolver.solver.constraints.IGraphConstraintFactory Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2024, IMT Atlantique. All rights reserved.
 *
 * Licensed under the BSD 4-clause license.
 *
 * See LICENSE file in the project root for full license information.
 */
package org.chocosolver.solver.constraints;

import org.chocosolver.solver.ISelf;
import org.chocosolver.solver.Model;
import org.chocosolver.solver.constraints.binary.PropGreaterOrEqualX_Y;
import org.chocosolver.solver.constraints.graph.basic.*;
import org.chocosolver.solver.constraints.graph.channeling.edges.*;
import org.chocosolver.solver.constraints.graph.channeling.nodes.PropNodeBoolChannel;
import org.chocosolver.solver.constraints.graph.channeling.nodes.PropNodeBoolsChannel;
import org.chocosolver.solver.constraints.graph.channeling.nodes.PropNodeSetChannel;
import org.chocosolver.solver.constraints.graph.connectivity.*;
import org.chocosolver.solver.constraints.graph.cost.trees.PropMaxDegVarTree;
import org.chocosolver.solver.constraints.graph.cost.trees.PropTreeCostSimple;
import org.chocosolver.solver.constraints.graph.cost.trees.lagrangian.PropGenericLagrDCMST;
import org.chocosolver.solver.constraints.graph.cost.tsp.PropCycleCostSimple;
import org.chocosolver.solver.constraints.graph.cost.tsp.lagrangian.PropLagrOneTree;
import org.chocosolver.solver.constraints.graph.cycles.PropAcyclic;
import org.chocosolver.solver.constraints.graph.cycles.PropCycle;
import org.chocosolver.solver.constraints.graph.degree.PropNodeDegreeAtLeastIncr;
import org.chocosolver.solver.constraints.graph.degree.PropNodeDegreeAtMostIncr;
import org.chocosolver.solver.constraints.graph.degree.PropNodeDegreeVar;
import org.chocosolver.solver.constraints.graph.inclusion.PropInclusion;
import org.chocosolver.solver.constraints.graph.symmbreaking.PropIncrementalAdjacencyMatrix;
import org.chocosolver.solver.constraints.graph.symmbreaking.PropIncrementalAdjacencyUndirectedMatrix;
import org.chocosolver.solver.constraints.graph.symmbreaking.PropSymmetryBreaking;
import org.chocosolver.solver.constraints.graph.symmbreaking.PropSymmetryBreakingEx;
import org.chocosolver.solver.constraints.graph.tree.PropArborescence;
import org.chocosolver.solver.constraints.graph.tree.PropArborescences;
import org.chocosolver.solver.constraints.graph.tree.PropReachability;
import org.chocosolver.solver.variables.*;
import org.chocosolver.util.objects.graphs.Orientation;
import org.chocosolver.util.tools.ArrayUtils;

/**
 * Some usual graph constraints
 *
 * @author Jean-Guillaume Fages
 */
public interface IGraphConstraintFactory extends ISelf {


    //***********************************************************************************
    // BASIC CONSTRAINTS
    //***********************************************************************************

    // counting

    /**
     * Create a constraint to force the number of nodes in g to be equal to nb
     *
     * @param g  a graph variable
     * @param nb an integer variable indicating the expected number of nodes in g
     * @return A constraint to force the number of nodes in g to be equal to nb
     */
    default Constraint nbNodes(GraphVar g, IntVar nb) {
        return new Constraint("nbNodes", new PropNbNodes(g, nb));
    }

    /**
     * Create a constraint to force the number of edges in g to be equal to nb
     *
     * @param g  a graph variable
     * @param nb an integer variable indicating the expected number of edges in g
     * @return A constraint to force the number of edges in g to be equal to nb
     */
    default Constraint nbEdges(GraphVar g, IntVar nb) {
        return new Constraint("nbEdges", new PropNbEdges(g, nb));
    }

    // loops

    /**
     * Create a constraint which ensures that 'loops' denotes the set
     * of vertices in g which have a loop, i.e. an edge of the form f(i,i)
     * i.e. vertex i in g => edge (i,i) in g
     *
     * @param g a graph variable
     * @return A constraint which makes sure every node has a loop
     */
    default Constraint loopSet(GraphVar g, SetVar loops) {
        return new Constraint("loopSet", new PropLoopSet(g, loops));
    }

    /**
     * Create a constraint which ensures g has nb loops
     * |(i,i) in g| = nb
     *
     * @param g  a graph variable
     * @param nb an integer variable counting the number of loops in g
     * @return A constraint which ensures g has nb loops
     */
    default Constraint nbLoops(GraphVar g, IntVar nb) {
        return new Constraint("nbLoops", new PropNbLoops(g, nb));
    }


    //***********************************************************************************
    // SIMPLE PROPERTY CONSTRAINTS
    //***********************************************************************************


    // symmetry

    /**
     * Creates a constraint which ensures that g is a symetric directed graph
     * This means (i,j) in g <=> (j,i) in g
     * Note that it may be preferable to use an undirected graph variable instead!
     *
     * @param g a directed graph variable
     * @return A constraint which ensures that g is a symetric directed graph
     */
    default Constraint symmetric(DirectedGraphVar g) {
        return new Constraint("symmetric", new PropSymmetric(g));
    }

    /**
     * Creates a constraint which ensures that g is an antisymetric directed graph
     * This means (i,j) in g => (j,i) notin g
     *
     * @param g a directed graph variable
     * @return A constraint which ensures that g is an antisymetric directed graph
     */
    default Constraint antisymmetric(DirectedGraphVar g) {
        return new Constraint("antisymmetric", new PropAntiSymmetric(g));
    }

    // Transitivity

    /**
     * Create a transitivity constraint
     * (i,j) in g and (j,k) in g => (i,k) in g
     * Does not consider loops
     * Enables to make cliques
     *
     * @param g A graph variable
     * @return A transitivity constraint
     */
    default Constraint transitivity(GraphVar g) {
        return new Constraint("transitivity", new PropTransitivity<>(g));
    }

    //***********************************************************************************
    // INCLUSION CONSTRAINTS
    //***********************************************************************************

    /**
     * Create an inclusion constraint between g1 and g2 such that
     * g1 is a subgraph of g2
     * Note that node are labelled with their indexes :
     * the vertex 0 in g1 corresponds to the vertex 0 in g2
     *
     * @param g1 An undirected graph variable
     * @param g2 An undirected graph variable
     * @return a constraint which ensures that g1 is a subgraph of g2
     */
    default Constraint subgraph(UndirectedGraphVar g1, UndirectedGraphVar g2) {
        return new Constraint("subgraph", new PropInclusion(g1, g2));
    }

    /**
     * Create an inclusion constraint between g1 and g2 such that
     * g1 is a subgraph of g2
     * Note that node are labelled with their indexes :
     * the vertex 0 in g1 corresponds to the vertex 0 in g2
     *
     * @param g1 A directed graph variable
     * @param g2 A directed graph variable
     * @return a constraint which ensures that g1 is a subGraph of g2
     */
    default Constraint subgraph(DirectedGraphVar g1, DirectedGraphVar g2) {
        return new Constraint("subgraph", new PropInclusion(g1, g2));
    }


    //***********************************************************************************
    // CHANNELING CONSTRAINTS
    //***********************************************************************************

    // Vertices

    /**
     * Channeling constraint :
     * int i in nodes <=> vertex i in g
     *
     * @param g a graph variable
     * @param nodes a set variable
     */
    default Constraint nodesChanneling(GraphVar g, SetVar nodes) {
        return new Constraint("nodesSetChanneling",
                new PropNodeSetChannel(nodes, g));
    }

    /**
     * Channeling constraint :
     * nodes[i] = 1 <=> vertex i in g
     *
     * @param g a graph variable
     * @param nodes a set variable
     */
    default Constraint nodesChanneling(GraphVar g, BoolVar[] nodes) {
        return new Constraint("nodesBoolsChanneling",
                new PropNodeBoolsChannel(nodes, g));
    }

    /**
     * Channeling constraint :
     * isIn = 1 <=> vertex 'vertex' in g
     *
     * @param g a graph variable
     * @param isIn a Boolean variable
     * @param vertex int
     */
    default Constraint nodeChanneling(GraphVar g, BoolVar isIn, int vertex) {
        return new Constraint("nodesBoolChanneling",
                new PropNodeBoolChannel(isIn, vertex, g));
    }

    // Directed edges

    /**
     * Channeling constraint :
     * isEdge = 1 <=> edge (from,to) in g
     *
     * @param g a graph variable
     * @param isEdge a Boolean variable
     * @param from index of the origin
     * @param to index of the destination
     */
    default Constraint edgeChanneling(DirectedGraphVar g, BoolVar isEdge, int from, int to) {
        return new Constraint("edgeChanneling",
                new PropEdgeBoolChannel(isEdge, from, to, g));
    }

    // Edge

    /**
     * Channeling constraint:
     * isEdge = 1 <=> edge (i,j) in g
     *
     * @param g a graph variable
     * @param isEdge a Boolean variable
     * @param i index of the origin
     * @param j index of the destination
     */
    default Constraint edgeChanneling(UndirectedGraphVar g, BoolVar isEdge, int i, int j) {
        return new Constraint("edgeChanneling",
                new PropEdgeBoolChannel(isEdge, i, j, g));
    }

    // Neighbors

    /**
     * Channeling constraint:
     * int j in neighbors[i] <=> edge (i,j) in g
     *
     * @param g a graph variable
     * @param neighbors array of set variables
     */
    default Constraint neighborsChanneling(UndirectedGraphVar g, SetVar[] neighbors) {
        return new Constraint("neighSetsChanneling",
                new PropNeighSetsChannel1(neighbors, g), new PropNeighSetsChannel2(neighbors, g));

    }

    /**
     * Channeling constraint:
     * neighbors[i][j] = 1 <=> edge (i,j) in g
     *
     * @param g a graph variable
     * @param neighbors a matrix of Boolean variables
     */
    default Constraint neighborsChanneling(UndirectedGraphVar g, BoolVar[][] neighbors) {
        return new Constraint("neighBoolsChanneling",
                new PropNeighBoolsChannel1(neighbors, g), new PropNeighBoolsChannel2(neighbors, g));
    }

    /**
     * Channeling constraint:
     * int j in neighborsOf <=> edge (node,j) in g
     *
     * @param g a graph variable
     * @param neighborsOf a set variable
     * @param node index of the node
     */
    default Constraint neighborsChanneling(UndirectedGraphVar g, SetVar neighborsOf, int node) {
        return new Constraint("neighSetChanneling",
                new PropNeighSetChannel(neighborsOf, node, g, new IncidentSet.SuccessorsSet()));
    }

    /**
     * Channeling constraint:
     * neighborsOf[j] = 1 <=> edge (node,j) in g
     *
     * @param g a graph variable
     * @param neighborsOf an array of Boolean variables
     * @param node index of the node
     */
    default Constraint neighborsChanneling(UndirectedGraphVar g, BoolVar[] neighborsOf, int node) {
        return new Constraint("neighBoolChanneling",
                new PropNeighBoolChannel(neighborsOf, node, g, new IncidentSet.SuccessorsSet()));
    }

    // Successors

    /**
     * Channeling constraint:
     * int j in successors[i] <=> edge (i,j) in g
     *
     * @param g a graph variable
     * @param successors an array of set variables
     */
    default Constraint successorsChanneling(DirectedGraphVar g, SetVar[] successors) {
        return new Constraint("succSetsChanneling",
                new PropNeighSetsChannel1(successors, g), new PropNeighSetsChannel2(successors, g));
    }

    /**
     * Channeling constraint:
     * successors[i][j] <=> edge (i,j) in g
     *
     * @param g a graph variable
     * @param successors a matrix of Boolean variables
     */
    default Constraint successorsChanneling(DirectedGraphVar g, BoolVar[][] successors) {
        return new Constraint("succBoolsChanneling",
                new PropNeighBoolsChannel1(successors, g), new PropNeighBoolsChannel2(successors, g));
    }

    /**
     * Channeling constraint:
     * int j in successorsOf <=> edge (node,j) in g
     *
     * @param g a graph variable
     * @param successorsOf a set variable
     * @param node index of the node
     */
    default Constraint successorsChanneling(DirectedGraphVar g, SetVar successorsOf, int node) {
        return new Constraint("succSetChanneling",
                new PropNeighSetChannel(successorsOf, node, g, new IncidentSet.SuccessorsSet()));
    }

    /**
     * Channeling constraint:
     * successorsOf[j] = 1 <=> edge (node,j) in g
     *
     * @param g a graph variable
     * @param successorsOf an array of Boolean variables
     * @param node index of the node
     */
    default Constraint successorsChanneling(DirectedGraphVar g, BoolVar[] successorsOf, int node) {
        return new Constraint("succBoolChanneling",
                new PropNeighBoolChannel(successorsOf, node, g, new IncidentSet.SuccessorsSet()));
    }

    // Predecessors

    /**
     * Channeling constraint:
     * int j in predecessorsOf <=> edge (j,node) in g
     *
     * @param g a graph variable
     * @param predecessorsOf a set variable
     * @param node index of the node
     */
    default Constraint predecessorsChanneling(DirectedGraphVar g, SetVar predecessorsOf, int node) {
        return new Constraint("predSetChanneling",
                new PropNeighSetChannel(predecessorsOf, node, g, new IncidentSet.PredecessorsSet()));
    }

    /**
     * Channeling constraint:
     * predecessorsOf[j] = 1 <=> edge (j,node) in g
     *
     * @param g a graph variable
     * @param predecessorsOf an array of Boolean variables
     * @param node index of the node
     */
    default Constraint predecessorsChanneling(DirectedGraphVar g, BoolVar[] predecessorsOf, int node) {
        return new Constraint("predBoolChanneling",
                new PropNeighBoolChannel(predecessorsOf, node, g, new IncidentSet.PredecessorsSet()));

    }


    //***********************************************************************************
    // DEGREE CONSTRAINTS
    //***********************************************************************************

    // degrees

    /**
     * Minimum degree constraint
     * for any vertex i in g, |(i,j)| >= minDegree
     * This constraint only holds on vertices that are mandatory
     *
     * @param g         undirected graph var
     * @param minDegree integer minimum degree of every node
     * @return a minimum degree constraint
     */
    default Constraint minDegree(UndirectedGraphVar g, int minDegree) {
        return new Constraint("minDegree", new PropNodeDegreeAtLeastIncr(g, minDegree));
    }

    /**
     * Minimum degree constraint
     * for any vertex i in g, |(i,j)| >= minDegree[i]
     * This constraint only holds on vertices that are mandatory
     *
     * @param g          undirected graph var
     * @param minDegrees integer array giving the minimum degree of each node
     * @return a minimum degree constraint
     */
    default Constraint minDegrees(UndirectedGraphVar g, int[] minDegrees) {
        return new Constraint("minDegrees", new PropNodeDegreeAtLeastIncr(g, minDegrees));
    }

    /**
     * Maximum degree constraint
     * for any vertex i in g, |(i,j)| <= maxDegree
     * This constraint only holds on vertices that are mandatory
     *
     * @param g         undirected graph var
     * @param maxDegree integer maximum degree
     * @return a maximum degree constraint
     */
    default Constraint maxDegree(UndirectedGraphVar g, int maxDegree) {
        return new Constraint("maxDegree", new PropNodeDegreeAtMostIncr(g, maxDegree));
    }

    /**
     * Maximum degree constraint
     * for any vertex i in g, |(i,j)| <= maxDegrees[i]
     * This constraint only holds on vertices that are mandatory
     *
     * @param g          undirected graph var
     * @param maxDegrees integer array giving the maximum degree of each node
     * @return a maximum degree constraint
     */
    default Constraint maxDegrees(UndirectedGraphVar g, int[] maxDegrees) {
        return new Constraint("maxDegrees", new PropNodeDegreeAtMostIncr(g, maxDegrees));
    }

    /**
     * Degrees constraint
     * for any vertex i in g, |(i,j)| = degrees[i]
     * A vertex which has been removed has a degree equal to 0
     * ENSURES EVERY VERTEX i FOR WHICH DEGREE[i]>0 IS MANDATORY
     *
     * @param g       undirected graph var
     * @param degrees integer array giving the degree of each node
     * @return a degree constraint
     */
    default Constraint degrees(UndirectedGraphVar g, IntVar[] degrees) {
        return new Constraint("degrees", new PropNodeDegreeVar(g, degrees));
    }

    // inDegrees

    /**
     * Minimum inner degree constraint
     * for any vertex i in g, |(j,i)| >= minDegree
     * This constraint only holds on vertices that are mandatory
     *
     * @param g         directed graph var
     * @param minDegree integer minimum degree of every node
     * @return a minimum inner degree constraint
     */
    default Constraint minInDegree(DirectedGraphVar g, int minDegree) {
        return new Constraint("minInDegree", new PropNodeDegreeAtLeastIncr(g, Orientation.PREDECESSORS, minDegree));
    }

    /**
     * Minimum inner degree constraint
     * for any vertex i in g, |(j,i)| >= minDegree[i]
     * This constraint only holds on vertices that are mandatory
     *
     * @param g          directed graph var
     * @param minDegrees integer array giving the minimum degree of each node
     * @return a minimum inner degree constraint
     */
    default Constraint minInDegrees(DirectedGraphVar g, int[] minDegrees) {
        return new Constraint("minInDegrees", new PropNodeDegreeAtLeastIncr(g, Orientation.PREDECESSORS, minDegrees));
    }

    /**
     * Maximum inner degree constraint
     * for any vertex i in g, |(j,i)| <= maxDegree
     * This constraint only holds on vertices that are mandatory
     *
     * @param g         directed graph var
     * @param maxDegree integer maximum degree
     * @return a maximum inner degree constraint
     */
    default Constraint maxInDegree(DirectedGraphVar g, int maxDegree) {
        return new Constraint("maxInDegree", new PropNodeDegreeAtMostIncr(g, Orientation.PREDECESSORS, maxDegree));
    }

    /**
     * Maximum inner degree constraint
     * for any vertex i in g, |(j,i)| <= maxDegrees[i]
     * This constraint only holds on vertices that are mandatory
     *
     * @param g          directed graph var
     * @param maxDegrees integer array giving the maximum degree of each node
     * @return a maximum inner degree constraint
     */
    default Constraint maxInDegrees(DirectedGraphVar g, int[] maxDegrees) {
        return new Constraint("maxInDegrees", new PropNodeDegreeAtMostIncr(g, Orientation.PREDECESSORS, maxDegrees));
    }

    /**
     * Degree inner constraint
     * for any vertex i in g, |(j,i)| = degrees[i]
     * A vertex which has been removed has a degree equal to 0
     * ENSURES EVERY VERTEX i FOR WHICH DEGREE[i]>0 IS MANDATORY
     *
     * @param g       directed graph var
     * @param degrees integer array giving the degree of each node
     * @return a degree inner constraint
     */
    default Constraint inDegrees(DirectedGraphVar g, IntVar[] degrees) {
        return new Constraint("inDegrees", new PropNodeDegreeVar(g, Orientation.PREDECESSORS, degrees));
    }

    // out-degrees

    /**
     * Minimum outer degree constraint
     * for any vertex i in g, |(i,j)| >= minDegree
     * This constraint only holds on vertices that are mandatory
     *
     * @param g         directed graph var
     * @param minDegree integer minimum degree of every node
     * @return a minimum outer degree constraint
     */
    default Constraint minOutDegree(DirectedGraphVar g, int minDegree) {
        return new Constraint("minOutDegrees", new PropNodeDegreeAtLeastIncr(g, Orientation.SUCCESSORS, minDegree));
    }

    /**
     * Minimum outer degree constraint
     * for any vertex i in g, |(i,j)| >= minDegree[i]
     * This constraint only holds on vertices that are mandatory
     *
     * @param g          directed graph var
     * @param minDegrees integer array giving the minimum degree of each node
     * @return a minimum outer degree constraint
     */
    default Constraint minOutDegrees(DirectedGraphVar g, int[] minDegrees) {
        return new Constraint("minOutDegrees", new PropNodeDegreeAtLeastIncr(g, Orientation.SUCCESSORS, minDegrees));
    }

    /**
     * Maximum outer degree constraint
     * for any vertex i in g, |(i,j)| <= maxDegree
     * This constraint only holds on vertices that are mandatory
     *
     * @param g         directed graph var
     * @param maxDegree integer maximum degree
     * @return a maximum outer degree constraint
     */
    default Constraint maxOutDegree(DirectedGraphVar g, int maxDegree) {
        return new Constraint("maxOutDegrees", new PropNodeDegreeAtMostIncr(g, Orientation.SUCCESSORS, maxDegree));
    }

    /**
     * Maximum outer degree constraint
     * for any vertex i in g, |(i,j)| <= maxDegrees[i]
     * This constraint only holds on vertices that are mandatory
     *
     * @param g          directed graph var
     * @param maxDegrees integer array giving the maximum outer degree of each node
     * @return a outer maximum degree constraint
     */
    default Constraint maxOutDegrees(DirectedGraphVar g, int[] maxDegrees) {
        return new Constraint("maxOutDegrees", new PropNodeDegreeAtMostIncr(g, Orientation.SUCCESSORS, maxDegrees));
    }

    /**
     * Outer degree constraint
     * for any vertex i in g, |(i,j)| = degrees[i]
     * A vertex which has been removed has a degree equal to 0
     * ENSURES EVERY VERTEX i FOR WHICH DEGREE[i]>0 IS MANDATORY
     *
     * @param g       directed graph var
     * @param degrees integer array giving the degree of each node
     * @return an outer degree constraint
     */
    default Constraint outDegrees(DirectedGraphVar g, IntVar[] degrees) {
        return new Constraint("outDegrees", new PropNodeDegreeVar(g, Orientation.SUCCESSORS, degrees));
    }


    //***********************************************************************************
    // CYCLE CONSTRAINTS
    //***********************************************************************************

    /**
     * g must form a cycle
     * Empty graph is accepted
     * @param g an undirected graph variable
     * @return a cycle constraint
     */
    default Constraint cycle(UndirectedGraphVar g) {
        Propagator pMaxDeg = new PropNodeDegreeAtMostIncr(g, 2);
        if (g.getMandatoryNodes().size() <= 1) {
            // Graphs with one node and a loop must be accepted
            IntVar nbNodes = g.getModel().intVar(g.getMandatoryNodes().size(), g.getPotentialNodes().size());
            g.getModel().ifThenElse(
                    g.getModel().isGeq(nbNodes, 2),
                    new Constraint("minDeg >= 2", new PropNodeDegreeAtLeastIncr(g, 2)),
                    new Constraint("minDeg >= 1", new PropNodeDegreeAtLeastIncr(g, 1))
            );
            return new Constraint("cycle",
                    new PropNbNodes(g, nbNodes),
                    pMaxDeg,
                    new PropConnected(g),
                    new PropCycle(g)
            );
        }
        return new Constraint("cycle",
                new PropNodeDegreeAtLeastIncr(g, 2),
                pMaxDeg,
                new PropConnected(g),
                new PropCycle(g)
        );
    }

    /**
     * Cycle elimination constraint
     * Prevent the graph from containing cycles
     * e.g. an edge set of the form {(i1,i2),(i2,i3),(i3,i1)}
     *
     * @param g a graph variable
     * @return A cycle elimination constraint
     */
    default Constraint noCycle(UndirectedGraphVar g) {
        return new Constraint("noCycle", new PropAcyclic(g));
    }

    /**
     * Cycle elimination constraint
     * Prevent the graph from containing circuits
     * e.g. an edge set of the form {(i1,i2),(i2,i3),(i3,i1)}
     *
     * @param g a graph variable
     * @return A cycle elimination constraint
     */
    default Constraint noCircuit(DirectedGraphVar g) {
        return new Constraint("noCycle", new PropAcyclic(g));
    }


    //***********************************************************************************
    // CONNECTIVITY CONSTRAINTS
    //***********************************************************************************

    /**
     * Creates a connectedness constraint which ensures that g is connected
     * 
* BEWARE : empty graphs or graph with 1 node are allowed (they are not disconnected...) * if one wants a graph with >= 2 nodes he should use the node number constraint (nbNodes) * connected only focuses on the graph structure to prevent two nodes not to be connected * if there is 0 or only 1 node, the constraint is therefore not violated *
* The purpose of CP is to compose existing constraints, and nbNodes already exists * * @param g an undirected graph variable * @return A connectedness constraint which ensures that g is connected */ default Constraint connected(UndirectedGraphVar g) { return new Constraint("connected", new PropConnected(g)); } /** * Creates a connectedness constraint which ensures that g is bi-connected * Beware : should be used in addition to connected(g) * The empty graph is not considered biconnected. * * @param g an undirected graph variable * @return A connectedness constraint which ensures that g is biconnected */ default Constraint biconnected(UndirectedGraphVar g) { return new Constraint("connected", new PropBiconnected(g)); } /** * Creates a connectedness constraint which ensures that g has nb connected components * * @param g an undirected graph variable * @param nb an integer variable indicating the expected number of connected components in g * @return A connectedness constraint which ensures that g has nb connected components */ default Constraint nbConnectedComponents(UndirectedGraphVar g, IntVar nb) { return new Constraint("NbCC", new PropNbCC(g, nb)); } /** * Creates a constraint which ensures that every connected component of g has a number of nodes bounded by * sizeMinCC and sizeMaxCC. * * @param g an undirected graph variable. * @param sizeMinCC An IntVar to be equal to the smallest connected component of g. * @param sizeMaxCC An IntVar to be equal to the largest connected component of g. * @return A SizeCC constraint. */ default Constraint sizeConnectedComponents(UndirectedGraphVar g, IntVar sizeMinCC, IntVar sizeMaxCC) { return new Constraint("SizeCC", new PropGreaterOrEqualX_Y(new IntVar[]{sizeMaxCC, sizeMinCC}), new PropSizeMinCC(g, sizeMinCC), new PropSizeMaxCC(g, sizeMaxCC)); } /** * Creates a constraint which ensures that every connected component of g has a minimum number of * nodes equal to sizeMinCC. * * @param g an undirected graph variable. * @param sizeMinCC An IntVar to be equal to the smallest connected component of g. * @return A SizeMinCC constraint. */ default Constraint sizeMinConnectedComponents(UndirectedGraphVar g, IntVar sizeMinCC) { return new Constraint("SizeMinCC", new PropSizeMinCC(g, sizeMinCC)); } /** * Creates a constraint which ensures that every connected component of g has a maximum number of * nodes equal to sizeMaxCC. * * @param g an undirected graph variable * @param sizeMaxCC An IntVar to be equal to the largest connected component of g. * @return A SizeMaxCC constraint. */ default Constraint sizeMaxConnectedComponents(UndirectedGraphVar g, IntVar sizeMaxCC) { return new Constraint("SizeMaxCC", new PropSizeMaxCC(g, sizeMaxCC)); } /** * Creates a strong connectedness constraint which ensures that g has exactly one strongly connected component * * @param g a directed graph variable * @return A strong connectedness constraint which ensures that g is strongly connected */ default Constraint stronglyConnected(DirectedGraphVar g) { return nbStronglyConnectedComponents(g, g.getModel().intVar(1)); } /** * Creates a strong connectedness constraint which ensures that g has nb strongly connected components * * @param g a directed graph variable * @param nb an integer variable indicating the expected number of connected components in g * @return A strong connectedness constraint which ensures that g has nb strongly connected components */ default Constraint nbStronglyConnectedComponents(DirectedGraphVar g, IntVar nb) { return new Constraint("NbSCC", new PropNbSCC(g, nb)); } //*********************************************************************************** // TREE CONSTRAINTS //*********************************************************************************** /** * Creates a tree constraint : g is connected and has no cycle * * @param g an undirected graph variable * @return a tree constraint */ default Constraint tree(UndirectedGraphVar g) { return new Constraint("tree", new PropAcyclic(g), new PropConnected(g)); } /** * Creates a forest constraint : g has no cycle but may have several connected components * * @param g an undirected graph variable * @return a forest constraint */ default Constraint forest(UndirectedGraphVar g) { return new Constraint("forest", new PropAcyclic(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 */ default Constraint directedTree(DirectedGraphVar 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("directedTree" , new PropArborescence(g, root) , new PropNodeDegreeAtMostIncr(g, Orientation.PREDECESSORS, nbPreds) , new PropNodeDegreeAtLeastIncr(g, Orientation.PREDECESSORS, nbPreds) ); } /** * Creates a directed forest constraint : * g form is composed of several disjoint (potentially singleton) arborescences * * @param g a directed graph variable * @return a directed forest constraint */ default Constraint directedForest(DirectedGraphVar g) { return new Constraint("directedForest", new PropArborescences(g), new PropNodeDegreeAtMostIncr(g, Orientation.PREDECESSORS, 1) ); } //*********************************************************************************** // PATH and REACHABILITY //*********************************************************************************** // reachability /** * Creates a constraint which ensures that every vertex in g is reachable by a simple path from the root. * * @param g a directed graph variable * @param root a vertex reaching every node * @return A constraint which ensures that every vertex in g is reachable by a simple path from the root */ default Constraint reachability(DirectedGraphVar g, int root) { return new Constraint("reachability_from_" + root, new PropReachability(g, root)); } //*********************************************************************************** // CLIQUES //*********************************************************************************** /** * partition a graph variable into nb cliques * * @param g a graph variable * @param nb expected number of cliques in g * @return a constraint which partitions g into nb cliques */ default Constraint nbCliques(UndirectedGraphVar g, IntVar nb) { return new Constraint("NbCliques", new PropTransitivity<>(g), new PropNbCC(g, nb), new PropNbCliques(g, nb) // redundant propagator ); } //*********************************************************************************** // DIAMETER //*********************************************************************************** /** * Creates a constraint which states that d is the diameter of g * i.e. d is the length (number of edges) of the largest shortest path among any pair of nodes * This constraint implies that g is connected * * @param g an undirected graph variable * @param d an integer variable * @return a constraint which states that d is the diameter of g */ default Constraint diameter(UndirectedGraphVar g, IntVar d) { return new Constraint("diameter", new PropConnected(g), new PropDiameter(g, d) ); } /** * Creates a constraint which states that d is the diameter of g * i.e. d is the length (number of edges) 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 */ default Constraint diameter(DirectedGraphVar g, IntVar d) { return new Constraint("NbCliques", new PropNbSCC(g, g.getModel().intVar(1)), new PropDiameter(g, d) ); } //*********************************************************************************** // OPTIMIZATION CONSTRAINTS //*********************************************************************************** /** * Constraint modeling the Traveling Salesman Problem * * @param graphVar graph variable representing a Hamiltonian cycle * @param costVar variable representing the cost of the cycle * @param edgeCosts cost matrix (should be symmetric) * @param lagrMode use the Lagrangian relaxation of the tsp * described by Held and Karp * {0:no Lagrangian relaxation, * 1:Lagrangian relaxation (since root node), * 2:Lagrangian relaxation but wait a first solution before running it} * @return a tsp constraint */ default Constraint tsp(UndirectedGraphVar graphVar, IntVar costVar, int[][] edgeCosts, int lagrMode) { Propagator[] props = ArrayUtils.append(cycle(graphVar).getPropagators(), new Propagator[]{new PropCycleCostSimple(graphVar, costVar, edgeCosts)}); if (lagrMode > 0) { PropLagrOneTree hk = new PropLagrOneTree(graphVar, costVar, edgeCosts); hk.waitFirstSolution(lagrMode == 2); props = ArrayUtils.append(props, new Propagator[]{hk}); } return new Constraint("TSP", props); } /** * Creates a degree-constrained minimum spanning tree constraint : * GRAPH is a spanning tree of cost COSTVAR and each vertex degree is constrained *

* BEWARE : assumes the channeling between GRAPH and DEGREES is already done * * @param graphVar an undirected graph variable * @param degrees the degree of every vertex * @param costVar variable representing the cost of the mst * @param edgeCosts cost matrix (should be symmetric) * @param lagrMode use the Lagrangian relaxation of the dcmst * {0:no Lagrangian relaxation, * 1:Lagrangian relaxation (since root node), * 2:Lagrangian relaxation but wait a first solution before running it} * @return a degree-constrained minimum spanning tree constraint */ default Constraint dcmst(UndirectedGraphVar graphVar, IntVar[] degrees, IntVar costVar, int[][] edgeCosts, int lagrMode) { Constraint treeCstr = tree(graphVar); treeCstr.ignore(); Propagator[] props = ArrayUtils.append( treeCstr.getPropagators() , new Propagator[]{ new PropTreeCostSimple(graphVar, costVar, edgeCosts) , new PropMaxDegVarTree(graphVar, degrees) } ); if (lagrMode > 0) { PropGenericLagrDCMST hk = new PropGenericLagrDCMST(graphVar, costVar, degrees, edgeCosts, lagrMode == 2); props = ArrayUtils.append(props, new Propagator[]{hk}); } return new Constraint("dcmst", props); } //*********************************************************************************** // SYMMETRY BREAKING CONSTRAINTS //*********************************************************************************** /** * Post a symmetry breaking constraint. This constraint is a symmetry breaking for * class of directed graphs which contain a directed tree with root in node 0. * (All nodes must be reachable from node 0) * Note, that this method post this constraint directly, so it cannot be reified. *

* This symmetry breaking method based on paper: * Ulyantsev V., Zakirzyanov I., Shalyto A. * BFS-Based Symmetry Breaking Predicates for DFA Identification * //Language and Automata Theory and Applications. – Springer International Publishing, 2015. – С. 611-622. * * @param graph graph to be constrainted */ default void postSymmetryBreaking(DirectedGraphVar graph) { Model m = ref(); // ---------------------- variables ------------------------ int n = graph.getNbMaxNodes(); // t[i, j] BoolVar[] t = m.boolVarArray("T[]", n * n); // p[i] IntVar[] p = new IntVar[n]; p[0] = m.intVar("P[0]", 0); for (int i = 1; i < n; i++) { p[i] = m.intVar("P[" + i + "]", 0, i - 1); } // ---------------------- constraints ----------------------- // t[i, j] <-> G new Constraint("AdjacencyMatrix", new PropIncrementalAdjacencyMatrix(graph, t)).post(); // (p[j] == i) ⇔ t[i, j] and AND(!t[k, j], 0 ≤ k < j) for (int i = 0; i < n - 1; i++) { IntVar I = m.intVar(i); for (int j = 1; j < n; j++) { BoolVar[] clause = new BoolVar[i + 1]; clause[i] = t[i + j * n]; for (int k = 0; k < i; k++) { clause[k] = t[k + j * n].not(); } Constraint c = m.and(clause); Constraint pij = m.arithm(p[j], "=", I); m.ifOnlyIf(pij, c); } } // p[i] ≤ p[i + 1] for (int i = 1; i < n - 1; i++) { m.arithm(p[i], "<=", p[i + 1]).post(); } } /** * Post a symmetry breaking constraint. This constraint is a symmetry breaking for * class of undirected connected graphs. * Note, that this method post this constraint directly, so it cannot be reified. *

* This symmetry breaking method based on paper: * Ulyantsev V., Zakirzyanov I., Shalyto A. * BFS-Based Symmetry Breaking Predicates for DFA Identification * //Language and Automata Theory and Applications. – Springer International Publishing, 2015. – С. 611-622. * * @param graph graph to be constrainted */ default void postSymmetryBreaking(UndirectedGraphVar graph) { Model m = ref(); // ---------------------- variables ------------------------ int n = graph.getNbMaxNodes(); // t[i, j] BoolVar[] t = m.boolVarArray("T[]", n * n); // p[i] IntVar[] p = new IntVar[n]; p[0] = m.intVar("P[0]", 0); for (int i = 1; i < n; i++) { p[i] = m.intVar("P[" + i + "]", 0, i - 1); } // ---------------------- constraints ----------------------- // t[i, j] <-> G new Constraint("AdjacencyMatrix", new PropIncrementalAdjacencyUndirectedMatrix(graph, t)).post(); // (p[j] == i) ⇔ t[i, j] and AND(!t[k, j], 0 ≤ k < j) for (int i = 0; i < n - 1; i++) { IntVar I = m.intVar(i); for (int j = 1; j < n; j++) { BoolVar[] clause = new BoolVar[i + 1]; clause[i] = t[i + j * n]; for (int k = 0; k < i; k++) { clause[k] = t[k + j * n].not(); } Constraint c = m.and(clause); Constraint pij = m.arithm(p[j], "=", I); m.ifOnlyIf(c, pij); } } // p[i] ≤ p[i + 1] for (int i = 1; i < n - 1; i++) { m.arithm(p[i], "<=", p[i + 1]).post(); } } /** * Creates a symmetry breaking constraint. This constraint is a symmetry breaking for * class of undirected connected graphs. *

* This symmetry breaking method based on paper: * Codish M. et al. * Breaking Symmetries in Graph Representation * //IJCAI. – 2013. – С. 3-9. * * @param graph graph to be constrainted */ default Constraint symmetryBreaking2(UndirectedGraphVar graph) { int n = graph.getNbMaxNodes(); BoolVar[] t = ref().boolVarArray("T[]", n * n); return new Constraint("symmBreak", new PropIncrementalAdjacencyUndirectedMatrix(graph, t), new PropSymmetryBreaking(t) ); } /** * Creates a symmetry breaking constraint. This constraint is a symmetry breaking for * class of undirected connected graphs. *

* This symmetry breaking method based on paper: * Codish M. et al. * Breaking Symmetries in Graph Representation * //IJCAI. – 2013. – С. 3-9. * * @param graph graph to be constrainted */ default Constraint symmetryBreaking3(UndirectedGraphVar graph) { int n = graph.getNbMaxNodes(); BoolVar[] t = ref().boolVarArray("T[]", n * n); return new Constraint("symmBreakEx", new PropIncrementalAdjacencyUndirectedMatrix(graph, t), new PropSymmetryBreakingEx(t) ); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy