### Find Shortest Path with Multiple Start Nodes (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates how to calculate the cheapest path from one of several possible starting nodes to a single destination. This example finds the cheapest way to get from either Artemis or Balela to Dentana. ```Clojure (alg/shortest-path airports {:start-nodes [:Artemis :Balela], :end-node :Dentana, :cost-attr :price}) ``` -------------------------------- ### Visualize Ubergraph Graph Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to visualize a graph using the `uber/viz-graph` function. This functionality requires GraphViz to be installed. The first example shows basic visualization, and the second shows how to save the visualization to a file with a specified format and filename. ```Clojure => (uber/viz-graph airports) ``` ```Clojure => (uber/viz-graph airports {:save {:filename "C:/temp/airports.png" :format :png}}) ``` -------------------------------- ### Find Shortest Path with Multiple End Nodes (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Shows how to determine the cheapest path from a single start node to one of several possible end nodes. This example helps find the cheapest airport for a visitor from Dentana to fly into (Artemis or Balela). ```Clojure (alg/shortest-path airports {:start-node :Dentana, :end-nodes [:Artemis :Balela], :cost-attr :price}) ``` -------------------------------- ### Clojure: Retrieving Node and Edge Attributes Examples Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates the basic usage of `node-with-attrs` and `edge-with-attrs` to retrieve a node or an edge along with its associated attribute map from a Ubergraph instance. ```clojure (node-with-attrs g :a) => [:a {:color :red}] (edge-with-attrs g #ubergraph.core.Edge{:id #uuid "5341be54-e501-4bcb-b22d-5fbcb5c828df", :src :a, :dest :c}) => [:a :c {:weight 10}] ``` -------------------------------- ### List All Reachable Destinations from a Source Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to get a list of all reachable destination nodes from a pre-computed `AllPathsFromSource` object. This provides a quick overview of all nodes accessible from the specified source. ```Clojure => (alg/all-destinations out-of-coulton) ``` -------------------------------- ### Find Shortest Path with End Node Predicate (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Explains how to use a predicate function to define qualifying end nodes instead of listing them explicitly. This example finds the cheapest way to get from Coulton to any small city (population less than 3000) for a weekend getaway. ```Clojure (alg/shortest-path airports {:start-node :Coulton, :end-node? (fn [n] (> 3000 (uber/attr airports n :population))), :cost-attr :price}) ``` -------------------------------- ### Ubergraph Constructor Initialization Patterns Source: https://github.com/engelberg/ubergraph/blob/master/README.md Examples of various data structures and patterns that can be passed as 'inits' to Ubergraph constructors. These patterns allow for flexible graph creation by defining nodes, edges, and their attributes in different formats, including simple lists and various adjacency map structures. ```Clojure [node attribute-map] ``` ```Clojure [src dest] ``` ```Clojure [src dest weight] ``` ```Clojure [src dest attribute-map] ``` ```Clojure {1 [2 3], 2 [3]} ``` ```Clojure {:a {:b 2, :c 3}} ``` ```Clojure {:a {:b {:weight 2}, :c {:weight 3}}} ``` -------------------------------- ### Demonstrate Shortest Path without Heuristic (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md An example of finding a 'word ladder' using `shortest-path` without a heuristic function. This snippet shows the time taken and the resulting path for transforming 'amigo' to 'enter' in a word graph. ```Clojure => (time (alg/nodes-in-path (alg/shortest-path wg "amigo" "enter"))) "Elapsed time: 25.430857 msecs" ("amigo" "amino" "amine" "amide" "abide" "abode" "anode" "anole" "anile" "anise" "arise" "prise" "prime" "prims" "pries" "prier" "pryer" "payer" "pater" "eater" "enter") ``` -------------------------------- ### Shortest Path with Custom Cost Function Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to use a custom cost function (`:cost-fn`) for pathfinding. This example prioritizes the number of edges by imposing a large base cost per edge, with `:distance` as a tiebreaker, showcasing advanced pathfinding capabilities. ```Clojure => (alg/pprint-path (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg, :cost-fn (fn [e] (+ 100000 (uber/attr airports e :distance)))})) ``` -------------------------------- ### Find Shortest Path with Edge Filtering Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to use an `:edge-filter` to exclude certain edges from the pathfinding algorithm. This example finds the fewest hops between two nodes while avoiding paths that use the `:AirLux` airline. ```Clojure (alg/shortest-path airports {:start-node :Dentana, :end-node :Egglesberg, :edge-filter (fn [e] (not= :AirLux (uber/attr airports e :airline)))}) ``` -------------------------------- ### Traverse Graph and Get Sequence of Discovered Paths Source: https://github.com/engelberg/ubergraph/blob/master/README.md Shows how to enable traversal mode (`:traverse true`) in `shortest-path` to get a sequence of path objects as they are discovered during the search process. This allows inspection of the search order, such as in a breadth-first search. ```Clojure => (alg/shortest-path airports {:start-node :Artemis, :traverse true}) ``` -------------------------------- ### Shortest Path with Negative Edge Weights (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates how `shortest-path` handles graphs with negative edge weights by automatically switching to the Bellman-Ford algorithm. This example defines a graph with negative weights and finds the shortest path from 's' to 'b'. ```Clojure (def negative-weight-example (uber/digraph [:s :a 5] [:s :c -2] [:c :a 2] [:c :d 3] [:a :b 1] [:b :c 2] [:b :d 7] [:b :t 3] [:d :t 10])) => (alg/shortest-path negative-weight-example :s :b :weight) ``` -------------------------------- ### Find Shortest Path using Breadth-First Search Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates how to find the shortest path between two nodes in a graph using `alg/shortest-path`. By default, this performs a breadth-first search, returning a path object. The example finds the path from :Artemis to :Egglesberg, showing the raw path object output. ```Clojure => (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg}) #ubergraph.alg.Path{:list-of-edges #, :cost 2, :end :Egglesberg, :last-edge #ubergraph.core.UndirectedEdge{:id #uuid "827f7769-db20-45c4-b3d9-272f47e87bcc", :src :Balela, :dest :Egglesberg, :mirror? false}} ``` -------------------------------- ### Shortest Path in Infinite Graph with Transition Function (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md This Clojure example demonstrates finding the shortest path in an infinite graph where nodes are natural numbers. The graph's edges are defined by a transition function allowing incrementing or doubling. The result is then pretty-printed to show the path and associated edge labels. ```clojure => (-> (alg/shortest-path (fn [n] [{:dest (* n 2) :label :double} {:dest (inc n) :label :increment}]) 1 19) alg/pprint-path) Total Cost: 6 1 -> 2 {:label :double} 2 -> 4 {:label :double} 4 -> 8 {:label :double} 8 -> 9 {:label :increment} 9 -> 18 {:label :double} 18 -> 19 {:label :increment} ``` -------------------------------- ### Extend Ubergraphs by Adding Nodes and Edges Source: https://github.com/engelberg/ubergraph/blob/master/README.md Provides examples of various functions for extending an existing Ubergraph. This includes `build-graph` for adding new initializers, `add-edges` and `add-edges*` for adding connections, and `add-nodes`, `add-nodes*`, `add-nodes-with-attrs`, and `add-nodes-with-attrs*` for adding nodes, optionally with attributes. The `*` variants accept sequences of arguments. ```clojure (build-graph graph1 [:d :a] [:d :e]) (add-edges graph1 [:d :a] [:d :e]) (add-edges* graph1 [[:d :a] [:d :e]]) (add-nodes graph1 :e) (add-nodes* graph1 [:e]) (add-nodes-with-attrs graph1 [:a {:happy true}] [:b {:sad true}]) (add-nodes-with-attrs* graph1 [[:a {:happy true}] [:b {:sad true}]]) ``` -------------------------------- ### Simplified Shortest Path Function Call Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates the 3-arity version of `alg/shortest-path`, which provides a more concise way to find the shortest path between two specific nodes. This simplifies the function call by directly passing the start and end nodes as arguments, rather than embedding them in a map. ```Clojure => (alg/shortest-path airports :Artemis :Egglesberg) ``` -------------------------------- ### Require Ubergraph Namespace in Clojure Source: https://github.com/engelberg/ubergraph/blob/master/README.md Example of requiring the 'ubergraph.core' namespace in a Clojure project's namespace header. It aliases the namespace as 'uber' for convenient access to its functions, making it easier to call Ubergraph's utilities. ```Clojure (ns example.core (:require [ubergraph.core :as uber])) ``` -------------------------------- ### Filter Traversed Paths by Minimum and Maximum Cost Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates how to apply cost constraints (`:min-cost`, `:max-cost`) when traversing paths. This example finds all cities that are exactly two hops (cost 2) away from `:Egglesberg` in a breadth-first search. ```Clojure => (map alg/end-of-path (alg/shortest-path airports {:start-node :Egglesberg, :traverse true, :min-cost 2, :max-cost 2})) ``` -------------------------------- ### Find Shortest Path with Node Filtering (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to find the shortest path between two nodes, filtering intermediate nodes based on a population attribute. This example finds the shortest path from Egglesberg to Artemis, only traversing cities with a population of at least 3000. ```Clojure (alg/shortest-path airports {:start-node :Egglesberg, :end-node :Artemis, :node-filter (fn [n] (<= 3000 (uber/attr airports n :population))), :cost-attr :distance}) ``` -------------------------------- ### Define Sample Multigraph for Ubergraph in Clojure Source: https://github.com/engelberg/ubergraph/blob/master/README.md This Clojure code defines a sample multigraph named `airports` using Ubergraph's `multigraph` and `add-directed-edges` functions. It includes node attributes such as population and various edge attributes like color, airline, price, and distance, representing flight routes between cities. This graph serves as an example for shortest path calculations. ```clojure (def airports (-> (uber/multigraph ; city attributes [:Artemis {:population 3000}] [:Balela {:population 2000}] [:Coulton {:population 4000}] [:Dentana {:population 1000}] [:Egglesberg {:population 5000}] ; airline routes [:Artemis :Balela {:color :blue, :airline :CheapAir, :price 200, :distance 40}] [:Artemis :Balela {:color :green, :airline :ThriftyLines, :price 167, :distance 40}] [:Artemis :Coulton {:color :green, :airline :ThriftyLines, :price 235, :distance 120}] [:Artemis :Dentana {:color :blue, :airline :CheapAir, :price 130, :distance 160}] [:Balela :Coulton {:color :green, :airline :ThriftyLines, :price 142, :distance 70}] [:Balela :Egglesberg {:color :blue, :airline :CheapAir, :price 350, :distance 50}]) (uber/add-directed-edges [:Dentana :Egglesberg {:color :red, :airline :AirLux, :price 80, :distance 50}] [:Egglesberg :Coulton {:color :red, :airline :AirLux, :price 80, :distance 30}] [:Coulton :Dentana {:color :red, :airline :AirLux, :price 80, :distance 65}]))) ``` -------------------------------- ### Overriding Ubergraph Constructor Ambiguity with Metadata Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to use Clojure metadata (`^:node` and `^:edge`) to explicitly guide the Ubergraph constructor's interpretation of ambiguous input patterns. This ensures that a given data structure is treated specifically as a node or an edge, resolving potential conflicts in interpretation. ```Clojure ^:node [{:a 1} {:b 2}] ``` ```Clojure ^:edge [{:a 1} {:b 2}] ``` -------------------------------- ### Find Cheapest Path by Price in Ubergraph Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates finding the shortest path based on a different edge attribute, `:price`. This highlights Ubergraph's flexibility in allowing searches on any attribute, unlike systems with a single 'weight' field. ```Clojure => (alg/pprint-path (alg/shortest-path airports :Artemis :Egglesberg :price)) ``` -------------------------------- ### Pretty Print Ubergraph Path Source: https://github.com/engelberg/ubergraph/blob/master/README.md Shows how to use `alg/pprint-path` to display a human-readable summary of a graph path. This function includes the total cost and a list of edges with their attributes, making it useful for quick inspection at the REPL. ```Clojure => (alg/pprint-path (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg})) Total Cost: 2 :Artemis -> :Dentana {:airline :CheapAir, :color :blue, :price 130, :distance 160} :Dentana -> :Egglesberg {:airline :AirLux, :color :red, :price 80, :distance 50} ``` -------------------------------- ### Pre-compute All Shortest Paths from a Source Source: https://github.com/engelberg/ubergraph/blob/master/README.md Shows how to pre-compute all shortest paths from a single source node (`:Coulton`) based on a cost attribute (`:distance`). This returns an `AllPathsFromSource` protocol instance, which acts as an efficient lookup table for subsequent path queries from the same source. ```Clojure (def out-of-coulton (alg/shortest-path airports {:start-node :Coulton, :cost-attr :distance})) ``` -------------------------------- ### Compact Shortest Path Query by Attribute Source: https://github.com/engelberg/ubergraph/blob/master/README.md Shows a more concise syntax for querying the shortest path between two nodes when a specific cost attribute (like `:distance`) is used. This is a common and compact way to express such queries. ```Clojure (alg/shortest-path airports :Coulton :Egglesberg :distance) ``` -------------------------------- ### Initialize Ubergraph with Custom Edge Attribute Maps Source: https://github.com/engelberg/ubergraph/blob/master/README.md Shows how to define edges with a full attribute map, allowing for multiple custom properties like `:price` and `:distance` in addition to `:weight`. This highlights Ubergraph's flexible attribute handling, where weights are not privileged fields. The `pprint` output confirms the storage of all specified attributes. ```clojure (def graph3 (uber/graph [:a :b {:weight 2 :price 200 :distance 10}] [:a :c {:weight 3 :price 300 :distance 20}])) => (uber/pprint graph3) Graph 3 Nodes: :c :b :a 2 Edges: :a <-> :c {:weight 3, :price 300, :distance 20} :a <-> :b {:weight 2, :price 200, :distance 10} ``` -------------------------------- ### Ubergraph shortest-path Function API Reference Source: https://github.com/engelberg/ubergraph/blob/master/README.md Detailed API documentation for Ubergraph's `shortest-path` function, outlining its parameters, return types, and various search specification options including cost functions, filters, and traversal settings. It explains how to specify start/end nodes, define custom costs, and filter nodes/edges for complex graph searches. ```APIDOC Finds the shortest path in graph g. You must specify a start node or a collection of start nodes from which to begin the search, however specifying an end node is optional. If an end node condition is specified, this function will return an implementation of the IPath protocol, representing the shortest path. Otherwise, it will search out as far as it can go, and return an implementation of the IAllPathsFromSource protocol, which contains all the data needed to quickly find the shortest path to a given destination (using IAllPathsFromSource's `path-to` protocol function). If :traverse is set to true, then the function will instead return a lazy sequence of the shortest paths from the start node(s) to each node in the graph in the order the nodes are encountered by the search process. Takes a search-specification map which must contain: Either :start-node (single node) or :start-nodes (collection) Map may contain the following entries: Either :end-node (single node) or :end-nodes (collection) or :end-node? (predicate function) :cost-fn - A function that takes an edge as an input and returns a cost (defaults to every edge having a cost of 1, i.e., breadth-first search if no cost-fn given) :cost-attr - Alternatively, can specify an edge attribute to use as the cost :heuristic-fn - A function that takes a node as an input and returns a lower-bound on the distance to a goal node, used to guide the search and make it more efficient. :node-filter - A predicate function that takes a node and returns true or false. If specified, only nodes that pass this node-filter test will be considered in the search. :edge-filter - A predicate function that takes an edge and returns true or false. If specified, only edges that pass this edge-filter test will be considered in the search. Map may contain the following additional entries if a traversal sequence is desired: :traverse true - Changes output to be a sequence of paths in order encountered. :min-cost - Filters traversal sequence, only applies if :traverse is set to true :max-cost - Filters traversal sequence, only applies if :traverse is set to true shortest-path has specific arities for the two most common combinations: (shortest-path g start-node end-node) (shortest-path g start-node end-node cost-attr) ``` -------------------------------- ### Create a Basic Ubergraph with Undirected Edges Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to initialize a simple Ubergraph using the `uber/graph` constructor. Edges are treated as bidirectional and undirected by default. The `uber/pprint` function is used to display the resulting graph structure, showing its nodes and edges. ```clojure (def graph1 (uber/graph [:a :b] [:a :c] [:b :d])) => (uber/pprint graph1) Graph 4 Nodes: :d :c :b :a 3 Edges: :b <-> :d :a <-> :c :a <-> :b ``` -------------------------------- ### Clojure: Importing Edges with Attributes Between Graphs Source: https://github.com/engelberg/ubergraph/blob/master/README.md Shows a practical application of `edge-with-attrs` for transferring complete edge information, including attributes, from one Ubergraph instance to another using `add-edges*`. ```clojure (add-edges* g1 (map (partial edge-with-attrs g2) (edges g2))) ``` -------------------------------- ### Find Shortest Path by Distance in Ubergraph Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to find the shortest path between two nodes in a graph using the `shortest-path` algorithm, specifying `:distance` as the cost attribute. The `pprint-path` function is used to display the path details and total cost. ```Clojure => (alg/pprint-path (alg/shortest-path airports {:start-node :Coulton, :end-node :Egglesberg, :cost-attr :distance})) ``` -------------------------------- ### Generate Ubergraph from Traversed Shortest Path (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to use `alg/paths->graph` to create an ubergraph from the results of `alg/shortest-path` when the `:traverse true` option is used. This captures all explored edges during the search process, providing insight into the search's progression. ```clojure => (-> (alg/shortest-path (fn [n] [{:dest (* n 2) :label :double} {:dest (inc n) :label :increment}]) {:start-node 1, :end-node 9, :traverse true}) alg/paths->graph uber/pprint) Digraph 9 Nodes: 1 {:cost-of-path 0} 4 {:cost-of-path 2} 6 {:cost-of-path 3} 3 {:cost-of-path 2} 2 {:cost-of-path 1} 9 {:cost-of-path 4} 5 {:cost-of-path 3} 16 {:cost-of-path 4} 8 {:cost-of-path 3} 8 Edges: 1 -> 2 {:label :double} 4 -> 8 {:label :double} 4 -> 5 {:label :increment} 3 -> 6 {:label :double} 2 -> 4 {:label :double} 2 -> 3 {:label :increment} 8 -> 16 {:label :double} 8 -> 9 {:label :increment} ``` -------------------------------- ### Query Edge Attributes with Edge Descriptions (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to retrieve specific attributes of an edge, such as weight or color, by providing an edge description. This includes using a simple [src dest weight] or [src dest attribute-map] format to identify the target edge. ```Clojure (weight g [1 4 {:color :red}]) (attr g [:a :b 5] :color) ``` -------------------------------- ### Ubergraph Constructor Dispatch Logic (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Explains how the versatile `ubergraph` constructor dynamically selects the appropriate graph type (multigraph, multidigraph, graph, or digraph) based on two boolean parameters: `allow-parallel-edges?` and `undirected-graph?`. ```Clojure (ubergraph true true ...) (ubergraph true false ...) (ubergraph false true ...) (ubergraph false false ...) ``` -------------------------------- ### Generate Ubergraph from Filtered State Space (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates using `alg/paths->graph` to capture the entire reachable state space when `alg/shortest-path` is called without an end condition, but with a `:node-filter` to constrain the search. This reveals all transitions within the filtered space, useful for exploring bounded infinite state spaces. ```clojure => (-> (alg/shortest-path (fn [n] [{:dest (* n 2) :label :double} {:dest (inc n) :label :increment}]) {:start-node 1, :node-filter #(< % 12)}) alg/paths->graph uber/pprint) Digraph 11 Nodes: 7 {:cost-of-path 4} 1 {:cost-of-path 0} 4 {:cost-of-path 2} 6 {:cost-of-path 3} 3 {:cost-of-path 2} 2 {:cost-of-path 1} 11 {:cost-of-path 5} 9 {:cost-of-path 4} 5 {:cost-of-path 3} 10 {:cost-of-path 4} 8 {:cost-of-path 3} 10 Edges: 1 -> 2 {:label :double} 4 -> 5 {:label :increment} 4 -> 8 {:label :double} 6 -> 7 {:label :increment} 3 -> 6 {:label :double} 2 -> 3 {:label :increment} 2 -> 4 {:label :double} 5 -> 10 {:label :double} 10 -> 11 {:label :increment} 8 -> 9 {:label :increment} ``` -------------------------------- ### shortest-path Function Transition Function Definition Source: https://github.com/engelberg/ubergraph/blob/master/README.md This docstring defines the `shortest-path` function's input for graph representation. It explains that a graph can be an `ubergraph` or a `transition function`, detailing the structure of the transition function: `(fn [node] [{:dest successor1, ...}])`. ```text Finds the shortest path in g, where g is either an ubergraph or a transition function that implies a graph. A transition function takes the form: (fn [node] [{:dest successor1, ...} {:dest successor2, ...} ...]) ``` -------------------------------- ### Extract Specific Path from Pre-computed Source Paths Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates how to retrieve a specific shortest path to a destination node (`:Artemis`) from a previously computed `AllPathsFromSource` lookup table. The `path-to` protocol function is used for this efficient lookup. ```Clojure => (alg/pprint-path (alg/path-to out-of-coulton :Artemis)) ``` -------------------------------- ### Access Details from Ubergraph Path Object Source: https://github.com/engelberg/ubergraph/blob/master/README.md After finding a path, these snippets demonstrate how to extract various details from the returned path object using functions like `alg/nodes-in-path`, `alg/edges-in-path`, `alg/start-of-path`, `alg/end-of-path`, `alg/cost-of-path`, and `alg/last-edge-of-path`. This allows programmatic access to the path's components and properties. ```Clojure => (alg/nodes-in-path (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg})) (:Artemis :Dentana :Egglesberg) ``` ```Clojure => (alg/edges-in-path (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg})) (#ubergraph.core.UndirectedEdge{:id #uuid "4e79cfc4-e15d-42ed-8cf6-44476f2ed972", :src :Artemis, :dest :Dentana, :mirror? false} #ubergraph.core.Edge{:id #uuid "4f1b2958-c355-4512-a5ca-9e89f5f49207", :src :Dentana, :dest :Egglesberg}) ``` ```Clojure => (alg/start-of-path (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg})) :Artemis ``` ```Clojure => (alg/end-of-path (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg})) :Egglesberg ``` ```Clojure => (alg/cost-of-path (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg})) 2 ``` ```Clojure => (alg/last-edge-of-path (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg})) #ubergraph.core.UndirectedEdge{:id #uuid "827f7769-db20-45c4-b3d9-272f47e87bcc", :src :Balela, :dest :Egglesberg, :mirror? false} ``` -------------------------------- ### Ubergraph Multigraph Constructor and Parallel Edges Source: https://github.com/engelberg/ubergraph/blob/master/README.md Introduces the `multigraph` constructor, which enables the creation of multigraphs allowing parallel edges between nodes. Explains how Ubergraph solves the limitation of Loom by identifying edges with a unique ID in addition to source and destination, allowing multiple edges between the same pair of nodes. ```APIDOC Ubergraph Multigraphs: multigraph(): - Constructor for creating a multigraph. - Allows "parallel edges" (multiple edges) between the same pair of nodes. - Edges are identified by a unique ID in addition to source and destination. ``` -------------------------------- ### Filter Edges Using Comprehensive Query Maps (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Shows how `find-edges` can accept a detailed query-map to filter edges based on source, destination, and arbitrary attributes like weight or size. It notes that queries without explicit source and destination may be less efficient. ```Clojure (find-edges g {:src :a, :dest :b, :weight 5}) (find-edges g {:dest :b, :size :large}) (find-edges g {:color :red}) ``` -------------------------------- ### Accessing Loom Protocols via Ubergraph Alias Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how Ubergraph provides convenient access to Loom's protocol functions directly through its own namespace alias ('uber'). This simplifies calls to common graph operations like 'out-edges' and 'add-attr', avoiding the need to explicitly reference Loom's specific namespaces. ```Clojure ;; Using Loom directly (loom.graph/out-edges graph node) (loom.attr/add-attr graph edge :key val) ;; Using Ubergraph alias (uber/out-edges graph node) (uber/add-attr graph edge :key val) ``` -------------------------------- ### Ubergraph Digraph Constructor and Edge Addition Source: https://github.com/engelberg/ubergraph/blob/master/README.md Explains the `digraph` constructor for creating directed graphs in Ubergraph. Notes that digraphs default to adding one-way directed edges but support adding undirected edges using `add-undirected-edges` or `add-undirected-edges*`. ```APIDOC Ubergraph Digraphs: digraph(): - Constructor for creating a directed graph. - Default behavior: adds edges as one-way directed edges. add-undirected-edges(graph: Graph, edges: list): - Adds undirected edges to a directed graph. add-undirected-edges*(graph: Graph, edges: list): - Adds undirected edges to a directed graph (alternative/variadic form). ``` -------------------------------- ### Find Shortest Path with Heuristic Function (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates the use of a heuristic function (`word-edit-distance`) with `shortest-path` to optimize the search for a word ladder. This snippet shows the reduced search time compared to the non-heuristic approach for transforming 'amigo' to 'enter'. ```Clojure => (time (alg/nodes-in-path (alg/shortest-path wg {:start-node "amigo" :end-node "enter" :heuristic-fn #(word-edit-distance % "enter")}))) ``` -------------------------------- ### Find All Edges Between Two Nodes (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates the fundamental usage of the `find-edges` function to locate all edges connecting a specified source node to a destination node within the graph `g`. ```Clojure (find-edges g :a :b) ``` -------------------------------- ### Define Sample Airport Graph Data Source: https://github.com/engelberg/ubergraph/blob/master/README.md This snippet defines the nodes and edges of an airport graph, including attributes like airline, color, price, and distance for each connection. It represents the raw data structure used to build the graph within the Clojure environment. ```Clojure :Coulton -> :Dentana {:airline :AirLux, :color :red, :price 80, :distance 65} :Balela <-> :Egglesberg {:airline :CheapAir, :color :blue, :price 350, :distance 50} :Balela <-> :Coulton {:airline :ThriftyLines, :color :green, :price 142, :distance 70} :Artemis <-> :Dentana {:airline :CheapAir, :color :blue, :price 130, :distance 160} :Artemis <-> :Coulton {:airline :ThriftyLines, :color :green, :price 235, :distance 120} :Artemis <-> :Balela {:airline :CheapAir, :color :blue, :price 200, :distance 40} :Artemis <-> :Balela {:airline :ThriftyLines, :color :green, :price 167, :distance 40} ``` -------------------------------- ### Add Ubergraph Leiningen Dependency Source: https://github.com/engelberg/ubergraph/blob/master/README.md Instructions to add Ubergraph as a dependency in a Leiningen project, specifying the version '0.9.0'. This line should be added to the project's 'project.clj' file under the ':dependencies' key. ```Clojure [ubergraph "0.9.0"] ``` -------------------------------- ### Serialize Ubergraph to EDN (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md Shows how to convert an ubergraph object into an EDN (Extensible Data Notation) representation using the `uber/ubergraph->edn` function. This allows for easy serialization of graph structures using standard EDN tools or conversion to other formats like JSON. ```clojure => (uber/ubergraph->edn graph3) {:allow-parallel? false, :undirected? true, :nodes [[:a {}] [:b {}] [:c {}]], :directed-edges [], :undirected-edges [[:a :b {:weight 2, :price 200, :distance 10}] [:a :c {:weight 3, :price 300, :distance 20}]]} ``` -------------------------------- ### Retrieve All Edges from an Ubergraph Graph Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to retrieve all edges from an Ubergraph graph using `uber/edges` and illustrates the internal structure of `ubergraph.core.UndirectedEdge` and `ubergraph.core.Edge` objects, including their UUIDs and mirror properties for undirected edges. ```clojure => (-> (uber/graph [:a :b]) (uber/add-directed-edges [:a :c]) uber/edges) (#ubergraph.core.UndirectedEdge{:id #uuid "8a8a69a4-f7b9-4992-b752-c3d976a32f21", :src :b, :dest :a, :mirror? true} #ubergraph.core.Edge{:id #uuid "5341be54-e501-4bcb-b22d-5fbcb5c828df", :src :a, :dest :c} #ubergraph.core.UndirectedEdge{:id #uuid "8a8a69a4-f7b9-4992-b752-c3d976a32f21", :src :a, :dest :b, :mirror? false}) ``` -------------------------------- ### Define Ubergraph Edges with Numeric Weights Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates how to include numeric weights when defining edges during Ubergraph initialization. Ubergraph stores weights as an attribute under the `:weight` keyword, allowing flexible manipulation. The output shows edges with their associated weight attributes. ```clojure (def graph2 (uber/graph [:a :b 2] [:a :c 3] [:b :d 4])) => (uber/pprint graph2) Graph 4 Nodes: :d :c :b :a 3 Edges: :b <-> :d {:weight 4} :a <-> :c {:weight 3} :a <-> :b {:weight 2} ``` -------------------------------- ### Clojure: Destructuring Edges with Attributes for Iteration Source: https://github.com/engelberg/ubergraph/blob/master/README.md Illustrates how `edge-with-attrs` can be used in conjunction with Clojure's `for` comprehension to easily destructure and iterate over edges, accessing their source, destination, and attributes. ```clojure (for [[src dest attrs] (map (partial edge-with-attrs g) (edges g))] ...) ``` -------------------------------- ### Ubergraph Edge Object Structure and Protocols Source: https://github.com/engelberg/ubergraph/blob/master/README.md Details the internal representation of Ubergraph's `Edge` and `UndirectedEdge` objects, including their common fields (`:src`, `:dest`, `uuid`) and the mechanism for handling undirected edges as mirrored pairs. Also describes key protocol functions for edge manipulation and inspection. ```APIDOC Ubergraph Edge Objects: ubergraph.core.Edge: - :id (UUID): Unique identifier for the edge, pointing to its attribute map. - :src (Node): Source node of the edge. - :dest (Node): Destination node of the edge. ubergraph.core.UndirectedEdge: - :id (UUID): Unique identifier for the edge, shared by mirrored pairs. - :src (Node): Source node of the edge. - :dest (Node): Destination node of the edge. - :mirror? (boolean): True if this is the mirrored edge in an undirected pair, false otherwise. Ubergraph Edge Protocol Functions: mirror-edge?(edge: Edge) -> boolean: - Returns true if the edge is the mirrored edge in an undirected pair, false for directed edges and non-mirrored undirected edges. src(edge: Edge) -> Node: - Returns the source node of the edge. dest(edge: Edge) -> Node: - Returns the destination node of the edge. edge?(obj: any) -> boolean: - Returns true if the object is an Ubergraph edge. directed-edge?(edge: Edge) -> boolean: - Returns true if the edge is a directed edge. undirected-edge?(edge: Edge) -> boolean: - Returns true if the edge is an undirected edge. other-direction(edge: Edge) -> Edge | nil: - For undirected edges, returns the other edge in the pair. Returns nil for directed edges. ``` -------------------------------- ### Ubergraph Supported Loom Protocols and Attribute Operations Source: https://github.com/engelberg/ubergraph/blob/master/README.md Lists the graph manipulation functions supported by Ubergraph, which are compatible with Loom's protocols. It also details Ubergraph's unique attribute management functions for nodes and edges, emphasizing the ability to add, retrieve, remove, and set attribute maps. ```APIDOC Loom Protocol Functions: - nodes: Returns all nodes in the graph. - edges: Returns all edges in the graph. - has-node?: Checks if a node exists. - has-edge?: Checks if an edge exists. - successors: Returns successors of a node. - out-degree: Returns the out-degree of a node. - out-edges: Returns outgoing edges from a node. - predecessors: Returns predecessors of a node. - in-degree: Returns the in-degree of a node. - in-edges: Returns incoming edges to a node. - transpose: Returns the transpose of the graph. - weight: Extracts the weight attribute from an edge. - add-nodes: Adds one or more nodes. - add-nodes*: Adds multiple nodes from a sequence. - add-edges: Adds one or more edges. - add-edges*: Adds multiple edges from a sequence. - remove-nodes: Removes one or more nodes. - remove-nodes*: Removes multiple nodes from a sequence. - remove-edges: Removes one or more edges. - remove-edges*: Removes multiple edges from a sequence. - remove-all: Removes all nodes and edges. Ubergraph Attribute Management Functions: - attr: Retrieves a specific attribute for a node or edge. - attrs: Retrieves all attributes for a node or edge. - add-attr: Adds or updates a single attribute for a node or edge. - add-attrs: Adds or updates multiple attributes for a node or edge. - remove-attr: Removes a specific attribute from a node or edge. - remove-attrs: Removes multiple attributes from a node or edge. - set-attrs: Overwrites all attributes for a node or edge with a new map. ``` -------------------------------- ### Extracting Edge Descriptions from a Path with Weighted Edges (Clojure) Source: https://github.com/engelberg/ubergraph/blob/master/README.md This Clojure snippet shows how to retrieve edge descriptions from a path found using a transition function, where edges include `:weight` attributes. Since no explicit Ubergraph objects are used, the function returns vectors of `[src dest attribute-map]` instead of actual `Edge` objects. ```clojure => (-> (alg/shortest-path (fn [n] [{:dest (* n 2) :label :double, :weight 3} {:dest (inc n) :label :increment, :weight 1}]) {:start-node 1, :end-node 19, :cost-attr :weight}) alg/edges-in-path) ([1 2 {:label :increment, :weight 1}] [2 3 {:label :increment, :weight 1}] [3 4 {:label :increment, :weight 1}] [4 8 {:label :double, :weight 3}] [8 9 {:label :increment, :weight 1}] [9 18 {:label :double, :weight 3}] [18 19 {:label :increment, :weight 1}]) ``` -------------------------------- ### Ubergraph Attribute Access Functions: node-with-attrs and edge-with-attrs Source: https://github.com/engelberg/ubergraph/blob/master/README.md Documentation for Ubergraph's convenience functions to retrieve nodes or edges along with their associated attribute maps. These functions provide a 'view' that includes attributes, useful for destructuring or transferring graph data. ```APIDOC node-with-attrs(graph: Ubergraph, node: any) -> [node: any, attribute-map: map] edge-with-attrs(graph: Ubergraph, edge: Edge | EdgeDescription) -> [src: any, dest: any, attribute-map: map] ``` -------------------------------- ### Serialize Ubergraph to Clojure-readable String using print-dup Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to serialize an ubergraph instance into a Clojure-readable string using `pr-str` with `*print-dup*` bound to true. This method ensures that the exact UUIDs and any cached hash values of the graph are preserved, allowing for precise reconstruction of the original graph structure. ```clojure => (binding [*print-dup* true] (pr-str graph3)) "#=(ubergraph.core.Ubergraph. #=(clojure.lang.PersistentArrayMap/create {:a #ubergraph.core.NodeInfo[#=(clojure.lang.PersistentArrayMap/create {:b #{#ubergraph.core.UndirectedEdge[#uuid \"9189ba27-1298-411a-910e-3a32245f1489\", :a, :b, false]}, :c #{#ubergraph.core.UndirectedEdge[#uuid \"f18e3829-e53c-4f30-bed8-db5ec9327458\", :a, :c, false]}}), #=(clojure.lang.PersistentArrayMap/create {:b #{#ubergraph.core.UndirectedEdge[#uuid \"9189ba27-1298-411a-910e-3a32245f1489\", :b, :a, true]}, :c #{#ubergraph.core.UndirectedEdge[#uuid \"f18e3829-e53c-4f30-bed8-db5ec9237458\", :c, :a, true]}}), 2, 2], :b #ubergraph.core.NodeInfo[#=(clojure.lang.PersistentArrayMap/create {:a #{#ubergraph.core.UndirectedEdge[#uuid \"9189ba27-1298-411a-910e-3a32245f1489\", :b, :a, true]}}), #=(clojure.lang.PersistentArrayMap/create {:a #{#ubergraph.core.UndirectedEdge[#uuid \"9189ba27-1298-411a-910e-3a32245f1489\", :a, :b, false]}}), 1, 1], :c #ubergraph.core.NodeInfo[#=(clojure.lang.PersistentArrayMap/create {:a #{#ubergraph.core.UndirectedEdge[#uuid \"f18e3829-e53c-4f30-bed8-db5ec9327458\", :c, :a, true]}}), #=(clojure.lang.PersistentArrayMap/create {:a #{#ubergraph.core.UndirectedEdge[#uuid \"f18e3829-e53c-4f30-bed8-db5ec9327458\", :a, :c, false]}}), 1, 1]}) false true #=(clojure.lang.PersistentArrayMap/create {#uuid \"9189ba27-1298-411a-910e-3a32245f1489\" #=(clojure.lang.PersistentArrayMap/create {:weight 2, :price 200, :distance 10}), #uuid \"f18e3829-e53c-4f30-bed8-db5ec9327458\" #=(clojure.lang.PersistentArrayMap/create {:weight 3, :price 300, :distance 20})}) #=(clojure.lang.Atom. nil))" ``` -------------------------------- ### Define Custom Function for Edge Details Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to create a custom function (`airport-edge-details`) to extract specific attributes from edges in a path. This allows for flexible data extraction and transformation based on user-defined criteria, leveraging Clojure's functional capabilities like `juxt` and `map`. ```Clojure (def airport-edge-details (juxt uber/src uber/dest #(uber/attr airports % :airline))) => (->> (alg/shortest-path airports {:start-node :Artemis, :end-node :Egglesberg}) alg/edges-in-path (map airport-edge-details)) ([:Artemis :Dentana :CheapAir] [:Dentana :Egglesberg :AirLux]) ``` -------------------------------- ### Add Directed Edges to an Undirected Ubergraph Source: https://github.com/engelberg/ubergraph/blob/master/README.md Demonstrates how to introduce a directed edge into a Ubergraph that primarily treats edges as undirected. The `uber/add-directed-edges` function allows explicit creation of directed connections. The `pprint` output clearly shows the new directed edge (`:a -> :d`) alongside the existing undirected ones. ```clojure => (uber/pprint (uber/add-directed-edges graph1 [:a :d])) Graph 4 Nodes: :d :c :b :a 4 Edges: :b <-> :d :a -> :d :a <-> :c :a <-> :b ```