Skip to content

Commit 833385b

Browse files
some graph utils
1 parent 2b190a6 commit 833385b

1 file changed

Lines changed: 280 additions & 0 deletions

File tree

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
package org.dllearner.utilities;
2+
3+
import java.io.File;
4+
import java.util.*;
5+
import java.util.stream.Collectors;
6+
import java.util.stream.Stream;
7+
8+
import org.jgrapht.Graph;
9+
import org.jgrapht.GraphPath;
10+
import org.jgrapht.graph.DefaultEdge;
11+
import org.jgrapht.graph.GraphWalk;
12+
import org.jgrapht.graph.builder.GraphTypeBuilder;
13+
import org.jgrapht.traverse.RandomWalkIterator;
14+
import org.semanticweb.owlapi.apibinding.OWLManager;
15+
import org.semanticweb.owlapi.dlsyntax.renderer.DLSyntaxObjectRenderer;
16+
import org.semanticweb.owlapi.io.ToStringRenderer;
17+
import org.semanticweb.owlapi.model.*;
18+
import static org.apache.jena.sys.JenaSystem.forEach;
19+
20+
/**
21+
*
22+
* Utility methods working on graph level by means of JGraphT API.
23+
*
24+
* @author Lorenz Buehmann
25+
*/
26+
public class GraphUtils {
27+
28+
public static Graph<OWLIndividual, DefaultEdge> aboxToGraph(OWLOntology ont) {
29+
30+
Set<OWLObjectPropertyAssertionAxiom> axioms = ont.getAxioms(AxiomType.OBJECT_PROPERTY_ASSERTION);
31+
32+
Graph<OWLIndividual, DefaultEdge> g = GraphTypeBuilder
33+
.directed()
34+
.allowingMultipleEdges(true)
35+
.edgeClass(DefaultEdge.class)
36+
.vertexClass(OWLIndividual.class)
37+
.buildGraph();
38+
39+
axioms.forEach(ax -> g.addEdge(ax.getSubject(), ax.getObject()));
40+
41+
return g;
42+
}
43+
44+
public static Graph<OWLIndividual, OWLPropertyEdge> aboxToLabeledGraph(OWLOntology ont) {
45+
46+
Set<OWLObjectPropertyAssertionAxiom> axioms = ont.getAxioms(AxiomType.OBJECT_PROPERTY_ASSERTION);
47+
48+
Graph<OWLIndividual, OWLPropertyEdge> g = GraphTypeBuilder
49+
.directed()
50+
.allowingMultipleEdges(true)
51+
.vertexClass(OWLIndividual.class)
52+
.edgeClass(OWLPropertyEdge.class)
53+
.buildGraph();
54+
55+
axioms.forEach(ax -> {
56+
g.addVertex(ax.getSubject());
57+
g.addVertex(ax.getObject());
58+
g.addEdge(ax.getSubject(), ax.getObject(), new OWLPropertyEdge(ax.getProperty()));
59+
});
60+
61+
return g;
62+
}
63+
64+
static class OWLPropertyEdge extends LabeledEdge<OWLObjectPropertyExpression> {
65+
public OWLPropertyEdge(OWLObjectPropertyExpression label) {
66+
super(label);
67+
}
68+
}
69+
70+
static class LabeledEdge<T> extends DefaultEdge {
71+
private T label;
72+
73+
/**
74+
* Constructs a labeled edge
75+
*
76+
* @param label the label of the new edge.
77+
*/
78+
public LabeledEdge(T label) {
79+
this.label = label;
80+
}
81+
82+
/**
83+
* Gets the label associated with this edge.
84+
*
85+
* @return edge label
86+
*/
87+
public T getLabel() {
88+
return label;
89+
}
90+
91+
@Override
92+
public String toString() {
93+
return "(" + getSource() + " : " + getTarget() + " : " + label + ")";
94+
}
95+
}
96+
97+
98+
public static void main(String[] args) throws OWLOntologyCreationException {
99+
ToStringRenderer.getInstance().setRenderer(new DLSyntaxObjectRenderer());
100+
101+
OWLOntology ont = OWLManager.createOWLOntologyManager().loadOntologyFromOntologyDocument(new File("/home/user/work/datasets/poker/poker_straight_flush_p5-n347.owl"));
102+
OWLClass hand = OWLManager.getOWLDataFactory().getOWLClass(IRI.create("http://dl-learner.org/examples/uci/poker#Hand"));
103+
final String targetClass = "straight_flush";
104+
105+
Graph<OWLIndividual, OWLPropertyEdge> g = aboxToLabeledGraph(ont);
106+
107+
Set<OWLIndividual> startNodes = ont.getIndividualsInSignature().stream()
108+
.filter(ind -> ont.getAnnotationAssertionAxioms(ind.asOWLNamedIndividual().getIRI()).stream()
109+
.map(OWLAnnotationAssertionAxiom::annotationValue)
110+
.map(OWLAnnotationValue::asLiteral)
111+
.anyMatch(lit -> lit.isPresent() && lit.get().getLiteral().equals(targetClass)))
112+
.limit(1)
113+
.collect(Collectors.toSet());
114+
115+
int maxPathLength = 10;
116+
117+
startNodes.forEach(node -> {
118+
119+
// compute all path up to length
120+
List<GraphPath<OWLIndividual, OWLPropertyEdge>> paths = new AllPaths<>(g).getAllPaths(node,true, maxPathLength);
121+
122+
// show all paths
123+
paths.forEach(System.out::println);
124+
125+
// show all paths but just the edges
126+
List<List<OWLObjectPropertyExpression>> pathEdges = paths.stream()
127+
.map(path -> path.getEdgeList().stream().map(LabeledEdge::getLabel).collect(Collectors.toList()))
128+
.collect(Collectors.toList());
129+
// pathEdges.forEach(System.out::println);
130+
131+
// show just the distinct list of the edge sequences
132+
List<List<OWLObjectPropertyExpression>> pathEdgesDistinct = new ArrayList<>(new HashSet<>(pathEdges));
133+
134+
Comparator<List<OWLObjectPropertyExpression>> c = Comparator.<List<OWLObjectPropertyExpression>>comparingInt(List::size).thenComparing(Object::toString);
135+
136+
Collections.sort(pathEdgesDistinct, c);
137+
pathEdgesDistinct.forEach(System.out::println);
138+
139+
});
140+
}
141+
142+
143+
144+
145+
static class AllPaths<V, E> {
146+
private final Graph<V, E> graph;
147+
148+
AllPaths(Graph<V, E> graph){
149+
this.graph = graph;
150+
}
151+
152+
private List<GraphPath<V, E>> generatePaths(
153+
Set<V> sourceVertices, boolean simplePathsOnly,
154+
Integer maxPathLength)
155+
{
156+
/*
157+
* We walk forwards through the network from the source vertices, exploring all outgoing
158+
* edges whose minimum distances is small enough.
159+
*/
160+
List<GraphPath<V, E>> completePaths = new ArrayList<>();
161+
Deque<List<E>> incompletePaths = new LinkedList<>();
162+
163+
// Input sanity checking
164+
if (maxPathLength != null && maxPathLength < 0) {
165+
throw new IllegalArgumentException("maxPathLength must be non-negative if defined");
166+
}
167+
168+
// Bootstrap the search with the source vertices
169+
for (V source : sourceVertices) {
170+
completePaths.add(GraphWalk.singletonWalk(graph, source, 0d));
171+
172+
if (maxPathLength != null && maxPathLength == 0) {
173+
continue;
174+
}
175+
176+
for (E edge : graph.outgoingEdgesOf(source)) {
177+
assert graph.getEdgeSource(edge).equals(source);
178+
179+
completePaths.add(makePath(Collections.singletonList(edge)));
180+
181+
if ((maxPathLength == null || maxPathLength > 1)) {
182+
List<E> path = Collections.singletonList(edge);
183+
incompletePaths.add(path);
184+
}
185+
}
186+
}
187+
188+
if (maxPathLength != null && maxPathLength == 0) {
189+
return completePaths;
190+
}
191+
192+
// Walk through the queue of incomplete paths
193+
for (List<E> incompletePath; (incompletePath = incompletePaths.poll()) != null;) {
194+
Integer lengthSoFar = incompletePath.size();
195+
assert (maxPathLength == null) || (lengthSoFar < maxPathLength);
196+
197+
E leafEdge = incompletePath.get(lengthSoFar - 1);
198+
V leafNode = graph.getEdgeTarget(leafEdge);
199+
200+
Set<V> pathVertices = new HashSet<>();
201+
for (E pathEdge : incompletePath) {
202+
pathVertices.add(graph.getEdgeSource(pathEdge));
203+
pathVertices.add(graph.getEdgeTarget(pathEdge));
204+
}
205+
206+
for (E outEdge : graph.outgoingEdgesOf(leafNode)) {
207+
// Proceed if the outgoing edge is marked and the mark
208+
// is sufficiently small
209+
if (maxPathLength == null || lengthSoFar <= maxPathLength) {
210+
List<E> newPath = new ArrayList<>(incompletePath);
211+
newPath.add(outEdge);
212+
213+
// If requested, make sure this path isn't self-intersecting
214+
if (simplePathsOnly && pathVertices.contains(graph.getEdgeTarget(outEdge))) {
215+
continue;
216+
}
217+
218+
GraphPath<V, E> completePath = makePath(newPath);
219+
assert sourceVertices.contains(completePath.getStartVertex());
220+
assert (maxPathLength == null) || (completePath.getLength() <= maxPathLength);
221+
completePaths.add(completePath);
222+
223+
// If this path is short enough, consider further extensions of it
224+
if ((maxPathLength == null) || (newPath.size() < maxPathLength)) {
225+
incompletePaths.addFirst(newPath);
226+
}
227+
}
228+
}
229+
}
230+
231+
assert incompletePaths.isEmpty();
232+
return completePaths;
233+
}
234+
235+
/**
236+
* Transform an ordered list of edges into a GraphPath.
237+
*
238+
* The weight of the generated GraphPath is set to the sum of the weights of the edges.
239+
*
240+
* @param edges the edges
241+
*
242+
* @return the corresponding GraphPath
243+
*/
244+
private GraphPath<V, E> makePath(List<E> edges)
245+
{
246+
V source = graph.getEdgeSource(edges.get(0));
247+
V target = graph.getEdgeTarget(edges.get(edges.size() - 1));
248+
double weight = edges.stream().mapToDouble(edge -> graph.getEdgeWeight(edge)).sum();
249+
return new GraphWalk<>(graph, source, target, edges, weight);
250+
}
251+
252+
public List<GraphPath<V, E>> getAllPaths(V sourceVertex, boolean simplePathsOnly, Integer maxPathLength) {
253+
return getAllPaths(
254+
Collections.singleton(sourceVertex),
255+
simplePathsOnly, maxPathLength);
256+
}
257+
258+
public List<GraphPath<V, E>> getAllPaths(
259+
Set<V> sourceVertices, boolean simplePathsOnly,
260+
Integer maxPathLength)
261+
{
262+
if ((maxPathLength != null) && (maxPathLength < 0)) {
263+
throw new IllegalArgumentException("maxPathLength must be non-negative if defined");
264+
}
265+
266+
if (!simplePathsOnly && (maxPathLength == null)) {
267+
throw new IllegalArgumentException(
268+
"If search is not restricted to simple paths, a maximum path length must be set to avoid infinite cycles");
269+
}
270+
271+
if ((sourceVertices.isEmpty())) {
272+
return Collections.emptyList();
273+
}
274+
275+
// Generate all the paths
276+
return generatePaths(
277+
sourceVertices, simplePathsOnly, maxPathLength);
278+
}
279+
}
280+
}

0 commit comments

Comments
 (0)