qarp.graphs¶
Graphs, hypergraphs and simplicial complexes for problem construction. Public depth: flat. Submodules are private.
- class qarp.graphs.Graph(*args, backend=None, **kwargs)[source]¶
Bases:
Graph- adjacency_matrix()[source]¶
Weighted adjacency matrix, rows/columns in node insertion order.
- Returns:
SciPy sparse array. Append .toarray() for dense representation.
- degree_matrix()[source]¶
Returns the degree matrix of the graph. The degree matrix is a diagonal matrix where each diagonal element is the degree of the corresponding node.
- Returns:
The degree matrix of the graph. Append .toarray() for dense representation.
- Return type:
SciPy sparse array
- classmethod from_qubit_operator(qubit_op) Graph[source]¶
Graph of a Z/ZZ
QubitOperator:Z_i Z_jterms become weighted edges andZ_iterms the node attributelinear; the constant is dropped.Inverse of
to_cost_hamiltonianup to that constant. Equal toqarp.graphs.qubit_operator_to_graph().
- incidence_matrix()[source]¶
Unsigned node × edge incidence matrix (entry 1 where the node is an endpoint), nodes in insertion order and edges in
self.edgesorder.- Returns:
SciPy sparse array. Append .toarray() for dense representation.
- laplacian_matrix()[source]¶
Weighted graph Laplacian
D − A, rows/columns in node insertion order.- Returns:
SciPy sparse array. Append .toarray() for dense representation.
- max_modularity_eigenvector()[source]¶
Returns the eigenvector relative to the largest eigenvalue of the modularity matrix.
Two behaviours are inherited from networkx’s
modularity_matrix: entries are indexed by node insertion order (not by label), and edge weights are ignored — every edge counts 1.- Returns:
The eigenvector relative to the largest eigenvalue of the modularity matrix.
- Return type:
np.ndarray
- Raises:
ValueError – If the graph has no nodes, or has nodes but no edges — the modularity matrix
B = A − k kᵀ / 2mis undefined at2m = 0.
- property n_qubits: int¶
highest label + 1, 0 when empty.
Labels are qubit indices, so a non-contiguous labelling such as
{0, 1, 3}still needs qubit 3 to exist: this is not the node count.- Raises:
TypeError – If a node label is not a non-negative integer.
- Type:
Qubit count implied by the node labels
- normalized_laplacian_matrix()[source]¶
Normalized Laplacian
I − D^{-1/2} A D^{-1/2}, node insertion order.An isolated node contributes a zero row and column (networkx’s convention), not NaN.
- Returns:
SciPy sparse array. Append .toarray() for dense representation.
- plot(highlight_nodes: Dict[int, str] | List[int] | None = None, figsize: Tuple | None = (4, 3), pos: Dict | None = None, with_labels: bool = True, node_color: str = 'lightblue', font_size: int = 9, return_fig: bool = False)[source]¶
Plots the graph.
- Parameters:
highlight_nodes – Optional dictionary mapping node IDs to colors for highlighting.
figsize – Size of the figure in inches.
pos – Optional dictionary of node positions. If None, a spring layout is computed.
with_labels – Whether to display node labels.
node_color – Default color used for nodes not in highlight_nodes.
font_size – Font size for node labels.
return_fig – If True, return (fig, ax) for external saving/customization.
- Returns:
(fig, ax) if return_fig is True, otherwise None.
- to_cost_hamiltonian(*, linear=None)[source]¶
Ising cost Hamiltonian
Σ_e w_e Z_i Z_j + Σ_i c_i Z_iof this graph.Thin wrapper over
qarp.graphs.graph_to_cost_hamiltonian(), which documents the convention (this is QAOA’s Ising form, not the MaxCut objective: minimising it maximises the cut,cut = (Σ_e w_e − ⟨H⟩) / 2).- Parameters:
linear – Mapping node → coefficient of its
Z_iterm.Nonereads the per-nodelinearattributes (set byfrom_qubit_operator).- Returns:
The cost Hamiltonian.
- Return type:
- to_graph_state_block(**kwargs)[source]¶
The graph-state preparation block:
Hon every qubit, thenCZper edge.A graph state is a hypergraph state whose hyperedges all have order 2, so this is the
HypergraphStateBlockon this graph’s edges, sized byn_qubits. Works on a base install: hypernetx is not required.- Parameters:
**kwargs – Forwarded to
HypergraphStateBlock(name,target_qubits).- Returns:
The (unbuilt) block.
- Return type:
- Raises:
ValueError – On a self-loop, which is no hyperedge (
CZneeds two qubits).
- class qarp.graphs.SimplicialComplex(simplices: Sequence[Sequence[int]])[source]¶
Bases:
object- add_simplex(simplex: Sequence[int]) None[source]¶
Adds a simplex and all its faces to the simplicial complex.
- Parameters:
simplex (Simplex) – The simplex to add.
- boundary_matrix(k: int)[source]¶
Signed boundary operator
∂_kfrom k-simplices to (k−1)-simplices.Rows index the (k−1)-simplices and columns the k-simplices, both in
get_simplices()order. The entry for the face obtained by deleting the i-th vertex of a (sorted) k-simplex is(−1)^i.∂_0is0 × f_0and∂_{dim+1}isf_dim × 0, sohodge_laplacianneeds no end cases.- Returns:
SciPy sparse array of ints. Append .toarray() for dense representation.
- cofaces(simplex: Sequence[int]) List[Tuple[int, ...]][source]¶
Every simplex having
simplexas a face — its closed star, so a presentsimplexis included and an absent one has no cofaces. Exactly the setremove_simplexdeletes. Sorted likeget_simplices.
- euler_characteristic() int[source]¶
χ = Σ_k (−1)^k f_k, the alternating sum of the f-vector; 0 when empty.
- get_simplices() List[Tuple[int]][source]¶
Returns a sorted list of simplices in the complex.
- Returns:
The list of simplices.
- Return type:
List[Tuple[int]]
- hodge_laplacian(k: int)[source]¶
Combinatorial Hodge Laplacian
L_k = ∂_kᵀ ∂_k + ∂_{k+1} ∂_{k+1}ᵀon the k-simplices (f_k × f_k).L_0is the graph Laplacian of the 1-skeleton. The matrix only — its spectrum is the caller’s business.- Returns:
SciPy sparse array of ints. Append .toarray() for dense representation.
- max_dimension() int[source]¶
Returns the dimension of the simplicial complex.
- Returns:
The highest dimension (i.e., max(len(simplex) - 1)).
- Return type:
- neighbors(node) List[source]¶
Vertices sharing a simplex with
node, sorted. Under closure this is the 1-skeleton neighbourhood: every co-member shares an edge too.
- num_simplices(order: int | None = None) int[source]¶
Number of simplices of the given order, or of all orders when
None.
- plot(figsize=(4, 3), return_fig=False)[source]¶
Plots the simplicial complex as points, edges and filled simplices.
Only facets (maximal simplices) are filled, so a tetrahedron reads as one body rather than four separate faces. Faces are implied by the fill and never separately outlined, which is what makes a missing face visible: the body stays filled and the line along the absent edge is simply not drawn. Order 3 is hatched, marking where the simplex is rather than claiming to depict it.
Vertices are placed by a spring layout over the 1-skeleton, seeded from
qarp.config.seed— which defaults toNone, so figures are reproducible only once the caller sets it.- Parameters:
- Returns:
(fig, ax) if return_fig is True, else None.
- Raises:
ValueError – If the complex has order above
MAX_PLOT_ORDER.
- remove_simplex(simplex: Sequence[int]) None[source]¶
Removes a simplex, and every simplex containing it, from the complex.
Cofaces have to go too: a complex that kept (0, 1, 2) after (0, 1) was removed would no longer be closed under faces. Faces of
simplexare left alone, so removing (0, 1) does not remove (0,) or (1,).The blast radius is the entire coface set, which can be most of the complex — removing a vertex removes every simplex it belongs to.
- Parameters:
simplex (Simplex) – The simplex to remove.
- Raises:
ValueError – If
simplexis not a list or tuple, or is empty. The empty simplex is a face of every simplex, so cascading on it would silently empty the complex.
- skeleton(k: int) SimplicialComplex[source]¶
The k-skeleton: a new complex of the simplices of order at most
k(closed automatically).k >= max_dimension()gives a copy.
- qarp.graphs.community_vector_to_sets(G: Graph, community_vector: list) list[source]¶
Converts a community vector to a list of sets of node labels, where each set contains the nodes in that community, based on the node ordering in the graph.
- qarp.graphs.generate_complete_simplicial_complex(n: int) SimplicialComplex[source]¶
Generates a complete simplicial complex.
Parameters: n (int): The number of nodes.
- Returns:
A complete simplicial complex with all possible simplices.
- Return type:
- qarp.graphs.generate_random_simplicial_complex(n: int, p: float) SimplicialComplex[source]¶
Generates a random simplicial complex.
Every non-empty subset of
range(n)is offered with probabilityp; closure then adds the faces of whatever was accepted. Draws come from the globalrandommodule, so seed withrandom.seedfor reproducibility.- Parameters:
- Returns:
A random simplicial complex with simplices included based on probability p.
- Return type:
- qarp.graphs.graph_to_cost_hamiltonian(graph, *, linear: Mapping | None = None) QubitOperator[source]¶
Ising cost Hamiltonian
Σ_e w_e Z_i Z_j + Σ_i c_i Z_iof any networkx graph.This is QAOA’s Ising form, not the MaxCut objective
Σ_e w_e (1 − Z_i Z_j) / 2: the two differ by a sign and an offset, so minimising this Hamiltonian maximises the cut, withcut = (Σ_e w_e − ⟨H⟩) / 2.Node labels are used directly as qubit indices and are validated as non-negative integers; non-contiguous labels are allowed. The edge weight is the
weightattribute, defaulting to 1.0 for an edge without one (whatever other attributes it carries).- Parameters:
graph – A networkx graph (
qarp.graphs.Graphor plainnx.Graph).linear – Mapping node → coefficient
c_iof itsZ_iterm.Nonereads the per-nodelinearattributes, whichqubit_operator_to_graph()sets; an explicit mapping replaces them.
- Returns:
The cost Hamiltonian.
- Return type:
- Raises:
TypeError – If a node label (or a
linearkey) is not a non-negative integer.ValueError – On a self-loop
(i, i):Z_i Z_iis the identity, so the edge has no ZZ term — pass a linear term throughlinear=instead.
- qarp.graphs.lists_to_tuples(lst: list) list[source]¶
Converts a list of lists describing edges or simplices into a list of tuples.
- qarp.graphs.qubit_operator_to_graph(qubit_op) Graph[source]¶
Graph of a
QubitOperatorwith onlyZandZ Zterms.Nodes are the qubits
0 … count_qubits − 1; eachZ_i Z_jterm becomes the edge(i, j)with attributeweightand eachZ_iterm the node attributelinearoni, sograph_to_cost_hamiltonian()inverts this up to the constant term, which has no home on a graph and is dropped.- Parameters:
qubit_op – QubitOperator with only Z or ZZ terms (plus a constant).
- Returns:
The native graph.
- Return type:
- Raises:
ValueError – On a non-Z Pauli or a term acting on more than two qubits.