-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Proto] Integrate the Pyqtorch's noisy simulation #423
Comments
What do you think @Roland-djee @gvelikova @jpmoutinho @dominikandreasseitz @rajaiitp ? |
I have changed my approach because the goal is not to create additional blocks but simply to add a noise parameter to the existing blocks. This parameter will allow me to add a noisy block after the existing blocks. The bitflip_noise = Noise(protocol=Noise.BITFLIP, options={"error_probability": 0.5})
phaseflip_noise = Noise(protocol=Noise.PHASEFLIP, options={"error_probability": 0.2})
noise = {
"bitflip": bitflip_noise,
"phaseflip": phaseflip_noise
} Below are the key points of this prototype: 1. Modification of the In class PrimitiveBlock(AbstractBlock):
"""
Primitive blocks represent elementary unitary operations.
#TODO: Add a description of the noise attribut
Examples are single/multi-qubit gates or Hamiltonian evolution.
See [`qadence.operations`](/qadence/operations.md) for a full list of
primitive blocks.
"""
name = "PrimitiveBlock"
def __init__(
self, qubit_support: tuple[int, ...], noise: Noise | dict[str, Noise] | None = None
):
self._qubit_support = qubit_support
self._noise = noise
@property
def qubit_support(self) -> Tuple[int, ...]:
return self._qubit_support
@property
def noise(self) -> Noise | dict[str, Noise] | None:
return self._noise
def digital_decomposition(self) -> AbstractBlock:
"""Decomposition into purely digital gates.
This method returns a decomposition of the Block in a
combination of purely digital single-qubit and two-qubit
'gates', by manual/custom knowledge of how this can be done efficiently.
:return:
"""
if self.noise is None:
raise ValueError(
"Decomposition into purely digital gates is only avalaible for unitary gate"
)
return self
...
def __eq__(self, other: object) -> bool:
if not isinstance(other, AbstractBlock):
raise TypeError(f"Cant compare {type(self)} to {type(other)}")
if isinstance(other, type(self)):
return self.qubit_support == other.qubit_support and self.noise == self.noise
return False
def _to_dict(self) -> dict:
return {
"type": type(self).__name__,
"qubit_support": self.qubit_support,
"tag": self.tag,
"noise": self.noise._to_dict()
if isinstance(self.noise, Noise)
else {k: v._to_dict() for k, v in self.noise.items()}
if self.noise
else None,
}
@classmethod
def _from_dict(cls, d: dict) -> PrimitiveBlock:
noise = d.get("noise")
if isinstance(noise, dict):
noise = {k: Noise._from_dict(v) for k, v in noise.items()}
elif noise is not None:
noise = Noise._from_dict(noise)
return cls(tuple(d["qubit_support"]), noise)
... 2.Modify All Subclasses of 3.Add Protocols to the @dataclass
class Noise:
BITFLIP = "BitFlip"
PHASEFLIP = "PhaseFlip"
PAULI_CHANNEL = "PauliChannel"
AMPLITUDE_DAMPING = "AmplitudeDamping"
PHASE_DAMPING = "PhaseDamping"
GENERALIZED_AMPLITUDE_DAMPING = "GeneralizedAmplitudeDamping"
DEPHASING = "dephasing"
DEPOLARIZING = "depolarizing" # check if no cap is ok for pyq
READOUT = "readout"
... 4.Modify the def convert_block():
...
elif block.noise:
protocols = []
error_probabilities = []
if isinstance(block.noise, dict):
for noise_instance in block.noise.values():
protocols.append(noise_instance.protocol)
error_probabilities.append(noise_instance.options.get("error_probability"))
elif isinstance(block.noise, Noise):
protocols.append(block.noise.protocol)
error_probabilities.append(block.noise.options.get("error_probability"))
return [pyq.Noisy_Sequence(primitive = block.name, noise = protocols, error_probability = error_probabilities)]
... 5. Add a constructor in class Noisy_Sequence:
def __init__(primitive: Primitive, noise: Noise | list[Noise, ...], error_probability: float | list[float,...]): (These are the last two steps; more details will be added later.) |
This issue is to present a prototype for integrating
pyq
's noise gates intoqadence
. The primary goal is to ensure that noise handling is effectively incorporated without disrupting the existing functionalities. Below are the key points of this prototype:1. Creation of NoisyPrimitivesBlocks:
• New blocks derived from
PrimitivesBlock
have been created, calledNoisyPrimitivesBlock
.• These blocks introduce a new input parameter,
noise_probability
, which allows specifying the probability of noise when creating a block.In
blocks/primitive.py
:2. Create Noisy Gates in Qadence:
• Prior to this, we added the noise gates name to the
OpName
class.• Develop blocks that will represent our noisy gates within
qadence
.• Create subclasses of
NoisyPrimitiveBlock
to implement these noise gates.For instance with the
BitFlip
gate. Inoperations/noise.py
:3.Modify convert_block function for pyq:
• Prior to this, we created the
single_qubit_noise_gateset
type list .• During the conversion of blocks to gates for
pyq
, add a condition for noise block inconvert_block
.• Ensure that the new
noise_probability
parameter is taken into account during this conversion.In
operations/__init__.py
:In
backends/pyqtorch/convert_ops.py
:The text was updated successfully, but these errors were encountered: