Source code for qrisp.qtypes.quantum_bool

"""
\********************************************************************************
* Copyright (c) 2023 the Qrisp authors
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
"""


import sys

from qrisp.core.quantum_variable import QuantumVariable
from qrisp.environments import control


[docs]class QuantumBool(QuantumVariable): """ QuantumBools are the quantum type, which represents boolean truth values. They are the return type of comparison operators like the equality ``==``. Apart from their behavior as a QuantumVariable, they can also be treated like :ref:`ControlEnvironments <ControlEnvironment>`. .. note: QuantumBools that are evaluated directly after a ``with`` statement are uncomputed automatically upon leaving the ControlEnvironment. Examples -------- We create a QuantumBool and set it to uniform superposition >>> from qrisp import QuantumBool, h >>> q_bool_0 = QuantumBool() >>> h(q_bool_0) >>> print(q_bool_0) {False: 0.5, True: 0.5} We create a second QuantumBool and evaluate some logical functions >>> q_bool_1 = QuantumBool() >>> print(q_bool_1 | q_bool_0) {False: 0.5, True: 0.5} >>> print(q_bool_1 & q_bool_0) {False: 1.0} QuantumBools are the results of comparisons: >>> from qrisp import QuantumFloat, QuantumChar >>> q_ch = QuantumChar() >>> q_ch[:] = {"g" : 1, "l" : -1} >>> q_bool_2 = (q_ch == "g") >>> q_bool_2.qs.statevector() sqrt(2)*(|g>*|True> - |l>*|False>)/2 For :ref:`QuantumFloats <QuantumFloat>`, numeric comparison is also possible: >>> qf = QuantumFloat(4) >>> h(qf[3]) >>> print(qf) {0: 0.5, 8: 0.5} >>> q_bool_3 = (qf >= 4) >>> print(q_bool_3) {False: 0.5, True: 0.5} To use a QuantumBool as a :ref:`ControlEnvironment`, we simply put it in a ``with`` statement: :: with q_bool_3: qf += 2 >>> print(qf) {0: 0.5, 10: 0.5} QuantumBools that are created directly after a ``with`` statement are uncomputed automatically: :: with qf == 10: q_bool_3.flip() >>> print(qf.qs) :: QuantumCircuit: -------------- ┌────────────┐ ┌───────────┐ qf.0: ─────┤0 ├─────┤0 ├──o─────────o── │ │ │ │ │ │ qf.1: ─────┤1 ├─────┤1 ├──■─────────■── │ │ │ __iadd__ │ │ │ qf.2: ─────┤2 ├─────┤2 ├──o─────────o── ┌───┐│ less_than │ │ │ │ │ qf.3: ┤ H ├┤3 ├─────┤3 ├──■─────────■── └───┘│ │┌───┐└─────┬─────┘ │ ┌───┐ │ lt_qbl.0: ─────┤4 ├┤ X ├──────■────────┼──┤ X ├──┼── │ │└───┘ │ └─┬─┘ │ lt_ancilla.0: ─────┤5 ├────────────────────┼────┼────┼── └────────────┘ ┌─┴─┐ │ ┌─┴─┐ cond_env.0: ─────────────────────────────────────┤ X ├──■──┤ X ├ └───┘ └───┘ Live QuantumVariables: --------------------- QuantumFloat qf QuantumBool lt_qbl Note that there is only a single QuantumBool listed in the "Live QuantumVariables" section, because the QuantumBool of the comparison ``qf == 10`` (called ``cond_env``) has been uncomputed. """ def __init__(self, qs=None, name=None): QuantumVariable.__init__(self, 1, qs=qs, name=name) self.qfloat_comparison = False def decoder(self, integer): return bool(integer) def __and__(self, other): from qrisp import mcx and_qbl = QuantumBool() mcx(self.reg + other.reg, and_qbl.reg) return and_qbl def __or__(self, other): from qrisp import mcx, x or_qbl = QuantumBool() x(self) x(other) mcx(self.reg + other.reg, or_qbl.reg) x(self) x(other) x(or_qbl) return or_qbl def __xor__(self, other): from qrisp import cx xor_qbl = QuantumBool() cx(self, xor_qbl) cx(other, xor_qbl) return xor_qbl
[docs] def flip(self): """ Flips the QuantumBool's value. """ from qrisp import x x(self) return self
def __invert__(self): inverted_qbl = QuantumBool() from qrisp import cx cx(self, inverted_qbl) inverted_qbl.flip() return inverted_qbl def __enter__(self): self.env = control(self) self.env.__enter__() def __exit__(self, a, b, c): ref_count = sys.getrefcount(self) # If the refcount is 5, this means that the QuantumBool has been # created in a "with" statement and can therefore no longer be reached # after exiting. We therefore uncompute self.env.__exit__(a, b, c) if ref_count == 5: self.uncompute() def __bool__(self): raise Exception("Tried to convert QuantumBool to classical bool (probable due using the and + or keywords - try using & + | instead)")