7bridges-eu / corallo

A tiny graph library in Clojure.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

7bridges clj-odbp

corallo

A tiny graph library that can be used both from Clojure and ClojureScript.

Clojars Project

Rationale

corallo was born out of our need to handle and check dependencies in graphs which describe processes containing tasks to be executed. It was deemed helpful and independent enough to be extracted into and released as a library of its own.

Usage

A graph in corallo is a Clojure map. For instance:

(def g {:vertexes {:a {:value "1" :in #{} :out #{:b}}
                   :b {:value "2" :in #{:a} :out #{:c}}
                   :c {:value "3" :in #{:b} :out #{:d}}
                   :d {:value "4" :in #{:c} :out #{}}}
        :edges {[:a :b] {}
                [:b :c] {}
                [:c :d] {}}})

You can manipulate the graph by adding vertexes:

user> (require '[corallo.graph :as graph])
user> (graph/add-vertex g :e "5")
{:vertexes {:a {:value "1", :in #{}, :out #{:b}},
            :b {:value "2", :in #{:a}, :out #{:c}},
            :c {:value "3", :in #{:b}, :out #{:d}},
            :d {:value "4", :in #{:c}, :out #{}},
            :e {:value "5", :in #{}, :out #{}}},
 :edges {[:a :b] {}, [:b :c] {}, [:c :d] {}}}

Or you can add an edge between two vertexes:

user> (-> (graph/add-vertex g :e "5")
          (graph/add-edge :d :e))
{:vertexes {:a {:value "1", :in #{}, :out #{:b}},
            :b {:value "2", :in #{:a}, :out #{:c}},
            :c {:value "3", :in #{:b}, :out #{:d}},
            :d {:value "4", :in #{:c}, :out #{:e}},
            :e {:value "5", :in #{:d}, :out #{}}},
 :edges {[:a :b] {}, [:b :c] {}, [:c :d] {}, [:d :e] {}}}

You can set the value of a vertex after the graph has been created:

user> (graph/set-vertex-value g :a "0")
{:vertexes {:a {:value "0", :in #{}, :out #{:b}},
            :b {:value "2", :in #{:a}, :out #{:c}},
            :c {:value "3", :in #{:b}, :out #{:d}},
            :d {:value "4", :in #{:c}, :out #{}}},
 :edges {[:a :b] {}, [:b :c] {}, [:c :d] {}}}

Or you can remove a vertex:

user> (graph/remove-vertex g :d)
{:vertexes {:a {:value "1", :in #{}, :out #{:b}},
            :b {:value "2", :in #{:a}, :out #{:c}},
            :c {:value "3", :in #{:b}, :out #{}}},
 :edges {[:a :b] {}, [:b :c] {}}}

The operations in corallo.graph leverage Clojure immutability, so they return a new graph instead of modifying the original one.

Edges can have properties:

user> (-> (graph/add-vertex g :e "5")
          (graph/add-edge :d :e {:p1 "a property"}))
{:vertexes {:a {:value "1", :in #{}, :out #{:b}},
            :b {:value "2", :in #{:a}, :out #{:c}},
            :c {:value "3", :in #{:b}, :out #{:d}},
            :d {:value "4", :in #{:c}, :out #{:e}},
            :e {:value "5", :in #{:d}, :out #{}}},
 :edges {[:a :b] {}, [:b :c] {}, [:c :d] {}, [:d :e] {:p1 "a property"}}}

user> (-> (graph/add-vertex g :e "5")
          (graph/add-edge :d :e)
          (graph/set-edge-properties :a :b {:p1 "a property"}))
{:vertexes {:a {:value "1", :in #{}, :out #{:b}},
            :b {:value "2", :in #{:a}, :out #{:c}},
            :c {:value "3", :in #{:b}, :out #{:d}},
            :d {:value "4", :in #{:c}, :out #{:e}},
            :e {:value "5", :in #{:d}, :out #{}}},
 :edges {[:a :b] {:p1 "a property"}, [:b :c] {}, [:c :d] {}, [:d :e] {}}}

Like vertexes, edges can be removed from the graph:

user> (graph/remove-edge g :c :d)
{:vertexes {:a {:value "1", :in #{}, :out #{:b}},
            :b {:value "2", :in #{:a}, :out #{:c}},
            :c {:value "3", :in #{:b}, :out #{}},
            :d {:value "4", :in #{}, :out #{}}},
 :edges {[:a :b] {}, [:b :c] {}}}

You can query the graph for information:

user> (graph/neighbors g :b)
#{:c :a}

user> (graph/adjacent? g :a :c)
false
user> (graph/adjacent? g :b :c)
true

The graph can be topologically sorted:

user> (require '[corallo.operations :as operations])
user> (operations/topo-sort g)
(:a :b :c :d)

And you can verify if the graph is acyclic and complete:

user> (operations/acyclic-graph? g)
true
user> (-> (graph/add-edge g :d :a)
          operations/acyclic-graph?)
false

user> (operations/complete-graph? g)
true
user> (-> (graph/remove-edge g :b :c)
          operations/complete-graph?)
false

Finally, in a Clojure namespace the graph can be rendered as a PNG file thanks to tangle:

user> (require '[corallo.render :as render])
user> (render/graph->png g "/tmp/graph.png")
nil

And this is the resulting image for the graph g:

Note that you can also get the byte array representing the graph image:

user> (render/graph->byte-array g)
[-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 86, 0,
 0, 1, 105, 8, 2, 0, 0, 0, -119, 111, 72, 108, 0, 0, 0, 6, 98, 75, 71, 68, 0,
 -1, 0, -1, 0, -1, -96, -67, -89, ...]

License

Copyright © 2019 7bridges s.r.l.

Distributed under the Apache License 2.0.

About

A tiny graph library in Clojure.

License:Apache License 2.0


Languages

Language:Clojure 100.0%