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"]