You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by ok...@apache.org on 2016/02/17 17:01:56 UTC

incubator-tinkerpop git commit: Created VertexProgramStep which is abstract and provides processNextStarts() functionality to TraversalVertexProgramStep and PageRankVertexProgramStep. Moved the PureTraversal model into the VertexProgramSteps. Added Times

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1154 969472f06 -> 11238b630


Created VertexProgramStep which is abstract and provides processNextStarts() functionality to TraversalVertexProgramStep and PageRankVertexProgramStep. Moved the PureTraversal model into the VertexProgramSteps. Added TimesModulating which allows steps to do what they wish with times(int). pageRank().times(20) for example. General cleanup.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/11238b63
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/11238b63
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/11238b63

Branch: refs/heads/TINKERPOP-1154
Commit: 11238b630bfc9af71f0a443eada36381c9f5fa15
Parents: 969472f
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Wed Feb 17 09:01:47 2016 -0700
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Wed Feb 17 09:01:47 2016 -0700

----------------------------------------------------------------------
 .../peerpressure/PeerPressureVertexProgram.java |  2 +-
 .../ranking/pagerank/PageRankVertexProgram.java |  4 +-
 .../traversal/TraversalVertexProgram.java       |  4 +-
 .../traversal/step/VertexComputing.java         |  5 ++
 .../traversal/step/map/ComputerResultStep.java  |  2 +-
 .../step/map/PageRankVertexProgramStep.java     | 77 +++++++++-----------
 .../step/map/TraversalVertexProgramStep.java    | 75 +++++++------------
 .../traversal/step/map/VertexProgramStep.java   | 60 +++++++++++++++
 .../traversal/dsl/graph/GraphTraversal.java     |  7 +-
 .../process/traversal/step/TimesModulating.java | 28 +++++++
 .../process/traversal/util/PureTraversal.java   | 41 ++++++++---
 11 files changed, 193 insertions(+), 112 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgram.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgram.java
index b53f914..daf49df 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/clustering/peerpressure/PeerPressureVertexProgram.java
@@ -80,7 +80,7 @@ public class PeerPressureVertexProgram extends StaticVertexProgram<Pair<Serializ
     public void loadState(final Graph graph, final Configuration configuration) {
         if (configuration.containsKey(EDGE_TRAVERSAL)) {
             this.edgeTraversal = PureTraversal.loadState(configuration, EDGE_TRAVERSAL, graph);
-            this.voteScope = MessageScope.Local.of(() -> this.edgeTraversal.getCompiled().clone());
+            this.voteScope = MessageScope.Local.of(() -> this.edgeTraversal.get().clone());
             this.countScope = MessageScope.Local.of(new MessageScope.Local.ReverseTraversalSupplier(this.voteScope));
         }
         this.maxIterations = configuration.getInt(MAX_ITERATIONS, 30);

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java
index d6d2e9b..9a3d54d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java
@@ -80,7 +80,7 @@ public class PageRankVertexProgram extends StaticVertexProgram<Double> {
             this.vertexTraversal = PureTraversal.loadState(configuration, VERTEX_TRAVERSAL, graph);
         if (configuration.containsKey(EDGE_TRAVERSAL)) {
             this.edgeTraversal = PureTraversal.loadState(configuration, EDGE_TRAVERSAL, graph);
-            this.incidentMessageScope = MessageScope.Local.of(() -> this.edgeTraversal.getCompiled().clone());
+            this.incidentMessageScope = MessageScope.Local.of(() -> this.edgeTraversal.get().clone());
             this.countMessageScope = MessageScope.Local.of(new MessageScope.Local.ReverseTraversalSupplier(this.incidentMessageScope));
         }
         this.vertexCountAsDouble = configuration.getDouble(VERTEX_COUNT, 1.0d);
@@ -146,7 +146,7 @@ public class PageRankVertexProgram extends StaticVertexProgram<Double> {
             vertex.property(VertexProperty.Cardinality.single, EDGE_COUNT, edgeCount);
             messenger.sendMessage(this.incidentMessageScope, initialPageRank / edgeCount);
         } else {
-            if (2 == memory.getIteration() && null != this.vertexTraversal && !TraversalUtil.test(vertex, this.vertexTraversal.getCompiled()))
+            if (2 == memory.getIteration() && null != this.vertexTraversal && !TraversalUtil.test(vertex, this.vertexTraversal.get()))
                 return;
             double newPageRank = IteratorUtils.reduce(messenger.receiveMessages(), 0.0d, (a, b) -> a + b);
             newPageRank = (this.alpha * newPageRank) + ((1.0d - this.alpha) / this.vertexCountAsDouble);

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java
index fa9054e..d8b4262 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java
@@ -106,7 +106,9 @@ public final class TraversalVertexProgram implements VertexProgram<TraverserSet<
         if (!configuration.containsKey(TRAVERSAL))
             throw new IllegalArgumentException("The configuration does not have a traversal supplier: " + TRAVERSAL);
         this.pureTraversal = PureTraversal.loadState(configuration, TRAVERSAL, graph);
-        this.traversal = this.pureTraversal.getCompiled();
+        this.traversal = this.pureTraversal.get();
+        if (!this.traversal.isLocked())
+            this.traversal.applyStrategies();
         this.traversalMatrix = new TraversalMatrix<>(this.traversal);
         for (final MapReducer<?, ?, ?, ?, ?> mapReducer : TraversalHelper.getStepsOfAssignableClassRecursively(MapReducer.class, this.traversal)) {
             this.mapReducers.add(mapReducer.getMapReduce());

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/VertexComputing.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/VertexComputing.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/VertexComputing.java
index 0cf144f..54accc1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/VertexComputing.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/VertexComputing.java
@@ -20,6 +20,7 @@
 package org.apache.tinkerpop.gremlin.process.computer.traversal.step;
 
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
+import org.apache.tinkerpop.gremlin.process.computer.VertexProgram;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 
 import java.util.function.Function;
@@ -30,4 +31,8 @@ import java.util.function.Function;
 public interface VertexComputing {
 
     public void setGraphComputerFunction(final Function<Graph, GraphComputer> graphComputerFunction);
+
+    public VertexProgram generateProgram(final Graph graph);
+
+    public GraphComputer generateComputer(final Graph graph);
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/ComputerResultStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/ComputerResultStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/ComputerResultStep.java
index d32e750..37d14c1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/ComputerResultStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/ComputerResultStep.java
@@ -76,7 +76,7 @@ public final class ComputerResultStep<S> extends AbstractStep<ComputerResult, S>
                 final ComputerResult result = this.starts.next().get();
                 result.memory().keys().forEach(key -> this.getTraversal().getSideEffects().set(key, result.memory().get(key)));
                 final Step endStep = this.getPreviousStep() instanceof TraversalVertexProgramStep ?
-                        ((TraversalVertexProgramStep) this.getPreviousStep()).computerTraversal.getEndStep() :
+                        ((TraversalVertexProgramStep) this.getPreviousStep()).computerTraversal.get().getEndStep() :
                         EmptyStep.instance();   // TODO: need to be selective and smart
                 if (endStep instanceof SideEffectCapStep) {
                     final List<String> sideEffectKeys = ((SideEffectCapStep<?, ?>) endStep).getSideEffectKeys();

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PageRankVertexProgramStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PageRankVertexProgramStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PageRankVertexProgramStep.java
index 7cc543a..68db42a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PageRankVertexProgramStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/PageRankVertexProgramStep.java
@@ -19,18 +19,16 @@
 
 package org.apache.tinkerpop.gremlin.process.computer.traversal.step.map;
 
-import org.apache.tinkerpop.gremlin.process.computer.ComputerResult;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgram;
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.VertexComputing;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TimesModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.util.PureTraversal;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
@@ -38,22 +36,19 @@ import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.concurrent.ExecutionException;
+import java.util.Set;
 import java.util.function.Function;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class PageRankVertexProgramStep extends AbstractStep<ComputerResult, ComputerResult> implements VertexComputing, TraversalParent, ByModulating {
+public final class PageRankVertexProgramStep extends VertexProgramStep implements TraversalParent, ByModulating, TimesModulating {
 
     private transient Function<Graph, GraphComputer> graphComputerFunction = Graph::compute;
 
-    private Traversal.Admin<Vertex, Edge> pageRankTraversal;
-    private Traversal.Admin<Vertex, Edge> purePageRankTraversal;
+    private PureTraversal<Vertex, Edge> edgeTraversal;
     private String pageRankProperty = PageRankVertexProgram.PAGE_RANK;
-    private boolean first = true;
-
+    private int times = 30;
 
     public PageRankVertexProgramStep(final Traversal.Admin traversal) {
         super(traversal);
@@ -61,43 +56,29 @@ public final class PageRankVertexProgramStep extends AbstractStep<ComputerResult
     }
 
     @Override
-    protected Traverser<ComputerResult> processNextStart() throws NoSuchElementException {
-        try {
-            if (this.first && this.getPreviousStep() instanceof EmptyStep) {
-                this.first = false;
-                final Graph graph = this.getTraversal().getGraph().get();
-                final GraphComputer graphComputer = this.graphComputerFunction.apply(graph).persist(GraphComputer.Persist.EDGES).result(GraphComputer.ResultGraph.NEW);
-                return this.traversal.getTraverserGenerator().generate(graphComputer.program(this.generateProgram(graph)).submit().get(), this, 1l);
-            } else {
-                final Traverser.Admin<ComputerResult> traverser = this.starts.next();
-                final Graph graph = traverser.get().graph();
-                final GraphComputer graphComputer = this.graphComputerFunction.apply(graph).persist(GraphComputer.Persist.EDGES).result(GraphComputer.ResultGraph.NEW);
-                return traverser.split(graphComputer.program(this.generateProgram(graph)).submit().get(), this);
-            }
-        } catch (final InterruptedException | ExecutionException e) {
-            throw new IllegalStateException(e.getMessage(), e);
-        }
+    public void modulateBy(final Traversal.Admin<?, ?> edgeTraversal) {
+        this.edgeTraversal = new PureTraversal<>((Traversal.Admin<Vertex, Edge>) edgeTraversal);
+        this.integrateChild(this.edgeTraversal.get());
     }
 
     @Override
-    public void modulateBy(final Traversal.Admin<?, ?> localChildTraversal) {
-        this.pageRankTraversal = this.integrateChild((Traversal.Admin) localChildTraversal);
-        this.purePageRankTraversal = this.pageRankTraversal.clone();
+    public void modulateBy(final String pageRankProperty) {
+        this.pageRankProperty = pageRankProperty;
     }
 
     @Override
-    public void modulateBy(final String pageRankProperty) {
-        this.pageRankProperty = pageRankProperty;
+    public void modulateTimes(int times) {
+        this.times = times;
     }
 
     @Override
     public List<Traversal.Admin<Vertex, Edge>> getLocalChildren() {
-        return Collections.singletonList(this.pageRankTraversal);
+        return Collections.singletonList(this.edgeTraversal.get());
     }
 
     @Override
     public String toString() {
-        return StringFactory.stepString(this, this.pageRankTraversal);
+        return StringFactory.stepString(this, this.edgeTraversal.get(), this.pageRankProperty, this.times);
     }
 
     @Override
@@ -105,25 +86,33 @@ public final class PageRankVertexProgramStep extends AbstractStep<ComputerResult
         this.graphComputerFunction = graphComputerFunction;
     }
 
-    private PageRankVertexProgram generateProgram(final Graph graph) {
+    @Override
+    public PageRankVertexProgram generateProgram(final Graph graph) {
+        this.edgeTraversal.reset();
+        final Traversal.Admin<Vertex, Edge> compiledTraversal = this.edgeTraversal.get();
+        compiledTraversal.setStrategies(TraversalStrategies.GlobalCache.getStrategies(graph.getClass()));
         return PageRankVertexProgram.build()
                 .property(this.pageRankProperty)
-                .edges(this.compileTraversal(graph))
+                .iterations(this.times)
+                .edges(compiledTraversal)
                 .create(graph);
     }
 
-    private final Traversal.Admin<Vertex, Edge> compileTraversal(final Graph graph) {
-        final Traversal.Admin<Vertex, Edge> compiledPageRankTraversal = this.purePageRankTraversal.clone();
-        compiledPageRankTraversal.setStrategies(TraversalStrategies.GlobalCache.getStrategies(graph.getClass()));
-        compiledPageRankTraversal.applyStrategies();
-        return compiledPageRankTraversal;
+    @Override
+    public Set<TraverserRequirement> getRequirements() {
+        return TraversalParent.super.getSelfAndChildRequirements();
+    }
+
+    @Override
+    public GraphComputer generateComputer(final Graph graph) {
+        return this.graphComputerFunction.apply(graph).persist(GraphComputer.Persist.EDGES).result(GraphComputer.ResultGraph.NEW);
     }
 
     @Override
     public PageRankVertexProgramStep clone() {
         final PageRankVertexProgramStep clone = (PageRankVertexProgramStep) super.clone();
-        clone.pageRankTraversal = clone.integrateChild(this.pageRankTraversal);
-        clone.purePageRankTraversal = clone.integrateChild(this.purePageRankTraversal);
+        clone.edgeTraversal = this.edgeTraversal.clone();
+        this.integrateChild(this.edgeTraversal.get());
         return clone;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/TraversalVertexProgramStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/TraversalVertexProgramStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/TraversalVertexProgramStep.java
index 7704347..7300a85 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/TraversalVertexProgramStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/TraversalVertexProgramStep.java
@@ -19,79 +19,49 @@
 
 package org.apache.tinkerpop.gremlin.process.computer.traversal.step.map;
 
-import org.apache.tinkerpop.gremlin.process.computer.ComputerResult;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.TraversalVertexProgram;
-import org.apache.tinkerpop.gremlin.process.computer.traversal.step.VertexComputing;
-import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.util.PureTraversal;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.ExecutionException;
 import java.util.function.Function;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class TraversalVertexProgramStep extends AbstractStep<ComputerResult, ComputerResult> implements TraversalParent, VertexComputing {
+public final class TraversalVertexProgramStep extends VertexProgramStep implements TraversalParent {
 
     private transient Function<Graph, GraphComputer> graphComputerFunction = Graph::compute;
-    public Traversal.Admin<?, ?> computerTraversal;
-    public Traversal.Admin<?, ?> pureComputerTraversal;
-
-    private boolean first = true;
+    public PureTraversal<?, ?> computerTraversal;
 
     public TraversalVertexProgramStep(final Traversal.Admin traversal, final Traversal.Admin<?, ?> computerTraversal) {
         super(traversal);
-        this.pureComputerTraversal = computerTraversal.clone();
-        this.computerTraversal = this.integrateChild(computerTraversal);
+        this.computerTraversal = new PureTraversal<>(computerTraversal);
+        this.integrateChild(this.computerTraversal.get());
     }
 
     public List<Traversal.Admin<?, ?>> getGlobalChildren() {
-        return Collections.singletonList(this.computerTraversal);
-    }
-
-    @Override
-    protected Traverser<ComputerResult> processNextStart() {
-        try {
-            if (this.first && this.getPreviousStep() instanceof EmptyStep) {
-                this.first = false;
-                final Graph graph = this.getTraversal().getGraph().get();
-                final GraphComputer graphComputer = this.getComputer(graph);
-                final ComputerResult result = graphComputer.program(TraversalVertexProgram.build().traversal(this.compileTraversal(graph)).create(graph)).submit().get();
-                return this.getTraversal().getTraverserGenerator().generate(result, (Step) this, 1l);
-            } else {
-                final Traverser.Admin<ComputerResult> traverser = this.starts.next();
-                final Graph graph = traverser.get().graph();
-                final GraphComputer graphComputer = this.getComputer(graph);
-                final ComputerResult result = graphComputer.program(TraversalVertexProgram.build().traversal(this.compileTraversal(graph)).create(graph)).submit().get();
-                return traverser.split(result, this);
-            }
-        } catch (final InterruptedException | ExecutionException e) {
-            throw new IllegalStateException(e.getMessage(), e);
-        }
+        return Collections.singletonList(this.computerTraversal.get());
     }
 
     @Override
     public String toString() {
-        return StringFactory.stepString(this, this.computerTraversal);
+        return StringFactory.stepString(this, this.computerTraversal.get());
     }
 
     @Override
     public TraversalVertexProgramStep clone() {
         final TraversalVertexProgramStep clone = (TraversalVertexProgramStep) super.clone();
-        clone.computerTraversal = this.integrateChild(this.computerTraversal.clone());
-        clone.pureComputerTraversal = this.pureComputerTraversal.clone();
+        clone.computerTraversal = this.computerTraversal.clone();
+        clone.integrateChild(this.computerTraversal.get());
         return clone;
     }
 
@@ -100,25 +70,30 @@ public final class TraversalVertexProgramStep extends AbstractStep<ComputerResul
         return TraversalParent.super.getSelfAndChildRequirements(TraverserRequirement.BULK);
     }
 
-    private final GraphComputer getComputer(final Graph graph) {
-        final GraphComputer graphComputer = this.graphComputerFunction.apply(graph);
-        if (!(this.getNextStep() instanceof ComputerResultStep))
-            graphComputer.persist(GraphComputer.Persist.EDGES).result(GraphComputer.ResultGraph.NEW);
-        return graphComputer;
+    @Override
+    public void setGraphComputerFunction(final Function<Graph, GraphComputer> graphComputerFunction) {
+        this.graphComputerFunction = graphComputerFunction;
     }
 
-    private final Traversal.Admin<?, ?> compileTraversal(final Graph graph) {
-        final Traversal.Admin<?, ?> compiledComputerTraversal = this.pureComputerTraversal.clone();
+    @Override
+    public TraversalVertexProgram generateProgram(final Graph graph) {
+        this.computerTraversal.reset();
+        final Traversal.Admin<?, ?> compiledComputerTraversal = this.computerTraversal.get();
         compiledComputerTraversal.setStrategies(TraversalStrategies.GlobalCache.getStrategies(graph.getClass()).clone());
         this.getTraversal().getStrategies().toList().forEach(compiledComputerTraversal.getStrategies()::addStrategies);
+        compiledComputerTraversal.setSideEffects(this.getTraversal().getSideEffects());
         compiledComputerTraversal.setParent(this);
-        compiledComputerTraversal.setSideEffects(this.computerTraversal.getSideEffects());
         compiledComputerTraversal.applyStrategies();
-        return compiledComputerTraversal;
+        return TraversalVertexProgram.build()
+                .traversal(compiledComputerTraversal)
+                .create(graph);
     }
 
     @Override
-    public void setGraphComputerFunction(final Function<Graph, GraphComputer> graphComputerFunction) {
-        this.graphComputerFunction = graphComputerFunction;
+    public GraphComputer generateComputer(final Graph graph) {
+        final GraphComputer graphComputer = this.graphComputerFunction.apply(graph);
+        if (!(this.getNextStep() instanceof ComputerResultStep))
+            graphComputer.persist(GraphComputer.Persist.EDGES).result(GraphComputer.ResultGraph.NEW);
+        return graphComputer;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/VertexProgramStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/VertexProgramStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/VertexProgramStep.java
new file mode 100644
index 0000000..a85f5b1
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/step/map/VertexProgramStep.java
@@ -0,0 +1,60 @@
+/*
+ * 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.computer.traversal.step.map;
+
+import org.apache.tinkerpop.gremlin.process.computer.ComputerResult;
+import org.apache.tinkerpop.gremlin.process.computer.traversal.step.VertexComputing;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+
+import java.util.NoSuchElementException;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public abstract class VertexProgramStep extends AbstractStep<ComputerResult, ComputerResult> implements VertexComputing {
+
+    protected boolean first = true;
+
+    public VertexProgramStep(final Traversal.Admin traversal) {
+        super(traversal);
+    }
+
+    @Override
+    protected Traverser<ComputerResult> processNextStart() throws NoSuchElementException {
+        try {
+            if (this.first && this.getPreviousStep() instanceof EmptyStep) {
+                this.first = false;
+                final Graph graph = this.getTraversal().getGraph().get();
+                return this.getTraversal().getTraverserGenerator().generate(this.generateComputer(graph).program(this.generateProgram(graph)).submit().get(), this, 1l);
+            } else {
+                final Traverser.Admin<ComputerResult> traverser = this.starts.next();
+                final Graph graph = traverser.get().graph();
+                return traverser.split(this.generateComputer(graph).program(this.generateProgram(graph)).submit().get(), this);
+            }
+        } catch (final InterruptedException | ExecutionException e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index ca903e6..62d6c4a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -33,6 +33,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.lambda.PredicateTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.TrueTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TimesModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.branch.BranchStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.branch.ChooseStep;
@@ -1135,7 +1136,11 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     public default GraphTraversal<S, E> times(final int maxLoops) {
-        return this.until(new LoopTraversal<>(maxLoops));
+        if (this.asAdmin().getEndStep() instanceof TimesModulating) {
+            ((TimesModulating) this.asAdmin().getEndStep()).modulateTimes(maxLoops);
+            return this;
+        } else
+            return this.until(new LoopTraversal<>(maxLoops));
     }
 
     public default <E2> GraphTraversal<S, E2> local(final Traversal<?, E2> localTraversal) {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TimesModulating.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TimesModulating.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TimesModulating.java
new file mode 100644
index 0000000..9bf71a0
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TimesModulating.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public interface TimesModulating {
+
+    public void modulateTimes(final int times);
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/11238b63/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PureTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PureTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PureTraversal.java
index 8d0c267..ce9b030 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PureTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/PureTraversal.java
@@ -29,27 +29,25 @@ import java.io.Serializable;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class PureTraversal<S, E> implements Serializable {
+public final class PureTraversal<S, E> implements Serializable, Cloneable {
 
-    private final Traversal.Admin<S, E> pureTraversal;
-    private transient Traversal.Admin<S, E> compiledTraversal;
+    private Traversal.Admin<S, E> pureTraversal;
+    private transient Traversal.Admin<S, E> cachedTraversal;
 
     public PureTraversal(final Traversal.Admin<S, E> pureTraversal) {
         this.pureTraversal = pureTraversal;
     }
 
-    public Traversal.Admin<S, E> getPure() {
-        return this.pureTraversal;
+    public void reset() {
+        this.cachedTraversal = null;
     }
 
-    public Traversal.Admin<S, E> getCompiled() {
-        if (null == this.compiledTraversal) {
-            this.compiledTraversal = this.pureTraversal.clone();
-            this.pureTraversal.getGraph().ifPresent(this.compiledTraversal::setGraph);
-            if (!this.compiledTraversal.isLocked())
-                this.compiledTraversal.applyStrategies();
+    public Traversal.Admin<S, E> get() {
+        if (null == this.cachedTraversal) {
+            this.cachedTraversal = this.pureTraversal.clone();
+            this.pureTraversal.getGraph().ifPresent(this.cachedTraversal::setGraph);
         }
-        return this.compiledTraversal;
+        return this.cachedTraversal;
     }
 
     public void storeState(final Configuration configuration, final String configurationKey) {
@@ -72,4 +70,23 @@ public final class PureTraversal<S, E> implements Serializable {
         pureTraversal.pureTraversal.setGraph(graph);
         return pureTraversal;
     }
+
+    ///////////
+
+    @Override
+    public String toString() {
+        return this.get().toString();
+    }
+
+    @Override
+    public PureTraversal<S, E> clone() {
+        try {
+            final PureTraversal<S, E> clone = (PureTraversal<S, E>) super.clone();
+            clone.pureTraversal = this.pureTraversal.clone();
+            clone.cachedTraversal = null;
+            return clone;
+        } catch (final CloneNotSupportedException e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
 }