in asterix-graphix/src/main/java/org/apache/asterix/graphix/lang/rewrite/canonical/CanonicalElementGeneratorFactory.java [111:188]
public List<PathPatternExpr> generateCanonicalPaths(EdgePatternExpr edgePatternExpr,
boolean minimizeExpansionLength) throws CompilationException {
EdgeDescriptor edgeDescriptor = edgePatternExpr.getEdgeDescriptor();
VertexPatternExpr leftVertex = edgePatternExpr.getLeftVertex();
VertexPatternExpr rightVertex = edgePatternExpr.getRightVertex();
VertexPatternExpr internalVertex = edgePatternExpr.getInternalVertex();
// Each variable below represents a loop nesting.
Set<ElementLabel> edgeLabelList = edgeDescriptor.getEdgeLabels();
Set<ElementLabel> leftLabelList = leftVertex.getLabels();
Set<ElementLabel> rightLabelList = rightVertex.getLabels();
Set<EdgeDirection> directionList = expandEdgeDirection(edgeDescriptor);
Set<ElementLabel> internalLabelList = internalVertex.getLabels();
// Determine the length of **expanded** path. For {N,M} w/ E labels... MIN(M, (1 + 2(E-1))).
int minimumExpansionLength, expansionLength;
if (minimizeExpansionLength) {
int maximumExpansionLength = 1 + 2 * (edgeLabelList.size() - 1);
minimumExpansionLength = Objects.requireNonNullElse(edgeDescriptor.getMinimumHops(), 1);
expansionLength = Objects.requireNonNullElse(edgeDescriptor.getMaximumHops(), maximumExpansionLength);
if (minimumExpansionLength > expansionLength) {
minimumExpansionLength = expansionLength;
}
} else {
minimumExpansionLength = Objects.requireNonNullElse(edgeDescriptor.getMinimumHops(), 1);
expansionLength = edgeDescriptor.getMaximumHops();
}
// Generate all valid paths, from minimumExpansionLength to maximumExpansionLength.
List<List<EdgePatternExpr>> canonicalPathList = new ArrayList<>();
IInternalVertexSupplier internalVertexSupplier = () -> {
VertexPatternExpr internalVertexCopy = deepCopyVisitor.visit(internalVertex, null);
VariableExpr internalVariable = internalVertex.getVariableExpr();
VariableExpr internalVariableCopy = graphixRewritingContext.getGraphixVariableCopy(internalVariable);
internalVertexCopy.setVariableExpr(internalVariableCopy);
return internalVertexCopy;
};
for (int pathLength = minimumExpansionLength; pathLength <= expansionLength; pathLength++) {
List<List<EdgePatternExpr>> expandedPathPattern = expandFixedPathPattern(pathLength, edgePatternExpr,
edgeLabelList, internalLabelList, directionList, deepCopyVisitor, internalVertexSupplier);
for (List<EdgePatternExpr> pathPattern : expandedPathPattern) {
for (ElementLabel leftLabel : leftLabelList) {
for (ElementLabel rightLabel : rightLabelList) {
List<EdgePatternExpr> pathCopy = deepCopyPathPattern(pathPattern, deepCopyVisitor);
// Set the labels of our leftmost vertex...
pathCopy.get(0).getLeftVertex().getLabels().clear();
pathCopy.get(0).getLeftVertex().getLabels().add(leftLabel);
// ...and our rightmost vertex.
pathCopy.get(pathCopy.size() - 1).getRightVertex().getLabels().clear();
pathCopy.get(pathCopy.size() - 1).getRightVertex().getLabels().add(rightLabel);
// Add our path if all edges are valid.
if (pathCopy.stream().allMatch(schemaKnowledgeTable::isValidEdge)) {
canonicalPathList.add(pathCopy);
}
}
}
}
}
// Wrap our edge lists into path patterns.
List<PathPatternExpr> pathPatternList = new ArrayList<>();
for (List<EdgePatternExpr> edgeList : canonicalPathList) {
List<VertexPatternExpr> vertexList = new ArrayList<>();
edgeList.forEach(e -> {
vertexList.add(e.getLeftVertex());
vertexList.add(e.getRightVertex());
});
VariableExpr variableExpr = deepCopyVisitor.visit(edgeDescriptor.getVariableExpr(), null);
PathPatternExpr pathPatternExpr = new PathPatternExpr(vertexList, edgeList, variableExpr);
pathPatternExpr.setSourceLocation(edgePatternExpr.getSourceLocation());
pathPatternList.add(pathPatternExpr);
}
return pathPatternList;
}