
org.xcsp.common.predicates.XNode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xcsp3-tools Show documentation
Show all versions of xcsp3-tools Show documentation
Java Tools for parsing XCSP3 instances, compiling JvCSP3 models, and checking solutions. For more information about XCSP3, follow www.xcsp.org
The newest version!
/*
* Copyright (c) 2016 XCSP3 Team ([email protected])
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.xcsp.common.predicates;
import static org.xcsp.common.Types.TypeExpr.ABS;
import static org.xcsp.common.Types.TypeExpr.ADD;
import static org.xcsp.common.Types.TypeExpr.DIST;
import static org.xcsp.common.Types.TypeExpr.DIV;
import static org.xcsp.common.Types.TypeExpr.IF;
import static org.xcsp.common.Types.TypeExpr.LONG;
import static org.xcsp.common.Types.TypeExpr.MAX;
import static org.xcsp.common.Types.TypeExpr.MIN;
import static org.xcsp.common.Types.TypeExpr.MOD;
import static org.xcsp.common.Types.TypeExpr.MUL;
import static org.xcsp.common.Types.TypeExpr.NEG;
import static org.xcsp.common.Types.TypeExpr.POW;
import static org.xcsp.common.Types.TypeExpr.SET;
import static org.xcsp.common.Types.TypeExpr.SPECIAL;
import static org.xcsp.common.Types.TypeExpr.SQR;
import static org.xcsp.common.Types.TypeExpr.SUB;
import static org.xcsp.common.Types.TypeExpr.VAR;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.xcsp.common.IVar;
import org.xcsp.common.IVar.Var;
import org.xcsp.common.Range;
import org.xcsp.common.Types.TypeArithmeticOperator;
import org.xcsp.common.Types.TypeConditionOperatorRel;
import org.xcsp.common.Types.TypeExpr;
import org.xcsp.common.Types.TypeLogicalOperator;
import org.xcsp.common.Types.TypeUnaryArithmeticOperator;
import org.xcsp.common.Utilities;
import org.xcsp.common.enumerations.EnumerationCartesian;
import org.xcsp.common.predicates.MatcherInterface.AbstractOperation;
/**
* This class is used for representing a node of a syntactic tree, which is built for functional expressions, and used especially with element
* {@code }. Subclasses of this class allow us to manage parent and leaf nodes.
*
* @author Christophe Lecoutre
*/
public abstract class XNode implements Comparable> {
// ************************************************************************
// ***** Static Methods
// ************************************************************************
public static XNodeParent node(TypeExpr type, XNode left, XNode right) {
return new XNodeParent<>(type, left, right);
}
public static XNodeParent node(AbstractOperation type, XNode left, XNode right) {
return new XNodeParentSpecial<>(type.name(), left, right);
}
public static XNodeParent node(TypeExpr type, XNode son) {
return new XNodeParent<>(type, son);
}
public static XNodeParent node(AbstractOperation type, XNode son) {
return new XNodeParentSpecial<>(type.name(), son);
}
public static XNodeParent node(TypeExpr type, XNode[] sons) {
return new XNodeParent<>(type, sons);
}
public static XNodeParent node(TypeExpr type, List> sons) {
return new XNodeParent<>(type, sons);
}
public static XNodeParent node(TypeExpr type, Stream> sons) {
return new XNodeParent<>(type, sons.toArray(XNode[]::new)); // sons.size()])); //collect(Collectors.toList()));
}
public static XNodeLeaf longLeaf(long value) {
return new XNodeLeaf<>(LONG, value);
}
public static XNodeLeaf specialLeaf(String value) {
return new XNodeLeaf<>(SPECIAL, value);
}
// ************************************************************************
// ***** Fields, Constructor and Methods
// ************************************************************************
/**
* The type of the node. For example, it can be {@code ADD}, {@code NOT}, or {@code LONG}.
*/
public TypeExpr type;
/**
* The sons (children) of the node. It is {@code null} if the node is a leaf.
*/
public final XNode[] sons;
/**
* Builds a node for a syntactic tree, with the specified type and the specified sons (children).
*
* @param type
* the type of the node
* @param sons
* the sons (children) of the node
*/
protected XNode(TypeExpr type, XNode[] sons) {
this.type = type;
this.sons = sons;
}
/**
* Returns the type of the node. For example {@code ADD}, {@code NOT}, or {@code LONG}. Note that we need this method for language Scala.
*
* @return the type of the node
*/
public final TypeExpr getType() {
return type;
}
public final XNode logicalInversion() {
assert type.isLogicallyInvertible();
type = type.logicalInversion();
return this;
}
/**
* Returns the arity of this node, i.e., the number of sons.
*
* @return the arity of this node
*/
public final int arity() {
return sons == null ? 0 : sons.length;
}
/**
* Returns the size of the tree rooted by this node, i.e., the number of nodes it contains.
*
* @return the size of the tree rooted by this node
*/
public abstract int size();
/**
* Returns the maximum value of a parameter number in the tree rooted by this node, or -1 if there is none.
*
* @return the maximum value of a parameter number in the tree rooted by this node, or -1
*/
public abstract int maxParameterNumber();
/**
* Returns the first node accepted by the specified predicate in the tree rooted by this node, or {@code null} otherwise.
*
* @param p
* a predicate to be applied on nodes
* @return the first node accepted by the specified predicate
*/
public abstract XNode firstNodeSuchThat(Predicate> p);
/**
* Adds to the specified list all nodes accepted by the specified predicate in the tree rooted by this node. The specifies list is returned.
*
* @param p
* a predicate to be applied on nodes
* @param list
* a list in which nodes are added
* @return a list with all nodes accepted by the specified predicate in the tree rooted by this node
*/
public abstract LinkedList> allNodesSuchThat(Predicate> p, LinkedList> list);
/**
* Returns a list containing all nodes accepted by the specified predicate in the tree rooted by this node. Nodes are added in infix manner.
*
* @param p
* a predicate to be applied on nodes
* @return a list with all nodes accepted by the specified predicate in the tree rooted by this node
*/
public LinkedList> allNodesSuchThat(Predicate> p) {
return allNodesSuchThat(p, new LinkedList>());
}
/**
* Builds a list with the sequence of variables encountered during a depth-first exploration of the tree rooted by this node. Multiple occurrences of the
* same variables are possible.
*
* @return the list of encountered variables during a depth-first exploration
*/
public final LinkedList listOfVars() {
return allNodesSuchThat(s -> s.type == VAR).stream().map(n -> (V) ((XNodeLeaf) n).value).collect(Collectors.toCollection(LinkedList::new));
}
/**
* Builds a list with the sequence of values (long integers) encountered during a depth-first exploration of the tree rooted by this node. Multiple
* occurrences of the same values are possible.
*
* @return the list of encountered values (integers) during a depth-first exploration
*/
public final LinkedList listOfVals() {
return allNodesSuchThat(s -> s.type == LONG).stream().map(n -> (Long) ((XNodeLeaf) n).value).collect(Collectors.toCollection(LinkedList::new));
}
/**
* Returns the (i+1)th variable encountered while traversing (in a depth-first manner) the tree rooted by this node, or {@code null} if such variable does
* not exist.
*
* @param i
* the index, starting at 0, of a variable
* @return the (i+1)th variable encountered in the tree rooted by this node
*/
public final V var(int i) {
if (i == 0) {
XNodeLeaf f = (XNodeLeaf) firstNodeSuchThat(n -> n.type == VAR);
return f == null ? null : (V) f.value;
}
LinkedList list = listOfVars();
return i >= list.size() ? null : list.get(i);
}
/**
* Returns the (i+1)th value encountered while traversing (in a depth-first manner) the tree rooted by this node, or {@code null} if such value does not
* exist.
*
* @param i
* the index, starting at 0, of a value
* @return the (i+1)th value encountered in the tree rooted by this node
*/
public final Integer val(int i) {
if (i == 0) {
XNodeLeaf f = (XNodeLeaf) firstNodeSuchThat(n -> n.type == LONG);
return f == null ? null : Utilities.safeInt((Long) f.value);
}
LinkedList list = listOfVals();
return i >= list.size() ? null : Utilities.safeInt(list.get(i));
}
public final TypeConditionOperatorRel relop(int i) {
if (i == 0) {
XNode f = firstNodeSuchThat(n -> n.type.isRelationalOperator());
return f == null ? null : f.type.toRelop();
}
LinkedList list = allNodesSuchThat(s -> s.type.isRelationalOperator()).stream().map(n -> n.type.toRelop())
.collect(Collectors.toCollection(LinkedList::new));
return i >= list.size() ? null : list.get(i);
}
public final TypeUnaryArithmeticOperator unalop(int i) {
if (i == 0) {
XNode f = firstNodeSuchThat(n -> n.type.isUnaryArithmeticOrLogicOperator());
return f == null ? null : f.type.toUnalop();
}
LinkedList list = allNodesSuchThat(s -> s.type.isUnaryArithmeticOrLogicOperator()).stream().map(n -> n.type.toUnalop())
.collect(Collectors.toCollection(LinkedList::new));
return i >= list.size() ? null : list.get(i);
}
public final TypeArithmeticOperator ariop(int i) {
if (i == 0) {
XNode f = firstNodeSuchThat(n -> n.type.isArithmeticOperator());
return f == null ? null : f.type.toAriop();
}
LinkedList list = allNodesSuchThat(s -> s.type.isArithmeticOperator()).stream().map(n -> n.type.toAriop())
.collect(Collectors.toCollection(LinkedList::new));
return i >= list.size() ? null : list.get(i);
}
public final TypeLogicalOperator logop(int i) {
if (i == 0) {
XNode f = firstNodeSuchThat(n -> n.type.isLogicalOperator());
return f == null ? null : f.type.toLogop();
}
LinkedList list = allNodesSuchThat(s -> s.type.isLogicalOperator()).stream().map(n -> n.type.toLogop())
.collect(Collectors.toCollection(LinkedList::new));
return i >= list.size() ? null : list.get(i);
}
/**
* Returns the list of variables in the tree rooted by this node, in the order they are encountered, or {@code null} if there is none. Contrary to vars(),
* the same variables may occur several times.
*
* @return the list of variables in the order they are encountered
*/
public final V[] arrayOfVars() {
LinkedList list = listOfVars();
return list.size() == 0 ? null : list.stream().toArray(s -> Utilities.buildArray(list.iterator().next().getClass(), s));
}
/**
* Returns the list of values (integers) in the tree rooted by this node, in the order they are encountered, or {@code null} if there is none. Of course,
* the same values may occur several times.
*
* @return the list of values (integers) in the order they are encountered
*/
public final int[] arrayOfVals() {
LinkedList list = listOfVals();
return list.size() == 0 ? new int[0] : list.stream().mapToInt(l -> Utilities.safeInt(l)).toArray();
}
/**
* Returns the set of variables in the tree rooted by this node, in the order they are collected, or {@code null} if there is none.
*
* @return the set of variables in the tree rooted by this node, or {@code null}
*/
public final V[] vars() {
LinkedHashSet set = new LinkedHashSet<>();
listOfVars().stream().forEach(x -> set.add(x));
return set.size() == 0 ? null : set.stream().toArray(s -> Utilities.buildArray(set.iterator().next().getClass(), s));
}
/**
* Return {@code true} iff the sequence of variables (without duplicates) encountered in the tree rooted by this node is exactly the specified array.
*
* @param t
* an array of variables
* @return {@code true} iff the sequence of variables encountered in the tree rooted by this node is exactly the specified array
*/
public final boolean exactlyVars(V[] t) {
V[] vars = vars();
return t.length == vars.length && IntStream.range(0, t.length).allMatch(i -> t[i] == vars[i]);
}
public final LinkedHashSet collectVarsToSet(LinkedHashSet set) {
listOfVars().stream().forEach(x -> set.add(x));
return set;
}
/**
* Returns a new tree, obtained from the tree rooted by this node by replacing symbols with integers, as defined by the specified map.
*
* @param mapOfSymbols
* a map associating integers with strings (symbols)
* @return a new tree, obtained by replacing symbols with integers, as defined by the specified map
*/
public abstract XNode replaceSymbols(Map mapOfSymbols);
/**
* a new tree, obtained from the tree rooted by this node by replacing values of leaves, as defined by the specified function
*
* @param f
* a function mapping objects to objects
* @return a new tree, obtained by replacing values of leaves, as defined by the specified function
*/
public abstract XNode replaceLeafValues(Function
© 2015 - 2025 Weber Informatics LLC | Privacy Policy