Class ScyllaCSRGraph
Immutable, read-only graph stored in Compressed Sparse Row (CSR) format, optimized for cache-efficient traversal and high-frequency neighbor queries.
Inherited Members
Namespace: Scylla.Core.Structures
Assembly: ScyllaCore.dll
Syntax
public sealed class ScyllaCSRGraph : IScyllaReadOnlyGraph, IScyllaGraph, IScyllaCollection
Remarks
CSR layout stores all outgoing edges in a single contiguous _edges array.
For each node at index i, its outgoing edges occupy the slice
_edges[_edgeOffsets[i].._edgeOffsets[i+1]].
This prefix-sum (row offset) scheme enables O(1) slice lookup and provides
3-4x faster neighbor iteration compared to adjacency lists due to spatial locality.
Once constructed, the graph is fully immutable. No nodes or edges can be added, removed, or modified. Calling Clear() will always throw InvalidOperationException. To build a mutable graph first and then freeze it into CSR format, use ScyllaAdjacencyListGraph with CreateFromGraph(IScyllaReadOnlyGraph).
Nodes are sorted by ID during construction for deterministic ordering. Node IDs do not need to be contiguous or start at zero.
Because the graph is immutable and all internal arrays are allocated once at construction time, concurrent reads from multiple threads are safe without synchronization. ThreadSafety is reported as Unsynchronized because no locking mechanism is provided; the immutability guarantee makes it inherently read-safe.
Convert an existing mutable graph to CSR:
var adjacency = ScyllaAdjacencyListGraph.CreateBuilder()
.Directed()
.Build();
adjacency.AddNode(0);
adjacency.AddNode(1);
adjacency.AddEdge(0, 1, 2.5f);
var csr = ScyllaCSRGraph.CreateFromGraph(adjacency);
Build a CSR graph directly using the fluent builder:
var csr = ScyllaCSRGraph.CreateBuilder()
.Directed()
.Weighted()
.AddNode(0)
.AddNode(1)
.AddNode(2)
.AddEdge(0, 1, 5.0f)
.AddEdge(1, 2, 3.0f)
.Build();
Properties
Capabilities
Gets the capability flags for this collection. Reports SupportsContains and SupportsCopyTo. ContainsNode(int) is O(1) via the internal hash map; CopyAllNodes(Span<ScyllaGraphNode>) and CopyAllEdges(Span<ScyllaGraphEdge>) are both supported.
Declaration
public ScyllaCollectionCapabilities Capabilities { get; }
Property Value
| Type | Description |
|---|---|
| ScyllaCollectionCapabilities |
Count
Gets the number of items in the collection, which equals NodeCount. This property satisfies the Count contract where nodes are treated as the primary collection element.
Declaration
public int Count { get; }
Property Value
| Type | Description |
|---|---|
| int |
EdgeCount
Gets the logical number of edges in the graph. For undirected graphs, each non-self-loop edge is counted once even though it is stored internally as two directed entries (one per direction).
Declaration
public int EdgeCount { get; }
Property Value
| Type | Description |
|---|---|
| int |
IsEmpty
Gets a value indicating whether the graph contains no nodes.
Returns true when NodeCount is zero.
Declaration
public bool IsEmpty { get; }
Property Value
| Type | Description |
|---|---|
| bool |
NodeCount
Gets the number of nodes stored in the graph.
Declaration
public int NodeCount { get; }
Property Value
| Type | Description |
|---|---|
| int |
Properties
Gets the structural property flags describing this graph instance. Possible flags include Directed and Weighted. The Mutable flag is always absent because ScyllaCSRGraph is immutable.
Declaration
public ScyllaGraphProperties Properties { get; }
Property Value
| Type | Description |
|---|---|
| ScyllaGraphProperties |
SyncRoot
Gets the synchronization root for this collection.
Always returns null because ScyllaCSRGraph is immutable and
requires no locking for concurrent reads.
Declaration
public object SyncRoot { get; }
Property Value
| Type | Description |
|---|---|
| object |
ThreadSafety
Gets the thread-safety classification for this graph. Reported as Unsynchronized because no locking mechanism is provided. However, because the graph is fully immutable after construction, concurrent reads from multiple threads are safe without synchronization.
Declaration
public ScyllaCollectionThreadSafety ThreadSafety { get; }
Property Value
| Type | Description |
|---|---|
| ScyllaCollectionThreadSafety |
Methods
Clear()
Not supported. ScyllaCSRGraph is immutable and cannot be cleared.
Declaration
public void Clear()
Exceptions
| Type | Condition |
|---|---|
| InvalidOperationException | Always thrown. Use CreateFromGraph(IScyllaReadOnlyGraph) or ScyllaCSRGraph.Builder to create a new graph instead. |
ContainsEdge(int, int)
Determines whether the graph contains a directed edge from one node to another.
For directed graphs, only the edge in the specified direction is checked.
For undirected graphs, both entries stored in the CSR array are considered, so
swapping fromID and toID will also return
true if the edge exists.
Declaration
public bool ContainsEdge(int fromID, int toID)
Parameters
| Type | Name | Description |
|---|---|---|
| int | fromID | ID of the source node. |
| int | toID | ID of the target node. |
Returns
| Type | Description |
|---|---|
| bool |
|
ContainsNode(int)
Determines whether the graph contains a node with the specified ID.
Declaration
public bool ContainsNode(int nodeID)
Parameters
| Type | Name | Description |
|---|---|---|
| int | nodeID | The integer ID of the node to look up. |
Returns
| Type | Description |
|---|---|
| bool |
|
CopyAllEdges(Span<ScyllaGraphEdge>)
Copies all logical edge descriptors from the graph into the provided span.
For undirected graphs, each non-self-loop edge is stored in the CSR array in both
directions, but this method copies only the canonical direction
(FromID < ToID), ensuring each edge appears exactly once in the output.
Self-loop edges (FromID == ToID) are always included exactly once.
If destination is smaller than the number of logical edges,
copying stops when the span is full.
Declaration
public int CopyAllEdges(Span<ScyllaGraphEdge> destination)
Parameters
| Type | Name | Description |
|---|---|---|
| Span<ScyllaGraphEdge> | destination | Span into which the ScyllaGraphEdge descriptors will be written. |
Returns
| Type | Description |
|---|---|
| int | The number of edges written into |
CopyAllNodes(Span<ScyllaGraphNode>)
Copies all node descriptors from the graph into the provided span.
Nodes are written in the same sorted-by-ID order used during construction.
If destination is smaller than NodeCount,
only as many nodes as fit are copied.
Declaration
public int CopyAllNodes(Span<ScyllaGraphNode> destination)
Parameters
| Type | Name | Description |
|---|---|---|
| Span<ScyllaGraphNode> | destination | Span into which the ScyllaGraphNode descriptors will be written. |
Returns
| Type | Description |
|---|---|
| int | The number of nodes written into |
CreateBuilder()
Creates a new fluent ScyllaCSRGraph.Builder for constructing a ScyllaCSRGraph incrementally.
Declaration
public static ScyllaCSRGraph.Builder CreateBuilder()
Returns
| Type | Description |
|---|---|
| ScyllaCSRGraph.Builder | A new ScyllaCSRGraph.Builder instance with default settings (directed, unweighted). |
CreateFromGraph(IScyllaReadOnlyGraph)
Creates a new immutable ScyllaCSRGraph by converting an existing IScyllaReadOnlyGraph into CSR format.
Declaration
public static ScyllaCSRGraph CreateFromGraph(IScyllaReadOnlyGraph source)
Parameters
| Type | Name | Description |
|---|---|---|
| IScyllaReadOnlyGraph | source | The source graph to convert. Must not be |
Returns
| Type | Description |
|---|---|
| ScyllaCSRGraph | A new ScyllaCSRGraph containing the same nodes and edges as
|
Remarks
Nodes are sorted by ID during construction for deterministic layout. The Mutable flag is stripped from the source graph's properties because the resulting CSR graph is immutable.
Neighbor data is read from the source graph using GetNeighborsNonAlloc(int, Span<ScyllaGraphEdge>) with a dynamically-sized reusable edge buffer, so the conversion allocates only the final CSR arrays.
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown when |
GetNeighborCount(int)
Returns the number of outgoing edges (neighbors) for the specified node. This is an O(1) operation because the count is derived directly from the prefix-sum offsets stored in the CSR array.
Declaration
public int GetNeighborCount(int nodeID)
Parameters
| Type | Name | Description |
|---|---|---|
| int | nodeID | The ID of the node to query. |
Returns
| Type | Description |
|---|---|
| int | The number of outgoing edges from |
GetNeighborsNonAlloc(int, Span<ScyllaGraphEdge>)
Copies the outgoing edges of the specified node into a caller-provided span, avoiding any heap allocation.
Declaration
public int GetNeighborsNonAlloc(int nodeID, Span<ScyllaGraphEdge> destination)
Parameters
| Type | Name | Description |
|---|---|---|
| int | nodeID | The ID of the node whose outgoing edges should be retrieved. |
| Span<ScyllaGraphEdge> | destination | Span into which the edge descriptors will be written. Must be allocated by the caller; no allocation is performed by this method. |
Returns
| Type | Description |
|---|---|
| int | The number of edges written into |
Remarks
The edges are copied directly from the contiguous CSR edge array, making this
operation highly cache-friendly. If destination is smaller than
the actual neighbor count, only as many edges as fit are copied. Use
GetNeighborCount(int) first to pre-size the buffer if all edges are needed.
TryGetEdge(int, int, out ScyllaGraphEdge)
Attempts to retrieve the edge descriptor for a connection between two nodes.
Declaration
public bool TryGetEdge(int fromID, int toID, out ScyllaGraphEdge edge)
Parameters
| Type | Name | Description |
|---|---|---|
| int | fromID | ID of the source node. |
| int | toID | ID of the target node. |
| ScyllaGraphEdge | edge | When this method returns |
Returns
| Type | Description |
|---|---|
| bool |
|
Remarks
For directed graphs, the edge is only found in the direction
fromID → toID.
For undirected graphs, both directions are stored in the CSR array, so either
ordering of the arguments will succeed.
TryGetNodeFlags(int, out ScyllaGraphNodeFlags)
Attempts to retrieve the ScyllaGraphNodeFlags for the specified node.
Declaration
public bool TryGetNodeFlags(int nodeID, out ScyllaGraphNodeFlags flags)
Parameters
| Type | Name | Description |
|---|---|---|
| int | nodeID | The ID of the node to query. |
| ScyllaGraphNodeFlags | flags | When this method returns |
Returns
| Type | Description |
|---|---|
| bool |
|