Source code for simulaqron.virtual_node.basics

#
# Copyright (c) 2017, Stephanie Wehner and Axel Dahlberg
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#    This product includes software developed by Stephanie Wehner, QuTech.
# 4. Neither the name of the QuTech organization nor the
#    names of its contributors may be used to endorse or promote products
#    derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import abc

from twisted.spread import pb


[docs]class QuantumError(pb.Error): def __init__(self, value): self.value = value def __str__(self): return repr(self.value)
[docs]class NoQubitError(QuantumError): pass
[docs]class VirtNetError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value)
[docs]class QuantumEngine(pb.Referenceable, abc.ABC): """ Basic quantum engine. Abstract class meant to be subclassed to implement different simulation backends. """ def __init__(self, node: str, num: int, maxQubits: int = 10): """ Initialize the simple engine. :param node: Node name this register is started from. :type node: str :param num: Number of this register. :type num: int :param maxQubits: maximum number of qubits this register supports. If not give, it will default to 10. :type maxQubits: int """ self.maxQubits = maxQubits # Each register has a number, this may be used be the ``outside`` application # using this simulator self.num = num # Node that actually simulates this register self.simNode = node
[docs] @abc.abstractmethod def add_fresh_qubit(self) -> int: """ Add a new qubit initialized in the :math:`|0>` state. :return: The qubit number :rtype: int """ pass
[docs] @abc.abstractmethod def add_qubit(self, newQubit) -> int: """ Add new qubit in the state described by the density matrix newQubit :param newQubit: The new qubit state :type newQubit: Any :return: The qubit number :rtype: int """ pass
[docs] @abc.abstractmethod def remove_qubit(self, qubitNum: int) -> None: """ Removes the qubit with the desired number qubitNum :param qubitNum: Qubit number :type qubitNum: int :rtype: None """ pass
[docs] @abc.abstractmethod def get_register_RI(self): """ Retrieves the entire register in real and imaginary parts and returns the result as a list. Twisted only likes to send real valued lists, not complex ones. :return: The real and imaginary parts of a qubit state :rtype: tuple """ pass
[docs] @abc.abstractmethod def get_density_matrix_RI(self): """ Retrieves the entire register in real and imaginary parts and returns the result of the outer product. In other words, if the qubit is in state :math:`|q>`, this function returns the density matrix :math:`|q><q|` of the qubit. :return: The density matrix real and imaginary parts of a qubit state """ pass
[docs] @abc.abstractmethod def apply_H(self, qubitNum): """ Applies a Hadamard gate to the qubits with number qubitNum. :param qubitNum: Qubit number :type qubitNum: int :rtype: None """ pass
[docs] @abc.abstractmethod def apply_K(self, qubitNum): """ Applies a K gate to the qubits with number qubitNum. Maps computational basis to Y eigenbasis. :param qubitNum: Qubit number :type qubitNum: int :rtype: None """ pass
[docs] @abc.abstractmethod def apply_X(self, qubitNum): """ Applies an X gate to the qubits with number qubitNum. :param qubitNum: Qubit number :type qubitNum: int :rtype: None """ pass
[docs] @abc.abstractmethod def apply_Z(self, qubitNum): """ Applies a Z gate to the qubits with number qubitNum. :param qubitNum: Qubit number :type qubitNum: int :rtype: None """ pass
[docs] @abc.abstractmethod def apply_Y(self, qubitNum): """ Applies a Y gate to the qubits with number qubitNum. :param qubitNum: Qubit number :type qubitNum: int :rtype: None """ pass
[docs] @abc.abstractmethod def apply_T(self, qubitNum): """ Applies a T gate to the qubits with number qubitNum. :param qubitNum: Qubit number :type qubitNum: int :rtype: None """ pass
[docs] @abc.abstractmethod def apply_rotation(self, qubitNum, n, a): """ Applies a rotation around the axis n with the angle a to qubit with number qubitNum. If n is zero a ValueError is raised. :param qubitNum: Qubit number :type qubitNum: int :param n: A tuple of three numbers specifying the rotation axis, e.g n=(1,0,0) :type n: Tuple[int, int, int] :param a: The rotation angle in radians. :type a: float :rtype: None """ pass
[docs] @abc.abstractmethod def apply_CNOT(self, qubitNum1, qubitNum2): """ Applies the CNOT to the qubit with the numbers qubitNum1 and qubitNum2. :param qubitNum1: Qubit number 1 :type qubitNum1: int :param qubitNum2: Qubit number 2 :type qubitNum2: int :rtype: None """ pass
[docs] @abc.abstractmethod def apply_CPHASE(self, qubitNum1, qubitNum2): """ Applies the CPHASE to the qubit with the numbers qubitNum1 and qubitNum2. :param qubitNum1: Qubit number 1 :type qubitNum1: int :param qubitNum2: Qubit number 2 :type qubitNum2: int :rtype: None """ pass
[docs] @abc.abstractmethod def apply_onequbit_gate(self, gateU, qubitNum): """ Applies a unitary gate to the specified qubit. :param gateU: Unitary to apply as Qobj :type gateU: Qobj :param qubitNum: The number of the qubit this gate is applied to :type qubitNum: int :rtype: None """ pass
[docs] @abc.abstractmethod def apply_twoqubit_gate(self, gateU, qubit1, qubit2): """ Applies a unitary gate to the two specified qubits. :param gateU: Unitary to apply as Qobj :type gateU: Qobj :param qubit1: The first qubit :type qubit1: int :param qubit2: The second qubit :type qubit2: int :rtype: None """ pass
[docs] @abc.abstractmethod def measure_qubit_inplace(self, qubitNum): """ Measures the desired qubit in the standard basis. This returns the classical outcome. The quantum register is in the post-measurment state corresponding to the obtained outcome. :param qubitNum: Qubit to be measured :type qubitNum: int :return: The measurement outcome :rtype: int """ pass
[docs] @abc.abstractmethod def measure_qubit(self, qubitNum): """ Measures the desired qubit in the standard basis. This returns the classical outcome and deletes the qubit. :param qubitNum: Qubit to be measured :type qubitNum: int :return: The measurement outcome :rtype: int """ pass
[docs] @abc.abstractmethod def replace_qubit(self, qubitNum, state): """ Replaces the qubit at position qubitNum with the one given by state. :param qubitNum: Qubit to be replaced :type qubitNum: int :param state: New state to write in the place of the old qubit. :type state: Any :rtype: None """ pass
[docs] @abc.abstractmethod def absorb(self, other): """ Absorb the qubits from the other engine into this one. This is done by tensoring the state at the end. :param other: The other qubit to absorb. :type other: int :rtype: None """ pass
[docs] @abc.abstractmethod def absorb_parts(self, R, I, activeQ): """ Absorb the qubits, given in pieces :param R: Real part of the qubit state as a list. :type R: List[float] :param I: Imaginary part as a list. :type I: List[float] :param activeQ: Active number of qubits :rtype: None """ pass