@Test
 public void testComputerAwareCountMatchAlgorithm() {
   // MAKE SURE OLAP JOBS ARE BIASED TOWARDS STAR GRAPH DATA
   final Consumer doNothing = s -> {};
   Traversal.Admin<?, ?> traversal =
       __.match(
               as("a").sideEffect(doNothing).as("b"), // 1
               as("b").sideEffect(doNothing).as("c"), // 2
               as("a").sideEffect(doNothing).as("d"), // 5
               as("c").sideEffect(doNothing).as("e"), // 4
               as("c").sideEffect(doNothing).as("f")) // 3
           .asAdmin();
   traversal.applyStrategies(); // necessary to enure step ids are unique
   MatchStep.CountMatchAlgorithm countMatchAlgorithm = new MatchStep.CountMatchAlgorithm();
   countMatchAlgorithm.initialize(
       TraversalEngine.Type.COMPUTER,
       ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren());
   Traversal.Admin<Object, Object> firstPattern =
       ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(0);
   Traversal.Admin<Object, Object> secondPattern =
       ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(1);
   Traversal.Admin<Object, Object> thirdPattern =
       ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(2);
   Traversal.Admin<Object, Object> forthPattern =
       ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(3);
   Traversal.Admin<Object, Object> fifthPattern =
       ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(4);
   countMatchAlgorithm
       .bundles
       .stream()
       .forEach(bundle -> assertEquals(0.0d, bundle.multiplicity, 0.0d));
   assertEquals(
       MatchStep.TraversalType.MATCH_TRAVERSAL,
       countMatchAlgorithm.getBundle(firstPattern).traversalType);
   assertEquals(
       MatchStep.TraversalType.MATCH_TRAVERSAL,
       countMatchAlgorithm.getBundle(secondPattern).traversalType);
   assertEquals(
       MatchStep.TraversalType.MATCH_TRAVERSAL,
       countMatchAlgorithm.getBundle(thirdPattern).traversalType);
   assertEquals(
       MatchStep.TraversalType.MATCH_TRAVERSAL,
       countMatchAlgorithm.getBundle(forthPattern).traversalType);
   assertEquals(
       MatchStep.TraversalType.MATCH_TRAVERSAL,
       countMatchAlgorithm.getBundle(fifthPattern).traversalType);
   assertEquals(firstPattern, countMatchAlgorithm.bundles.get(0).traversal);
   assertEquals(secondPattern, countMatchAlgorithm.bundles.get(1).traversal);
   assertEquals(thirdPattern, countMatchAlgorithm.bundles.get(2).traversal);
   assertEquals(forthPattern, countMatchAlgorithm.bundles.get(3).traversal);
   assertEquals(fifthPattern, countMatchAlgorithm.bundles.get(4).traversal);
   // MAKE THE SECOND PATTERN EXPENSIVE
   countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
   // MAKE THE THIRD PATTERN MORE EXPENSIVE THAN FORTH
   countMatchAlgorithm.recordStart(EmptyTraverser.instance(), thirdPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
   // MAKE THE FORTH PATTERN EXPENSIVE
   countMatchAlgorithm.recordStart(EmptyTraverser.instance(), forthPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), forthPattern);
   countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), forthPattern);
   //
   Traverser.Admin traverser =
       B_LP_O_P_S_SE_SL_TraverserGenerator.instance().generate(1, EmptyStep.instance(), 1l);
   traverser.addLabels(Collections.singleton("a"));
   assertEquals(firstPattern, countMatchAlgorithm.apply(traverser));
   traverser = traverser.split(1, EmptyStep.instance());
   traverser.getTags().add(firstPattern.getStartStep().getId());
   traverser.addLabels(Collections.singleton("b"));
   //
   assertEquals(secondPattern, countMatchAlgorithm.apply(traverser));
   traverser = traverser.split(1, EmptyStep.instance());
   traverser.getTags().add(secondPattern.getStartStep().getId());
   traverser.addLabels(Collections.singleton("c"));
   //
   assertEquals(fifthPattern, countMatchAlgorithm.apply(traverser));
   traverser = traverser.split(1, EmptyStep.instance());
   traverser.getTags().add(fifthPattern.getStartStep().getId());
   traverser.addLabels(Collections.singleton("f"));
   //
   assertEquals(forthPattern, countMatchAlgorithm.apply(traverser));
   traverser = traverser.split(1, EmptyStep.instance());
   traverser.getTags().add(forthPattern.getStartStep().getId());
   traverser.addLabels(Collections.singleton("e"));
   //
   assertEquals(thirdPattern, countMatchAlgorithm.apply(traverser));
   traverser = traverser.split(1, EmptyStep.instance());
   traverser.getTags().add(thirdPattern.getStartStep().getId());
   traverser.addLabels(Collections.singleton("d"));
 }
  @Test
  public void testCountMatchAlgorithm() {
    // MAKE SURE THE SORT ORDER CHANGES AS MORE RESULTS ARE RETURNED BY ONE OR THE OTHER TRAVERSAL
    Traversal.Admin<?, ?> traversal =
        __.match(as("a").out().as("b"), as("c").in().as("d")).asAdmin();
    MatchStep.CountMatchAlgorithm countMatchAlgorithm = new MatchStep.CountMatchAlgorithm();
    countMatchAlgorithm.initialize(
        TraversalEngine.Type.STANDARD,
        ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren());
    Traversal.Admin<Object, Object> firstPattern =
        ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(0);
    Traversal.Admin<Object, Object> secondPattern =
        ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(1);
    //
    assertEquals(2, countMatchAlgorithm.bundles.size());
    countMatchAlgorithm
        .bundles
        .stream()
        .forEach(bundle -> assertEquals(0.0d, bundle.multiplicity, 0.0d));
    assertEquals(firstPattern, countMatchAlgorithm.bundles.get(0).traversal);
    assertEquals(secondPattern, countMatchAlgorithm.bundles.get(1).traversal);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), firstPattern);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), firstPattern);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
    assertEquals(firstPattern, countMatchAlgorithm.bundles.get(0).traversal);
    assertEquals(secondPattern, countMatchAlgorithm.bundles.get(1).traversal);
    assertEquals(
        MatchStep.TraversalType.MATCH_TRAVERSAL,
        countMatchAlgorithm.getBundle(firstPattern).traversalType);
    assertEquals(
        MatchStep.TraversalType.MATCH_TRAVERSAL,
        countMatchAlgorithm.getBundle(secondPattern).traversalType);
    assertEquals(2l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
    assertEquals(3l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
    assertEquals(0l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
    assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
    ////
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), firstPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
    assertEquals(2l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
    assertEquals(3l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
    assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
    assertEquals(3l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
    assertEquals(0.5d, countMatchAlgorithm.getBundle(firstPattern).multiplicity, 0.01d);
    assertEquals(1.0d, countMatchAlgorithm.getBundle(secondPattern).multiplicity, 0.01d);
    assertEquals(firstPattern, countMatchAlgorithm.bundles.get(0).traversal);
    assertEquals(secondPattern, countMatchAlgorithm.bundles.get(1).traversal);
    // CHECK RE-SORTING AS MORE DATA COMES IN
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), firstPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), firstPattern);
    assertEquals(1.5d, countMatchAlgorithm.getBundle(firstPattern).multiplicity, 0.01d);
    assertEquals(1.0d, countMatchAlgorithm.getBundle(secondPattern).multiplicity, 0.01d);
    assertEquals(secondPattern, countMatchAlgorithm.bundles.get(0).traversal);
    assertEquals(firstPattern, countMatchAlgorithm.bundles.get(1).traversal);

    ///////  MAKE SURE WHERE PREDICATE TRAVERSALS ARE ALWAYS FIRST AS THEY ARE SIMPLY .hasNext()
    // CHECKS
    traversal =
        __.match(as("a").out().as("b"), as("c").in().as("d"), where("a", P.eq("b"))).asAdmin();
    countMatchAlgorithm = new MatchStep.CountMatchAlgorithm();
    countMatchAlgorithm.initialize(
        TraversalEngine.Type.STANDARD,
        ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren());
    assertEquals(3, countMatchAlgorithm.bundles.size());
    firstPattern = ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(0);
    secondPattern = ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(1);
    Traversal.Admin<Object, Object> thirdPattern =
        ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(2);
    ///
    countMatchAlgorithm
        .bundles
        .stream()
        .forEach(bundle -> assertEquals(0.0d, bundle.multiplicity, 0.0d));
    assertEquals(
        MatchStep.TraversalType.MATCH_TRAVERSAL,
        countMatchAlgorithm.getBundle(firstPattern).traversalType);
    assertEquals(
        MatchStep.TraversalType.MATCH_TRAVERSAL,
        countMatchAlgorithm.getBundle(secondPattern).traversalType);
    assertEquals(
        MatchStep.TraversalType.WHERE_PREDICATE,
        countMatchAlgorithm.getBundle(thirdPattern).traversalType);
    assertEquals(firstPattern, countMatchAlgorithm.bundles.get(0).traversal);
    assertEquals(secondPattern, countMatchAlgorithm.bundles.get(1).traversal);
    assertEquals(thirdPattern, countMatchAlgorithm.bundles.get(2).traversal);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), firstPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), firstPattern);
    assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
    assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
    assertEquals(0l, countMatchAlgorithm.getBundle(thirdPattern).startsCount);
    assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
    assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
    assertEquals(0l, countMatchAlgorithm.getBundle(thirdPattern).endsCount);
    assertEquals(1.0d, countMatchAlgorithm.getBundle(firstPattern).multiplicity, 0.01d);
    assertEquals(0.0d, countMatchAlgorithm.getBundle(secondPattern).multiplicity, 0.01d);
    assertEquals(0.0d, countMatchAlgorithm.getBundle(thirdPattern).multiplicity, 0.01d);
    assertEquals(thirdPattern, countMatchAlgorithm.bundles.get(0).traversal);
    assertEquals(secondPattern, countMatchAlgorithm.bundles.get(1).traversal);
    assertEquals(firstPattern, countMatchAlgorithm.bundles.get(2).traversal);
    //
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), thirdPattern);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), thirdPattern);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), thirdPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
    assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
    assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
    assertEquals(3l, countMatchAlgorithm.getBundle(thirdPattern).startsCount);
    assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
    assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
    assertEquals(6l, countMatchAlgorithm.getBundle(thirdPattern).endsCount);
    assertEquals(1.0d, countMatchAlgorithm.getBundle(firstPattern).multiplicity, 0.01d);
    assertEquals(0.0d, countMatchAlgorithm.getBundle(secondPattern).multiplicity, 0.01d);
    assertEquals(2.0d, countMatchAlgorithm.getBundle(thirdPattern).multiplicity, 0.01d);
    assertEquals(thirdPattern, countMatchAlgorithm.bundles.get(0).traversal);
    assertEquals(secondPattern, countMatchAlgorithm.bundles.get(1).traversal);
    assertEquals(firstPattern, countMatchAlgorithm.bundles.get(2).traversal);
    //
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
    countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
    assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
    assertEquals(4l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
    assertEquals(3l, countMatchAlgorithm.getBundle(thirdPattern).startsCount);
    assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
    assertEquals(6l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
    assertEquals(6l, countMatchAlgorithm.getBundle(thirdPattern).endsCount);
    assertEquals(1.0d, countMatchAlgorithm.getBundle(firstPattern).multiplicity, 0.01d);
    assertEquals(1.5d, countMatchAlgorithm.getBundle(secondPattern).multiplicity, 0.01d);
    assertEquals(2.0d, countMatchAlgorithm.getBundle(thirdPattern).multiplicity, 0.01d);
    assertEquals(thirdPattern, countMatchAlgorithm.bundles.get(0).traversal);
    assertEquals(firstPattern, countMatchAlgorithm.bundles.get(1).traversal);
    assertEquals(secondPattern, countMatchAlgorithm.bundles.get(2).traversal);
  }