Arborescence.Abstractions
0.17.0
dotnet add package Arborescence.Abstractions --version 0.17.0
NuGet\Install-Package Arborescence.Abstractions -Version 0.17.0
<PackageReference Include="Arborescence.Abstractions" Version="0.17.0" />
paket add Arborescence.Abstractions --version 0.17.0
#r "nuget: Arborescence.Abstractions, 0.17.0"
// Install Arborescence.Abstractions as a Cake Addin #addin nuget:?package=Arborescence.Abstractions&version=0.17.0 // Install Arborescence.Abstractions as a Cake Tool #tool nuget:?package=Arborescence.Abstractions&version=0.17.0
Abstractions — Arborescence Graph Library
This package provides graph-related abstractions. These abstractions fall into two groups: interfaces and concepts.
Interfaces are direct contracts for algorithms, constraints on their type parameters. The most important ones are:
IOutNeighborsAdjacency<TVertex, TNeighbors>
{
TNeighbors EnumerateOutNeighbors(TVertex vertex);
}
IHeadIncidence<TVertex, TEdge>
{
bool TryGetHead(TEdge edge, out TVertex head);
}
IOutEdgesIncidence<TVertex, TEdges>
{
TEdges EnumerateOutEdges(TVertex vertex);
}
Note that IGraph<TVertex, TEdge>
is not such a primary abstraction.
Utility interfaces are not directly used as type constraints in algorithms.
They simply group primary interfaces together, and may be convenient for users to implement.
IGraph<TVertex, TEdge> :
ITailIncidence<TVertex, TEdge>,
IHeadIncidence<TVertex, TEdge> { }
IForwardIncidence<TVertex, TEdge, TEdges> :
IHeadIncidence<TVertex, TEdge>,
IOutEdgesIncidence<TVertex, TEdges> { }
The library treats the term graph in a specific sense. The closest analog in mathematics is the notion of a quiver[^Q] — a directed graph[^DG] where loops and multiple edges between two vertices are allowed.
Let's look at an example of four airports (Omsk, London, Istanbul, Taipei) and five flights between them:
BA676
┌───────>───────┐ EVA5288
│ TK1980 │ TK24 ┌─>─┐
[LHR]─────>─────[IST]─────>─────[TPE] │
└───────<───────┘ └───┘
BA677
[OMS]
The same in Graphviz notation:
digraph Flights {
rankdir=LR
node [shape=box fontname="Times-Italic"]
OMS // Omsk
LHR // London
IST // Istanbul
TPE // Taipei
edge [fontname="Monospace"]
LHR -> IST [label="BA676"]
LHR -> IST [label="TK1980"]
IST -> LHR [label="BA677"]
IST -> TPE [label="TK24"]
TPE -> TPE [label="EVA5288"]
}
Here common restrictions of simple directed graphs are relaxed:
- parallel edges like
BA676
andTK1980
are permitted, - antiparallel edges like
TK1980
andBA677
are also fine, - nothing special about loops like edge
EVA5288
[^EVA], - isolated vertices like OMS are allowed too.
The edges are not treated as a set of ordered pairs of vertices.
Instead, they are described in terms of two incidence functions tail and head mapping the edges to their endpoints.
In the example above, the tail function is defined as { BA676
↦ LHR, TK1980
↦ LHR, BA677
↦ IST, TK24
↦ IST, EVA5288
↦ TPE }.
There are two distinct notions of multiple edges:
- Without their own identity[^EWO]: the identity of an edge is defined solely by the two vertices it connects. Let's ignore for now the flight ids in the figure above. Then outgoing edges of vertex LHR would be two entries of the same endpoints pair: ⟨LHR, IST⟩ and ⟨LHR, IST⟩ again.
- With their own identity[^EWI]: edges are primitive entities just like vertices.
In this case, the outgoing edges of vertex LHR are two different independent edges
BA676
andTK1980
, which just occasionally happen to have the same endpoints.
Another useful function maps the vertex to its outgoing edges, making a graph traversable.
It must be consistent with the incidence function:
∀ v ∀ e e ∈ out-edges(v) ⇔ v = tail(e)
Together these functions form a scheme:
┌ tail : E → V?
Graph ┤
└ head : E → V? ┐
├ Forward Incidence
out-edges : V → [E] ┘
The adjacency interface provides access to the neighbors of a vertex in a graph. In some contexts there is only concern for the vertices, while the edges are not important.
Basic usage
We start with the simpler abstraction of an adjacency graph, where the edges (flights) are of no interest, only the connected vertices (airports).
using NeighborEnumerator = System.ArraySegment<string>.Enumerator;
public sealed class FlightAdjacencyGraph :
IOutNeighborsAdjacency<string, NeighborEnumerator>
{
private readonly Dictionary<string, string[]> _neighborsByAirport;
private FlightAdjacencyGraph(
Dictionary<string, string[]> neighborsByAirport) =>
_neighborsByAirport = neighborsByAirport;
public NeighborEnumerator EnumerateOutNeighbors(string vertex) =>
_neighborsByAirport.TryGetValue(vertex, out string[]? neighbors)
? new ArraySegment<string>(neighbors).GetEnumerator()
: ArraySegment<string>.Empty.GetEnumerator();
public static FlightAdjacencyGraph Create()
{
Dictionary<string, string[]> neighborsByAirport = new(3)
{
{ "LHR", new[] { "IST", "IST" } },
{ "IST", new[] { "LHR", "TPE" } },
{ "TPE", new[] { "TPE" } }
};
return new(neighborsByAirport);
}
}
Where can we fly from Istanbul?
var adjacencyGraph = FlightAdjacencyGraph.Create();
NeighborEnumerator istanbulNeighborEnumerator =
adjacencyGraph.EnumerateOutNeighbors("IST");
while (istanbulNeighborEnumerator.MoveNext())
Console.WriteLine(istanbulNeighborEnumerator.Current);
Expected output is:
LHR
TPE
The second example demonstrates an incidence graph.
Let's consider only the digits of the flight ids for simplicity, so we could encode them as integers: 676
instead of BA676
, 1980
instead of TK1980
, and so on.
using EdgeEnumerator = System.ArraySegment<int>.Enumerator;
public sealed class FlightIncidenceGraph :
IGraph<string, int>, IForwardIncidence<string, int, EdgeEnumerator>
{
private readonly Dictionary<int, string> _destinationByFlight;
private readonly Dictionary<string, int[]> _flightsByOrigin;
private readonly Dictionary<int, string> _originByFlight;
private FlightIncidenceGraph(
Dictionary<int, string> originByFlight,
Dictionary<int, string> destinationByFlight,
Dictionary<string, int[]> flightsByOrigin)
{
_originByFlight = originByFlight;
_destinationByFlight = destinationByFlight;
_flightsByOrigin = flightsByOrigin;
}
public EdgeEnumerator EnumerateOutEdges(string vertex) =>
_flightsByOrigin.TryGetValue(vertex, out int[]? flights)
? new ArraySegment<int>(flights).GetEnumerator()
: ArraySegment<int>.Empty.GetEnumerator();
public bool TryGetTail(int edge, [MaybeNullWhen(false)] out string tail) =>
_originByFlight.TryGetValue(edge, out tail);
public bool TryGetHead(int edge, [MaybeNullWhen(false)] out string head) =>
_destinationByFlight.TryGetValue(edge, out head);
public static FlightIncidenceGraph Create()
{
Dictionary<int, string> originByFlight = new(5)
{
{ 676, "LHR" }, { 1980, "LHR" }, { 677, "IST" }, { 24, "IST" }, { 5288, "TPE" }
};
Dictionary<int, string> destinationByFlight = new(5)
{
{ 676, "IST" }, { 1980, "IST" }, { 677, "LHR" }, { 24, "TPE" }, { 5288, "TPE" }
};
Dictionary<string, int[]> flightsByOrigin = new(3)
{
{ "LHR", new[] { 676, 1980 } },
{ "IST", new[] { 677, 24 } },
{ "TPE", new[] { 5288 } }
};
return new(originByFlight, destinationByFlight, flightsByOrigin);
}
}
Which flights are available from Istanbul?
var incidenceGraph = FlightIncidenceGraph.Create();
EdgeEnumerator istanbulFlightEnumerator =
incidenceGraph.EnumerateOutEdges("IST");
while (istanbulFlightEnumerator.MoveNext())
Console.WriteLine(istanbulFlightEnumerator.Current);
Expected output is:
677
24
Which airports are connected by the flight 676
?
if (incidenceGraph.TryGetTail(676, out string? flight676Origin))
Console.WriteLine(flight676Origin);
if (incidenceGraph.TryGetHead(676, out string? flight676Destination))
Console.WriteLine(flight676Destination);
Expected output is:
LHR
IST
[^DG]: Directed graph
https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)#Directed_graph
[^EVA]: EVA Air introduces special flight to nowhere
https://edition.cnn.com/travel/article/eva-air-hello-kitty-fathers-day-flight/index.html
https://flightaware.com/live/flight/EVA5288
[^EWI]: Edges with own identity
https://en.wikipedia.org/wiki/Multigraph#Directed_multigraph_(edges_with_own_identity)
[^EWO]: Edges without own identity
https://en.wikipedia.org/wiki/Multigraph#Directed_multigraph_(edges_without_own_identity)
[^Q]: Quiver<br /> https://en.wikipedia.org/wiki/Quiver_(mathematics)
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp1.0 was computed. netcoreapp1.1 was computed. netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard1.0 is compatible. netstandard1.1 was computed. netstandard1.2 was computed. netstandard1.3 was computed. netstandard1.4 was computed. netstandard1.5 was computed. netstandard1.6 was computed. netstandard2.0 is compatible. netstandard2.1 is compatible. |
.NET Framework | net45 was computed. net451 was computed. net452 was computed. net46 was computed. net461 is compatible. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen30 was computed. tizen40 was computed. tizen60 was computed. |
Universal Windows Platform | uap was computed. uap10.0 was computed. |
Windows Phone | wp8 was computed. wp81 was computed. wpa81 was computed. |
Windows Store | netcore was computed. netcore45 was computed. netcore451 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.1
- No dependencies.
-
.NETStandard 1.0
- No dependencies.
-
.NETStandard 2.0
- No dependencies.
-
.NETStandard 2.1
- No dependencies.
NuGet packages (5)
Showing the top 5 NuGet packages that depend on Arborescence.Abstractions:
Package | Downloads |
---|---|
Arborescence.Traversal
Graph traversal algorithms: BFS, DFS. Commonly used types: • Adjacency.EnumerableBfs<TVertex, TNeighborEnumerator> • Adjacency.EnumerableDfs<TVertex, TNeighborEnumerator> • Adjacency.EnumerableGenericSearch<TVertex, TNeighborEnumerator> • Adjacency.EagerBfs<TVertex, TNeighborEnumerator> • Adjacency.EagerDfs<TVertex, TNeighborEnumerator> • Incidence.EnumerableBfs<TVertex, TEdge, TEdgeEnumerator> • Incidence.EnumerableDfs<TVertex, TEdge, TEdgeEnumerator> • Incidence.EnumerableGenericSearch<TVertex, TEdge, TEdgeEnumerator> • Incidence.EagerBfs<TVertex, TEdge, TEdgeEnumerator> • Incidence.EagerDfs<TVertex, TEdge, TEdgeEnumerator> |
|
Arborescence.Models
Data structures that provide a generic implementation of graph interfaces and collection concepts. Commonly used types: • AdditiveMonoid<T> • AdjacencyEnumerator<TVertex, TEdge, TGraph, TEdgeEnumerator> • IncidenceEnumerator<TVertex, TNeighborEnumerator> • ListAdjacencyGraph<TVertex, TVertexMultimap> • ListIncidenceGraph<TVertex, TEdge, …> • ListEnumeratorProvider<T> |
|
Arborescence.Models.Specialized
Special graph data structures that provide efficient implementation when vertices are integers from a contiguous range. Commonly used types: • Int32AdjacencyGraph • Int32IncidenceGraph |
|
Arborescence.Traversal.Specialized
Graph traversal algorithms specialized for integer vertices from a contiguous range. Commonly used types: • Adjacency.EnumerableBfs<TNeighborEnumerator> • Adjacency.EnumerableDfs<TNeighborEnumerator> • Adjacency.EnumerableGenericSearch<TNeighborEnumerator> • Adjacency.EagerBfs<TNeighborEnumerator> • Adjacency.EagerDfs<TNeighborEnumerator> • Incidence.EnumerableBfs<TEdge, TEdgeEnumerator> • Incidence.EnumerableDfs<TEdge, TEdgeEnumerator> • Incidence.EnumerableGenericSearch<TEdge, TEdgeEnumerator> • Incidence.EagerBfs<TEdge, TEdgeEnumerator> • Incidence.EagerDfs<TEdge, TEdgeEnumerator> |
|
Arborescence.Search
Graph search algorithms: Dijkstra. Commonly used types: - Adjacency.AdditiveEnumerableDijkstra<TVertex, TWeight> - Adjacency.AdditiveEnumerableDijkstra<TVertex, TNeighborEnumerator, TWeight> - Adjacency.EnumerableDijkstra<TVertex, TWeight> - Adjacency.EnumerableDijkstra<TVertex, TNeighborEnumerator, TWeight> |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.17.0 | 559 | 1/11/2024 |
0.16.3 | 1,103 | 1/1/2024 |
0.16.2 | 620 | 7/27/2023 |
0.16.0 | 658 | 6/4/2023 |
0.15.0 | 1,653 | 1/17/2023 |
0.14.0 | 1,017 | 1/7/2023 |
0.13.0 | 1,120 | 6/27/2021 |
0.10.0 | 1,730 | 5/29/2021 |
0.9.0 | 1,004 | 1/15/2021 |
0.7.1 | 1,861 | 12/26/2020 |
0.7.0 | 1,141 | 12/25/2020 |
0.6.0 | 1,088 | 11/9/2020 |
0.1.1 | 3,410 | 7/5/2020 |