added MathStepTest to test hashCode() and the custom variable finder. Found a couple of problems in my parser and I fixed them. Forgot to make MathStep a PathProcessor so that OLAP is smart about data access. Both OLTP and OLAP tests pass.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/dfddccaa Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/dfddccaa Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/dfddccaa Branch: refs/heads/TINKERPOP-1799 Commit: dfddccaaa85898e046e6b7a5bd81da3d94777d7d Parents: c36493b Author: Marko A. Rodriguez <[email protected]> Authored: Wed Oct 4 11:01:53 2017 -0600 Committer: Marko A. Rodriguez <[email protected]> Committed: Wed Oct 4 11:01:53 2017 -0600 ---------------------------------------------------------------------- .../process/traversal/step/map/MathStep.java | 47 ++++++++++++---- .../traversal/step/map/MathStepTest.java | 58 ++++++++++++++++++++ .../structure/TinkerGraphPlayTest.java | 2 +- 3 files changed, 95 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/dfddccaa/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java index ef88aac..6dd5338 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java @@ -21,10 +21,12 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map; import net.objecthunter.exp4j.Expression; import net.objecthunter.exp4j.ExpressionBuilder; +import org.apache.commons.lang.StringUtils; import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating; +import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor; import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; @@ -32,6 +34,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalRing; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -39,35 +42,41 @@ import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class MathStep<S> extends MapStep<S, Double> implements ByModulating, TraversalParent, Scoping { +public final class MathStep<S> extends MapStep<S, Double> implements ByModulating, TraversalParent, Scoping, PathProcessor { private static final String CURRENT = "_"; private final String equation; private final Set<String> variables; - private final Expression expression; private TraversalRing<Object, Number> traversalRing = new TraversalRing<>(); + private Set<String> keepLabels; public MathStep(final Traversal.Admin traversal, final String equation) { super(traversal); this.equation = equation; this.variables = MathStep.getVariables(this.equation); - this.expression = new ExpressionBuilder(this.equation) - .variables(this.variables) - .implicitMultiplication(false) - .build(); + + } + + @Override + protected Traverser.Admin<Double> processNextStart() { + return PathProcessor.processTraverserPathLabels(super.processNextStart(), this.keepLabels); } @Override protected Double map(final Traverser.Admin<S> traverser) { + final Expression expression = new ExpressionBuilder(this.equation) + .variables(this.variables) + .implicitMultiplication(false) + .build(); for (final String var : this.variables) { - this.expression.setVariable(var, TraversalUtil.applyNullable( + expression.setVariable(var, TraversalUtil.applyNullable( var.equals(CURRENT) ? traverser.get() : this.getNullableScopeValue(Pop.last, var, traverser), this.traversalRing.next()).doubleValue()); } this.traversalRing.reset(); - return this.expression.evaluate(); + return expression.evaluate(); } @Override @@ -116,10 +125,15 @@ public final class MathStep<S> extends MapStep<S, Double> implements ByModulatin @Override public Set<String> getScopeKeys() { - return this.variables; + if (this.variables.contains(CURRENT)) { + final Set<String> temp = new HashSet<>(this.variables); + temp.remove(CURRENT); + return temp; + } else + return this.variables; } - private static final Set<String> getVariables(final String equation) { + protected static final Set<String> getVariables(final String equation) { final StringBuilder builder = new StringBuilder(); final char[] chars = equation.toCharArray(); for (int i = 0; i < chars.length; i++) { @@ -132,7 +146,8 @@ public final class MathStep<S> extends MapStep<S, Double> implements ByModulatin } final Set<String> variables = new LinkedHashSet<>(); for (final String slot : builder.toString().split(" ")) { - if (!slot.trim().isEmpty() && !slot.equals("abs") && !slot.equals("acos") && + if (!slot.trim().isEmpty() && !StringUtils.isNumeric(slot) && + !slot.equals("abs") && !slot.equals("acos") && !slot.equals("asin") && !slot.equals("atan") && !slot.equals("cbrt") && !slot.equals("ceil") && !slot.equals("cos") && !slot.equals("cosh") && !slot.equals("exp") && !slot.equals("floor") && !slot.equals("log") && @@ -143,4 +158,14 @@ public final class MathStep<S> extends MapStep<S, Double> implements ByModulatin } return variables; } + + @Override + public void setKeepLabels(final Set<String> labels) { + this.keepLabels = labels; + } + + @Override + public Set<String> getKeepLabels() { + return this.keepLabels; + } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/dfddccaa/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStepTest.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStepTest.java new file mode 100644 index 0000000..334a367 --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStepTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tinkerpop.gremlin.process.traversal.step.map; + +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.both; +import static org.junit.Assert.assertEquals; + +/** + * @author Marko A. Rodriguez (http://markorodriguez.com) + */ +public class MathStepTest extends StepTest { + + @Override + protected List<Traversal> getTraversals() { + return Arrays.asList( + __.math("a+b"), + __.math("a+b").by("age"), + __.math("a/b").by("age"), + __.math("a+b").by("age").by(both().count()), + __.math("sin a + b") + ); + } + + @Test + public void shouldParseVariablesCorrectly() { + assertEquals(Arrays.asList("a", "b"), new ArrayList<>(MathStep.getVariables("a + b / 2"))); + assertEquals(Arrays.asList("a", "b"), new ArrayList<>(MathStep.getVariables("a + b / sin 2"))); + assertEquals(Arrays.asList("a", "b", "_", "x", "z"), new ArrayList<>(MathStep.getVariables("(a + b / _) + log2 (x^3)^z"))); + assertEquals(Arrays.asList("a", "b", "_", "x", "z"), new ArrayList<>(MathStep.getVariables("(a + b / _) + log2 (x^3)^z + b + a"))); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/dfddccaa/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java ---------------------------------------------------------------------- diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java index 736b146..2fb0d68 100644 --- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java @@ -71,7 +71,7 @@ public class TinkerGraphPlayTest { public void testPlay8() throws Exception { Graph graph = TinkerFactory.createModern(); GraphTraversalSource g = graph.traversal(); - System.out.println(g.V().values("age").toList()); + System.out.println(g.V().values("age").math("sin _").toList()); } @Test
