private void expandPathPattern()

in asterix-graphix/src/main/java/org/apache/asterix/graphix/lang/rewrite/resolve/ExhaustiveSearchResolver.java [156:243]


    private void expandPathPattern(EdgePatternExpr unexpandedPathPattern, Deque<PatternGroup> inputPatternGroups,
            Deque<PatternGroup> outputPatternGroups) throws CompilationException {
        EdgeDescriptor unexpandedEdgeDescriptor = unexpandedPathPattern.getEdgeDescriptor();
        VariableExpr edgeVariable = unexpandedEdgeDescriptor.getVariableExpr();
        Set<ElementLabel> edgeLabelSet = unexpandedEdgeDescriptor.getEdgeLabels();
        Set<ElementLabel> expandedEdgeLabelSet =
                expandElementLabels(unexpandedPathPattern, edgeLabelSet, schemaKnowledgeTable);

        // Determine our candidates for internal vertex labels.
        Set<ElementLabel> vertexLabelSet = schemaKnowledgeTable.getVertexLabels();

        // Determine the direction of our edges.
        Set<EdgeDirection> edgeDirectionSet = new HashSet<>();
        if (unexpandedEdgeDescriptor.getEdgeDirection() != EdgeDirection.RIGHT_TO_LEFT) {
            edgeDirectionSet.add(EdgeDirection.LEFT_TO_RIGHT);
        }
        if (unexpandedEdgeDescriptor.getEdgeDirection() != EdgeDirection.LEFT_TO_RIGHT) {
            edgeDirectionSet.add(EdgeDirection.RIGHT_TO_LEFT);
        }

        // Determine the length of **expanded** path. For {N,M} w/ E labels... MIN(M, (1 + 2(E-1))).
        int minimumExpansionLength, expansionLength;
        Integer minimumHops = unexpandedEdgeDescriptor.getMinimumHops();
        Integer maximumHops = unexpandedEdgeDescriptor.getMaximumHops();
        if (Objects.equals(minimumHops, maximumHops) && minimumHops != null && minimumHops == 1) {
            // Special case: we have a path disguised as an edge.
            minimumExpansionLength = 1;
            expansionLength = 1;

        } else {
            int maximumExpansionLength = 1 + 2 * (expandedEdgeLabelSet.size() - 1);
            minimumExpansionLength = Objects.requireNonNullElse(minimumHops, 1);
            expansionLength = Objects.requireNonNullElse(maximumHops, maximumExpansionLength);
            if (minimumExpansionLength > expansionLength) {
                minimumExpansionLength = expansionLength;
            }
        }

        // Generate all possible paths, from minimumExpansionLength to expansionLength.
        List<List<EdgePatternExpr>> candidatePaths = new ArrayList<>();
        for (int pathLength = minimumExpansionLength; pathLength <= expansionLength; pathLength++) {
            List<List<EdgePatternExpr>> expandedPathPattern = expandFixedPathPattern(pathLength, unexpandedPathPattern,
                    expandedEdgeLabelSet, vertexLabelSet, edgeDirectionSet, deepCopyVisitor,
                    () -> deepCopyVisitor.visit(unexpandedPathPattern.getInternalVertex(), null));
            candidatePaths.addAll(expandedPathPattern);
        }

        // Push the labels of our pattern group to our edge.
        final BiConsumer<PatternGroup, EdgePatternExpr> vertexLabelUpdater = (p, e) -> {
            VariableExpr leftVariable = e.getLeftVertex().getVariableExpr();
            VariableExpr rightVariable = e.getRightVertex().getVariableExpr();
            p.getVertexPatternSet().forEach(v -> {
                VariableExpr vertexVariable = v.getVariableExpr();
                if (leftVariable.equals(vertexVariable)) {
                    e.getLeftVertex().getLabels().clear();
                    e.getLeftVertex().getLabels().addAll(v.getLabels());
                }
                if (rightVariable.equals(vertexVariable)) {
                    e.getRightVertex().getLabels().clear();
                    e.getRightVertex().getLabels().addAll(v.getLabels());
                }
            });
        };

        // Push our expansion to our pattern groups.
        while (!inputPatternGroups.isEmpty()) {
            PatternGroup unexpandedPatternGroup = inputPatternGroups.pop();
            for (List<EdgePatternExpr> candidatePath : candidatePaths) {
                PatternGroup expandedPatternGroup = new PatternGroup();
                expandedPatternGroup.getVertexPatternSet().addAll(unexpandedPatternGroup.getVertexPatternSet());
                for (EdgePatternExpr edgePatternExpr : unexpandedPatternGroup.getEdgePatternSet()) {
                    if (edgePatternExpr.getEdgeDescriptor().getVariableExpr().equals(edgeVariable)) {
                        for (EdgePatternExpr candidateEdge : candidatePath) {
                            EdgePatternExpr copyEdgePattern = deepCopyVisitor.visit(candidateEdge, null);
                            vertexLabelUpdater.accept(expandedPatternGroup, copyEdgePattern);
                            expandedPatternGroup.getEdgePatternSet().add(copyEdgePattern);
                        }

                    } else {
                        EdgePatternExpr copyEdgePattern = deepCopyVisitor.visit(edgePatternExpr, null);
                        vertexLabelUpdater.accept(expandedPatternGroup, copyEdgePattern);
                        expandedPatternGroup.getEdgePatternSet().add(copyEdgePattern);
                    }
                }
                outputPatternGroups.push(expandedPatternGroup);
            }
        }
    }