Graph Theory

Currently implemented for the Jung library.

Eventually Axle will provide its own basic Graph implementation, which will remove Jung as a dependency of axle-core.

Directed Graph

Example with String is the vertex value and an Edge type with two values (a String and an Int) to represent the edges

val (a, b, c, d) = ("a", "b", "c", "d")

class Edge(val s: String, val i: Int)

Invoke the DirectedGraph typeclass with type parameters that denote that we will use Jung's DirectedSparseGraph as the graph type, with String and Edge as vertex and edge values, respectively.

import edu.uci.ics.jung.graph.DirectedSparseGraph
import axle.algebra._
import axle.jung._

val jdg = DirectedGraph.k2[DirectedSparseGraph, String, Edge]

Use the jdg witness's make method to create the directed graph

val dg = jdg.make(List(a, b, c, d),
  List(
    (a, b, new Edge("hello", 1)),
    (b, c, new Edge("world", 4)),
    (c, d, new Edge("hi", 3)),
    (d, a, new Edge("earth", 1)),
    (a, c, new Edge("!", 7)),
    (b, d, new Edge("hey", 2))))
import cats.implicits._
import axle.syntax.directedgraph.directedGraphOps
import axle.syntax.finite.finiteOps

dg.vertexProjection.size
// res1: Int = 4

dg.edgeProjection.size
// res2: Int = 6

dg.findVertex(_ === "a").map(v => dg.successors(v))
// res3: Option[Set[String]] = Some(value = Set("b", "c"))

dg.findVertex(_ === "c").map(v => dg.successors(v))
// res4: Option[Set[String]] = Some(value = Set("d"))

dg.findVertex(_ === "c").map(v => dg.predecessors(v))
// res5: Option[Set[String]] = Some(value = Set("a", "b"))

dg.findVertex(_ === "c").map(v => dg.neighbors(v))
// res6: Option[Set[String]] = Some(value = Set("a", "b", "d"))

Create a Visualization of the graph

import cats.Show

implicit val showEdge: Show[Edge] = new Show[Edge] {
  def show(e: Edge): String = e.s + " " + e.i
}

import axle.visualize._

val dVis = DirectedGraphVisualization[DirectedSparseGraph[String, Edge], String, Edge](
  dg,
  width = 300,
  height = 300,
  border = 10,
  radius = 10,
  arrowLength = 10,
  color = Color.green,
  borderColor = Color.black,
  fontSize = 12
)

Render as sn SVG file

import axle.web._
import cats.effect._

dVis.svg[IO]("docwork/images/SimpleDirectedGraph.svg").unsafeRunSync()

directed graph

Undirected Graph

An undirected graph using the same dataa:

val (a, b, c, d) = ("a", "b", "c", "d")

class Edge(val s: String, val i: Int)

Invoke the UndirectedGraph typeclass with type parameters that denote that we will use Jung's UndirectedSparseGraph as the graph type, with String and Edge as vertex and edge values, respectively.

import edu.uci.ics.jung.graph.UndirectedSparseGraph
import axle.algebra._
import axle.jung._

val jug = UndirectedGraph.k2[UndirectedSparseGraph, String, Edge]

Use the jug witness's make method to create the undirected graph

val ug = jug.make(List(a, b, c, d),
  List(
    (a, b, new Edge("hello", 10)),
    (b, c, new Edge("world", 1)),
    (c, d, new Edge("hi", 3)),
    (d, a, new Edge("earth", 7)),
    (a, c, new Edge("!", 1)),
    (b, d, new Edge("hey", 2))))
import cats.implicits._
import axle.syntax.undirectedgraph.undirectedGraphOps
import axle.syntax.finite.finiteOps

ug.vertexProjection.size
// res9: Int = 4

ug.edgeProjection.size
// res10: Int = 6

ug.findVertex(_ == "c").map(v => ug.neighbors(v))
// res11: Option[Iterable[String]] = Some(value = Iterable("a", "b", "d"))

ug.findVertex(_ == "a").map(v => ug.neighbors(v))
// res12: Option[Iterable[String]] = Some(value = Iterable("b", "c", "d"))

Create a Visualization of the graph

import cats.Show

implicit val showEdge: Show[Edge] = new Show[Edge] {
  def show(e: Edge): String = e.s + " " + e.i
}

import axle.visualize._

val uVis = UndirectedGraphVisualization[UndirectedSparseGraph[String, Edge], String, Edge](
  ug,
  width = 300,
  height = 300,
  border = 10,
  color = Color.yellow)

Render as an SVG file

import axle.web._
import cats.effect._

uVis.svg[IO]("docwork/images/SimpleUndirectedGraph.svg").unsafeRunSync()

undirected graph