diff options
Diffstat (limited to 'searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule')
-rw-r--r-- | searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticOperator.java | 63 | ||||
-rw-r--r-- | searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java | 69 | ||||
-rw-r--r-- | searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java | 22 | ||||
-rwxr-xr-x | searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/OperationNode.java (renamed from searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticNode.java) | 38 | ||||
-rw-r--r-- | searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/Operator.java | 67 | ||||
-rw-r--r-- | searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TruthOperator.java | 50 |
6 files changed, 97 insertions, 212 deletions
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticOperator.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticOperator.java deleted file mode 100644 index 959045a63a0..00000000000 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticOperator.java +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.searchlib.rankingexpression.rule; - -import com.yahoo.searchlib.rankingexpression.evaluation.Value; - -import java.util.List; - -/** - * A mathematical operator - * - * @author bratseth - */ -public enum ArithmeticOperator { - - OR(0, "||") { public Value evaluate(Value x, Value y) { - return x.or(y); - }}, - AND(1, "&&") { public Value evaluate(Value x, Value y) { - return x.and(y); - }}, - PLUS(2, "+") { public Value evaluate(Value x, Value y) { - return x.add(y); - }}, - MINUS(3, "-") { public Value evaluate(Value x, Value y) { - return x.subtract(y); - }}, - MULTIPLY(4, "*") { public Value evaluate(Value x, Value y) { - return x.multiply(y); - }}, - DIVIDE(5, "/") { public Value evaluate(Value x, Value y) { - return x.divide(y); - }}, - MODULO(6, "%") { public Value evaluate(Value x, Value y) { - return x.modulo(y); - }}, - POWER(7, "^") { public Value evaluate(Value x, Value y) { - return x.power(y); - }}; - - /** A list of all the operators in this in order of decreasing precedence */ - public static final List<ArithmeticOperator> operatorsByPrecedence = List.of(POWER, MODULO, DIVIDE, MULTIPLY, MINUS, PLUS, AND, OR); - - private final int precedence; - private final String image; - - private ArithmeticOperator(int precedence, String image) { - this.precedence = precedence; - this.image = image; - } - - /** Returns true if this operator has precedence over the given operator */ - public boolean hasPrecedenceOver(ArithmeticOperator op) { - return precedence > op.precedence; - } - - public abstract Value evaluate(Value x, Value y); - - @Override - public String toString() { - return image; - } - -} diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java deleted file mode 100644 index e726a351f74..00000000000 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.searchlib.rankingexpression.rule; - -import com.yahoo.searchlib.rankingexpression.Reference; -import com.yahoo.searchlib.rankingexpression.evaluation.Context; -import com.yahoo.searchlib.rankingexpression.evaluation.Value; -import com.yahoo.tensor.TensorType; -import com.yahoo.tensor.evaluation.TypeContext; - -import java.util.Deque; -import java.util.List; -import java.util.Objects; - -/** - * A node which returns the outcome of a comparison. - * - * @author bratseth - */ -public class ComparisonNode extends BooleanNode { - - /** The operator string of this condition. */ - private final TruthOperator operator; - - private final List<ExpressionNode> conditions; - - public ComparisonNode(ExpressionNode leftCondition, TruthOperator operator, ExpressionNode rightCondition) { - conditions = List.of(leftCondition, rightCondition); - this.operator = operator; - } - - @Override - public List<ExpressionNode> children() { - return conditions; - } - - public TruthOperator getOperator() { return operator; } - - public ExpressionNode getLeftCondition() { return conditions.get(0); } - - public ExpressionNode getRightCondition() { return conditions.get(1); } - - @Override - public StringBuilder toString(StringBuilder string, SerializationContext context, Deque<String> path, CompositeNode parent) { - getLeftCondition().toString(string, context, path, this).append(' ').append(operator).append(' '); - return getRightCondition().toString(string, context, path, this); - } - - @Override - public TensorType type(TypeContext<Reference> context) { - return TensorType.empty; // by definition - } - - @Override - public Value evaluate(Context context) { - Value leftValue = getLeftCondition().evaluate(context); - Value rightValue = getRightCondition().evaluate(context); - return leftValue.compare(operator,rightValue); - } - - @Override - public ComparisonNode setChildren(List<ExpressionNode> children) { - if (children.size() != 2) throw new IllegalArgumentException("A comparison test must have 2 children"); - return new ComparisonNode(children.get(0), operator, children.get(1)); - } - - @Override - public int hashCode() { return Objects.hash(operator, conditions); } - -} diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java index 9f07f146264..97e9a74f9c8 100644 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java @@ -106,10 +106,10 @@ public class LambdaFunctionNode extends CompositeNode { } private Optional<DoubleBinaryOperator> getDirectEvaluator() { - if ( ! (functionExpression instanceof ArithmeticNode)) { + if ( ! (functionExpression instanceof OperationNode)) { return Optional.empty(); } - ArithmeticNode node = (ArithmeticNode) functionExpression; + OperationNode node = (OperationNode) functionExpression; if ( ! (node.children().get(0) instanceof ReferenceNode) || ! (node.children().get(1) instanceof ReferenceNode)) { return Optional.empty(); } @@ -121,16 +121,16 @@ public class LambdaFunctionNode extends CompositeNode { if (node.operators().size() != 1) { return Optional.empty(); } - ArithmeticOperator operator = node.operators().get(0); + Operator operator = node.operators().get(0); switch (operator) { - case OR: return asFunctionExpression((left, right) -> ((left != 0.0) || (right != 0.0)) ? 1.0 : 0.0); - case AND: return asFunctionExpression((left, right) -> ((left != 0.0) && (right != 0.0)) ? 1.0 : 0.0); - case PLUS: return asFunctionExpression((left, right) -> left + right); - case MINUS: return asFunctionExpression((left, right) -> left - right); - case MULTIPLY: return asFunctionExpression((left, right) -> left * right); - case DIVIDE: return asFunctionExpression((left, right) -> left / right); - case MODULO: return asFunctionExpression((left, right) -> left % right); - case POWER: return asFunctionExpression(Math::pow); + case or: return asFunctionExpression((left, right) -> ((left != 0.0) || (right != 0.0)) ? 1.0 : 0.0); + case and: return asFunctionExpression((left, right) -> ((left != 0.0) && (right != 0.0)) ? 1.0 : 0.0); + case plus: return asFunctionExpression((left, right) -> left + right); + case minus: return asFunctionExpression((left, right) -> left - right); + case multiply: return asFunctionExpression((left, right) -> left * right); + case divide: return asFunctionExpression((left, right) -> left / right); + case modulo: return asFunctionExpression((left, right) -> left % right); + case power: return asFunctionExpression(Math::pow); } return Optional.empty(); } diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/OperationNode.java index c3e39197316..0512e1dad2f 100755 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticNode.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/OperationNode.java @@ -16,26 +16,26 @@ import java.util.List; import java.util.Objects; /** - * A binary mathematical operation + * A sequence of binary operations. * * @author bratseth */ -public final class ArithmeticNode extends CompositeNode { +public final class OperationNode extends CompositeNode { private final List<ExpressionNode> children; - private final List<ArithmeticOperator> operators; + private final List<Operator> operators; - public ArithmeticNode(List<ExpressionNode> children, List<ArithmeticOperator> operators) { + public OperationNode(List<ExpressionNode> children, List<Operator> operators) { this.children = List.copyOf(children); this.operators = List.copyOf(operators); } - public ArithmeticNode(ExpressionNode leftExpression, ArithmeticOperator operator, ExpressionNode rightExpression) { + public OperationNode(ExpressionNode leftExpression, Operator operator, ExpressionNode rightExpression) { this.children = List.of(leftExpression, rightExpression); this.operators = List.of(operator); } - public List<ArithmeticOperator> operators() { return operators; } + public List<Operator> operators() { return operators; } @Override public List<ExpressionNode> children() { return children; } @@ -50,7 +50,7 @@ public final class ArithmeticNode extends CompositeNode { child.next().toString(string, context, path, this); if (child.hasNext()) string.append(" "); - for (Iterator<ArithmeticOperator> op = operators.iterator(); op.hasNext() && child.hasNext();) { + for (Iterator<Operator> op = operators.iterator(); op.hasNext() && child.hasNext();) { string.append(op.next().toString()).append(" "); child.next().toString(string, context, path, this); if (op.hasNext()) @@ -68,14 +68,14 @@ public final class ArithmeticNode extends CompositeNode { */ private boolean nonDefaultPrecedence(CompositeNode parent) { if ( parent == null) return false; - if ( ! (parent instanceof ArithmeticNode arithmeticParent)) return false; + if ( ! (parent instanceof OperationNode operationParent)) return false; // The line below can only be correct in both only have one operator. // Getting this correct is impossible without more work. // So for now we only handle the simple case correctly, and use a safe approach by adding // extra parenthesis just in case.... - return arithmeticParent.operators.get(0).hasPrecedenceOver(this.operators.get(0)) - || ((arithmeticParent.operators.size() > 1) || (operators.size() > 1)); + return operationParent.operators.get(0).hasPrecedenceOver(this.operators.get(0)) + || ((operationParent.operators.size() > 1) || (operators.size() > 1)); } @Override @@ -96,8 +96,8 @@ public final class ArithmeticNode extends CompositeNode { // Apply in precedence order: Deque<ValueItem> stack = new ArrayDeque<>(); stack.push(new ValueItem(null, child.next().evaluate(context))); - for (Iterator<ArithmeticOperator> it = operators.iterator(); it.hasNext() && child.hasNext();) { - ArithmeticOperator op = it.next(); + for (Iterator<Operator> it = operators.iterator(); it.hasNext() && child.hasNext();) { + Operator op = it.next(); if ( ! stack.isEmpty()) { while (stack.size() > 1 && ! op.hasPrecedenceOver(stack.peek().op)) { popStack(stack); @@ -121,30 +121,30 @@ public final class ArithmeticNode extends CompositeNode { public CompositeNode setChildren(List<ExpressionNode> newChildren) { if (children.size() != newChildren.size()) throw new IllegalArgumentException("Expected " + children.size() + " children but got " + newChildren.size()); - return new ArithmeticNode(newChildren, operators); + return new OperationNode(newChildren, operators); } @Override public int hashCode() { return Objects.hash(children, operators); } - public static ArithmeticNode resolve(ExpressionNode left, ArithmeticOperator op, ExpressionNode right) { - if ( ! (left instanceof ArithmeticNode leftArithmetic)) return new ArithmeticNode(left, op, right); + public static OperationNode resolve(ExpressionNode left, Operator op, ExpressionNode right) { + if ( ! (left instanceof OperationNode leftArithmetic)) return new OperationNode(left, op, right); List<ExpressionNode> newChildren = new ArrayList<>(leftArithmetic.children()); newChildren.add(right); - List<ArithmeticOperator> newOperators = new ArrayList<>(leftArithmetic.operators()); + List<Operator> newOperators = new ArrayList<>(leftArithmetic.operators()); newOperators.add(op); - return new ArithmeticNode(newChildren, newOperators); + return new OperationNode(newChildren, newOperators); } private static class ValueItem { - final ArithmeticOperator op; + final Operator op; Value value; - public ValueItem(ArithmeticOperator op, Value value) { + public ValueItem(Operator op, Value value) { this.op = op; this.value = value; } diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/Operator.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/Operator.java new file mode 100644 index 00000000000..02af88b2c58 --- /dev/null +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/Operator.java @@ -0,0 +1,67 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.searchlib.rankingexpression.rule; + +import com.yahoo.searchlib.rankingexpression.evaluation.Value; + +import java.util.Arrays; +import java.util.List; +import java.util.function.BiFunction; + +/** + * A mathematical operator + * + * @author bratseth + */ +public enum Operator { + + // In order from lowest to highest precedence + or("||", (x, y) -> x.or(y)), + and("&&", (x, y) -> x.and(y)), + largerOrEqual(">=", (x, y) -> x.largerOrEqual(y)), + larger(">", (x, y) -> x.larger(y)), + smallerOrEqual("<=", (x, y) -> x.smallerOrEqual(y)), + smaller("<", (x, y) -> x.smaller(y)), + approxEqual("~=", (x, y) -> x.approxEqual(y)), + notEqual("!=", (x, y) -> x.notEqual(y)), + equal("==", (x, y) -> x.equal(y)), + plus("+", (x, y) -> x.add(y)), + minus("-", (x, y) -> x.subtract(y)), + multiply("*", (x, y) -> x.multiply(y)), + divide("/", (x, y) -> x.divide(y)), + modulo("%", (x, y) -> x.modulo(y)), + power("^", true, (x, y) -> x.power(y)); + + /** A list of all the operators in this in order of increasing precedence */ + public static final List<Operator> operatorsByPrecedence = Arrays.stream(Operator.values()).toList(); + + private final String image; + private final boolean rightPrecedence; + private final BiFunction<Value, Value, Value> function; + + Operator(String image, BiFunction<Value, Value, Value> function) { + this(image, false, function); + } + + Operator(String image, boolean rightPrecedence, BiFunction<Value, Value, Value> function) { + this.image = image; + this.rightPrecedence = rightPrecedence; + this.function = function; + } + + /** Returns true if this operator has precedence over the given operator */ + public boolean hasPrecedenceOver(Operator other) { + if (operatorsByPrecedence.indexOf(this) == operatorsByPrecedence.indexOf(other)) + return rightPrecedence; + return operatorsByPrecedence.indexOf(this) > operatorsByPrecedence.indexOf(other); + } + + public final Value evaluate(Value x, Value y) { + return function.apply(x, y); + } + + @Override + public String toString() { + return image; + } + +} diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TruthOperator.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TruthOperator.java deleted file mode 100644 index fc259867923..00000000000 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TruthOperator.java +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.searchlib.rankingexpression.rule; - -import java.io.Serializable; - -/** - * A mathematical operator - * - * @author bratseth - */ -public enum TruthOperator implements Serializable { - - SMALLER("<") { public boolean evaluate(double x, double y) { return x<y; } }, - SMALLEREQUAL("<=") { public boolean evaluate(double x, double y) { return x<=y; } }, - EQUAL("==") { public boolean evaluate(double x, double y) { return x==y; } }, - APPROX_EQUAL("~=") { public boolean evaluate(double x, double y) { return approxEqual(x,y); } }, - LARGER(">") { public boolean evaluate(double x, double y) { return x>y; } }, - LARGEREQUAL(">=") { public boolean evaluate(double x, double y) { return x>=y; } }, - NOTEQUAL("!=") { public boolean evaluate(double x, double y) { return x!=y; } }; - - private final String operatorString; - - TruthOperator(String operatorString) { - this.operatorString = operatorString; - } - - /** Perform the truth operation on the input */ - public abstract boolean evaluate(double x, double y); - - @Override - public String toString() { return operatorString; } - - public static TruthOperator fromString(String string) { - for (TruthOperator operator : values()) - if (operator.toString().equals(string)) - return operator; - throw new IllegalArgumentException("Illegal truth operator '" + string + "'"); - } - - private static boolean approxEqual(double x,double y) { - if (y < -1.0 || y > 1.0) { - x = Math.nextAfter(x/y, 1.0); - y = 1.0; - } else { - x = Math.nextAfter(x, y); - } - return x==y; - } - -} |