Skip to content
A tiny graph library in Clojure.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
resources Add logo May 9, 2019
src Make corallo available in ClojureScript May 13, 2019
test Make corallo available in ClojureScript May 13, 2019
.gitignore Do not ignore pom.xml May 13, 2019
LICENSE
README.md Make corallo available in ClojureScript May 13, 2019
deps.edn Make corallo available in ClojureScript May 13, 2019
pom.xml

README.md

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.

You can’t perform that action at this time.