From be4d30b877f70d8b4c6b0282b7db9f8db5322fec Mon Sep 17 00:00:00 2001 From: Raitis Veinbahs Date: Wed, 7 Feb 2024 17:20:25 +0100 Subject: [PATCH] chore: Update scala-graph to 2.0.1 (DEV-3072) --- .../prequery/TopologicalSortUtilSpec.scala | 35 ++++++++------- project/Dependencies.scala | 2 +- .../GravsearchQueryOptimisation.scala | 44 ++++++++++--------- .../prequery/TopologicalSortUtil.scala | 14 +++--- 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/integration/src/test/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/TopologicalSortUtilSpec.scala b/integration/src/test/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/TopologicalSortUtilSpec.scala index b64085e62b..ffaec6e029 100644 --- a/integration/src/test/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/TopologicalSortUtilSpec.scala +++ b/integration/src/test/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/TopologicalSortUtilSpec.scala @@ -5,8 +5,8 @@ package org.knora.webapi.util.search.gravsearch.prequery -import scalax.collection.Graph -import scalax.collection.GraphEdge.* +import scalax.collection.hyperedges.DiHyperEdge +import scalax.collection.immutable.Graph import org.knora.webapi.CoreSpec import org.knora.webapi.messages.util.search.gravsearch.prequery.TopologicalSortUtil @@ -15,15 +15,16 @@ import org.knora.webapi.messages.util.search.gravsearch.prequery.TopologicalSort * Tests [[TopologicalSortUtil]]. */ class TopologicalSortUtilSpec extends CoreSpec { - type NodeT = Graph[Int, DiHyperEdge]#NodeT + type GraphT = Graph[Int, DiHyperEdge[Int]] + type NodeT = GraphT#NodeT - private def nodesToValues(orders: Set[Vector[NodeT]]): Set[Vector[Int]] = orders.map(_.map(_.value)) + private def nodesToValues(orders: Set[Vector[NodeT]]): Set[Vector[Int]] = orders.map(_.map(_.outer)) "TopologicalSortUtilSpec" should { "return all topological orders of a graph with one leaf" in { - val graph: Graph[Int, DiHyperEdge] = - Graph[Int, DiHyperEdge](DiHyperEdge[Int](2, 4), DiHyperEdge[Int](2, 7), DiHyperEdge[Int](4, 5)) + val graph: GraphT = + Graph.from(List(DiHyperEdge[Int](2)(4), DiHyperEdge[Int](2)(7), DiHyperEdge[Int](4)(5))) val allOrders: Set[Vector[Int]] = nodesToValues( TopologicalSortUtil @@ -38,13 +39,15 @@ class TopologicalSortUtilSpec extends CoreSpec { } "return all topological orders of a graph with multiple leaves" in { - val graph: Graph[Int, DiHyperEdge] = - Graph[Int, DiHyperEdge]( - DiHyperEdge[Int](2, 4), - DiHyperEdge[Int](2, 7), - DiHyperEdge[Int](2, 8), - DiHyperEdge[Int](4, 5), - DiHyperEdge[Int](7, 3) + val graph: GraphT = + Graph.from( + List( + DiHyperEdge[Int](2)(4), + DiHyperEdge[Int](2)(7), + DiHyperEdge[Int](2)(8), + DiHyperEdge[Int](4)(5), + DiHyperEdge[Int](7)(3) + ) ) val allOrders: Set[Vector[Int]] = nodesToValues( @@ -61,7 +64,7 @@ class TopologicalSortUtilSpec extends CoreSpec { } "return an empty set of orders for an empty graph" in { - val graph: Graph[Int, DiHyperEdge] = Graph[Int, DiHyperEdge]() + val graph: GraphT = Graph.empty val allOrders: Set[Vector[Int]] = nodesToValues( TopologicalSortUtil @@ -72,8 +75,8 @@ class TopologicalSortUtilSpec extends CoreSpec { } "return an empty set of orders for a cyclic graph" in { - val graph: Graph[Int, DiHyperEdge] = - Graph[Int, DiHyperEdge](DiHyperEdge[Int](2, 4), DiHyperEdge[Int](4, 7), DiHyperEdge[Int](7, 2)) + val graph: GraphT = + Graph.from(List(DiHyperEdge[Int](2)(4), DiHyperEdge[Int](4)(7), DiHyperEdge[Int](7)(2))) val allOrders: Set[Vector[Int]] = nodesToValues( TopologicalSortUtil diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 8472b66dd9..c1f3df61c9 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -92,7 +92,7 @@ object Dependencies { val rdf4jClient = "org.eclipse.rdf4j" % "rdf4j-client" % "4.3.9" val rdf4jShacl = "org.eclipse.rdf4j" % "rdf4j-shacl" % "4.3.9" val saxonHE = "net.sf.saxon" % "Saxon-HE" % "12.4" - val scalaGraph = "org.scala-graph" %% "graph-core" % "1.13.6" // Scala 3 incompatible + val scalaGraph = "org.scala-graph" %% "graph-core" % "2.0.1" // Should be Scala 3 compatible val titaniumJSONLD = "com.apicatalog" % "titanium-json-ld" % "1.3.3" val xmlunitCore = "org.xmlunit" % "xmlunit-core" % "2.9.1" diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/GravsearchQueryOptimisation.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/GravsearchQueryOptimisation.scala index 52b1179a22..296a890215 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/GravsearchQueryOptimisation.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/GravsearchQueryOptimisation.scala @@ -5,8 +5,8 @@ package org.knora.webapi.messages.util.search.gravsearch.prequery -import scalax.collection.Graph -import scalax.collection.GraphEdge.DiHyperEdge +import scalax.collection.hyperedges.DiHyperEdge +import scalax.collection.immutable.Graph import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.SmartIri @@ -18,10 +18,13 @@ import org.knora.webapi.messages.util.search.gravsearch.types.GravsearchTypeInsp import org.knora.webapi.messages.util.search.gravsearch.types.GravsearchTypeInspectionUtil import org.knora.webapi.messages.util.search.gravsearch.types.TypeableEntity +import GravsearchQueryOptimisation.StringHyperGraph + /** * A feature factory that constructs Gravsearch query optimisation algorithms. */ object GravsearchQueryOptimisation { + type StringHyperGraph = Graph[String, DiHyperEdge[String]] def optimiseQueryPatterns( patterns: Seq[QueryPattern], @@ -191,11 +194,10 @@ private object ReorderPatternsByDependency { */ private def createAndSortGraph(statementPatterns: Seq[StatementPattern]): Seq[QueryPattern] = { @scala.annotation.tailrec - def makeGraphWithoutCycles(graphComponents: Seq[(String, String)]): Graph[String, DiHyperEdge] = { - val graph: Graph[String, DiHyperEdge] = graphComponents.foldLeft(Graph.empty[String, DiHyperEdge]) { - (graph, edgeDef) => - val edge: DiHyperEdge[String] = DiHyperEdge(edgeDef._1, edgeDef._2) - graph ++ Vector(edge) // add nodes and edges to graph + def makeGraphWithoutCycles(graphComponents: Seq[(String, String)]): StringHyperGraph = { + val graph: StringHyperGraph = graphComponents.foldLeft(Graph.empty: StringHyperGraph) { (graph, edgeDef) => + val edge = DiHyperEdge(edgeDef._1)(edgeDef._2) + graph ++ Vector(edge) // add nodes and edges to graph } if (graph.isCyclic) { @@ -205,8 +207,8 @@ private object ReorderPatternsByDependency { // the cyclic node is the one that cycle starts and ends with val cyclicNode: graph.NodeT = cycle.endNode val cyclicEdge: graph.EdgeT = cyclicNode.edges.last - val originNodeOfCyclicEdge: String = cyclicEdge._1.value - val TargetNodeOfCyclicEdge: String = cyclicEdge._2.value + val originNodeOfCyclicEdge: String = cyclicEdge.node1.outer + val TargetNodeOfCyclicEdge: String = cyclicEdge.node2.outer val graphComponentsWithOutCycle = graphComponents.filterNot(edgeDef => edgeDef.equals((originNodeOfCyclicEdge, TargetNodeOfCyclicEdge))) @@ -216,7 +218,7 @@ private object ReorderPatternsByDependency { } } - def createGraph: Graph[String, DiHyperEdge] = { + def createGraph: StringHyperGraph = { val graphComponents: Seq[(String, String)] = statementPatterns.map { statementPattern => // transform every statementPattern to pair of nodes that will consist an edge. val node1 = statementPattern.subj.toSparql @@ -235,10 +237,10 @@ private object ReorderPatternsByDependency { * @return the filtered topological orders. */ def findOrdersNotEndingWithObjectOfRdfType( - orders: Set[Vector[Graph[String, DiHyperEdge]#NodeT]], + orders: Set[Vector[StringHyperGraph#NodeT]], statementPatterns: Seq[StatementPattern] - ): Set[Vector[Graph[String, DiHyperEdge]#NodeT]] = { - type NodeT = Graph[String, DiHyperEdge]#NodeT + ): Set[Vector[StringHyperGraph#NodeT]] = { + type NodeT = StringHyperGraph#NodeT // Find the nodes that are objects of rdf:type in the statement patterns. val nodesThatAreObjectsOfRdfType: Set[String] = statementPatterns.filter { statementPattern => @@ -252,7 +254,7 @@ private object ReorderPatternsByDependency { // Filter out the topological orders that end with any of those nodes. orders.filterNot { (order: Vector[NodeT]) => - nodesThatAreObjectsOfRdfType.contains(order.last.value) + nodesThatAreObjectsOfRdfType.contains(order.last.outer) } } @@ -265,16 +267,16 @@ private object ReorderPatternsByDependency { * @return a topological order. */ def findBestTopologicalOrder( - graph: Graph[String, DiHyperEdge], + graph: StringHyperGraph, statementPatterns: Seq[StatementPattern] - ): Vector[Graph[String, DiHyperEdge]#NodeT] = { - type NodeT = Graph[String, DiHyperEdge]#NodeT + ): Vector[StringHyperGraph#NodeT] = { + type NodeT = StringHyperGraph#NodeT /** * An ordering for sorting topological orders. */ object TopologicalOrderOrdering extends Ordering[Vector[NodeT]] { - private def orderToString(order: Vector[NodeT]) = order.map(_.value).mkString("|") + private def orderToString(order: Vector[NodeT]) = order.map(_.outer).mkString("|") override def compare(left: Vector[NodeT], right: Vector[NodeT]): Int = orderToString(left).compare(orderToString(right)) @@ -313,10 +315,10 @@ private object ReorderPatternsByDependency { } def sortStatementPatterns( - createdGraph: Graph[String, DiHyperEdge], + createdGraph: StringHyperGraph, statementPatterns: Seq[StatementPattern] ): Seq[QueryPattern] = { - type NodeT = Graph[String, DiHyperEdge]#NodeT + type NodeT = StringHyperGraph#NodeT // Try to find the best topological order for the graph. val topologicalOrder: Vector[NodeT] = @@ -326,7 +328,7 @@ private object ReorderPatternsByDependency { if (topologicalOrder.nonEmpty) { // Yes. Sort the statement patterns according to the reverse topological order. topologicalOrder.foldRight(Vector.empty[QueryPattern]) { (node, sortedStatements) => - val nextStatements = statementPatterns.filter(_.obj.toSparql.equals(node.value)).toVector + val nextStatements = statementPatterns.filter(_.obj.toSparql.equals(node.outer)).toVector nextStatements ++ sortedStatements } } else { diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/TopologicalSortUtil.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/TopologicalSortUtil.scala index edd16a5361..03435aa7bc 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/TopologicalSortUtil.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/TopologicalSortUtil.scala @@ -5,8 +5,8 @@ package org.knora.webapi.messages.util.search.gravsearch.prequery -import scalax.collection.Graph -import scalax.collection.GraphEdge.DiHyperEdge +import scalax.collection.hyperedges.DiHyperEdge +import scalax.collection.immutable.Graph /** * A utility for finding all topological orders of a graph. @@ -20,8 +20,10 @@ object TopologicalSortUtil { * @param graph the graph to be sorted. * @tparam T the type of the nodes in the graph. */ - def findAllTopologicalOrderPermutations[T](graph: Graph[T, DiHyperEdge]): Set[Vector[Graph[T, DiHyperEdge]#NodeT]] = { - type NodeT = Graph[T, DiHyperEdge]#NodeT + def findAllTopologicalOrderPermutations[T]( + graph: Graph[T, DiHyperEdge[T]] + ): Set[Vector[Graph[T, DiHyperEdge[T]]#NodeT]] = { + type NodeT = Graph[T, DiHyperEdge[T]]#NodeT /** * Finds all possible topological order permutations of a graph using layer information. This method considers all @@ -55,7 +57,9 @@ object TopologicalSortUtil { // Get those nodes within a layer that are origins of outgoing edges to the nodes already in set of ordered nodes. val origins: Set[NodeT] = acc.foldRight(Set.empty[NodeT]) { (node, originsAcc) => val maybeOriginNode: Option[NodeT] = - layerNodes.find(layerNode => graph.edges.contains(DiHyperEdge(layerNode, node))) + layerNodes.find { layerNode => + graph.edges.find(DiHyperEdge(layerNode.outer)(node.outer)).isDefined + } // Is there any edge which has its origin in this layer and target in already visited layers? maybeOriginNode match { // Yes. Add the origin node to the topological order