#
# Copyright © 2022-2024 University of Strasbourg. All Rights Reserved.
# Copyright © 2032-2024 QPerfect. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use thas file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from abc import ABC, abstractmethod
import copy
import mimiqcircuits as mc
import symengine as se
import sympy as sp
from mimiqcircuits.canvas import _gate_name_padding
[docs]
class Operation(ABC):
"""
Abstract base class for quantum operations.
"""
_name = None
_num_qubits = None
_num_qregs = 1
_qregsizes = None
_num_bits = None
_num_cregs = 0
_cregsizes = None
_num_zvars = None
_num_zregs = 0
_zregsizes = None
_parnames = ()
@property
def num_qubits(self):
return self._num_qubits
@num_qubits.setter
def num_qubits(self, value):
raise ValueError("Cannot set num_qubits. Read only parameter.")
@property
def num_qregs(self):
return self._num_qregs
@num_qregs.setter
def num_qregs(self, value):
raise ValueError("Cannot set num_qregs. Read only parameter.")
@property
def num_bits(self):
return self._num_bits
@num_bits.setter
def num_bits(self, value):
raise ValueError("Cannot set num_bits. Read only parameter.")
@property
def num_zvars(self):
return self._num_zvars
@num_zvars.setter
def num_zvars(self, value):
raise ValueError("Cannot set num_zvars. Read only parameter.")
@property
def num_cregs(self):
return self._num_cregs
@num_cregs.setter
def num_cregs(self, value):
raise ValueError("Cannot set num_cregs. Read only parameter.")
@property
def qregsizes(self):
return self._qregsizes
@qregsizes.setter
def qregsizes(self, value):
raise ValueError("Cannot set qregsizes. Read only parameter.")
@property
def cregsizes(self):
return self._cregsizes
@cregsizes.setter
def cregsizes(self, value):
raise ValueError("Cannot set cregsizes. Read only parameter.")
@property
def zregsizes(self):
return self._zregsizes
@zregsizes.setter
def zregsizes(self, value):
raise ValueError("Cannot set zregsizes. Read only parameter.")
@property
def name(self):
return self._name
@name.setter
def name(self, value):
raise ValueError("Cannot set name. Read only parameter.")
@property
def parnames(self):
return self._parnames
@parnames.setter
def parnames(self, value):
raise ValueError("Cannot set parnames. Read only parameter.")
[docs]
def getparams(self):
return [getattr(self, pn) for pn in self._parnames]
[docs]
def is_symbolic(self):
return any(
isinstance(param, (se.Basic, sp.Basic, str)) and not param.is_number
for param in self.getparams()
)
[docs]
def getparam(self, pn):
if pn not in self.parnames:
raise ValueError(f"Parameter {pn} not found.")
return getattr(self, pn)
def __str__(self):
return self.name
def __repr__(self):
return str(self)
def __eq__(self, other):
return isinstance(other, type(self)) and self.__dict__ == other.__dict__
[docs]
def copy(self):
return copy.copy(self)
[docs]
def deepcopy(self):
return copy.deepcopy(self)
[docs]
@abstractmethod
def iswrapper(self):
pass
[docs]
def isopalias(self):
return False
[docs]
def numparams(self):
return len(self.getparams())
def _decompose(self, circ, qubits, bits, zvars):
return circ.push(self, *qubits, *bits, *zvars)
[docs]
def decompose(self):
return self._decompose(
mc.Circuit(),
range(self.num_qubits),
range(self.num_bits),
range(self.num_zvars),
)
[docs]
def evaluate(self, d):
return self
[docs]
def isidentity(self):
return False
[docs]
def asciiwidth(self, qubits, bits, zvars):
# Calculate padding for qubits, bits, and zvars
namepadding = _gate_name_padding(qubits, bits, zvars)
# Calculate the width contribution of zvars
zvar_width = len(",".join(map(str, zvars))) if zvars else 0
# Assume operation has a string representation (e.g., __str__)
operation_repr = str(self)
# Calculate the width: | + (num + space) + name + zvars (if any) + |
if zvars and not qubits:
# If there are zvars but no qubits, ensure width includes zvars fully
return 1 + max(namepadding + len(operation_repr), zvar_width) + 1
else:
# Regular case where zvars and qubits are both present or only qubits
return 1 + namepadding + len(operation_repr) + 1
[docs]
def get_operation(self):
return self
# export operations
__all__ = ["Operation"]