# Graph

[![Actions Status](https://github.com/antononcube/Raku-Graph/actions/workflows/linux.yml/badge.svg)](https://github.com/antononcube/Raku-Graph/actions)
[![Actions Status](https://github.com/antononcube/Raku-Graph/actions/workflows/macos.yml/badge.svg)](https://github.com/antononcube/Raku-Graph/actions)
[![Actions Status](https://github.com/antononcube/Raku-Graph/actions/workflows/windows.yml/badge.svg)](https://github.com/antononcube/Raku-Graph/actions)

[![](https://raku.land/zef:antononcube/Graph/badges/version)](https://raku.land/zef:antononcube/Graph)
[![License: Artistic-2.0](https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg)](https://opensource.org/licenses/Artistic-2.0)
[![AAA4prediction](https://img.shields.io/badge/AAA4prediction-YouTube-red)](https://youtube.com/@AAA4prediction)

Raku package for (discrete mathematics) graph data structures and algorithms.

For a quick introduction see the video ["Graph demo in Raku (teaser)"](https://www.youtube.com/watch?v=0uJl9q7jIf8), [AAv1], (5 min.)

**Remark:** This package is *not* for drawing and rendering images. 
It is for the abstract data structure [***graph***](https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)). 

------

## Installation

From Zef ecosystem:

```
zef install Graph
```

From GitHub:

```
zef install https://github.com/antononcube/Raku-Graph.git
```

-------

## Design and implementation details

### Motivation

- Needless to say, Graph theory is huge.
  - But certain algorithms like path and cycle finding are relatively easy to implement
    and are fundamental both mathematics-wise and computer-science-wise.
- Having fast shortest path finding algorithms in graphs should be quite a booster for geography related projects.

### Design

- The central entity is the `Graph` class.
- `Graph` is as generic as possible.
  - Meaning it is for directed graphs.
  - Undirected graphs are represented as directed graphs.
    - I.e. with twice as many edges than necessary.
  - The current graph representation is with hash-of-hashes, (`adjacency-map`), that keeps from-to-weight relationships.
    - For example, `$g.adjacency-map<1><2>` gives the weight of the edge connecting vertex "1" to vertex "2".
  - The vertexes are only strings.
    - Not a "hard" design decision.
    - More general vertexes can be imitated (in the future) with vertex tags.
      - This is related to having (in Raku) sparse matrices with named rows and columns. 
- Since I know Mathematica / Wolfram Language (WL) very well, many of the method names and signatures are
  strongly influenced by the corresponding functions in WL.
  - I do not follow them too strictly, though.
  - One reason is that with Raku it is much easier to have and use named arguments than with WL.


### Implementation

- I was considering re-programming Perl5’s "Graph", [JHp1], into Raku, but it turned out it was easier to write the algorithms directly in Raku.
  - (To me at least...)
- The classes creating special graphs, like, grid-graph, star-graph, etc., are sub-classes of `Graph` 
   with files in the sub-directory "Graph".
  - See usage of such classes [here](./examples/Named-graphs.raku).

### Visualization

- Visualizing the graphs (the objects of the class `Graph`) is very important.
  - Has to be done from the very beginning of the development.
    - (Again, for me at least...)
- The class `Graph` has the methods `dot`, `graphml`, `mermaid`, and `wl` for representing the graphs for 
  GraphViz, GraphML, Mermaid-JS, and Wolfram Language (WL) respectively.
- Mermaid's graph nodes and edges arrangement algorithm can produce "unexpected" images for the standard, parameterized graphs.
  - Like, "grid graph", "cycle graph", etc.

### Performance

- So far, I have tested the path finding algorithms on "Graph" on small graphs and moderate size graphs.
  - The largest random graph I used had 1000 vertexes and 1000 edges.
  - Mathematica (aka Wolfram Language) can be 500 ÷ 10,000 faster.
  - I hope good heuristic functions for the "A* search" method would make `find-shortest-path` fast enough,
    for say country / continent route systems.
    - With the larger, 1,000-vertex random graphs finding paths with the method "a-star" is ≈50 faster than with the method "dijkstra". 
      - See [here](./examples/Performance.raku).
- Setting up comprehensive performance profiling and correctness testing is somewhat involved.
  - One main impediment is that in Raku one cannot expect and specify same random numbers between different sessions. 

------

## Usage examples

Here we create a dataset of edges:

```perl6
my @edges =
        { from => '1', to => '5', weight => 1 },
        { from => '1', to => '7', weight => 1 },
        { from => '2', to => '3', weight => 1 },
        { from => '2', to => '4', weight => 1 },
        { from => '2', to => '6', weight => 1 },
        { from => '2', to => '7', weight => 1 },
        { from => '2', to => '8', weight => 1 },
        { from => '2', to => '10', weight => 1 },
        { from => '2', to => '12', weight => 1 },
        { from => '3', to => '4', weight => 1 },
        { from => '3', to => '8', weight => 1 },
        { from => '4', to => '9', weight => 1 },
        { from => '5', to => '12', weight => 1 },
        { from => '6', to => '7', weight => 1 },
        { from => '9', to => '10', weight => 1 },
        { from => '11', to => '12', weight => 1 };

@edges.elems;
```

**Remark:** If there is no `weight` key in the edge records the weight of the edge is taken to be 1.

Here we create a graph object with the edges dataset:

```perl6
use Graph;

my $graph = Graph.new;
$graph.add-edges(@edges);
```

Here are basic properties of the graph:

```perl6
say 'edge count   : ', $graph.edge-count;
say 'vertex count : ', $graph.vertex-count;
say 'vertex list  : ', $graph.vertex-list;
```

Here we display the graph using [Mermaid-JS](https://mermaid.js.org), (see also, [AAp1]):

```perl6, output.lang=mermaid, output.prompt=NONE
$graph.mermaid(d=>'TD')
```

Here we find the shortest path between nodes "1" and "4":

```perl6
say 'find-shortest-path : ', $graph.find-shortest-path('1', '4');
```

Here we find all paths between "1" and "4", (and sort them by length and vertex names):

```perl6
say 'find-path : ' , $graph.find-path('1', '4', count => Inf).sort({ $_.elems ~ ' ' ~ $_.join(' ') });
```

Here we find a [Hamiltonian path](https://en.wikipedia.org/wiki/Hamiltonian_path) in the graph:

```perl6
say 'find-hamiltonian-path : ' , $graph.find-hamiltonian-path();
```

Here we find a cycle:

```perl6
say 'find-cycle : ' , $graph.find-cycle().sort({ $_.elems ~ ' ' ~ $_.join(' ') });
```

Here we find all cycles in the graph:

```perl6
say 'find-cycle (all): ' , $graph.find-cycle(count => Inf).sort({ $_.elems ~ ' ' ~ $_.join(' ') });
```

-------

## Graph plotting

### Graph formats

The class `Graph` has the following methods of graph visualization:

- `wl` for making [Wolfram Language graphs](https://reference.wolfram.com/language/ref/Graph.html)
- `dot` for visualizing via [Graphviz](https://graphviz.org) using the [DOT language](https://graphviz.org/doc/info/lang.html)
- `graphml` for [GraphML](http://graphml.graphdrawing.org) visualizations
- `mermaid` for [Mermaid-JS](https://mermaid.js.org) visualizations

### Visualizing via DOT format

In Jupyter notebooks with a Raku kernel graph visualization can be done with the method `dot` and its adverb ":svg".

First, [install Graphviz](https://graphviz.org/download/).

On macOS the installation can be done with:

```
brew install graphviz
```

Here a wheel graph is made and its DOT format is converted into SVG format (rendered automatically in Jupyter notebooks):

```perl6, eval=FALSE
use Graph::Wheel;
Graph::Wheel.new(12).dot(:svg)
```

For more details see notebook ["DOT-visualizations.ipynb"](./docs/DOT-visualizations.ipynb).

### Visualizing via D3.js

In Jupyter notebooks with a Raku kernel graph visualization can be done with the function `js-d3-graph-plot` 
of the package ["JavaScript::D3"](https://github.com/antononcube/Raku-JavaScript-D3).

The visualizations with "JavaScript::D3" are very capricious. Currently they:

- Do not work with [JupyterLab](https://jupyter.org), but only with the "classical" Jupyter notebook.
- Work nicely with the Jupyter notebook plugin(s) of Visual Studio Code, but often require re-loading of the notebooks.

The points above were the main reasons to develop the DOT format visualization. 
Most of the documentation notebooks show the graphs using both "JavaScript::D3" and DOT-SVG. 

-------

## CLI

The package provides the Command Line Interface (CLI) script `graph-creation` that can be used to 
create graphs and export them to different formats. For example:

```shell
graph-creation Grid --rows=3 --columns=2 --format=dot
```

-------

## TODO

### Main, core features

- [X] DONE Rename the attribute `.adjacency-list` to `.adjacency-map`
  - Makes it consistent with `Math::SparseMatrix`.
- [ ] TODO Object methods
  - [X] DONE Str and gist methods
  - [X] DONE Deep copy
  - [X] DONE Creation from another graph.
  - [ ] TODO Ingest vertexes and edges of another `Graph` object
  - [ ] TODO Comparison: `eqv` and `ne`
- [X] DONE Disjoint graphs
  - The graphs can be disjoint as long as the components have edges.
  - Related, the class `Graph` does supports "lone vertices."
    - They have empty adjacency values.
- [ ] TODO Vertexes
  - [X] DONE Vertex list
  - [X] DONE Vertex count
  - [X] DONE Vertex degree
  - [X] DONE in-degree, edges-at
  - [X] DONE out-degree, edges-from
  - [X] DONE Delete vertex(es)
  - [X] DONE Add vertex
  - [X] DONE Has vertex
  - [ ] TODO Vertex tags support
- [ ] TODO Edges
  - [X] DONE Edge list
  - [X] DONE Edge dataset
  - [X] DONE Edge count
  - [X] DONE Add edge
  - [X] DONE Delete edge(s)
  - [X] DONE Has edge
  - [ ] TODO Edge tags support
- [ ] TODO Matrix representation
  - Sparse matrices are needed before "seriously" considering this.
  - Sparse matrices should be easy to create using the (already implemented) edge dataset.
  - [X] DONE Adjacency matrix (dense)
  - [ ] TODO Adjacency matrix (sparse)
  - [X] DONE Incidence matrix (dense)
  - [ ] TODO Incidence matrix (sparse)

### Graph programming

- [ ] TODO Depth first scan / traversal
  - Scan a graph in a depth-first order.
  - This is already implemented, it has to be properly refactored.
    - See Depth-First Search (DFS) named (private) methods.
- [ ] TODO Breadth first scan / traversal  
  - Scan a graph in a breadth-first order.

### Paths, cycles, flows

- [X] DONE Shortest paths
  - [X] DONE Find shortest path
  - [X] DONE Find Hamiltonian paths
    - For both the whole graph or for a given pair of vertexes.
    - Algorithms:
      - [X] Backtracking, `method => 'backtracking'`)
      - [X] Application Warnsdorf's rule for backtracking, `:warnsdorf-rule`
      - [X] Angluin-Valiant (probabilistic), `method => 'random'`
- [ ] TODO Flows
  - [ ] TODO Find maximum flow
  - [ ] TODO Find minimum cost flow
- [ ] TODO Distances
  - [X] DONE Graph distance
    - See shortest path.
  - [ ] TODO Graph distance matrix
    - Again, requires choosing a matrix Raku class or package.
      - Just using a dense matrix for now.
    - [X] DONE Dense
    - [ ] TODO Sparse
- [X] DONE Longest shortest paths
  - [X] DONE Vertex eccentricity
  - [X] DONE Graph radius
  - [X] DONE Graph diameter
  - [X] DONE Graph center
  - [X] DONE Graph periphery
- [X] DONE Weakly connected component  
- [X] DONE Strongly connected component
  - [X] DONE [Tarjan's algorithm](https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
  - [ ] TODO [Kosaraju's algorithm](https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm) 
- [X] DONE Vertex component
  - [X] DONE Fast 1-edge length paths
  - [X] DONE Fast longer-than-one paths
    - Fast (enough) when the number of input vertexes is small
    - Using Dijkstra's algorithm to find all vertex-distance pairs per input vertex.
- [X] DONE Topological sort
  - Using Tarjan's algorithm
- [ ] TODO Cycles and tours
  - [X] DONE Find cycle
    - [X] Just one cycle
    - [X] All cycles
  - [ ] TODO Find shortest tour
  - [ ] TODO Find postman tour
    - [X] DONE Eulerian and semi-Eulerian graphs
    - [ ] TODO General graphs
  - [ ] TODO Find Eulerian cycle
  - [ ] TODO Find Hamiltonian cycle
  - [ ] TODO Find cycle matrix
- [ ] TODO Independent paths
  - [X] DONE Find paths
  - [ ] TODO Find edge independent paths
  - [ ] TODO Find edge vertex paths

### Matching, coloring

- [X] DONE Check is a graph bipartite
- [X] DONE [Hungarian algorithm for bipartite graphs](https://en.wikipedia.org/wiki/Hungarian_algorithm)
  - At [tum.de](https://algorithms.discrete.ma.tum.de/graph-algorithms/matchings-hungarian-method/index_en.html)
- [ ] TODO Perfect match for bipartite graphs
- [ ] TODO Matching edges

### Operations

- [ ] TODO Unary graph operations
  - [X] DONE Reversed graph
  - [X] DONE Complement graph
  - [X] DONE Subgraph
    - For given vertices and/or edges.
  - [X] DONE Neighborhood graph
    - For given vertices and/or edges.
  - [X] DONE Make undirected
    - Can be implemented as `Graph.new($g, :!directed)`.
    - But maybe it is more efficient to directly manipulate `adjacency-map`.
  - [X] DONE Make directed
    - It is not just a flag change of `$!directed`.
    - Implement the methods: `Whatever`, "Acyclic", "Random".
  - [ ] TODO Edge contraction
  - [ ] TODO Vertex contraction
  - [ ] TODO Line graph
  - [ ] TODO Dual graph
- [ ] TODO Binary graph operations
  - [X] DONE Union of graphs
  - [X] DONE Intersection of graphs
  - [X] DONE Difference of graphs
  - [X] DONE Disjoint union of graphs
  - [ ] TODO Product of graphs (AKA "box product")
    - [ ] TODO Cartesian
    - [ ] TODO Co-normal
    - [ ] TODO Lexicographic
    - [ ] TODO Normal
    - [ ] TODO Rooted
    - [ ] TODO Strong
    - [ ] TODO Tensor

### Construction

- [X] DONE Construction of parameterized graphs
  - [X] DONE [Complete graphs](https://en.wikipedia.org/wiki/Complete_graph)
    - [X] DONE Single argument
    - [X] DONE List argument (for K-partite graphs)
  - [X] DONE [Cycle graphs](https://en.wikipedia.org/wiki/Cycle_graph)
  - [X] DONE [Hypercube graphs](https://en.wikipedia.org/wiki/Hypercube_graph)
  - [X] DONE [Grid graphs](https://en.wikipedia.org/wiki/Lattice_graph)
  - [X] DONE [Leaper graphs](https://mathworld.wolfram.com/LeaperGraph.html)
  - [X] DONE [Knight tour graphs](https://en.wikipedia.org/wiki/Knight%27s_graph)
  - [X] DONE [Star graphs](https://en.wikipedia.org/wiki/Star_graph)
  - [X] DONE Path graphs
  - [X] DONE [Wheel graphs](https://en.wikipedia.org/wiki/Wheel_graph)
  - [X] DONE Indexed graphs
  - [X] DONE [Hexagonal grid graphs](https://mathworld.wolfram.com/HexagonalGridGraph.html) 
- [X] DONE Construction of random graphs
  - Since different kinds of vertex-edge distributions exists, separate distributions objects are used.
    - See `Graph::Distribution`.
  - [X] DONE [Barabasi-Albert distribution](https://en.wikipedia.org/wiki/Barabási–Albert_model) 
  - [X] DONE Bernoulli distribution 
  - [X] DONE [de Solla Price's model distribution](https://en.wikipedia.org/wiki/Price%27s_model) 
  - [X] DONE "Simple" random `(m, n)` graphs with m-vertexes and n-edges between them
    - This was the first version of `Graph::Random`.
    - Refactored to be done via the uniform graph distribution.
  - [X] DONE [Watts–Strogatz model distribution](https://en.wikipedia.org/wiki/Watts–Strogatz_model) 
  - [X] DONE Uniform distribution
- [ ] TODO Construction of *individual* graphs
  - [ ] TODO Bull graph
  - [X] DONE Butterfly graph
  - [ ] TODO Chavatal graph
  - [ ] TODO Diamond graph
  - [ ] TODO Durer graph
  - [ ] TODO Franklin graph
  - [X] DONE [Petersen graph](https://en.wikipedia.org/wiki/Petersen_graph)
  - [ ] TODO Wagner graph
- [ ] TODO Creation from 
  - [ ] TODO Adjacency matrix (dense)
  - [ ] TODO Adjacency matrix (sparse)
  - [ ] TODO Incidence matrix (dense)
  - [ ] TODO Incidence matrix (sparse)

### CLI

- [ ] TODO Come up with a meaningful CLI script functionalities exposure
  - [X] One script or separate creation and graph-operations scripts?
    - At first just one script, `graph-creation`.
    - Later on, one script can be used for, say, both creation and verification.
  - [ ] What is the set of commands?
- [ ] TODO CLI functionalities
  - [X] DONE Graph creation
  - [ ] TODO Graph tests over graphs given with JSON files
  - [ ] DONE Produce the Graphviz DOT, WL, Mermaid, JSON representations
    - [X] DONE For specified with parameters graphs
    - [ ] TODO For JSON files
- [ ] TODO Understanding commands like "hamiltonian path" or "grid graph"
  - Not just "hamiltonian-path" and "grid-graph".
 
### Tests

- [ ] TODO Unit tests
  - [X] DONE Sanity
  - [X] DONE Undirected graphs
  - [X] DONE Vertex removal
  - [X] DONE Edge removal
  - [X] DONE Bipartite graph check
  - [ ] TODO Directed graphs cycles
- [ ] TODO Cross-verification with Wolfram Language (aka Mathematica)
  - [X] DONE General workflow programming/setup
  - [ ] TODO Path finding
  - [ ] TODO Cycle finding

### Documentation

- [X] DONE Basic usage over undirected graphs
- [ ] TODO Basic usage over directed graphs
- [X] DONE Regular graphs creation (Grid, Wheel, etc.)
  - [Notebook with a gallery of graphs](./docs/Named-graphs-gallery.ipynb)
- [X] DONE Random graphs creation
- [X] DONE DOT language visualizations

-------

## References

### Articles

[Wk1] Wikipedia entry, ["Graph (discrete mathematics)"](https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)).

[Wk2] Wikipedia entry, ["Graph theory"](https://en.wikipedia.org/wiki/Graph_theory).

[Wk3] Wikipedia entry, ["Glossary of graph theory"](https://en.wikipedia.org/wiki/Glossary_of_graph_theory).

[Wk4] Wikipedia entry, ["List of graphs"](https://en.wikipedia.org/wiki/List_of_graphs) (aka "Gallery of named graphs.")

[Wk5] Wikipedia entry, ["Hamiltonian path"](https://en.wikipedia.org/wiki/Hamiltonian_path).

[AA1] Anton Antonov,
["Graph Neat Examples in Raku – Set 1"](https://rakuforprediction.wordpress.com/2024/12/01/graph-neat-examples-in-raku-set-1/),
(2024),
[RakuForPrediction at WordPress](https://rakuforprediction.wordpress.com).

[AA2] Anton Antonov,
["Graph Neat Examples in Raku – Set 2"](https://rakuforprediction.wordpress.com/2024/12/06/graph-neat-examples-in-raku-set-2/),
(2024),
[RakuForPrediction at WordPress](https://rakuforprediction.wordpress.com).

[AA3] Anton Antonov,
["Graph Neat Examples in Raku – Set 3"](https://rakuforprediction.wordpress.com/2024/12/10/graph-neat-examples-in-raku-set-3/),
(2024),
[RakuForPrediction at WordPress](https://rakuforprediction.wordpress.com).

[AA4] Anton Antonov,
["Day 12 – Graphs in Raku"](https://raku-advent.blog/2024/12/12/day-12-graphs-in-raku/),
(2024),
[Raku Advent Calendar 2024](https://raku-advent.blog/2024/12/26/the-2024-raku-advent-posts/).


### Packages

[AAp1] Anton Antonov,
[WWW::MermaidInk Raku package](https://github.com/antononcube/Raku-WWW-MermaidInk),
(2023),
[GitHub/antononcube](https://github.com/antononcube).

[AAp2] Anton Antonov,
[Proc::ZMQed Raku package](https://github.com/antononcube/Raku-Proc-ZMQed),
(2022),
[GitHub/antononcube](https://github.com/antononcube).

[AAp3] Anton Antonov,
[JavaScript:3 Raku package](https://github.com/antononcube/Raku-JavaScript-D3),
(2022-2024),
[GitHub/antononcube](https://github.com/antononcube).

[JHp1] Jarkko Hietaniemi,
[Graph Perl package](https://metacpan.org/dist/Graph/view/lib/Graph.pod),
(1998-2014),
[MetaCPAN](https://metacpan.org).

### Videos

[AAv1] Anton Antonov,
["Graph demo in Raku (teaser)"](https://www.youtube.com/watch?v=0uJl9q7jIf8),
(2024),
[YouTube/@AAA4Prediction](https://www.youtube.com/@AAA4Prediction).

[AAv2] Anton Antonov,
["Graph neat examples in Raku (Set 1)"](https://www.youtube.com/watch?v=5qXgqqRZHow),
(2024),
[YouTube/@AAA4Prediction](https://www.youtube.com/@AAA4Prediction).

[AAv3] Anton Antonov,
["Raku RAG demo"](https://www.youtube.com/watch?v=JHO2Wk1b-Og),
(2024),
[YouTube/@AAA4Prediction](https://www.youtube.com/@AAA4Prediction).

[AAv4] Anton Antonov,
["Sparse matrix neat examples in Raku"](https://www.youtube.com/watch?v=kQo3wpiUu6w),
(2024),
[YouTube/@AAA4Prediction](https://www.youtube.com/@AAA4Prediction).

[AAv5] Anton Antonov,
["Graph neat examples in Raku (Set 2)"](https://www.youtube.com/watch?v=E7qhutQcWCY),
(2024),
[YouTube/@AAA4Prediction](https://www.youtube.com/@AAA4Prediction).

[AAv6] Anton Antonov,
["Graph neat examples in Raku (Set 3)"](https://www.youtube.com/watch?v=S_3e7liz4KM),
(2024),
[YouTube/@AAA4Prediction](https://www.youtube.com/@AAA4Prediction).

[AAv7] Anton Antonov,
["Chess positions and knight's tours via graphs (in Raku)"](https://www.youtube.com/watch?v=fwQrQyWC7R0),
(2024),
[YouTube/@AAA4Prediction](https://www.youtube.com/@AAA4Prediction).

[AAv8] Anton Antonov,
["Graph neat examples in Raku (Set 4)"](https://youtu.be/dabUhXW1pkw),
(2025),
[YouTube/@AAA4Prediction](https://www.youtube.com/@AAA4Prediction).
