about summary refs log tree commit diff
path: root/users/wpcarro/emacs/.emacs.d/wpc/graph.el
diff options
context:
space:
mode:
Diffstat (limited to 'users/wpcarro/emacs/.emacs.d/wpc/graph.el')
-rw-r--r--users/wpcarro/emacs/.emacs.d/wpc/graph.el95
1 files changed, 95 insertions, 0 deletions
diff --git a/users/wpcarro/emacs/.emacs.d/wpc/graph.el b/users/wpcarro/emacs/.emacs.d/wpc/graph.el
new file mode 100644
index 000000000000..9965622bb6d7
--- /dev/null
+++ b/users/wpcarro/emacs/.emacs.d/wpc/graph.el
@@ -0,0 +1,95 @@
+;;; graph.el --- Working with in-memory graphs -*- lexical-binding: t -*-
+
+;; Author: William Carroll <wpcarro@gmail.com>
+;; Version: 0.0.1
+;; URL: https://git.wpcarro.dev/wpcarro/briefcase
+;; Package-Requires: ((emacs "24.3"))
+
+;;; Commentary:
+;;
+;; Remember that there are optimal three ways to model a graph:
+;; 1. Edge List
+;; 2. Vertex Table (a.k.a. Neighbors Table)
+;; 3. Adjacency Matrix
+;;
+;; I may call these "Edges", "Neighbors", "Adjacencies" to avoid verbose naming.
+;; For now, I'm avoiding dealing with Adjacency Matrices as I don't have an
+;; immediate use-case for them.  This is subject to change.
+;;
+;; There are also hybrid representations of graphs that combine the three
+;; aforementioned models.  I believe Erlang's digraph module models graphs in
+;; Erlang Term Storage (i.e. ETS) this way.
+;; TODO: Verify this claim.
+;;
+;; Graphs can be weighted or unweighted.  They can also be directed or
+;; undirected.
+;; TODO: Create a table explaining all graph variants.
+;;
+;; TODO: Figure out the relationship of this module and tree.el, which should in
+;; principle overlap.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; For now, I'll support storing *either* neighbors or edges in the graph struct
+;; as long as both aren't set, since that introduces consistency issues.  I may
+;; want to handle that use-case in the future, but not now.
+(cl-defstruct graph neighbors edges)
+
+;; TODO: How do you find the starting point for a topo sort?
+(defun graph-sort (xs)
+  "Return a topological sort of XS.")
+
+(defun graph-from-edges (xs)
+  "Create a graph struct from the Edge List, XS.
+The user must pass in a valid Edge List since asserting on the shape of XS might
+  be expensive."
+  (make-graph :edges xs))
+
+(defun graph-from-neighbors (xs)
+  "Create a graph struct from a Neighbors Table, XS.
+The user must pass in a valid Neighbors Table since asserting on the shape of
+  XS might be expensive."
+  (make-graph :neighbors xs))
+
+(defun graph-instance? (xs)
+  "Return t if XS is a graph struct."
+  (graph-p xs))
+
+;; TODO: Model each of the mapping functions into an isomorphism.
+(defun graph-edges->neighbors (xs)
+  "Map Edge List, XS, into a Neighbors Table."
+  (prelude-assert (graph-instance? xs)))
+
+(defun graph-neighbors->edges (xs)
+  "Map Neighbors Table, XS, into an Edge List."
+  (prelude-assert (graph-instance? xs)))
+
+;; Below are three different models of the same unweighted, directed graph.
+
+(defvar graph-edges
+  '((a . b) (a . c) (a . e)
+    (b . c) (b . d)
+    (c . e)
+    (d . f)
+    (e . d) (e . f)))
+
+(defvar graph-neighbors
+  ((a b c e)
+   (b c d)
+   (c e)
+   (d f)
+   (e d g)
+   (f)))
+
+(provide 'graph)
+;;; graph.el ends here