Orientation Module

class chipfiring.CFOrientation.OrientationState(value)[source]

Bases: Enum

Represents the possible states of an edge orientation.

NO_ORIENTATION = 0
SOURCE_TO_SINK = 1
SINK_TO_SOURCE = 2
class chipfiring.CFOrientation.CFOrientation(graph: CFGraph, orientations: List[Tuple[str, str]])[source]

Bases: object

Represents an orientation of edges in a chip-firing graph.

__init__(graph: CFGraph, orientations: List[Tuple[str, str]])[source]

Initialize the orientation with a graph and list of oriented edges.

Parameters:
  • graph – A CFGraph object representing the underlying graph

  • orientations – List of tuples (source_name, sink_name) where source_name and sink_name are strings representing vertex names. Each tuple indicates that the edge is oriented from source to sink.

Raises:
  • ValueError – If an edge specified in orientations does not exist in the graph

  • ValueError – If multiple orientations are specified for the same edge

Example

>>> vertices = {"A", "B", "C"}
>>> edges = [("A", "B", 2), ("B", "C", 1), ("A", "C", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientations = [("A", "B"), ("B", "C")]
>>> orientation = CFOrientation(graph, orientations)
check_fullness() bool[source]

Check if all edges have an orientation and update is_full.

Returns:

True if all edges have an orientation, False otherwise

Example

>>> vertices = {"v1", "v2", "v3"}
>>> edges = [("v1", "v2", 1), ("v2", "v3", 1), ("v1", "v3", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientation = CFOrientation(graph, [("v1", "v2")])
>>> orientation.check_fullness()
False
>>> # Now complete the orientation
>>> from chipfiring.CFOrientation import Vertex, OrientationState
>>> v2, v3 = Vertex("v2"), Vertex("v3")
>>> orientation.set_orientation(v2, v3, OrientationState.SOURCE_TO_SINK)
>>> v1, v3 = Vertex("v1"), Vertex("v3")
>>> orientation.set_orientation(v1, v3, OrientationState.SOURCE_TO_SINK)
>>> orientation.check_fullness()
True
set_orientation(source: Vertex, sink: Vertex, state: OrientationState) None[source]

Helper method to set orientation and update in/out degrees.

Parameters:
  • source – Source vertex

  • sink – Sink vertex

  • state – New orientation state

Example

>>> vertices = {"A", "B", "C"}
>>> edges = [("A", "B", 2), ("B", "C", 1), ("A", "C", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientation = CFOrientation(graph, [])
>>> from chipfiring.CFOrientation import OrientationState, Vertex
>>> v_a = Vertex("A")
>>> v_b = Vertex("B")
>>> orientation.set_orientation(v_a, v_b, OrientationState.SOURCE_TO_SINK)
>>> orientation.get_out_degree("A")
2  # A-B edge has valence 2
>>> orientation.get_in_degree("B")
2
get_orientation(v1_name: str, v2_name: str) Tuple[str, str] | None[source]

Get the orientation of an edge between two vertices.

Parameters:
  • v1_name – Name of first vertex

  • v2_name – Name of second vertex

Returns:

Tuple (source_name, sink_name) indicating the orientation, or None if the edge exists but has no orientation

Raises:

ValueError – If the edge does not exist

Example

>>> vertices = {"v1", "v2", "v3"}
>>> edges = [("v1", "v2", 1), ("v2", "v3", 1), ("v1", "v3", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientations = [("v1", "v2"), ("v2", "v3"), ("v1", "v3")]
>>> orientation = CFOrientation(graph, orientations)
>>> orientation.get_orientation("v1", "v2")
('v1', 'v2')
>>> orientation.get_orientation("v2", "v1")  # Order doesn't matter
('v1', 'v2')
>>> # For a partially oriented graph:
>>> partial = CFOrientation(graph, [("v1", "v2")])
>>> partial.get_orientation("v1", "v2")
('v1', 'v2')
>>> partial.get_orientation("v2", "v3")
None
is_source(vertex_name: str, neighbor_name: str) bool | None[source]

Check if a vertex is the source of an oriented edge.

Parameters:
  • vertex_name – Name of the vertex to check

  • neighbor_name – Name of the neighboring vertex

Returns:

True if the vertex is the source of the edge, False if the vertex is the sink of the edge, None if the edge exists but has no orientation

Raises:

ValueError – If the edge does not exist

Example

>>> vertices = {"v1", "v2", "v3"}
>>> edges = [("v1", "v2", 1), ("v2", "v3", 1), ("v1", "v3", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientations = [("v1", "v2"), ("v2", "v3"), ("v1", "v3")]
>>> orientation = CFOrientation(graph, orientations)
>>> orientation.is_source("v1", "v2")
True
>>> orientation.is_source("v2", "v1")
False
>>> # For an unoriented edge
>>> partial = CFOrientation(graph, [("v1", "v2")])
>>> partial.is_source("v2", "v3")
None
is_sink(vertex_name: str, neighbor_name: str) bool | None[source]

Check if a vertex is the sink of an oriented edge.

Parameters:
  • vertex_name – Name of the vertex to check

  • neighbor_name – Name of the neighboring vertex

Returns:

True if the vertex is the sink of the edge, False if the vertex is the source of the edge, None if the edge exists but has no orientation

Raises:

ValueError – If the edge does not exist

Example

>>> vertices = {"v1", "v2", "v3"}
>>> edges = [("v1", "v2", 1), ("v2", "v3", 1), ("v1", "v3", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientations = [("v1", "v2"), ("v2", "v3"), ("v1", "v3")]
>>> orientation = CFOrientation(graph, orientations)
>>> orientation.is_sink("v1", "v2")
False
>>> orientation.is_sink("v2", "v1")
True
>>> # For an unoriented edge
>>> partial = CFOrientation(graph, [("v1", "v2")])
>>> partial.is_sink("v2", "v3")
None
get_in_degree(vertex_name: str) int[source]

Get the in-degree of a vertex, which is the sum of valences of edges oriented into the vertex.

Parameters:

vertex_name – Name of the vertex to get the in-degree for

Returns:

The in-degree of the vertex

Raises:

ValueError – If the vertex name is not found in the graph

Example

>>> vertices = {"v1", "v2", "v3"}
>>> edges = [("v1", "v2", 1), ("v2", "v3", 1), ("v1", "v3", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientations = [("v1", "v2"), ("v2", "v3"), ("v1", "v3")]
>>> orientation = CFOrientation(graph, orientations)
>>> orientation.get_in_degree("v1")
0
>>> orientation.get_in_degree("v2")
1  # from v1
>>> orientation.get_in_degree("v3")
2  # from v1, v2
get_out_degree(vertex_name: str) int[source]

Get the out-degree of a vertex, which is the sum of valences of edges oriented out of the vertex.

Parameters:

vertex_name – Name of the vertex to get the out-degree for

Returns:

The out-degree of the vertex

Raises:

ValueError – If the vertex name is not found in the graph

Example

>>> vertices = {"v1", "v2", "v3"}
>>> edges = [("v1", "v2", 1), ("v2", "v3", 1), ("v1", "v3", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientations = [("v1", "v2"), ("v2", "v3"), ("v1", "v3")]
>>> orientation = CFOrientation(graph, orientations)
>>> orientation.get_out_degree("v1")
2
>>> orientation.get_out_degree("v2")
1  # to v3
>>> orientation.get_out_degree("v3")
0
reverse() CFOrientation[source]

Return a new CFOrientation object with all edge orientations reversed.

Raises:

RuntimeError – If the current orientation is not full (i.e., contains unoriented edges).

Returns:

A new CFOrientation object representing the reversed orientation.

Example

>>> vertices = {"v1", "v2", "v3"}
>>> edges = [("v1", "v2", 1), ("v2", "v3", 1), ("v1", "v3", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientations = [("v1", "v2"), ("v2", "v3"), ("v1", "v3")]
>>> orientation = CFOrientation(graph, orientations)
>>> reversed_orientation = orientation.reverse()
>>> reversed_orientation.get_orientation("v1", "v2")
('v2', 'v1')
>>> reversed_orientation.get_orientation("v2", "v3")
('v3', 'v2')
>>> reversed_orientation.get_orientation("v1", "v3")
('v3', 'v1')
divisor() CFDivisor[source]

Returns the divisor associated with the orientation; by definition, for each vertex v, the degree of v in the divisor is the in-degree of v in the orientation minus 1.

Raises:

RuntimeError – If the current orientation is not full (i.e., contains unoriented edges).

Returns:

A new CFDivisor object representing the calculated divisor.

Example

>>> vertices = {"v1", "v2", "v3"}
>>> edges = [("v1", "v2", 1), ("v2", "v3", 1), ("v1", "v3", 1)]
>>> graph = CFGraph(vertices, edges)
>>> orientations = [("v1", "v2"), ("v2", "v3"), ("v1", "v3")]
>>> orientation = CFOrientation(graph, orientations)
>>> div = orientation.divisor()
>>> div.get_degree("v1")
-1  # in-degree 0 - 1
>>> div.get_degree("v2")
0   # in-degree 1 - 1
>>> div.get_degree("v3")
1   # in-degree 2 - 1
canonical_divisor() CFDivisor[source]

Returns the canonical divisor associated with the graph; by definition, the canonical divisor of an orientation is equal to the divisor of the orientation plus the divisor of the reverse of the orientation. After simplifying, we get that for each vertex v, the degree of v in the canonical divisor is the valence of v minus 2.

Returns:

A new CFDivisor object representing the canonical divisor.

Example

>>> vertices = {"a", "b", "c"}
>>> edges = [("a", "b", 2), ("b", "c", 3)]  # Multi-graph
>>> graph = CFGraph(vertices, edges)
>>> orientation = CFOrientation(graph, [])  # Orientation doesn't matter
>>> canonical = orientation.canonical_divisor()
>>> canonical.get_degree("a")
0   # valence 2 - 2
>>> canonical.get_degree("b")
3   # valence 5 - 2
>>> canonical.get_degree("c")
1   # valence 3 - 2
to_dict() Dict[str, Any][source]

Converts the CFOrientation instance to a dictionary representation.

Returns:

A dictionary with ‘graph’ and ‘orientations’.

classmethod from_dict(data: Dict[str, Any]) CFOrientation[source]

Creates a CFOrientation instance from a dictionary representation.

Parameters:

data – A dictionary with ‘graph’ (CFGraph representation) and ‘orientations’ (list of [source_name, sink_name] tuples).

Returns:

A CFOrientation instance.