aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/main/java
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2020-09-21 23:09:03 +0200
committerJon Bratseth <bratseth@gmail.com>2020-09-21 23:09:03 +0200
commitc20e365ef13438169c55911b65e6d201cbef8760 (patch)
tree67b1c1b89b37dbd1f8061b0b9c968f897db22dd9 /searchlib/src/main/java
parent0c260f43b83325821b237a00cb5b69e0ac687ce2 (diff)
Don't fold division by zero
This preserves 0/0 expressions such that NaN can be produced at runtime.
Diffstat (limited to 'searchlib/src/main/java')
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Value.java5
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/transform/Simplifier.java58
2 files changed, 42 insertions, 21 deletions
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Value.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Value.java
index 382cbb7ce9a..071fc6e9fc2 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Value.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Value.java
@@ -30,6 +30,11 @@ public abstract class Value {
return new DoubleValue(asDouble());
}
+ /** Returns true if this has a double value which is NaN */
+ public boolean isNaN() {
+ return hasDouble() && Double.isNaN(asDouble());
+ }
+
/** Returns this as a tensor value */
public abstract Tensor asTensor();
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/transform/Simplifier.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/transform/Simplifier.java
index 394faee71a8..1522e0025c7 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/transform/Simplifier.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/transform/Simplifier.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.transform;
+import com.yahoo.document.update.ArithmeticValueUpdate;
import com.yahoo.searchlib.rankingexpression.evaluation.DoubleValue;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.searchlib.rankingexpression.rule.ArithmeticNode;
@@ -46,6 +47,7 @@ public class Simplifier extends ExpressionTransformer<TransformContext> {
}
private ExpressionNode transformArithmetic(ArithmeticNode node) {
+ // Fold the subset of expressions that are constant (such that in "1 + 2 + var")
if (node.children().size() > 1) {
List<ExpressionNode> children = new ArrayList<>(node.children());
List<ArithmeticOperator> operators = new ArrayList<>(node.operators());
@@ -54,32 +56,34 @@ public class Simplifier extends ExpressionTransformer<TransformContext> {
node = new ArithmeticNode(children, operators);
}
- if (isConstant(node))
+ if (isConstant(node) && ! node.evaluate(null).isNaN())
return new ConstantNode(node.evaluate(null));
- else if (allMultiplicationOrDivision(node) && hasZero(node)) // disregarding the /0 case
+ else if (allMultiplicationOrDivision(node) && hasZero(node) && ! hasDivisionByZero(node))
return new ConstantNode(new DoubleValue(0));
else
return node;
}
- private void transform(ArithmeticOperator operator, List<ExpressionNode> children, List<ArithmeticOperator> operators) {
+ private void transform(ArithmeticOperator operatorToTransform,
+ List<ExpressionNode> children, List<ArithmeticOperator> operators) {
int i = 0;
while (i < children.size()-1) {
- if ( ! operators.get(i).equals(operator)) {
- i++;
- continue;
- }
-
- ExpressionNode child1 = children.get(i);
- ExpressionNode child2 = children.get(i + 1);
- if (isConstant(child1) && isConstant(child2) && hasPrecedence(operators, i)) {
- Value evaluated = new ArithmeticNode(child1, operators.remove(i), child2).evaluate(null);
- children.set(i, new ConstantNode(evaluated.freeze()));
- children.remove(i+1);
+ boolean transformed = false;
+ if ( operators.get(i).equals(operatorToTransform)) {
+ ExpressionNode child1 = children.get(i);
+ ExpressionNode child2 = children.get(i + 1);
+ if (isConstant(child1) && isConstant(child2) && hasPrecedence(operators, i)) {
+ Value evaluated = new ArithmeticNode(child1, operators.get(i), child2).evaluate(null);
+ if ( ! evaluated.isNaN()) { // Don't replace by NaN
+ operators.remove(i);
+ children.set(i, new ConstantNode(evaluated.freeze()));
+ children.remove(i + 1);
+ transformed = true;
+ }
+ }
}
- else { // try the next index
+ if ( ! transformed) // try the next index
i++;
- }
}
}
@@ -105,22 +109,34 @@ public class Simplifier extends ExpressionTransformer<TransformContext> {
private boolean allMultiplicationOrDivision(ArithmeticNode node) {
for (ArithmeticOperator o : node.operators())
- if (o == ArithmeticOperator.PLUS || o == ArithmeticOperator.MINUS)
+ if (o != ArithmeticOperator.MULTIPLY && o != ArithmeticOperator.DIVIDE)
return false;
return true;
}
private boolean hasZero(ArithmeticNode node) {
for (ExpressionNode child : node.children()) {
- if ( ! (child instanceof ConstantNode)) continue;
- ConstantNode constant = (ConstantNode)child;
- if ( ! constant.getValue().hasDouble()) return false;
- if (constant.getValue().asDouble() == 0.0)
+ if (isZero(child))
return true;
}
return false;
}
+ private boolean hasDivisionByZero(ArithmeticNode node) {
+ for (int i = 1; i < node.children().size(); i++) {
+ if ( node.operators().get(i - 1) == ArithmeticOperator.DIVIDE && isZero(node.children().get(i)))
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isZero(ExpressionNode node) {
+ if ( ! (node instanceof ConstantNode)) return false;
+ ConstantNode constant = (ConstantNode)node;
+ if ( ! constant.getValue().hasDouble()) return false;
+ return constant.getValue().asDouble() == 0.0;
+ }
+
private boolean isConstant(ExpressionNode node) {
if (node instanceof ConstantNode) return true;
if (node instanceof ReferenceNode) return false;