diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 123a7d714..0903cc078 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -465,9 +465,6 @@ Ali Asadi, Amintor Dusko, Diego Guala, Joseph Lee, Luis Alfredo Nuñez Meneses, * Enable setting the PennyLane version when invoking, for example, `make docker-build version=master pl_version=master`. [(#791)](https://github.com/PennyLaneAI/pennylane-lightning/pull/791) -* Add a Catalyst-specific wrapping class for Lightning Kokkos. - [(#770)](https://github.com/PennyLaneAI/pennylane-lightning/pull/770) - ### Documentation * The installation instructions for all lightning plugins have been improved. @@ -614,7 +611,7 @@ Ali Asadi, Astral Cai, Ahmed Darwish, Amintor Dusko, Vincent Michaud-Rioux, Luis * Changed the name of `lightning.tensor` to `default.tensor` with the `quimb` backend. [(#719)](https://github.com/PennyLaneAI/pennylane-lightning/pull/719) - + * `lightning.qubit` and `lightning.kokkos` adhere to user-specified mid-circuit measurement configuration options. [(#736)](https://github.com/PennyLaneAI/pennylane-lightning/pull/736) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp index 9806c8e19..79b97de21 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp @@ -799,7 +799,6 @@ class GateImplementationsLM : public PauliGenerator { applyNCHadamard(arr, num_qubits, {}, {}, wires, inverse); } - template static void applyNCS(std::complex *arr, const std::size_t num_qubits, diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 9f6e08bd8..337309665 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -62,287 +62,19 @@ from ._measurements import LightningMeasurements from ._state_vector import LightningStateVector -try: - # pylint: disable=import-error, unused-import - from pennylane_lightning.lightning_qubit_ops import backend_info - - LQ_CPP_BINARY_AVAILABLE = True -except ImportError: - LQ_CPP_BINARY_AVAILABLE = False - -Result_or_ResultBatch = Union[Result, ResultBatch] -QuantumTapeBatch = Sequence[QuantumTape] -QuantumTape_or_Batch = Union[QuantumTape, QuantumTapeBatch] -PostprocessingFn = Callable[[ResultBatch], Result_or_ResultBatch] - - -def simulate( - circuit: QuantumScript, - state: LightningStateVector, - mcmc: dict = None, - postselect_mode: str = None, -) -> Result: - """Simulate a single quantum script. - - Args: - circuit (QuantumTape): The single circuit to simulate - state (LightningStateVector): handle to Lightning state vector - mcmc (dict): Dictionary containing the Markov Chain Monte Carlo - parameters: mcmc, kernel_name, num_burnin. Descriptions of - these fields are found in :class:`~.LightningQubit`. - postselect_mode (str): Configuration for handling shots with mid-circuit measurement - postselection. Use ``"hw-like"`` to discard invalid shots and ``"fill-shots"`` to - keep the same number of shots. Default is ``None``. - - Returns: - Tuple[TensorLike]: The results of the simulation - - Note that this function can return measurements for non-commuting observables simultaneously. - """ - if mcmc is None: - mcmc = {} - state.reset_state() - has_mcm = any(isinstance(op, MidMeasureMP) for op in circuit.operations) - if circuit.shots and has_mcm: - results = [] - aux_circ = qml.tape.QuantumScript( - circuit.operations, - circuit.measurements, - shots=[1], - trainable_params=circuit.trainable_params, - ) - for _ in range(circuit.shots.total_shots): - state.reset_state() - mid_measurements = {} - final_state = state.get_final_state( - aux_circ, mid_measurements=mid_measurements, postselect_mode=postselect_mode - ) - results.append( - LightningMeasurements(final_state, **mcmc).measure_final_state( - aux_circ, mid_measurements=mid_measurements - ) - ) - return tuple(results) - final_state = state.get_final_state(circuit) - return LightningMeasurements(final_state, **mcmc).measure_final_state(circuit) - - -def jacobian(circuit: QuantumTape, state: LightningStateVector, batch_obs=False, wire_map=None): - """Compute the Jacobian for a single quantum script. - - Args: - circuit (QuantumTape): The single circuit to simulate - state (LightningStateVector): handle to Lightning state vector - batch_obs (bool): Determine whether we process observables in parallel when - computing the jacobian. This value is only relevant when the lightning - qubit is built with OpenMP. Default is False. - wire_map (Optional[dict]): a map from wire labels to simulation indices - - Returns: - TensorLike: The Jacobian of the quantum script - """ - if wire_map is not None: - [circuit], _ = qml.map_wires(circuit, wire_map) - state.reset_state() - final_state = state.get_final_state(circuit) - return LightningAdjointJacobian(final_state, batch_obs=batch_obs).calculate_jacobian(circuit) - - -def simulate_and_jacobian( - circuit: QuantumTape, state: LightningStateVector, batch_obs=False, wire_map=None -): - """Simulate a single quantum script and compute its Jacobian. - - Args: - circuit (QuantumTape): The single circuit to simulate - state (LightningStateVector): handle to Lightning state vector - batch_obs (bool): Determine whether we process observables in parallel when - computing the jacobian. This value is only relevant when the lightning - qubit is built with OpenMP. Default is False. - wire_map (Optional[dict]): a map from wire labels to simulation indices - - Returns: - Tuple[TensorLike]: The results of the simulation and the calculated Jacobian - - Note that this function can return measurements for non-commuting observables simultaneously. - """ - if wire_map is not None: - [circuit], _ = qml.map_wires(circuit, wire_map) - res = simulate(circuit, state) - jac = LightningAdjointJacobian(state, batch_obs=batch_obs).calculate_jacobian(circuit) - return res, jac - - -def vjp( - circuit: QuantumTape, - cotangents: Tuple[Number], - state: LightningStateVector, - batch_obs=False, - wire_map=None, -): - """Compute the Vector-Jacobian Product (VJP) for a single quantum script. - Args: - circuit (QuantumTape): The single circuit to simulate - cotangents (Tuple[Number, Tuple[Number]]): Gradient-output vector. Must - have shape matching the output shape of the corresponding circuit. If - the circuit has a single output, ``cotangents`` may be a single number, - not an iterable of numbers. - state (LightningStateVector): handle to Lightning state vector - batch_obs (bool): Determine whether we process observables in parallel when - computing the VJP. This value is only relevant when the lightning - qubit is built with OpenMP. - wire_map (Optional[dict]): a map from wire labels to simulation indices - - Returns: - TensorLike: The VJP of the quantum script - """ - if wire_map is not None: - [circuit], _ = qml.map_wires(circuit, wire_map) - state.reset_state() - final_state = state.get_final_state(circuit) - return LightningAdjointJacobian(final_state, batch_obs=batch_obs).calculate_vjp( - circuit, cotangents - ) - - -def simulate_and_vjp( - circuit: QuantumTape, - cotangents: Tuple[Number], - state: LightningStateVector, - batch_obs=False, - wire_map=None, -): - """Simulate a single quantum script and compute its Vector-Jacobian Product (VJP). - Args: - circuit (QuantumTape): The single circuit to simulate - cotangents (Tuple[Number, Tuple[Number]]): Gradient-output vector. Must - have shape matching the output shape of the corresponding circuit. If - the circuit has a single output, ``cotangents`` may be a single number, - not an iterable of numbers. - state (LightningStateVector): handle to Lightning state vector - batch_obs (bool): Determine whether we process observables in parallel when - computing the jacobian. This value is only relevant when the lightning - qubit is built with OpenMP. - wire_map (Optional[dict]): a map from wire labels to simulation indices - - Returns: - Tuple[TensorLike]: The results of the simulation and the calculated VJP - Note that this function can return measurements for non-commuting observables simultaneously. - """ - if wire_map is not None: - [circuit], _ = qml.map_wires(circuit, wire_map) - res = simulate(circuit, state) - _vjp = LightningAdjointJacobian(state, batch_obs=batch_obs).calculate_vjp(circuit, cotangents) - return res, _vjp - - -_operations = frozenset( - { - "Identity", - "QubitUnitary", - "MultiControlledX", - "DiagonalQubitUnitary", - "PauliX", - "PauliY", - "PauliZ", - "MultiRZ", - "GlobalPhase", - "Hadamard", - "S", - "Adjoint(S)", - "T", - "Adjoint(T)", - "SX", - "Adjoint(SX)", - "CNOT", - "SWAP", - "ISWAP", - "PSWAP", - "Adjoint(ISWAP)", - "SISWAP", - "Adjoint(SISWAP)", - "SQISW", - "CSWAP", - "Toffoli", - "CY", - "CZ", - "PhaseShift", - "ControlledPhaseShift", - "RX", - "RY", - "RZ", - "Rot", - "CRX", - "CRY", - "CRZ", - "C(PauliX)", - "C(PauliY)", - "C(PauliZ)", - "C(Hadamard)", - "C(S)", - "C(T)", - "C(SX)", - "C(PhaseShift)", - "C(RX)", - "C(RY)", - "C(RZ)", - "C(Rot)", - "C(SWAP)", - "C(IsingXX)", - "C(IsingXY)", - "C(IsingYY)", - "C(IsingZZ)", - "C(SingleExcitation)", - "C(SingleExcitationMinus)", - "C(SingleExcitationPlus)", - "C(DoubleExcitation)", - "C(DoubleExcitationMinus)", - "C(DoubleExcitationPlus)", - "C(MultiRZ)", - "C(GlobalPhase)", - "C(QubitUnitary)", - "CRot", - "IsingXX", - "IsingYY", - "IsingZZ", - "IsingXY", - "SingleExcitation", - "SingleExcitationPlus", - "SingleExcitationMinus", - "DoubleExcitation", - "DoubleExcitationPlus", - "DoubleExcitationMinus", - "QubitCarry", - "QubitSum", - "OrbitalRotation", - "QFT", - "ECR", - "BlockEncode", - "C(BlockEncode)", - } -) -# The set of supported operations. - - -_observables = frozenset( - { - "PauliX", - "PauliY", - "PauliZ", - "Hadamard", - "Hermitian", - "Identity", - "Projector", - "SparseHamiltonian", - "Hamiltonian", - "LinearCombination", - "Sum", - "SProd", - "Prod", - "Exp", - } -) -# The set of supported observables. +_to_matrix_ops = { + "BlockEncode": OperatorProperties(controllable=True), + "DiagonalQubitUnitary": OperatorProperties(), + "ECR": OperatorProperties(), + "ISWAP": OperatorProperties(), + "OrbitalRotation": OperatorProperties(), + "PSWAP": OperatorProperties(), + "QubitCarry": OperatorProperties(), + "QubitSum": OperatorProperties(), + "SISWAP": OperatorProperties(), + "SQISW": OperatorProperties(), + "SX": OperatorProperties(), +} def stopping_condition(op: Operator) -> bool: diff --git a/tests/test_gates.py b/tests/test_gates.py index aad11d51c..37f54a9f6 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -472,9 +472,9 @@ def circuit(): qml.PauliY, qml.PauliZ, qml.Hadamard, - qml.SX, qml.S, qml.T, + qml.SX, qml.PhaseShift, qml.RX, qml.RY,