@Test public void shouldCalculateStartLabelCorrectly() { Traversal.Admin<?, ?> traversal = match( where(and(as("a").out("created").as("b"), as("b").in("created").count().is(eq(3)))), as("a").both().as("b"), where(as("b").in())) .asAdmin(); assertEquals( "a", MatchStep.Helper.computeStartLabel( ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren())); ///// traversal = match( where("a", P.neq("c")), as("a").out("created").as("b"), or( as("a").out("knows").has("name", "vadas"), as("a").in("knows").and().as("a").has(T.label, "person")), as("b").in("created").as("c"), as("b").in("created").count().is(P.gt(1))) .asAdmin(); assertEquals( "a", MatchStep.Helper.computeStartLabel( ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren())); }
@Test public void testPreCompilationOfWherePredicate() { final List<Traversal.Admin<?, ?>> traversals = Arrays.asList( __.match(as("a").out().as("b"), as("c").where(P.neq("d"))).asAdmin(), __.match(as("a").out().as("b"), where("c", P.neq("d"))).asAdmin()); assertEquals( 1, new HashSet<>(traversals) .size()); // the two patterns should pre-compile to the same traversal traversals.forEach( traversal -> { MatchStep<?, ?> matchStep = (MatchStep<?, ?>) traversal.getStartStep(); // assertFalse(matchStep.getStartLabel().isPresent()); assertEquals(2, matchStep.getGlobalChildren().size()); Traversal.Admin<Object, Object> pattern = matchStep.getGlobalChildren().get(0); assertEquals( "a", ((MatchStep.MatchStartStep) pattern.getStartStep()).getSelectKey().get()); assertEquals(VertexStep.class, pattern.getStartStep().getNextStep().getClass()); assertEquals("b", ((MatchStep.MatchEndStep) pattern.getEndStep()).getMatchKey().get()); // pattern = matchStep.getGlobalChildren().get(1); assertEquals(MatchStep.MatchStartStep.class, pattern.getStartStep().getClass()); assertEquals( "c", ((MatchStep.MatchStartStep) pattern.getStartStep()).getSelectKey().get()); assertEquals(WherePredicateStep.class, pattern.getStartStep().getNextStep().getClass()); assertEquals( MatchStep.MatchEndStep.class, pattern.getStartStep().getNextStep().getNextStep().getClass()); assertFalse( ((WherePredicateStep<?>) pattern.getStartStep().getNextStep()) .getStartKey() .isPresent()); assertEquals( "d", ((WherePredicateStep<?>) pattern.getStartStep().getNextStep()) .getPredicate() .get() .getOriginalValue()); }); }
private static Set<Scoping.Variable> getVariableLocations( final Set<Scoping.Variable> variables, final Traversal.Admin<?, ?> traversal) { if (variables.size() == 2) return variables; // has both START and END so no need to compute further final Step<?, ?> startStep = traversal.getStartStep(); if (StartStep.isVariableStartStep(startStep)) variables.add(Scoping.Variable.START); else if (startStep instanceof WherePredicateStep) { if (((WherePredicateStep) startStep).getStartKey().isPresent()) variables.add(Scoping.Variable.START); } else if (startStep instanceof WhereTraversalStep.WhereStartStep) { if (!((WhereTraversalStep.WhereStartStep) startStep).getScopeKeys().isEmpty()) variables.add(Scoping.Variable.START); } else if (startStep instanceof MatchStep.MatchStartStep) { if (((MatchStep.MatchStartStep) startStep).getSelectKey().isPresent()) variables.add(Scoping.Variable.START); } else if (startStep instanceof MatchStep) { ((MatchStep<?, ?>) startStep) .getGlobalChildren() .forEach(child -> TraversalHelper.getVariableLocations(variables, child)); } else if (startStep instanceof ConnectiveStep || startStep instanceof NotStep || startStep instanceof WhereTraversalStep) ((TraversalParent) startStep) .getLocalChildren() .forEach(child -> TraversalHelper.getVariableLocations(variables, child)); /// final Step<?, ?> endStep = traversal.getEndStep(); if (endStep instanceof WherePredicateStep) { if (((WherePredicateStep) endStep).getStartKey().isPresent()) variables.add(Scoping.Variable.END); } else if (endStep instanceof WhereTraversalStep.WhereEndStep) { if (!((WhereTraversalStep.WhereEndStep) endStep).getScopeKeys().isEmpty()) variables.add(Scoping.Variable.END); } else if (endStep instanceof MatchStep.MatchEndStep) { if (((MatchStep.MatchEndStep) endStep).getMatchKey().isPresent()) variables.add(Scoping.Variable.END); } else if (!endStep.getLabels().isEmpty()) variables.add(Scoping.Variable.END); /// return variables; }
@Test public void testPreCompilationOfStartAndEnds() { final Traversal.Admin<?, ?> traversal = __.match(as("a").out().as("b"), as("c").path().as("d")).asAdmin(); final MatchStep<?, ?> matchStep = (MatchStep<?, ?>) traversal.getStartStep(); assertEquals(MatchStep.class, traversal.getStartStep().getClass()); assertEquals(2, matchStep.getGlobalChildren().size()); Traversal.Admin<Object, Object> pattern = matchStep.getGlobalChildren().get(0); assertEquals("a", ((MatchStep.MatchStartStep) pattern.getStartStep()).getSelectKey().get()); assertEquals(VertexStep.class, pattern.getStartStep().getNextStep().getClass()); assertEquals("b", ((MatchStep.MatchEndStep) pattern.getEndStep()).getMatchKey().get()); // pattern = matchStep.getGlobalChildren().get(1); assertEquals("c", ((MatchStep.MatchStartStep) pattern.getStartStep()).getSelectKey().get()); assertEquals(PathStep.class, pattern.getStartStep().getNextStep().getClass()); assertEquals("d", ((MatchStep.MatchEndStep) pattern.getEndStep()).getMatchKey().get()); }
@Override public void apply(final Traversal.Admin<?, ?> traversal) { final TraversalParent parent = traversal.getParent(); int size = traversal.getSteps().size(); Step prev = null; for (int i = 0; i < size; i++) { final Step curr = traversal.getSteps().get(i); if (curr instanceof CountGlobalStep && i < size - 1) { final Step next = traversal.getSteps().get(i + 1); if (next instanceof IsStep && !(prev instanceof RangeGlobalStep)) { // if a RangeStep was provided, assume that the user knows what // he's doing final IsStep isStep = (IsStep) next; final P isStepPredicate = isStep.getPredicate(); Long highRange = null; boolean useNotStep = false; for (P p : isStepPredicate instanceof ConnectiveP ? ((ConnectiveP<?>) isStepPredicate).getPredicates() : Collections.singletonList(isStepPredicate)) { final Object value = p.getValue(); final BiPredicate predicate = p.getBiPredicate(); if (value instanceof Number) { final long highRangeOffset = INCREASED_OFFSET_SCALAR_PREDICATES.contains(predicate) ? 1L : 0L; final Long highRangeCandidate = ((Number) value).longValue() + highRangeOffset; final boolean update = highRange == null || highRangeCandidate > highRange; if (update) { if (parent instanceof EmptyStep) { useNotStep = true; } else { if (parent instanceof RepeatStep) { final RepeatStep repeatStep = (RepeatStep) parent; useNotStep = Objects.equals(traversal, repeatStep.getUntilTraversal()) || Objects.equals(traversal, repeatStep.getEmitTraversal()); } else { useNotStep = parent instanceof FilterStep || parent instanceof SideEffectStep; } } highRange = highRangeCandidate; useNotStep &= curr.getLabels().isEmpty() && next.getLabels().isEmpty() && next.getNextStep() instanceof EmptyStep && ((highRange <= 1L && predicate.equals(Compare.lt)) || (highRange == 1L && (predicate.equals(Compare.eq) || predicate.equals(Compare.lte)))); } } else { final Long highRangeOffset = RANGE_PREDICATES.get(predicate); if (value instanceof Collection && highRangeOffset != null) { final Object high = Collections.max((Collection) value); if (high instanceof Number) { final Long highRangeCandidate = ((Number) high).longValue() + highRangeOffset; final boolean update = highRange == null || highRangeCandidate > highRange; if (update) highRange = highRangeCandidate; } } } } if (highRange != null) { if (useNotStep) { traversal.asAdmin().removeStep(next); // IsStep traversal.asAdmin().removeStep(curr); // CountStep size -= 2; if (prev != null) { final Traversal.Admin inner = __.start().asAdmin(); TraversalHelper.insertAfterStep(prev, inner.getStartStep(), inner); TraversalHelper.replaceStep(prev, new NotStep<>(traversal, inner), traversal); } else { traversal.asAdmin().addStep(new NotStep<>(traversal, __.identity())); } } else { TraversalHelper.insertBeforeStep( new RangeGlobalStep<>(traversal, 0L, highRange), curr, traversal); } i++; } } } prev = curr; } }
@Test public void testPreCompilationOfOr() { final List<Traversal.Admin<?, ?>> traversals = Arrays.asList( __.match(as("a").out().as("b"), or(as("c").path().as("d"), as("e").coin(0.5).as("f"))) .asAdmin(), __.match(as("a").out().as("b"), as("c").path().as("d").or().as("e").coin(0.5).as("f")) .asAdmin()); assertEquals( 1, new HashSet<>(traversals) .size()); // the two patterns should pre-compile to the same traversal traversals.forEach( traversal -> { final MatchStep<?, ?> matchStep = (MatchStep<?, ?>) traversal.getStartStep(); assertEquals(2, matchStep.getGlobalChildren().size()); Traversal.Admin<Object, Object> pattern = matchStep.getGlobalChildren().get(0); assertEquals( "a", ((MatchStep.MatchStartStep) pattern.getStartStep()).getSelectKey().get()); assertEquals(VertexStep.class, pattern.getStartStep().getNextStep().getClass()); assertEquals("b", ((MatchStep.MatchEndStep) pattern.getEndStep()).getMatchKey().get()); // pattern = matchStep.getGlobalChildren().get(1); assertEquals(MatchStep.class, pattern.getStartStep().getClass()); assertEquals( ConnectiveStep.Connective.OR, ((MatchStep<?, ?>) pattern.getStartStep()).getConnective()); assertEquals( "c", ((MatchStep.MatchStartStep) ((MatchStep<?, ?>) pattern.getStartStep()) .getGlobalChildren() .get(0) .getStartStep()) .getSelectKey() .get()); assertEquals( PathStep.class, ((MatchStep<?, ?>) pattern.getStartStep()) .getGlobalChildren() .get(0) .getStartStep() .getNextStep() .getClass()); assertEquals( "d", ((MatchStep.MatchEndStep) ((MatchStep<?, ?>) pattern.getStartStep()) .getGlobalChildren() .get(0) .getEndStep()) .getMatchKey() .get()); assertEquals( "e", ((MatchStep.MatchStartStep) ((MatchStep<?, ?>) pattern.getStartStep()) .getGlobalChildren() .get(1) .getStartStep()) .getSelectKey() .get()); assertEquals( CoinStep.class, ((MatchStep<?, ?>) pattern.getStartStep()) .getGlobalChildren() .get(1) .getStartStep() .getNextStep() .getClass()); assertEquals( "f", ((MatchStep.MatchEndStep) ((MatchStep<?, ?>) pattern.getStartStep()) .getGlobalChildren() .get(1) .getEndStep()) .getMatchKey() .get()); }); }
@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); }