/*
* 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.jena.sparql.path.eval ;
import java.util.* ;
import org.apache.jena.atlas.iterator.Iter ;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.Node ;
import org.apache.jena.sparql.path.P_Mod ;
import org.apache.jena.sparql.path.P_NegPropSet ;
import org.apache.jena.sparql.path.Path ;
/** Path evaluation visitor that provide distinct nodes visited only.
*
* This is NOT SPARQL semantics.
*
* This class exists for experimentation.
* It is written to get the right results - not necessarily with maximum efficiency.
*/
final class PathEngine1 extends PathEngine
{
private boolean forwardMode ;
public PathEngine1(Graph graph, boolean forward) {
super(graph, null) ;
this.forwardMode = forward ;
}
protected Collection<Node> collector() {
return new HashSet<Node>() ;
}
protected Set<Node> visitedAcc() {
return new HashSet<Node>() ;
}
@Override
protected void flipDirection() {
forwardMode = !forwardMode ;
}
@Override
protected boolean direction() {
return forwardMode ;
}
@Override
protected void doAlt(Path pathStepLeft, Path pathStepRight, Node node, Collection<Node> output) {
// Must be duplicate supressing.
Collection<Node> nodes = collector() ;
// Insert directly.
eval(pathStepLeft, node, nodes) ;
// Need to reduce/check other side.
eval(pathStepRight, node, nodes) ;
output.addAll(nodes) ;
}
@Override
protected void doSeq(Path pathStepLeft, Path pathStepRight, Node node, Collection<Node> output) {
Path part1 = forwardMode ? pathStepLeft : pathStepRight ;
Path part2 = forwardMode ? pathStepRight : pathStepLeft ;
Collection<Node> nodes = collector() ;
eval(part1, node, nodes) ;
Collection<Node> nodes2 = collector() ;
for (Node n : nodes)
eval(part2, n, nodes2) ;
output.addAll(nodes2) ;
}
// Can use .addAll if collector is set-like.
private static void fillUnique(Iterator<Node> nodes, Collection<Node> acc) {
for (; nodes.hasNext();) {
Node n = nodes.next() ;
if ( !acc.contains(n) )
acc.add(n) ;
}
}
@Override
protected void doMultiLengthPath(Path pathStep, Node node, long min1, long max1, Collection<Node> output) {
// This algorithm can be used for counting {n,m}
// abstract ALP(=>rename?) , doFixedLength
if ( min1 == P_Mod.UNSET )
// {,N}
min1 = 0 ;
// do 0-min1 steps, not collecting.
Collection<Node> collectStartPoints = collector() ;
if ( min1 > 0 )
doFixedLengthPath(pathStep, node, min1, collectStartPoints) ;
else
collectStartPoints.add(node) ;
// System.out.println("Start points: "+collectStartPoints) ;
// {N,M} = {N} then {0,M-N}
int length = (int)(max1 - min1) ;
Collection<Node> visited = collector() ;
for (Node n : collectStartPoints)
doMultiLengthPath(pathStep, n, length, visited, output) ;
}
// {0,length}
protected void doMultiLengthPath(Path pathStep, Node node, long length, Collection<Node> visited, Collection<Node> output) {
if ( visited.contains(node) )
return ;
visited.add(node) ;
output.add(node) ;
if ( length == 0 )
return ;
// One step.
Iterator<Node> iter = eval(pathStep, node) ;
for (; iter.hasNext();) {
Node m = iter.next() ;
if ( visited.contains(m) )
continue ;
doMultiLengthPath(pathStep, m, length - 1, visited, output) ;
}
}
// // Do {0,length}
// private void doFixedLengthPath(Path path, Node node, int length, Collection<Node> visited) {
// System.out.printf("doModPath (%d) %s\n", length, node) ;
// ALP1(forwardMode, 0, length, node, path, visited) ;
// }
@Override
protected void doFixedLengthPath(Path pathStep, Node node, long fixedLength, Collection<Node> output) {
// Special for small?
// if ( fixedLength < 3 )
// {}
Collection<Node> visited = visitedAcc() ;
if ( fixedLength == 0 ) {
doZero(pathStep, node, output) ;
return ;
}
if ( fixedLength == 1 ) {
Iter<Node> iter = eval(pathStep, node) ;
iter.forEachRemaining(n->{
if ( !output.contains(n) )
output.add(n) ;
});
return ;
}
// Loop, not recurse.
Iter<Node> iter = eval(pathStep, node) ;
iter.forEachRemaining(n->{
doFixedLengthPath(pathStep, n, fixedLength - 1, output) ;
}) ;
return ;
}
@Override
protected void doZeroOrMore(Path path, Node node, Collection<Node> output) {
Set<Node> visited = visitedAcc() ;
ALP1(forwardMode, 0, -1, node, path, visited) ;
output.addAll(visited) ;
}
@Override
protected void doOneOrMore(Path path, Node node, Collection<Node> output) {
Set<Node> visited = visitedAcc() ;
// Do one step without including.
Iter<Node> iter1 = eval(path, node) ;
for (; iter1.hasNext();) {
Node n1 = iter1.next() ;
ALP1(forwardMode, 0, -1, n1, path, visited) ;
}
output.addAll(visited) ;
}
private void ALP1(boolean forwardMode, int stepCount, int maxStepCount, Node node, Path path, Set<Node> visited) {
if ( maxStepCount >= 0 && stepCount > maxStepCount )
return ;
// If visited not a set ...
// if ( visited.contains(node) )
// return ;
if ( !visited.add(node) )
return ;
Iter<Node> iter1 = eval(path, node) ;
// For each step, add to results and recurse.
for (; iter1.hasNext();) {
Node n1 = iter1.next() ;
ALP1(forwardMode, stepCount + 1, maxStepCount, n1, path, visited) ;
}
// Different from ALP-counting.
// visited.remove(node) ;
}
@Override
protected void doNegatedPropertySet(P_NegPropSet pathNotOneOf, Node node, Collection<Node> output) {
// X !(:a|:b|^:c|^:d) Y = { X !(:a|:b) Y } UNION { Y !(:c|:d) X }
if ( pathNotOneOf.getFwdNodes().size() > 0 ) {
Iterator<Node> nodes1 = stepExcludeForwards(node, pathNotOneOf.getFwdNodes()) ;
fillUnique(nodes1, output) ;
}
if ( pathNotOneOf.getBwdNodes().size() > 0 ) {
Iterator<Node> nodes2 = stepExcludeBackwards(node, pathNotOneOf.getBwdNodes()) ;
fillUnique(nodes2, output) ;
}
}
@Override
protected void doZeroOrOne(Path pathStep, Node node, Collection<Node> output) {
eval(pathStep, node, output) ;
if ( !output.contains(node) )
output.add(node) ;
}
@Override
protected void doZero(Path path, Node node, Collection<Node> output) {
if ( !output.contains(node) )
output.add(node) ;
}
}