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

org.chocosolver.solver.variables.IViewFactory 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.variables;

import org.chocosolver.solver.ISelf;
import org.chocosolver.solver.Model;
import org.chocosolver.solver.variables.view.RealView;
import org.chocosolver.solver.variables.view.bool.BoolEqView;
import org.chocosolver.solver.variables.view.bool.BoolLeqView;
import org.chocosolver.solver.variables.view.bool.BoolNotView;
import org.chocosolver.solver.variables.view.bool.BoolSetView;
import org.chocosolver.solver.variables.view.graph.directed.DirectedEdgeInducedSubgraphView;
import org.chocosolver.solver.variables.view.graph.directed.DirectedGraphUnionView;
import org.chocosolver.solver.variables.view.graph.directed.DirectedNodeInducedSubgraphView;
import org.chocosolver.solver.variables.view.graph.undirected.EdgeInducedSubgraphView;
import org.chocosolver.solver.variables.view.graph.undirected.NodeInducedSubgraphView;
import org.chocosolver.solver.variables.view.graph.undirected.UndirectedGraphUnionView;
import org.chocosolver.solver.variables.view.integer.IntAffineView;
import org.chocosolver.solver.variables.view.set.*;
import org.chocosolver.util.objects.graphs.IGraph;
import org.chocosolver.util.objects.setDataStructures.ISet;
import org.chocosolver.util.tools.VariableUtils;

import java.util.Arrays;

import static java.lang.Math.max;

/**
 * Interface to make views (BoolVar, IntVar, RealVar and SetVar)
 * 

* A kind of factory relying on interface default implementation to allow (multiple) inheritance * * @author Jean-Guillaume FAGES */ public interface IViewFactory extends ISelf { //************************************************************************************* // BOOLEAN VARIABLES //************************************************************************************* /** * Creates a view over bool holding the logical negation of bool (ie, ¬BOOL). * * @param bool a boolean variable. * @return a BoolVar equal to not(bool) (or 1-bool) */ default BoolVar boolNotView(BoolVar bool) { if (bool.hasNot()) { return bool.not(); } else { BoolVar not; if (bool.isInstantiated()) { not = bool.getValue() == 1 ? ref().boolVar(false) : ref().boolVar(true); } else { if (ref().getSettings().enableViews()) { not = new BoolNotView<>(bool); } else { not = ref().boolVar("not(" + bool.getName() + ")"); ref().arithm(not, "!=", bool).post(); } not.setNot(true); } bool._setNot(not); not._setNot(bool); return not; } } /** * Creates a boolean view b over a set variable S such that: *

* given v an integer, b = true iff S contains v. * * @param setVar The set variable to observe. * @param v The value to observe in the set variable. * @return A BoolVar equals to S.contains(v). */ default BoolVar setBoolView(SetVar setVar, int v) { return new BoolSetView<>(v, setVar); } /** * Creates an array of boolean views b over a set variable S such that: *

* b[i - offset] = true <=> i in S. * * @param setVar The set variable to observe * @param size The size of the bool var array * @param offset The offset * @return A BoolVar array such that b[i - offset] = true <=> i in S. */ default BoolVar[] setBoolsView(SetVar setVar, int size, int offset) { BoolVar[] bools = new BoolVar[size]; for (int i = 0; i < size; i++) { bools[i] = setBoolView(setVar, i + offset); } return bools; } //************************************************************************************* // INTEGER VARIABLES //************************************************************************************* /** * Create an affine view based on var, i.e. view = a * var + b * * @param a a coefficient * @param var an integer variable * @param b a constant * @return an affine view */ default IntVar intView(int a, IntVar var, int b) { if (a == 1 && b == 0) { return var; } else if (a == 0) { return ref().intVar(b); } else if (var.isInstantiated()) { return ref().intVar(var.getValue() * a + b); } else if (ref().getSettings().enableViews()) { for (int i = 0; i < var.getNbViews(); i++) { if (var.getView(i) instanceof IntAffineView) { IntAffineView v = (IntAffineView) var.getView(i); if (v.equals(var, a, b)) { return var.getView(i).asIntVar(); } } } if (var instanceof IntAffineView) { IntAffineView view = (IntAffineView) var; int av = (view.p ? 1 : -1) * view.a * a; int bv = a * view.b + b; if (av == 1 && bv == 0) { return view.getVariable(); }else{ return intView(av, view.getVariable(), bv); } } else { return new IntAffineView<>(var, a, b); } } else { int lb, ub; if (a > 0) { lb = var.getLB() * a + b; ub = var.getUB() * a + b; } else { lb = var.getUB() * a + b; ub = var.getLB() * a + b; } String name = "(" + var.getName() + "*" + a + "+" + b + ")"; IntVar ov; if (var.hasEnumeratedDomain()) { ov = ref().intVar(name, lb, ub, false); } else { ov = ref().intVar(name, lb, ub, true); } if (a == 1) { ref().arithm(var, "-", ov, "=", -b).post(); } else if (a == -1) { ref().arithm(var, "+", ov, "=", b).post(); } else if (b == 0) { ref().scalar(new IntVar[]{var}, new int[]{a}, "=", ov).post(); } else { ref().scalar(new IntVar[]{var, ov}, new int[]{a, -1}, "=", -b).post(); } return ov; } } /** * Create a view based on var, i.e. view = |var| * * @param var an integer variable * @return an abs view */ default IntVar abs(IntVar var) { if (var.isInstantiated()) { return ref().intVar(Math.abs(var.getValue())); } else if (var.getLB() >= 0) { return var; } else if (var.getUB() <= 0) { return intView(-1, var, 0); } else { int ub = max(-var.getLB(), var.getUB()); String name = "|" + var.getName() + "|"; IntVar abs; if (var.hasEnumeratedDomain()) { abs = ref().intVar(name, 0, ub, false); } else { abs = ref().intVar(name, 0, ub, true); } ref().absolute(abs, var).post(); return abs; } } /** * Create a view based on var, i.e. view = var + b * * @param var an integer variable * @param b a constant * @return a plus view * @see #intView(int, IntVar, int) */ default IntVar offset(IntVar var, int b) { return intView(1, var, b); } /** * Create a view based on var, i.e. view = (var == v) * * @param var an integer variable * @param v a constant * @return a boolean view */ default BoolVar isEq(IntVar var, int v) { if (var.isInstantiatedTo(v)) { return ref().boolVar(true); } else if (!var.contains(v)) { return ref().boolVar(false); } else { if (VariableUtils.isBool(var)) { BoolVar bvar = (BoolVar) var; if (v == 0) { return bvar.not(); } else { return bvar; } } if (ref().getSettings().enableViews()) { int p = checkDeclaredView(var, v, BoolEqView.class, ref().getSettings().checkDeclaredViews()); if (p >= 0) { return var.getView(p).asBoolVar(); } else { return new BoolEqView<>(var, v); } } else { BoolVar b = ref().boolVar(); ref().reifyXeqC(var, v, b); return b; } } } /** * Create a view based on var, i.e. view = (var >= v) * * @param var an integer variable * @param v a constant * @return a boolean view */ default BoolVar isGeq(IntVar var, int v) { if (var.getLB() >= v) { return ref().boolVar(true); } else if (var.getUB() < v) { return ref().boolVar(false); } else { if (VariableUtils.isBool(var)) { BoolVar bvar = (BoolVar) var; assert v == 1; return bvar; } if (ref().getSettings().enableViews()) { int p = checkDeclaredView(var, v - 1, BoolLeqView.class, ref().getSettings().checkDeclaredViews()); if (p >= 0) { return var.getView(p).asBoolVar().not(); } else { return new BoolLeqView<>(var, v - 1).not(); } } else { BoolVar b = ref().boolVar(); ref().reifyXgtC(var, v - 1, b); return b; } } } /** * Create a view based on var, i.e. view = (var <= v) * * @param var an integer variable * @param v a constant * @return a boolean view */ default BoolVar isLeq(IntVar var, int v) { if (var.getUB() <= v) { return ref().boolVar(true); } else if (var.getLB() > v) { return ref().boolVar(false); } else { if (ref().getSettings().enableViews()) { int p = checkDeclaredView(var, v, BoolLeqView.class, ref().getSettings().checkDeclaredViews()); if (p >= 0) { return var.getView(p).asBoolVar(); } else { return new BoolLeqView<>(var, v); } } else { BoolVar b = ref().boolVar(); ref().reifyXltC(var, v + 1, b); return b; } } } /** * Create a view based on var, i.e. view = var * a * * @param var an integer variable * @param a a coefficient * @return a mul view * @see #intView(int, IntVar, int) */ default IntVar mul(IntVar var, int a) { return intView(a, var, 0); } /** * Create a view based on var, i.e. view = (var != v) * * @param var an integer variable * @param v a constant * @return a boolean view */ default BoolVar isNeq(IntVar var, int v) { if (var.isInstantiatedTo(v)) { return ref().boolVar(false); } else if (!var.contains(v)) { return ref().boolVar(true); } else { if (ref().getSettings().enableViews()) { int p = checkDeclaredView(var, v, BoolEqView.class, ref().getSettings().checkDeclaredViews()); if (p >= 0) { return var.getView(p).asBoolVar().not(); } else { return new BoolEqView<>(var, v).not(); } } else { BoolVar b = ref().boolVar(); ref().reifyXneC(var, v, b); return b; } } } /** * Create a view based on var, i.e. view = -var * * @param var an integer variable * @return a neg view * @see #intView(int, IntVar, int) */ default IntVar neg(IntVar var) { return intView(-1, var, 0); } /** * @see #intView(int, IntVar, int) * @deprecated */ @Deprecated default IntVar intOffsetView(IntVar var, int cste) { return intView(1, var, cste); } /** * @see #intView(int, IntVar, int) * @deprecated */ @Deprecated default IntVar intMinusView(IntVar var) { return intView(-1, var, 0); } /** * @see #intView(int, IntVar, int) * @deprecated */ @Deprecated default IntVar intScaleView(IntVar var, int cste) { return intView(cste, var, 0); } /** * Creates a view over var such that: |var|. *

*
- if var is already instantiated, returns a fixed variable; *
- if the lower bound of var is greater or equal to 0, returns var; *
- if the upper bound of var is less or equal to 0, return a minus view; *
- otherwise, returns an absolute view; *

* * @param var an integer variable. * @return an IntVar equal to the absolute value of var * @see #abs(IntVar) * @deprecated */ @Deprecated default IntVar intAbsView(IntVar var) { return abs(var); } /** * @see #intView(int, IntVar, int) * @deprecated */ @Deprecated default IntVar intAffineView(int a, IntVar x, int b) { return intView(a, x, b); } /** * Creates a view over x such that: (x = c) ⇔ b. *

* * @param x an integer variable. * @param c a constant * @return a BoolVar that reifies x = c * @deprecated * @see #isEq(IntVar, int) */ @Deprecated default BoolVar intEqView(IntVar x, int c) { return isEq(x, c); } /** * Creates a view over x such that: (x != c) ⇔ b. *

* * @param x an integer variable. * @param c a constant * @return a BoolVar that reifies x != c * @deprecated * @see #isNeq(IntVar, int) */ @Deprecated default BoolVar intNeView(IntVar x, int c) { return isNeq(x, c); } /** * Creates a view over x such that: (x ≤ c) ⇔ b. *

* * @param x an integer variable. * @param c a constant * @return a BoolVar that reifies x ≤ c * @deprecated * @see #isLeq(IntVar, int) */ @Deprecated default BoolVar intLeView(IntVar x, int c) { return isLeq(x, c); } /** * Creates a view over x such that: (x ≥ c) ⇔ b. *

* * @param x an integer variable. * @param c a constant * @return a BoolVar that reifies x ≥ c * @see #isGeq(IntVar, int) * @deprecated */ @Deprecated default BoolVar intGeView(IntVar x, int c) { return isGeq(x, c); } @SuppressWarnings("rawtypes") static int checkDeclaredView(IntVar x, int c, Class clazz, boolean check) { for (int i = 0; check && i < x.getNbViews(); i++) if (clazz.isInstance(x.getView(i))) { if (clazz == BoolEqView.class) { BoolEqView v = (BoolEqView) x.getView(i); if (v.cste == c) { return i; } } else if (clazz == BoolLeqView.class) { BoolLeqView v = (BoolLeqView) x.getView(i); if (v.cste == c) { return i; } } } return -1; } //************************************************************************************* // REAL VARIABLES //************************************************************************************* /** * Creates a real view of var, i.e. a RealVar of domain equal to the domain of var. * This should be used to include an integer variable in an expression/constraint requiring RealVar * * @param var the integer variable to be viewed as a RealVar * @param precision double precision (e.g., 0.00001d) * @return a RealVar of domain equal to the domain of var */ default RealVar realIntView(IntVar var, double precision) { if (ref().getSettings().enableViews()) { return new RealView<>(var, precision); } else { double lb = var.getLB(); double ub = var.getUB(); RealVar rv = ref().realVar("(real)" + var.getName(), lb, ub, precision); ref().realIbexGenericConstraint("{0} = {1}", rv, var).post(); return rv; } } /** * Creates an array of real views for a set of integer variables * This should be used to include an integer variable in an expression/constraint requiring RealVar * * @param ints the array of integer variables to be viewed as real variables * @param precision double precision (e.g., 0.00001d) * @return a real view of ints */ default RealVar[] realIntViewArray(IntVar[] ints, double precision) { RealVar[] reals = new RealVar[ints.length]; if (ref().getSettings().enableViews()) { for (int i = 0; i < ints.length; i++) { reals[i] = realIntView(ints[i], precision); } } else { for (int i = 0; i < ints.length; i++) { double lb = ints[i].getLB(); double ub = ints[i].getUB(); reals[i] = ref().realVar("(real)" + ints[i].getName(), lb, ub, precision); ref().realIbexGenericConstraint("{0} = {1}", reals[i], ints[i]).post(); } } return reals; } // MATRIX /** * Creates a matrix of real views for a matrix of integer variables * This should be used to include an integer variable in an expression/constraint requiring RealVar * * @param ints the matrix of integer variables to be viewed as real variables * @param precision double precision (e.g., 0.00001d) * @return a real view of ints */ default RealVar[][] realIntViewMatrix(IntVar[][] ints, double precision) { RealVar[][] vars = new RealVar[ints.length][ints[0].length]; for (int i = 0; i < ints.length; i++) { vars[i] = realIntViewArray(ints[i], precision); } return vars; } //************************************************************************************* // SET VARIABLES //************************************************************************************* // OVER ARRAY OF BOOLEAN VARIABLES /** * Create a set view over an array of boolean variables defined such that: * boolVars[x - offset] = True <=> x in setView * This view is equivalent to the {@link org.chocosolver.solver.constraints.set.PropBoolChannel} constraint. * * @param boolVars observed boolean variables * @param offset Offset between boolVars array indices and set elements * @return a set view such that boolVars[x - offset] = True <=> x in setView */ default SetVar boolsSetView(BoolVar[] boolVars, int offset) { return new SetBoolsView<>(offset, boolVars); } // OVER ARRAY OF INTEGER VARIABLES /** * Create a set view over an array of integer variables, such that: * intVars[x - offset] = v[x - offset] <=> x in set view. * * @param intVars array of integer variables * @param v array of integers that "toggle" integer variables index inclusion in the set view * @param offset offset between intVars indices and setViews elements * @return a set view such that intVars[x - offset] = v[x - offset] <=> x in setView. */ default SetVar intsSetView(IntVar[] intVars, int[] v, int offset) { return new SetIntsView<>(v, offset, intVars); } /** * Create a set view over an array of integer variables, such that: * intVars[x - offset] = v <=> x in set view. * * @param intVars array of integer variables * @param v integer that "toggle" integer variables index inclusion in the set view * @param offset offset between intVars indices and setViews elements * @return a set view such that intVars[x - offset] = v <=> x in setView. */ default SetVar intsSetView(IntVar[] intVars, int v, int offset) { int[] vals = new int[intVars.length]; Arrays.fill(vals, v); return intsSetView(intVars, vals, offset); } /** * Instantiate an array of set views over an array of integer variables, such that: * x in setViews[y - offset1] <=> intVars[x - offset2] = y. *

* This view is equivalent to the {@link org.chocosolver.solver.constraints.set.PropIntChannel} constraint. * * @param intVars array of integer variables * @param nbSets number of set views to create * @param offset1 offset between setViews indices and intVars values * @param offset2 offset between intVars indices and setViews elements * @return an array of set views such that x in setViews[y - offset1] <=> intVars[x - offset2] = y. */ default SetVar[] intsSetsView(IntVar[] intVars, int nbSets, int offset1, int offset2) { SetVar[] setVars = new SetVar[nbSets]; for (int i = 0; i < nbSets; i++) { setVars[i] = intsSetView(intVars, i + offset1, offset2); } return setVars; } // OVER SET VARIABLES /** * Creates a set view representing the union of a list of set variables. * * @param sets The set variables to observe. * @return A set union view. */ default SetVar setUnionView(SetVar... sets) { return new SetUnionView("setUnion", sets); } /** * Creates a set view representing the intersection of a list of set variables. * * @param sets The set variables to observe. * @return A set intersection view. */ default SetVar setIntersectionView(SetVar... sets) { return new SetIntersectionView("setIntersection", sets); } /** * Creates a set view z representing the set difference between x and y: z = x \ y. * * @param x A set variable. * @param y A set variable. * @return A set difference z view such that z = x \ y. */ default SetVar setDifferenceView(SetVar x, SetVar y) { return new SetDifferenceView("setDifference", x, y); } // OVER GRAPH VARIABLES /** * Creates a set view over the set of nodes of a graph variable. * * @param g observed graph variable * @return a set view over the set of nodes of a graph variable */ default SetVar graphNodeSetView(GraphVar g) { return new SetNodeGraphView<>(g); } /** * Creates a set view over the set of successors of a node of a directed graph variable. * * @param g observed graph variable * @param node observed node * @return a set view over the set of successors of a node of a directed graph variable. */ default SetVar graphSuccessorsSetView(DirectedGraphVar g, int node) { return new SetSuccessorsGraphView<>(g, node); } /** * Creates a set view over the set of predecessors of a node of a directed graph variable. * * @param g observed graph variable * @param node observed node * @return a set view over the set of predecessors of a node of a directed graph variable. */ default SetVar graphPredecessorsSetView(DirectedGraphVar g, int node) { return new SetPredecessorsGraphView<>(g, node); } /** * Creates a set view over the set of neighbors of a node of an undirected graph variable. * * @param g observed graph variable * @param node observed node * @return a set view over the set of neighbors of a node of an undirected graph variable. */ default SetVar graphNeighborsSetView(UndirectedGraphVar g, int node) { return new SetSuccessorsGraphView<>(g, node); } //************************************************************************************* // GRAPH VARIABLES //************************************************************************************* /** * Creates a graph view G' = (V', E') from another graph G = (V, E) such that: * V' = V \ nodes (set difference) if exclude = true, else V' = V \cap nodes (set intersection) * E' = { (x, y) \in E | x \in V' \land y \in V' }. * * @param g The graph variable to observe * @param nodes the set of nodes to construct the view from (see exclude parameter) * @param exclude if true, V' = V \ nodes (set difference), else V' = V \cap nodes (set intersection) */ default UndirectedGraphVar nodeInducedSubgraphView(UndirectedGraphVar g, ISet nodes, boolean exclude) { return new NodeInducedSubgraphView(g.getName() + "[" + nodes.toString() + "]", g, nodes, exclude); } /** * Creates a graph view G' = (V', E') from another graph G = (V, E) such that: * V' = V \ nodes (set difference) if exclude = true, else V' = V \cap nodes (set intersection) * E' = { (x, y) \in E | x \in V' \land y \in V' }. * * @param g The graph variable to observe * @param nodes the set of nodes to construct the view from (see exclude parameter) * @param exclude if true, V' = V \ nodes (set difference), else V' = V \cap nodes (set intersection) */ default DirectedGraphVar nodeInducedSubgraphView(DirectedGraphVar g, ISet nodes, boolean exclude) { return new DirectedNodeInducedSubgraphView(g.getName() + "[" + nodes.toString() + "]", g, nodes, exclude); } /** * Construct an edge-induced subgraph view G = (V', E') from G = (V, E) such that: * V' = { x \in V | \exists y \in V s.t. (x, y) \in E' } * E' = E \ edges (set difference) if exclude = true, else E' = E \cap edges (set intersection). * * @param g observed variable * @param edges the set of edges (array of couples) to construct the subgraph from (see exclude parameter) * @param exclude if true, E' = E \ edges (set difference), else E' = E \cap edges (set intersection) */ default UndirectedGraphVar edgeInducedSubgraphView(UndirectedGraphVar g, int[][] edges, boolean exclude) { return new EdgeInducedSubgraphView(g.getName() + "{" + Arrays.deepToString(edges) + "}", g, edges, exclude); } /** * Construct an edge-induced subgraph view G = (V', E') from G = (V, E) such that: * V' = { x \in V | \exists y \in V s.t. (x, y) \in E' } * E' = E \ edges (set difference) if exclude = true, else E' = E \cap edges (set intersection). * * @param g observed variable * @param edges the set of edges (array of couples) to construct the subgraph from (see exclude parameter) * @param exclude if true, E' = E \ edges (set difference), else E' = E \cap edges (set intersection) */ default DirectedGraphVar edgeInducedSubgraphView(DirectedGraphVar g, int[][] edges, boolean exclude) { return new DirectedEdgeInducedSubgraphView(g.getName() + "{" + Arrays.deepToString(edges) + "}", g, edges, exclude); } /** * Construct an undirected graph union view G = (V, E) from a set of undirected graphs {G_1 = (V_1, E_1), ..., G_k = (V_k, E_k)} such that : * V = V_1 \cup ... \cup V_k (\cup = set union); * E = E_1 \cup ... \cup E_k. * * @param graphVars the graphs to construct the union view from * @return An undirected graph union view */ default UndirectedGraphVar graphUnionView(UndirectedGraphVar... graphVars) { return new UndirectedGraphUnionView("GraphUnionView", graphVars); } /** * Construct a directed graph union view G = (V, E) from a set of directed graphs {G_1 = (V_1, E_1), ..., G_k = (V_k, E_k)} such that : * V = V_1 \cup ... \cup V_k (\cup = set union); * E = E_1 \cup ... \cup E_k. * * @param graphVars the graphs to construct the union view from * @return A directed graph union view */ default DirectedGraphVar graphUnionView(DirectedGraphVar... graphVars) { return new DirectedGraphUnionView("GraphUnionView", graphVars); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy