# Source code for mitiq.mitiq_pyquil.pyquil_utils

```
# Copyright (C) 2020 Unitary Fund
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""pyQuil utitility functions."""
import numpy as np
from pyquil import Program
# Backend and Noise simulation
from pyquil import get_qc
from pyquil.gates import X, Y, Z, MEASURE
from pyquil.noise import append_kraus_to_gate
from pyquil.simulation.matrices import I as npI, X as npX, Y as npY, Z as npZ
QVM = get_qc("1q-qvm")
# Set the random seeds for testing
QVM.qam.random_seed = 1337
np.random.seed(1001)
[docs]def random_identity_circuit(depth=None):
"""Returns a single-qubit identity circuit based on Pauli gates."""
# initialize a quantum circuit
prog = Program()
# index of the (inverting) final gate: 0=I, 1=X, 2=Y, 3=Z
k_inv = 0
# apply a random sequence of Pauli gates
for _ in range(depth):
# random index for the next gate: 1=X, 2=Y, 3=Z
k = np.random.choice([1, 2, 3])
# apply the Pauli gate "k"
if k == 1:
prog += X(0)
elif k == 2:
prog += Y(0)
elif k == 3:
prog += Z(0)
# update the inverse index according to
# the product rules of Pauli matrices k and k_inv
if k_inv == 0:
k_inv = k
elif k_inv == k:
k_inv = 0
else:
_ = [1, 2, 3]
_.remove(k_inv)
_.remove(k)
k_inv = _[0]
# apply the final inverse gate
if k_inv == 1:
prog += X(0)
elif k_inv == 2:
prog += Y(0)
elif k_inv == 3:
prog += Z(0)
return prog
[docs]def run_with_noise(circuit: Program, noise: float, shots: int) -> float:
"""Returns the expectation value of a circuit run several times with noise.
Args:
circuit: Quantum circuit as :class:`~pyquil.quil.Program`.
noise: Noise constant for depolarizing channel.
shots: Number of shots the circuit is run.
Returns:
expval: Expectation value.
"""
# apply depolarizing noise to all gates
kraus_ops = [
np.sqrt(1 - noise) * npI,
np.sqrt(noise / 3) * npX,
np.sqrt(noise / 3) * npY,
np.sqrt(noise / 3) * npZ,
]
circuit.define_noisy_gate("X", [0], append_kraus_to_gate(kraus_ops, npX))
circuit.define_noisy_gate("Y", [0], append_kraus_to_gate(kraus_ops, npY))
circuit.define_noisy_gate("Z", [0], append_kraus_to_gate(kraus_ops, npZ))
# set number of shots
circuit.wrap_in_numshots_loop(shots)
# we want to simulate noise, so we run without compiling
results = QVM.run(circuit)
expval = (results == [0]).sum() / shots
return expval
[docs]def run_program(pq: Program, shots: int = 500) -> float:
"""Returns the expectation value of a circuit run several times.
Args:
pq: Quantum circuit as :class:`~pyquil.quil.Program`.
shots: (Default: 500) Number of shots the circuit is run.
Returns:
expval: Expectation value.
"""
pq.wrap_in_numshots_loop(shots)
results = QVM.run(pq)
expval = (results == [0]).sum() / shots
return expval
[docs]def add_depolarizing_noise(pq: Program, noise: float) -> Program:
"""Returns a quantum program with depolarizing channel noise.
Args:
pq: Quantum program as :class:`~pyquil.quil.Program`.
noise: Noise constant for depolarizing channel.
Returns:
pq: Quantum program with added noise.
"""
pq = pq.copy()
# apply depolarizing noise to all gates
kraus_ops = [
np.sqrt(1 - noise) * npI,
np.sqrt(noise / 3) * npX,
np.sqrt(noise / 3) * npY,
np.sqrt(noise / 3) * npZ,
]
pq.define_noisy_gate("X", [0], append_kraus_to_gate(kraus_ops, npX))
pq.define_noisy_gate("Y", [0], append_kraus_to_gate(kraus_ops, npY))
pq.define_noisy_gate("Z", [0], append_kraus_to_gate(kraus_ops, npZ))
return pq
NATIVE_NOISE = 0.007
[docs]def scale_noise(pq: Program, param: float) -> Program:
"""Returns a circuit rescaled by the depolarizing noise parameter.
Args:
pq: Quantum circuit as :class:`~pyquil.quil.Program`.
param: noise scaling.
Returns:
Quantum program with added noise.
"""
noise = param * NATIVE_NOISE
assert noise <= 1.0, (
"Noise scaled to {} is out of bounds (<=1.0) for "
"depolarizing channel.".format(noise)
)
return add_depolarizing_noise(pq, noise)
[docs]def measure(circuit, qid):
"""Returns a circuit adding a register for readout results.
Args:
circuit: Quantum circuit as :class:`~pyquil.quil.Program`.
qid: position of the measurement in the circuit.
Returns:
Quantum program with added measurement.
"""
ro = circuit.declare("ro", "BIT", 1)
circuit += MEASURE(qid, ro[0])
return circuit
```