11package net .sansa_stack .inference .rules
22
3+ import java .util .stream .Collectors
4+
35import scala .collection .JavaConverters ._
46import scala .language .{existentials , implicitConversions }
57import scalax .collection .GraphPredef ._
@@ -13,6 +15,7 @@ import org.apache.jena.graph.Node
1315import org .apache .jena .reasoner .TriplePattern
1416import org .apache .jena .reasoner .rulesys .Rule
1517import org .apache .jena .vocabulary .RDFS
18+ import org .jgrapht .alg .CycleDetector
1619import org .jgrapht .alg .cycle .TarjanSimpleCycles
1720
1821import net .sansa_stack .inference .utils .RuleUtils ._
@@ -82,13 +85,24 @@ object RuleDependencyGraphGenerator extends Logging {
8285 }
8386
8487 // 3. pruning
85- if (pruned) {
86- g = removeEdgesWithPredicateAlreadyTC(g)
87- g = removeCyclesIfPredicateIsTC(g)
88- g = removeEdgesWithCycleOverTCNode(g)
89- // g = prune(g)
90- // g = prune1(g)
88+ val pruningRules = List (
89+ removeLoops _,
90+ removeEdgesWithPredicateAlreadyTC _,
91+ removeCyclesIfPredicateIsTC _,
92+ removeEdgesWithCycleOverTCNode _
93+ ,removeCycles _
94+ // ,prune _
95+ )
96+
97+ for ((rule, i) <- pruningRules.zipWithIndex) g = {
98+ println(s " $i. " + " *" * 40 )
99+ rule.apply(g)
91100 }
101+ var cnt = 1
102+ pruningRules.foreach(rule => {
103+
104+
105+ })
92106
93107 g
94108 }
@@ -164,21 +178,81 @@ object RuleDependencyGraphGenerator extends Logging {
164178 ret
165179 }
166180
181+ def removeLoops (graph : RuleDependencyGraph ): RuleDependencyGraph = {
182+ debug(" removing non-TC loops" )
183+ var edges2Remove = Seq [Graph [Rule , LDiEdge ]# EdgeT ]()
184+
185+ graph.nodes.toSeq.foreach(node => {
186+
187+ val loopEdge = node.outgoing.find(_.target == node)
188+
189+ if (loopEdge.isDefined) {
190+
191+ val edge = loopEdge.get
192+
193+ val rule = node.value
194+
195+ val isTC = RuleUtils .isTransitiveClosure(rule, edge.label.asInstanceOf [TriplePattern ].getPredicate)
196+
197+ if (! isTC) {
198+ edges2Remove :+= edge
199+ debug(s " loop of node $node" )
200+ }
201+ }
202+ })
203+
204+ val newNodes = graph.nodes.map(node => node.value)
205+ val newEdges = graph.edges.clone().filterNot(e => edges2Remove.contains(e)).map(edge => edge.toOuter)
206+
207+ new RuleDependencyGraph (newNodes, newEdges)
208+ }
209+
210+ def removeCycles (graph : RuleDependencyGraph ): RuleDependencyGraph = {
211+ debug(" removing redundant cycles" )
212+ var edges2Remove = Seq [Graph [Rule , LDiEdge ]# EdgeT ]()
213+
214+
215+ // convert to JGraphT graph for algorithms not contained in Scala Graph API
216+ val g = GraphUtils .asJGraphtRuleSetGraph(graph)
217+
218+
219+ val cycleDetector = new CycleDetector [Rule , LabeledEdge [Rule , TriplePattern ]](g)
220+
221+ val cycleDetector2 = new TarjanSimpleCycles [Rule , LabeledEdge [Rule , TriplePattern ]](g)
222+ val allCycles = cycleDetector2.findSimpleCycles()
223+
224+ graph.nodes.toSeq.foreach(node => {
225+ debug(s " NODE ${node.value}" )
226+
227+ // get cycles of length 3
228+ val cycles = cycleDetector.findCyclesContainingVertex(node.value)
229+ debug(cycles.asScala.mkString(" ," ))
230+
231+ debug(allCycles.asScala.filter(cycle => cycle.contains(node.value)).map(cycle => cycle.asScala.map(rule => rule.getName)).mkString(" \n " ))
232+
233+ })
234+
235+ val newNodes = graph.nodes.map(node => node.value)
236+ val newEdges = graph.edges.clone().filterNot(e => edges2Remove.contains(e)).map(edge => edge.toOuter)
237+
238+ new RuleDependencyGraph (newNodes, newEdges)
239+ }
240+
167241 def prune (graph : RuleDependencyGraph ): RuleDependencyGraph = {
168242 var redundantEdges = Seq [Graph [Rule , LDiEdge ]# EdgeT ]()
169243
170244// graph.outerNodeTraverser.foreach(n => println(n))
171245
172246 // for each node n in G
173- graph.nodes.foreach(node => {
247+ graph.nodes.toSeq. foreach(node => {
174248 debug(" #" * 20 )
175249 debug(s " NODE: ${node.value.getName}" )
176250
177251 // get all direct successors
178252 var successors = node.innerNodeTraverser.withParameters(Parameters (maxDepth = 1 )).toList
179253 // remove node itself, if it's a cyclic node
180254 successors = successors.filterNot(_.equals(node))
181- debug(s " SUCCESSORS: ${successors.map(n => n.value.getName)}" )
255+ debug(s " DIRECT SUCCESSORS: ${successors.map(n => n.value.getName).mkString( " , " )}" )
182256
183257 if (successors.size > 1 ) {
184258 // get pairs of successors
@@ -188,22 +262,22 @@ object RuleDependencyGraphGenerator extends Logging {
188262 debug(s " PAIR: ${pair._1.value.getName}, ${pair._2.value.getName}" )
189263 val n1 = pair._1
190264 val edge1 = node.innerEdgeTraverser.filter(e => e.source == node && e.target == n1).head
265+
191266 val n2 = pair._2
192267 val edge2 = node.innerEdgeTraverser.filter(e => e.source == node && e.target == n2).head
193268
194269 // n --p--> n1
195270 val path1 = node.withSubgraph(edges = ! _.equals(edge2)) pathTo n2
196271 if (path1.isDefined) {
197- debug(s " PATH TO: ${n2.value.getName}" )
198- debug(s " PATH: ${path1.get.edges.toList.map(edge => asString(edge))}" )
272+ debug(s " PATH TO ${n2.value.getName}: ${path1.get.edges.toList.map(edge => asString(edge))}" )
199273 val edges = path1.get.edges.toList
200274 edges.foreach(edge => {
201275 debug(s " EDGE: ${asString(edge)}" )
202276 })
203277 val last = edges.last.value
204278
205279 if (last.label == edge2.label) {
206- debug(" redundant" )
280+ debug(s " redundant edge $edge2 " )
207281 redundantEdges :+= edge2
208282 }
209283 } else {
@@ -221,7 +295,7 @@ object RuleDependencyGraphGenerator extends Logging {
221295 val last = edges.last.value
222296
223297 if (last.label == edge1.label) {
224- debug(" redundant" )
298+ debug(s " redundant edge $edge1 " )
225299 redundantEdges :+= edge1
226300 }
227301 } else {
@@ -243,7 +317,7 @@ object RuleDependencyGraphGenerator extends Logging {
243317 var redundantEdges = Seq [Graph [Rule , LDiEdge ]# EdgeT ]()
244318
245319 // for each node n in G
246- graph.nodes.foreach(node => {
320+ graph.nodes.toSeq. foreach(node => {
247321 debug(" #" * 20 )
248322 debug(s " NODE: ${node.value.getName}" )
249323
@@ -265,7 +339,7 @@ object RuleDependencyGraphGenerator extends Logging {
265339 var redundantEdges = Seq [Graph [Rule , LDiEdge ]# EdgeT ]()
266340
267341 // for each node n in G
268- graph.nodes.foreach(node => {
342+ graph.nodes.toSeq. foreach(node => {
269343 debug(" #" * 20 )
270344 debug(s " NODE: ${node.value.getName}" )
271345
@@ -359,7 +433,7 @@ object RuleDependencyGraphGenerator extends Logging {
359433 var redundantEdges = Seq [Graph [Rule , LDiEdge ]# EdgeT ]()
360434
361435 // for each node n in G
362- graph.nodes.foreach(node => {
436+ graph.nodes.toSeq. foreach(node => {
363437 debug(" #" * 20 )
364438 debug(s " NODE: ${node.value.getName}" )
365439
@@ -370,7 +444,7 @@ object RuleDependencyGraphGenerator extends Logging {
370444 debug(s " SUCCESSORS: ${successors.map(n => n.value.getName)}" )
371445
372446 // check for nodes that do compute the TC
373- successors.foreach(n => {
447+ successors.toSeq. foreach(n => {
374448 debug(s " successor: ${n.value.getName}" )
375449 val rule = n.value
376450 val edges = node.innerEdgeTraverser.filter(e => e.target == n && e.source != n)
@@ -415,7 +489,7 @@ object RuleDependencyGraphGenerator extends Logging {
415489 var redundantEdges = Seq [Graph [Rule , LDiEdge ]# EdgeT ]()
416490
417491 // for each node n in G
418- graph.nodes.foreach(node => {
492+ graph.nodes.toSeq. foreach(node => {
419493 val rule = node.value
420494
421495 // we only handle cyclic rules
0 commit comments