qadence
qadence copied to clipboard
[Feature] Add digital noise from PyQ
Description
Ongoing work in adding the noise from PyQ. Supersedes https://github.com/pasqal-io/qadence/pull/469.
Currently in this branch the basics should be working:
from qadence import NoiseType, DigitalNoise
from qadence import RX, run
noise = DigitalNoise(NoiseType.BITFLIP, error_probability = 0.2)
noise = DigitalNoise.bitflip(error_probability = 0.2) # equivalent
op = RX(0, torch.pi, noise = noise)
run(op)
---
DensityMatrix([[[0.2000+0.0000e+00j, 0.0000+3.6739e-17j],
[0.0000-3.6739e-17j, 0.8000+0.0000e+00j]]])
Note that currently the DigitalNoise
is simply a name alias for the NoiseProtocol
class directly from PyQ, which you can find here: https://github.com/pasqal-io/pyqtorch/blob/main/pyqtorch/noise/protocol.py.
The approach in https://github.com/pasqal-io/qadence/pull/469 was instead to change the Noise
dataclass in qadence.noise.protocols
to include the same options, but then there was already an option there called DEPOLARIZING
which got changed to DEPOLARIZING_PYQ
... I am not so sure what is the best approach here, this should be revised.
Furthermore, I have also drafted a transpilation function to add noise to gates within a composite block or circuit. It works like this:
from qadence import RX, DigitalNoise, set_noise, chain, run
n_qubits = 2
block = chain(RX(i, f"theta_{i}") for i in range(n_qubits))
noise = DigitalNoise.bitflip(error_probability = 0.1)
# The function changes the block in place:
set_noise(block, noise)
run(block)
The code above should add the defined bitflip protocol to every gate in the block. It should also work if it is a QuantumCircuit
. There is an extra optional argument to specify the type of block we want to apply noise to. E.g., let's say we want to apply noise only to X
gates, then it will run an if isinstance(block, target_class): ...
at every leaf block in the block tree:
from qadence import RX, X, DigitalNoise, set_noise, chain, run
n_qubits = 2
block = chain(RX(i, f"theta_{i}") for i in range(n_qubits))
noise = DigitalNoise.bitflip(error_probability = 0.1)
# The function changes the block in place:
set_noise(block, noise, target_class = X)
run(block)
The snippet above will just return a statevector because there exists no X
gates in that composite block. We can also try to print the noise for each of the gates and see that it works:
from qadence import RX, X, DigitalNoise, set_noise, chain, run
n_qubits = 2
block = chain(RX(0, "theta"), X(0))
noise = DigitalNoise.bitflip(error_probability = 0.1)
set_noise(block, noise, target_class = X)
for block in block.blocks:
print(block.noise)
---
> None
> BitFlip(prob: 0.1)
What is left to do:
- Serialization: to check the
_to_dict
and_from_dict
stuff in https://github.com/pasqal-io/qadence/pull/469 - Including the noise in each block string: if added, check how it behaves with visualization.
- Properly review the code, and check if something else from https://github.com/pasqal-io/qadence/pull/469 should be added. See about harmonizing the
DigitalNoise
with theNoise
and etc... I like the interface of theNoiseProtocol
from pyq, so it would be nice to still keep it when using it in Qadence. - Add tests! While writing some finals things for this MR description I think I ran an instance of
set_noise
that did not apply the noise correctly... But now I was trying to replicate it to put it here and I couldn't 😅 So yes for sure test it thoroughly. - Docs! I think this should have a nice separate page in the Contents section: https://pasqal-io.github.io/qadence/latest/content/block_system/