Source code for qolumbina.programs.state_preparation.graph_state

# The original version of the following code is sourced from Qiskit circuit library:
# https://github.com/Qiskit/qiskit/blob/stable/2.3/qiskit/circuit/library/graph_state.py#L89-L173
#
# Original repository link:
# https://github.com/Qiskit/qiskit/tree/f14e0b29a484795034447ea5bfb637fe845c194f
#
# This program is adapted for use as a benchmark in controlled software testing experiments.
# No modifications in functional changes were made to the original code.
#
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Graph State circuit and gate."""

from __future__ import annotations

import numpy as np
from qiskit.circuit.quantumcircuit import QuantumCircuit, Gate
from qiskit.circuit.exceptions import CircuitError
# from qiskit.utils.deprecation import deprecate_func

# ---------- benchmark registration ----------
from ..benchmark_registry import register_benchmark
from pathlib import Path
@register_benchmark(
    Path(__file__).stem,
    family=Path(__file__).resolve().parent.name,
    description="Prepare a graph state based on an adjacency matrix",
    class_name="GraphState",
    source={
        "repo": "https://github.com/Qiskit/qiskit/tree/f14e0b29a484795034447ea5bfb637fe845c194f",
        "file": "qiskit/circuit/library/graph_state.py",
        "sdk": "Qiskit",
        "available_doc": True
    },
    testability_refactoring=None,
)
def create_graph_state(adjacency_matrix: list | np.ndarray) -> QuantumCircuit:
    return GraphState(adjacency_matrix=adjacency_matrix)

[docs] class GraphState(QuantumCircuit): r"""Circuit to prepare a graph state. Given a graph G = (V, E), with the set of vertices V and the set of edges E, the corresponding graph state is defined as .. math:: |G\rangle = \prod_{(a,b) \in E} CZ_{(a,b)} {|+\rangle}^{\otimes |V|} Such a state can be prepared by first preparing all qubits in the :math:`+` state, then applying a :math:`CZ` gate for each corresponding graph edge. Graph state preparation circuits are Clifford circuits, and thus easy to simulate classically. However, by adding a layer of measurements in a product basis at the end, there is evidence that the circuit becomes hard to simulate [2]. Reference Circuit: .. plot:: :alt: Diagram illustrating the previously described circuit. from qiskit.circuit.library import GraphState from qiskit.visualization.library import _generate_circuit_library_visualization import rustworkx as rx G = rx.generators.cycle_graph(5) circuit = GraphState(rx.adjacency_matrix(G)) circuit.name = "Graph state" _generate_circuit_library_visualization(circuit) References: [1] M. Hein, J. Eisert, H.J. Briegel, Multi-party Entanglement in Graph States, `arXiv:0307130 <https://arxiv.org/pdf/quant-ph/0307130.pdf>`_ [2] D. Koh, Further Extensions of Clifford Circuits & their Classical Simulation Complexities. `arXiv:1512.07892 <https://arxiv.org/pdf/1512.07892.pdf>`_ """ # @deprecate_func( # since="2.1", # additional_msg="Use qiskit.circuit.library.GraphStateGate instead.", # removal_timeline="in Qiskit 3.0", # ) def __init__(self, adjacency_matrix: list | np.ndarray) -> None: r"""Create graph state preparation circuit. Args: adjacency_matrix: Adjacency matrix representing the graph, which is presented in a form of :math:`n`-by-:math:`n` list of 0-1 lists. Raises: CircuitError: If adjacency_matrix is not symmetric. The circuit prepares a graph state with the given adjacency matrix. """ adjacency_matrix = np.asarray(adjacency_matrix) if not np.allclose(adjacency_matrix, adjacency_matrix.transpose()): raise CircuitError("The adjacency matrix must be symmetric.") graph_state_gate = GraphStateGate(adjacency_matrix) super().__init__(graph_state_gate.num_qubits) self.compose(graph_state_gate, range(graph_state_gate.num_qubits), inplace=True) # Automatically decompose for simulator compatibility self._decompose_for_simulator() def _decompose_for_simulator(self): decomposed_circuit = self.decompose() self.data = decomposed_circuit.data
[docs] class GraphStateGate(Gate): r"""A gate representing a graph state. """ def __init__(self, adjacency_matrix: list | np.ndarray) -> None: r""" Args: adjacency_matrix: Adjacency matrix representing the graph, which is presented in a form of :math:`n`-by-:math:`n` list of 0-1 lists. Raises: CircuitError: If adjacency_matrix is not symmetric. The gate represents a graph state with the given adjacency matrix. """ adjacency_matrix = np.asarray(adjacency_matrix) if not np.allclose(adjacency_matrix, adjacency_matrix.transpose()): raise CircuitError("The adjacency matrix must be symmetric.") num_qubits = len(adjacency_matrix) super().__init__(name="graph_state", num_qubits=num_qubits, params=[adjacency_matrix]) def _define(self): adjacency_matrix = self.adjacency_matrix circuit = QuantumCircuit(self.num_qubits) circuit.h(range(self.num_qubits)) for i in range(self.num_qubits): for j in range(i + 1, self.num_qubits): if adjacency_matrix[i][j] == 1: circuit.cz(i, j) self.definition = circuit
[docs] def validate_parameter(self, parameter): """Parameter validation""" return parameter
@property def adjacency_matrix(self): """Returns the adjacency matrix.""" return self.params[0] def __eq__(self, other): return ( isinstance(other, GraphStateGate) and self.num_qubits == other.num_qubits and np.all(self.adjacency_matrix == other.adjacency_matrix) )