Source code for mimiqcircuits.operations.inverse

#
# Copyright © 2022-2023 University of Strasbourg. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this 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.
#

import mimiqcircuits as mc
import sympy as sp
import symengine as se
import mimiqcircuits.lazy as lz
from mimiqcircuits.printutils import print_wrapped_parens


[docs] class Inverse(mc.Operation): """Inverse of the wrapped quantum operation. The inversion is not performed right away, but only when the circuit is cached or executed. .. warning:: Users should not use `Inverse` directly but rather the `inverse` method, which performs all the necessary simplifications (e.g., `op.inverse().inverse() == op`) Examples: >>> from mimiqcircuits import * >>> Inverse(GateP(1)).matrix() [1.0, 0] [0, 0.54030230586814 - 0.841470984807897*I] <BLANKLINE> >>> c = Circuit() >>> c.push(Inverse(GateP(1)), 1) 2-qubit circuit with 1 instructions: └── P(1)† @ q[1] <BLANKLINE> """ _name = "Inverse" _num_qubits = None _num_bits = 0 _num_cregs = 0 _op = None def __init__(self, operation, *args, **kwargs): if isinstance(operation, type) and issubclass(operation, mc.Operation): op = operation(*args, **kwargs) elif isinstance(operation, mc.Operation): op = operation else: raise ValueError("Operation must be an Operation object or type.") if isinstance(op, (mc.Barrier, mc.Reset, mc.Measure)): raise TypeError(f"{op.__class__.__name__} cannot be Inversed operation.") if op.num_bits != 0: raise ValueError("Cannot inverte operation with classical bits.") self.op = op super().__init__() self._num_qubits = op.num_qubits self._num_qregs = op._num_qregs self._qregsizes = op._qregsizes self._parnames = op.parnames def __str__(self): return f"{print_wrapped_parens(self.op)}†"
[docs] def iswrapper(self): return True
[docs] def inverse(self): return self.op
[docs] def getparams(self): return self.op.getparams()
def _power(self, pwr): return mc.Power(self, pwr)
[docs] def power(self, *args): if len(args) == 0: return lz.power(self) elif len(args) == 1: pwr = args[0] return self._power(pwr) else: raise ValueError("Invalid number of arguments.")
def __pow__(self, pwr): return self.power(pwr)
[docs] def control(self, *args): if len(args) == 0: return lz.control(self) elif len(args) == 1: num_controls = args[0] return mc.Control(num_controls, self) else: raise ValueError("Invalid number of arguments.")
[docs] def parallel(self, *args): if len(args) == 0: return lz.parallel(self) elif len(args) == 1: num_repeats = args[0] return mc.Parallel(num_repeats, self) else: raise ValueError("Invalid number of arguments.")
[docs] def matrix(self): return se.Matrix(sp.simplify(sp.Matrix(self.op.matrix().inv()).evalf()))
[docs] def evaluate(self, d): return self.op.evaluate(d).inverse()
def _decompose(self, circ, qubits, bits): newc = self.op._decompose(mc.Circuit(), qubits, bits).inverse() circ.append(newc) return circ
__all__ = ["Inverse"]