summaryrefslogtreecommitdiffstats
path: root/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule
diff options
context:
space:
mode:
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.java63
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java69
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java22
-rwxr-xr-xsearchlib/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.java67
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TruthOperator.java50
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;
- }
-
-}