groupBy on graph not compiling

23 views
Skip to first unread message

Martin Senne

unread,
Jul 12, 2018, 10:49:16 AM7/12/18
to scala-graph
Hi folks,

I want to partition a graph into several partitions using groupBy based on a certain node (outer type) attribute.
I am assuming I can use groupBy for that task.

Still and for some reason, I am not able to perform a groupBy on a graph, as I run into a type mismatch:

Minimal reproducing example


    import scalax.collection.GraphPredef._
    import scalax.collection.GraphEdge._

    import scalax.collection.Graphval h = Graph("2"~>"3", "3"~>"1", "5")

    val r1: Map[Boolean, Graph[String, DiEdge]] = h.groupBy((i:String) => true )

    // both r2 and r3 yields type mismatch, similar:
    //      [error]  found   : String => String
    //      [error]  required: scalax.collection.GraphPredef.Param[String,scalax.collection.GraphEdge.UnDiEdge] => ?
    val r2 = h.groupBy( (i:String) => i.toInt )
    val r3: Map[Int, Graph[String, DiEdge]] = h.groupBy[Int]( (i:String) => i.toInt )


Any ideas, why r1 compiles, but r2 and r3 do not?
I suspect the implicit resolution from Param type into OuterNode type to be responsible?

Many thanks and cheers,

Martin


Martin Senne

unread,
Jul 12, 2018, 10:54:28 AM7/12/18
to scala-graph
import scalax.collection.GraphPredef._
import scalax.collection.GraphEdge._

import scalax.collection.Graph


val h
= Graph("2"~>"3", "3"~>"1", "5")


val r1: Map[Boolean, Graph[String, DiEdge]] = h.groupBy((i:String) => true )

// both r2 and r3 yields type mismatch, similar:
//   [error] found   : String => String
//   [error] required: scalax.collection.GraphPredef.Param[String,scalax.collection.GraphEdge.UnDiEdge] => ?
val r2
= h.groupBy( (i:String) => i.toInt )
val r3
: Map[Int, Graph[String, DiEdge]] = h.groupBy[Int]( (i:String) => i.toInt )


Proper highlighting.

Peter Empen

unread,
Jul 13, 2018, 2:43:45 AM7/13/18
to scala-graph
Hello Martin,

if you call groupBy on the graph you are grouping all graph elements. Graph elements are nodes and edges. What you obviously want instead is to group nodes only. In that case call h.nodes.groupBy.

Note that the nodes method yields the inner nodes so call nodes.toOuter if you need just the outer nodes.

Peter

Martin Senne

unread,
Jul 13, 2018, 7:14:29 AM7/13/18
to scala-graph
Hi Peter,

thanks for your answer so far.

Sorry, that I did not define the problem precisely enough. ( in short: I want the respective subgraphs )

Say I have a graph h with Nodes = {A, B, C, D, E}; Edges = {A -> B, C ->D, C->E}
Further, all nodes have an attribute:
A.attr = 1; B. attr = 1
C.attr = 2; D.attr = 2, E.attr = 2

What I want is to obtain is the
  • subgraph h_1 with nodes {A, B} and edges {A->B} and
  • subgraph h_2 with nodes {C, D, E} and edges {C->D, C->E}

So, the subgraph based on the attribute value.

Any ideas?

Thanks and cheers,

Martin

Martin Senne

unread,
Jul 13, 2018, 7:42:45 AM7/13/18
to scala-graph
Hi all, hi Peter,

I have put my last example and comment into working code.
Value m contains the result I want to obtain (but with groupBy)

object SubgraphTest {

 
def main(args: Array[String]): Unit = {


   
import scalax.collection.GraphPredef._
   
import scalax.collection.GraphEdge._
   
import scalax.collection.Graph


    val a
= Entry("A", 1)
    val b
= Entry("B", 1)
    val c
= Entry("C", 2)
    val d
= Entry("D", 2)
    val e
= Entry("E", 2)

    val h
= Graph(a, b, c, d, e, a ~> b, c ~> d, c ~> e)

    val
as = Set(1, 2)

   
// this works but is inefficient wrt. runtime
    val m
: Map[Int, Graph[Entry, DiEdge]]
   
= as.map((a: Int) => (a, h.filter((e: Entry) => e.attr == a))).toMap

    println
(m(1))
    println
(m(2))

   
// what I really want
   
// val m2 = h.groupBy( (e: Entry) => e.attr )     // does not compile
 
}
}


Peter Empen

unread,
Jul 14, 2018, 6:49:00 AM7/14/18
to scala-graph
I now better understand. I'd suggest

object Martin extends App {

import scalax.collection.GraphPredef._
import scalax.collection.Graph

case class Entry(name: String, attr: Int)


val a = Entry("A", 1)
val b = Entry("B", 1)
val c = Entry("C", 2)
val d = Entry("D", 2)
val e = Entry("E", 2)

  val h = Graph(a ~> b, c ~> d, c ~> e)

val m2 = h.groupBy {
case h.InnerNode(inner) => inner.value.attr
case h.InnerEdge(h.EdgeT(source, _)) => source.attr
}

m2 foreach println
}

You still need to decide on how to handle different attr's sitting at a given edge. I'm just reading the source.

Hope this helps
Peter
Reply all
Reply to author
Forward
0 new messages