Ejemplo n.º 1
0
def compile_to_cc(gate) -> QCircuit:
    if not gate.is_controlled:
        return QCircuit.wrap_gate(gate)
    cl = len(gate.control)
    target = gate.target
    control = gate.control
    if cl <= 2:
        return QCircuit.wrap_gate(gate)
    name = gate.name
    back = QCircuit()
    if name in ['X', 'x', 'Y', 'y', 'Z', 'z', 'H', 'h']:
        if isinstance(gate, PowerGateImpl):
            power = gate.parameter
        else:
            power = 1.0
        new = PowerGateImpl(name=name,
                            power=power,
                            target=target,
                            control=control)
        back += compile_power_gate(gate=new, cut=True)
    elif isinstance(gate, RotationGateImpl):
        partial = compile_controlled_rotation(gate=gate)
        back += compile_to_cc(gate=partial)
    elif isinstance(gate, PhaseGateImpl):
        partial = compile_controlled_phase(gate=gate)
        back += compile_to_cc(gate=partial)
    else:
        print(gate)
        raise TequilaException('frankly, what the f**k is this gate?')
    return back
Ejemplo n.º 2
0
def compile_controlled_rotation(gate: RotationGateImpl) -> QCircuit:
    """
    Recompilation of a controlled-rotation gate
    Basis change into Rz then recompilation of controled Rz, then change basis back
    :param gate: The rotational gate
    :return: set of gates wrapped in QCircuit class
    """

    if not gate.is_controlled():
        return QCircuit.wrap_gate(gate)

    if not isinstance(gate, RotationGateImpl):
        return QCircuit.wrap_gate(gate)

    if len(gate.target) > 1:
        return compile_controlled_rotation(gate=compile_multitarget(gate=gate))

    target = gate.target
    control = gate.control
    k = len(control)
    cind = _pattern(k) + [k - 1]

    result = QCircuit()
    result += change_basis(target=target, axis=gate._axis)
    coeff = -1 / pow(2, k)
    for i, ci in enumerate(cind):
        coeff *= -1

        result += Rz(target=target, angle=coeff * gate.parameter)
        result += CNOT(control[ci], target)
    result += change_basis(target=target, axis=gate._axis, daggered=True)

    result.n_qubits = result.max_qubit() + 1
    return result
Ejemplo n.º 3
0
def compile_generalized_rotation_gate(gate,
                                      compile_exponential_pauli: bool = False):
    """
    Parameters
    ----------
    gate
    compile_exponential_pauli

    Returns
    -------

    """
    if gate.generator is None or gate.name.lower() in [
            'phase', 'rx', 'ry', 'rz'
    ]:
        return QCircuit.wrap_gate(gate)
    if not hasattr(gate, "eigenvalues_magnitude"):
        return QCircuit.wrap_gate(gate)

    steps = 1 if not hasattr(gate, "steps") else gate.steps

    return do_compile_trotterized_gate(generator=gate.generator,
                                       steps=steps,
                                       randomize=False,
                                       factor=gate.parameter,
                                       control=gate.control)
Ejemplo n.º 4
0
def compile_controlled_rotation(gate: RotationGateImpl,
                                angles: list = None) -> QCircuit:
    """
    Recompilation of a controlled-rotation gate
    Basis change into Rz then recompilation of controled Rz, then change basis back
    :param gate: The rotational gate
    :param angles: new angles to set, given as a list of two. If None the angle in the gate is used (default)
    :return: set of gates wrapped in QCircuit class
    """

    if not gate.is_controlled():
        return QCircuit.wrap_gate(gate)

    if not isinstance(gate, RotationGateImpl):
        return QCircuit.wrap_gate(gate)

    if angles is None:
        angles = [gate.parameter / 2, -gate.parameter / 2]

    if len(gate.target) > 1:
        return compile_controlled_rotation(gate=compile_multitarget(gate=gate),
                                           angles=angles)

    target = gate.target
    control = gate.control
    result = QCircuit()
    result += change_basis(target=target, axis=gate._axis)
    result += RotationGateImpl(axis="z", target=target, angle=angles[0])
    result += QGateImpl(name="X", target=target, control=control)
    result += RotationGateImpl(axis="Z", target=target, angle=angles[1])
    result += QGateImpl(name="X", target=target, control=control)
    result += change_basis(target=target, axis=gate._axis, daggered=True)

    result.n_qubits = result.max_qubit() + 1
    return result
Ejemplo n.º 5
0
def compile_controlled_phase(gate) -> QCircuit:
    if not isinstance(gate, PhaseGateImpl):
        return QCircuit.wrap_gate(gate)
    if len(gate.control) == 0:
        return QCircuit.wrap_gate(gate)
    count = len(gate.control)
    result = QCircuit()
    phase = gate.parameter

    if count == 1:
        result += H(target=gate.target)
        result += CNOT(gate.control, gate.target)
        result += H(target=gate.target)
        result += Phase(gate.parameter + numpy.pi, target=gate.target)
    elif count == 2:
        result += Rz(angle=phase / (2**2), target=gate.control[0])
        result += Rz(angle=phase / (2**(1)),
                     target=gate.control[1],
                     control=gate.control[0])
        result += Rz(angle=phase, target=gate.target, control=gate.control)

    elif count >= 3:
        result += Rz(angle=phase / (2**count), target=gate.control[0])
        for i in range(1, count):
            result += Rz(angle=phase / (2**(count - i)),
                         target=gate.control[i],
                         control=gate.control[0:i])
        result += Rz(angle=phase, target=gate.target, control=gate.control)
    return result
Ejemplo n.º 6
0
def compile_controlled_power(gate: PowerGateImpl) -> QCircuit:
    """
    Recompilation of a controlled-power gate
    Basis change into Z then recompilation of controled Z, then change basis back
    :param gate: The power gate
    :return: set of gates wrapped in QCircuit class
    """
    if not gate.is_controlled():
        return QCircuit.wrap_gate(gate)

    if not isinstance(gate, PowerGateImpl):
        return QCircuit.wrap_gate(gate)

    if len(gate.target) > 1:
        return compile_controlled_power(gate=compile_multitarget(gate=gate))

    power = gate.power
    target = gate.target
    control = gate.control

    result = QCircuit()
    result += Phase(target=control[0], control=control[1:], phi=power * pi / 2)
    result += change_basis(target=target, name=gate.name)
    result += Rz(target=target, control=control, angle=power * pi)
    result += change_basis(target=target, name=gate.name, daggered=True)

    result.n_qubits = result.max_qubit() + 1
    return result
Ejemplo n.º 7
0
def compile_controlled_phase(gate) -> QCircuit:
    """
    Compile multi-controlled phase gates to 1q - phase gate and multi-controlled Rz gates.
    Parameters
    ----------
    gate:
        the gate.

    Returns
    -------
    QCircuit, the result of compilation.
    """
    if not isinstance(gate, PhaseGateImpl):
        return QCircuit.wrap_gate(gate)

    if len(gate.control) == 0:
        return QCircuit.wrap_gate(gate)

    phase = gate.parameter

    result = QCircuit()
    result += Phase(target=gate.control[0],
                    control=gate.control[1:],
                    phi=phase / 2)
    result += Rz(target=gate.target, control=gate.control, angle=phase)
    return compile_controlled_phase(result)
Ejemplo n.º 8
0
def compile_multitarget(gate, variables=None) -> QCircuit:
    targets = gate.target

    # don't compile real multitarget gates
    if hasattr(gate, "generator") or hasattr(gate, "generators") or hasattr(
            gate, "paulistring"):
        return QCircuit.wrap_gate(gate)

    if isinstance(gate, ExponentialPauliGateImpl) or isinstance(
            gate, TrotterizedGateImpl):
        return QCircuit.wrap_gate(gate)

    if len(targets) == 1:
        return QCircuit.wrap_gate(gate)

    if isinstance(gate, MeasurementImpl):
        return QCircuit.wrap_gate(gate)

    if gate.name.lower() in ["swap", "iswap"]:
        return QCircuit.wrap_gate(gate)

    result = QCircuit()
    for t in targets:
        gx = copy.deepcopy(gate)
        gx._target = (t, )
        result += gx

    return result
Ejemplo n.º 9
0
def compile_power_base(gate):
    """
    Base case of compile_power_gate: convert a 1-qubit parametrized power gate into rotation gates.
    Parameters
    ----------
    gate:
        the gate.

    Returns
    -------
        A QCircuit; the result of compilation.
    """
    if not isinstance(gate, PowerGateImpl):
        return QCircuit.wrap_gate(gate)

    if gate.is_controlled():
        return QCircuit.wrap_gate(gate)

    power = gate.power
    if gate.name.lower() in ['h', 'hadamard']:
        ### off by global phase of Exp[ pi power /2]
        theta = power * numpy.pi

        result = QCircuit()
        result += Ry(angle=-numpy.pi / 4, target=gate.target)
        result += Rz(angle=theta, target=gate.target)
        result += Ry(angle=numpy.pi / 4, target=gate.target)
    elif gate.name == 'X':
        ### off by global phase of Exp[ pi power /2]
        '''
        if we wanted to do it formally we would use the following
        a=-numpy.pi/2
        b=numpy.pi/2
        theta = power*numpy.pi

        result = QCircuit()
        result+= Rz(angle=b,target=gate.target)
        result+= Ry(angle=theta,target=gate.target)
        result+= Rz(angle=a,target=gate.target)
        '''
        result = Rx(angle=power * numpy.pi, target=gate.target)
    elif gate.name == 'Y':
        ### off by global phase of Exp[ pi power /2]
        theta = power * numpy.pi

        result = QCircuit()
        result += Ry(angle=theta, target=gate.target)
    elif gate.name == 'Z':
        ### off by global phase of Exp[ pi power /2]
        a = 0
        b = power * numpy.pi
        theta = 0
        result = QCircuit()
        result += Rz(angle=b, target=gate.target)
    else:
        raise TequilaException('passed a gate with name ' + gate.name +
                               ', which cannot be handled!')
    return result
Ejemplo n.º 10
0
def compile_power_gate(gate, cut=False) -> QCircuit:
    if not isinstance(gate, PowerGateImpl):
        return QCircuit.wrap_gate(gate)
    if gate.name.lower() in ['h', 'hadamard']:
        return QCircuit.wrap_gate(gate=gate)
    if not gate.is_controlled():
        return compile_power_base(gate=gate)

    return power_recursor(gate=gate, cut=cut)
Ejemplo n.º 11
0
def ExpPauli(paulistring: typing.Union[PauliString, str],
             angle,
             control: typing.Union[list, int] = None):
    """Exponentiated Pauligate:
    
    ExpPauli(PauliString, angle) = exp(-i* angle/2* PauliString)

    Parameters
    ----------
    paulistring :
        given as PauliString structure or as string or dict or list
        if given as string: Format should be like X(0)Y(3)Z(2)
        if given as list: Format should be like [(0,'X'),(3,'Y'),(2,'Z')]
        if given as dict: Format should be like { 0:'X', 3:'Y', 2:'Z' }
    angle :
        the angle (will be multiplied by paulistring coefficient if there is one)
    control :
        control qubits
    paulistring: typing.Union[PauliString :
        
    str] :
        
    control: typing.Union[list :
        
    int] :
         (Default value = None)

    Returns
    -------
    type
        Gate wrapped in circuit

    """

    if isinstance(paulistring, str):
        ps = PauliString.from_string(string=paulistring)
    elif isinstance(paulistring, list):
        ps = PauliString.from_openfermion(key=list)
    elif isinstance(paulistring, dict):
        ps = PauliString(data=paulistring)
    else:
        ps = paulistring

    # Failsave: If the paulistring contains just one pauli matrix
    # it is better to initialize a rotational gate due to strange conventions in some simulators
    if len(ps.items()) == 1:
        target, axis = tuple(ps.items())[0]
        return QCircuit.wrap_gate(
            impl.RotationGateImpl(axis=axis,
                                  target=target,
                                  angle=ps.coeff * assign_variable(angle),
                                  control=control))
    else:
        return QCircuit.wrap_gate(
            impl.ExponentialPauliGateImpl(paulistring=ps,
                                          angle=angle,
                                          control=control))
Ejemplo n.º 12
0
def compile_gaussian_gate(gate, compile_exponential_pauli: bool = False):
    if not hasattr(gate, "generator"):
        return QCircuit.wrap_gate(gate)
    if not hasattr(gate, "shift"):
        return QCircuit.wrap_gate(gate)

    return do_compile_trotterized_gate(generator=gate.generator,
                                       steps=gate.steps,
                                       randomize=False,
                                       factor=gate.parameter,
                                       control=gate.control)
Ejemplo n.º 13
0
def _initialize_power_gate(name: str,
                           target: typing.Union[list, int],
                           control: typing.Union[list, int] = None,
                           power=None) -> QCircuit:
    if power is None or power in [1, 1.0]:
        return QCircuit.wrap_gate(
            QGateImpl(name=name, target=target, control=control))
    else:
        return QCircuit.wrap_gate(
            PowerGateImpl(name=name,
                          power=power,
                          target=target,
                          control=control))
Ejemplo n.º 14
0
def compile_swap(gate) -> QCircuit:
    """
    Compile swap gates into CNOT.
    Parameters
    ----------
    gate:
        the gate.

    Returns
    -------
    QCircuit, the result of compilation.
    """
    if gate.name.lower() == "swap":
        if len(gate.target) != 2:
            raise TequilaCompilerException("SWAP gates needs two targets")
        power = 1
        if hasattr(gate, "power"):
            if power is None or power in [1, 1.0]:
                pass
            else:
                raise TequilaCompilerException(
                    "Parametrized SWAPs should be decomposed on top level! Something went wrong"
                )

        c = []
        if gate.control is not None:
            c = gate.control
        return X(target=gate.target[0], control=[gate.target[1]]) \
               + X(target=gate.target[1], control=[gate.target[0]] + list(c), power=power) \
               + X(target=gate.target[0], control=[gate.target[1]])

    else:
        return QCircuit.wrap_gate(gate)
Ejemplo n.º 15
0
def compile_trotterized_gate(gate, compile_exponential_pauli: bool = False):
    if not hasattr(gate, "generators") or not hasattr(gate, "steps"):
        return QCircuit.wrap_gate(gate)

    c = 1.0
    result = QCircuit()
    if gate.join_components:
        for step in range(gate.steps):
            if gate.randomize_component_order:
                numpy.random.shuffle(gate.generators)
            for i, g in enumerate(gate.generators):
                if gate.angles is not None:
                    c = gate.angles[i]
                result += do_compile_trotterized_gate(generator=g,
                                                      steps=1,
                                                      factor=c / gate.steps,
                                                      randomize=gate.randomize,
                                                      control=gate.control)
    else:
        if gate.randomize_component_order:
            numpy.random.shuffle(gate.generators)
        for i, g in enumerate(gate.generators):
            if gate.angles is not None:
                c = gate.angles[i]
            result += do_compile_trotterized_gate(generator=g,
                                                  steps=gate.steps,
                                                  factor=c,
                                                  randomize=gate.randomize,
                                                  control=gate.control)

    if compile_exponential_pauli:
        return compile_exponential_pauli_gate(result)
    else:
        return result
Ejemplo n.º 16
0
def compile_toffoli(gate) -> QCircuit:
    if gate.name.lower != 'x':
        return QCircuit.wrap_gate(gate)
    control = gate.control
    c1 = control[1]
    c0 = control[0]
    target = gate.target
    result = QCircuit()
    result += H(target)
    result += CNOT(c1, target)
    result += T(target).dagger()
    result += CNOT(c0, target)
    result += T(target)
    result += CNOT(c1, target)
    result += T(target).dagger()
    result += CNOT(c0, target)
    result += T(c1)
    result += T(target)
    result += CNOT(c0, c1)
    result += H(target)
    result += T(c0)
    result += T(c1).dagger()
    result += CNOT(c0, c1)

    return (result)
Ejemplo n.º 17
0
def RotationGate(axis: int,
                 angle: typing.Union[typing.Hashable, numbers.Number],
                 target: typing.Union[list, int],
                 control: typing.Union[list, int] = None):
    """
    Notes
    ----------
    Initialize an abstract rotation gate of the form

    .. math::
        R_{\\text{axis}}(\\text{angle}) = e^{-i\\frac{\\text{angle}}{2} \\sigma_{\\text{axis}}}


    Parameters
    ----------
    axis
        integer 1 for x, 2 for y, 3 for z
    angle
        Hashable type (will be treated as Variable) or Numeric type (static angle)
    target
        integer or list of integers
    control
        integer or list of integers

    Returns
    -------
    QCircuit object with this RotationGate
    """
    return QCircuit.wrap_gate(
        RotationGateImpl(axis=axis,
                         angle=angle,
                         target=target,
                         control=control))
Ejemplo n.º 18
0
def Rz(angle,
       target: typing.Union[list, int],
       control: typing.Union[list, int] = None) -> QCircuit:
    """
    Notes
    ----------
    Rz gate of the form

    .. math::
        R_{z}(\\text{angle}) = e^{-i\\frac{\\text{angle}}{2} \\sigma_{z}}


    Parameters
    ----------
    angle
        Hashable type (will be treated as Variable) or Numeric type (static angle)
    target
        integer or list of integers
    control
        integer or list of integers

    Returns
    QCircuit object with this RotationGate
    -------
    """
    return QCircuit.wrap_gate(
        RotationGateImpl(axis=2, angle=angle, target=target, control=control))
Ejemplo n.º 19
0
def compile_ry(gate: RotationGateImpl,
               controlled_rotation: bool = False) -> QCircuit:
    """
    Compile Ry gates into Rx and Rz.
    Parameters
    ----------
    gate:
        the gate.
    controlled_rotation:
        determines if the decomposition of the controlled-Ry gate will be performed in compile_controlled_rotation,
        if not, decomposition will be performed here

    Returns
    -------
    QCircuit, the result of compilation.
    """
    if gate.name.lower() == "ry":

        if not (gate.is_controlled() and controlled_rotation):

            return Rz(target=gate.target, control=None, angle=-numpy.pi / 2) \
                   + Rx(target=gate.target, control=gate.control, angle=gate.parameter) \
                   + Rz(target=gate.target, control=None, angle=numpy.pi / 2)

    return QCircuit.wrap_gate(gate)
Ejemplo n.º 20
0
def PowerGate(name: str,
              target: typing.Union[list, int],
              power: float = None,
              angle: float = None,
              control: typing.Union[list, int] = None,
              generator: QubitHamiltonian = None):
    """
    Initialize a (potentially parametrized) gate which is supported on the backend

    Parameters
    ----------
    name: str
        name of the gate on the backend (usually, H, X, Y, Z)
    target
        int or list of int
    power
        numeric type (fixed exponent) or hashable type (parametrized exponent)
        will be interpreted as
    angle
        similar to power, but will be interpreted as
        .. math::
           U=e^{-i\\frac{angle}{2} generator}
    control
        int or list of int

    Returns
    -------

    """
    return QCircuit.wrap_gate(
        impl.PowerGateImpl(name=name,
                           power=power,
                           target=target,
                           control=control,
                           generator=generator))
Ejemplo n.º 21
0
def compile_swap(gate) -> QCircuit:
    """
    Compile swap gates into CNOT.
    Parameters
    ----------
    gate:
        the gate.

    Returns
    -------
    QCircuit, the result of compilation.
    """
    if gate.name.lower() == "swap":
        if len(gate.target) != 2:
            raise TequilaCompilerException("SWAP gates needs two targets")
        if hasattr(gate, "power") and gate.parameter != 1:
            raise TequilaCompilerException(
                "SWAP gate with power can not be compiled into CNOTS")

        c = []
        if gate.control is not None:
            c = gate.control
        return X(target=gate.target[0], control=gate.target[1] + c) \
               + X(target=gate.target[1], control=gate.target[0] + c) \
               + X(target=gate.target[0], control=gate.target[1] + c)

    else:
        return QCircuit.wrap_gate(gate)
Ejemplo n.º 22
0
def compile_trotterized_gate(gate, compile_exponential_pauli: bool = False):
    """
    Parameters
    ----------
    gate
    compile_exponential_pauli

    Returns
    -------

    """
    if not hasattr(gate, "steps") or hasattr(gate, "eigenvalues_magnitude"):
        return QCircuit.wrap_gate(gate)

    randomize = False
    if hasattr(gate, "randomize"):
        randomize = gate.randomize
    result = do_compile_trotterized_gate(generator=gate.generator,
                                         steps=gate.steps,
                                         factor=gate.parameter,
                                         randomize=randomize,
                                         control=gate.control)

    if compile_exponential_pauli:
        return compile_exponential_pauli_gate(result)
    else:
        return result
Ejemplo n.º 23
0
def Phase(phi: typing.Union[typing.Hashable, numbers.Number],
          target: typing.Union[list, int],
          control: typing.Union[list, int] = None) -> QCircuit:
    """
    Notes
    ----------
    Initialize an abstract phase gate which acts as

    .. math::
        S(\\phi) = \\begin{pmatrix} 1 & 0 \\\\ 0 & e^{i\\phi} \\end{pmatrix}

    Parameters
    ----------
    phi
        defines the phase, can be numeric type (static gate) or hashable non-numeric type (parametrized gate)
    target
        int or list of int
    control
        int or list of int

    Returns
    -------
    QCircuit object

    """
    return QCircuit.wrap_gate(
        PhaseGateImpl(phase=phi, target=target, control=control))
Ejemplo n.º 24
0
def compile_phase(gate) -> QCircuit:
    """
    Compile phase gates into Rz gates and cnots, if controlled
    Parameters
    ----------
    gate:
        the gate

    Returns
    -------
    QCircuit, the result of compilation.
    """
    if not isinstance(gate, PhaseGateImpl):
        return QCircuit.wrap_gate(gate)
    phase = gate.parameter
    result = QCircuit()
    if len(gate.control) == 0:
        return Rz(angle=phase, target=gate.target)

    if len(gate.control) == 1:
        result += Rz(angle=phase / 2, target=gate.control, control=None)
        result += Rz(angle=phase, target=gate.target, control=gate.control)
        return result
    else:
        return compile_controlled_phase(gate)
Ejemplo n.º 25
0
def _initialize_power_gate(name: str,
                           target: typing.Union[list, int],
                           generator,
                           control: typing.Union[list, int] = None,
                           power=None,
                           angle=None) -> QCircuit:
    target = list_assignment(target)

    if angle is not None:
        angle = assign_variable(angle)
        if power is not None:
            power = power * angle / np.pi
        else:
            power = angle / np.pi

    if power is None or power in [1, 1.0]:
        gates = [
            impl.QGateImpl(name=name,
                           target=q,
                           control=control,
                           generator=generator(q)) for q in target
        ]
    else:
        gates = [
            impl.PowerGateImpl(name=name,
                               power=power,
                               target=q,
                               control=control,
                               generator=generator(q)) for q in target
        ]

    return QCircuit.wrap_gate(gates)
Ejemplo n.º 26
0
def hadamard_axbxc(gate) -> QCircuit:
    """
    Decompose 1 control parametrized hadamard into single qubit rotation and CNOT.
    Parameters
    ----------
    gate:
        the gate

    Returns
    -------
    QCircuit, the result of compilation.
    """
    if not isinstance(gate, PowerGateImpl) or gate.name not in [
            'H', 'h', 'hadamard'
    ]:
        return QCircuit.wrap_gate(gate)
    power = gate.parameter
    target = gate.target
    a = power.wrap(a_calc)
    b = power.wrap(b_calc)
    theta = power.wrap(theta_calc)
    phase = power * jnp.pi / 2

    result = QCircuit()

    result += Rz((a - b) / 2, target)
    result += CNOT(gate.control, target)
    result += Rz(-(a + b) / 2, target)
    result += Ry(-theta / 2, target)
    result += CNOT(gate.control, target)
    result += Ry(theta / 2, target)
    result += Rz(a, target)
    result += Phase(numpy.pi * power / 2, gate.control)

    return result
Ejemplo n.º 27
0
def hadamard_base(gate) -> QCircuit:
    """
    base case for hadamard compilation; returns powers of hadamard as sequence of single qubit rotations.
    Parameters
    ----------
    gate:
        the gate.

    Returns
    -------
        A QCircuit; the result of compilation.
    """
    if not isinstance(gate, PowerGateImpl) or gate.name not in [
            'H', 'h', 'hadamard'
    ]:
        return QCircuit.wrap_gate(gate)
    power = gate.parameter
    a = power.wrap(a_calc)
    b = power.wrap(b_calc)
    theta = power.wrap(theta_calc)

    result = QCircuit()

    result += Rz(angle=b, target=gate.target)
    result += Ry(angle=theta, target=gate.target)
    result += Rz(angle=a, target=gate.target)

    return result
Ejemplo n.º 28
0
def compile_exponential_pauli_gate(gate) -> QCircuit:
    """
    Returns the circuit: exp(i*angle*paulistring)
    primitively compiled into X,Y Basis Changes and CNOTs and Z Rotations
    :param paulistring: The paulistring in given as tuple of tuples (openfermion format)
    like e.g  ( (0, 'Y'), (1, 'X'), (5, 'Z') )
    :param angle: The angle which parametrizes the gate -> should be real
    :returns: the above mentioned circuit as abstract structure
    """

    if hasattr(gate, "paulistring"):

        angle = gate.paulistring.coeff * gate.parameter

        circuit = QCircuit()

        # the general circuit will look like:
        # series which changes the basis if necessary
        # series of CNOTS associated with basis changes
        # Rz gate parametrized on the angle
        # series of CNOT (inverted direction compared to before)
        # series which changes the basis back
        ubasis = QCircuit()
        ubasis_t = QCircuit()
        cnot_cascade = QCircuit()

        last_qubit = None
        previous_qubit = None
        for k, v in gate.paulistring.items():
            pauli = v
            qubit = [k]  # wrap in list for targets= ...

            # see if we need to change the basis
            axis = 2
            if pauli.upper() == "X":
                axis = 0
            elif pauli.upper() == "Y":
                axis = 1
            ubasis += change_basis(target=qubit, axis=axis)
            ubasis_t += change_basis(target=qubit, axis=axis, daggered=True)

            if previous_qubit is not None:
                cnot_cascade += X(target=qubit, control=previous_qubit)
            previous_qubit = qubit
            last_qubit = qubit

        reversed_cnot = cnot_cascade.dagger()

        # assemble the circuit
        circuit += ubasis
        circuit += cnot_cascade
        circuit += Rz(target=last_qubit, angle=angle, control=gate.control)
        circuit += reversed_cnot
        circuit += ubasis_t

        return circuit

    else:
        return QCircuit.wrap_gate(gate)
Ejemplo n.º 29
0
def QGate(name,
          target: typing.Union[list, int],
          control: typing.Union[list, int] = None,
          generator: QubitHamiltonian = None):
    return QCircuit.wrap_gate(
        impl.QGateImpl(name=name,
                       target=target,
                       control=control,
                       generator=generator))
Ejemplo n.º 30
0
def Trotterized(generators: typing.List[QubitHamiltonian],
                steps: int,
                angles: typing.Union[
                    typing.List[typing.Hashable], typing.List[numbers.Real], typing.List[Variable]] = None,
                control: typing.Union[list, int] = None,
                parameters: TrotterParameters = None) -> QCircuit:
    """

    Parameters
    ----------
    generators :
        list of generators
    angles :
        coefficients for each generator
    steps :
        trotter steps
    control :
        control qubits
    parameters :
        Additional Trotter parameters, if None then defaults are used
    generators: typing.List[QubitHamiltonian] :
        
    steps: int :
        
    angles: typing.Union[typing.List[typing.Hashable] :
        
    typing.List[numbers.Real] :
        
    typing.List[Variable]] :
         (Default value = None)
    control: typing.Union[list :
        
    int] :
         (Default value = None)
    parameters: TrotterParameters :
         (Default value = None)

    Returns
    -------
    QCircuit

    """

    # convenience
    if not (isinstance(generators, list) or isinstance(generators, tuple)):
        generators = [generators]
    if not (isinstance(angles, list) or isinstance(angles, tuple)):
        angles = [angles]

    if parameters is None:
        parameters = TrotterParameters()

    assigned_angles = [assign_variable(angle) for angle in angles]

    return QCircuit.wrap_gate(
        TrotterizedGateImpl(generators=generators, angles=assigned_angles, steps=steps, control=control,
                            **parameters.__dict__))