예제 #1
0
    def wrapper(gate, **kwargs):
        if hasattr(gate, "gates"):
            result = QCircuit()
            for g in gate.gates:
                result += f(gate=g, **kwargs)
            return result

        elif hasattr(gate, 'U'):
            cU = QCircuit()
            for g in gate.U.gates:
                cU += f(gate=g, **kwargs)
            return type(gate)(U=cU, H=gate.H)
        elif hasattr(gate, 'transformation'):
            compiled = []
            for E in gate.args:
                if hasattr(E, 'name'):
                    compiled.append(E)
                else:
                    cU = QCircuit()
                    for g in E.U.gates:
                        cU += f(gate=g, **kwargs)
                    compiled.append(type(E)(U=cU, H=E.H))
            return type(gate)(args=compiled,
                              transformation=gate._transformation)
        else:
            return f(gate=gate, **kwargs)
예제 #2
0
    def wrapper(gate, **kwargs):
        if hasattr(gate, "gates"):
            result = QCircuit()
            for g in gate.gates:
                result += f(gate=g, **kwargs)
            return result

        elif hasattr(gate, 'U'):
            cU = QCircuit()
            for g in gate.U.gates:
                cU += f(gate=g, **kwargs)
            return type(gate)(U=cU, H=gate.H)
        elif hasattr(gate, 'transformations'):
            outer = []
            for args in gate.argsets:
                compiled = []
                for E in args:
                    if hasattr(E, 'name'):
                        compiled.append(E)
                    else:
                        cU = QCircuit()
                        for g in E.U.gates:
                            cU += f(gate=g, **kwargs)
                        compiled.append(type(E)(U=cU, H=E.H))
                outer.append(compiled)
            if isinstance(gate, Objective):
                return type(gate)(args=outer[0],
                                  transformation=gate._transformation)
            if isinstance(gate, VectorObjective):
                return type(gate)(argsets=outer,
                                  transformations=gate._transformations)
        else:
            return f(gate=gate, **kwargs)
예제 #3
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)
예제 #4
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
예제 #5
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)
예제 #6
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
예제 #7
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
예제 #8
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
예제 #9
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
예제 #10
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
예제 #11
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
예제 #12
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
예제 #13
0
def change_basis(target, axis, daggered=False):
    """
    helper function; returns circuit that performs change of basis.
    Parameters
    ----------
    target:
        the qubit having its basis changed
    axis:
        The axis of rotation to shift into.
    daggered: bool:
        adjusts the sign of the gate if axis = 1, I.E, change of basis about Y axis.

    Returns
    -------
    QCircuit that performs change of basis on target qubit onto desired axis

    """
    if isinstance(axis, str):
        axis = RotationGateImpl.string_to_axis[axis.lower()]

    if axis == 0:
        return H(target=target)
    elif axis == 1 and daggered:
        return Rx(angle=-numpy.pi / 2, target=target)
    elif axis == 1:
        return Rx(angle=numpy.pi / 2, target=target)
    else:
        return QCircuit()
예제 #14
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
예제 #15
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
예제 #16
0
def do_compile_trotterized_gate(generator, steps, factor, randomize, control):
    """
    Todo: Jakob, plz write
    """
    assert (generator.is_hermitian())
    circuit = QCircuit()
    factor = factor / steps
    for index in range(steps):
        paulistrings = generator.paulistrings
        if randomize:
            numpy.random.shuffle(paulistrings)
        for ps in paulistrings:
            coeff = to_float(ps.coeff)
            if len(ps._data) == 0 and len(control) > 0:
                circuit += Phase(target=control[0],
                                 control=control[1:],
                                 phi=-factor * coeff / 2)
            elif len(ps._data) > 0:
                circuit += ExpPauli(paulistring=ps.naked(),
                                    angle=factor * coeff,
                                    control=control)
            else:
                # ignore global phases
                pass
    return circuit
예제 #17
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)
예제 #18
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)
예제 #19
0
    def sample_paulistring(self, samples: int, paulistring, variables, *args,
                           **kwargs) -> numbers.Real:
        """
        Sample an individual pauli word (pauli string) and return the average result thereof.
        Parameters
        ----------
        samples: int:
            how many samples to evaluate.
        paulistring:
            the paulistring to be sampled.
        args
        kwargs

        Returns
        -------
        float:
            the average result of sampling the chosen paulistring
        """

        not_in_u = [
            q for q in paulistring.qubits if q not in self.abstract_qubits
        ]
        reduced_ps = paulistring.trace_out_qubits(qubits=not_in_u)
        if reduced_ps.coeff == 0.0:
            return 0.0
        if len(reduced_ps._data.keys()) == 0:
            return reduced_ps.coeff

        # make basis change and translate to backend
        basis_change = QCircuit()
        qubits = []
        for idx, p in reduced_ps.items():
            qubits.append(idx)
            basis_change += change_basis(target=idx, axis=p)

        # add basis change to the circuit
        # deepcopy is necessary to avoid changing the circuits
        # can be circumvented by optimizing the measurements
        # on construction: tq.ExpectationValue(H=H, U=U, optimize_measurements=True)
        circuit = self.create_circuit(circuit=copy.deepcopy(self.circuit),
                                      abstract_circuit=basis_change)
        # run simulators
        counts = self.sample(samples=samples,
                             circuit=circuit,
                             read_out_qubits=qubits,
                             variables=variables,
                             *args,
                             **kwargs)
        # compute energy
        E = 0.0
        n_samples = 0
        for key, count in counts.items():
            parity = key.array.count(1)
            sign = (-1)**parity
            E += sign * count
            n_samples += count
        assert n_samples == samples
        E = E / samples * paulistring.coeff
        return E
예제 #20
0
    def sample_paulistring(self, samples: int, paulistring, *args,
                           **kwargs) -> numbers.Real:
        # make basis change and translate to backend
        basis_change = QCircuit()
        not_in_u = [
        ]  # all indices of the paulistring which are not part of the circuit i.e. will always have the same outcome
        qubits = []
        for idx, p in paulistring.items():
            if idx not in self.abstract_qubit_map:
                not_in_u.append(idx)
            else:
                qubits.append(idx)
                basis_change += change_basis(target=idx, axis=p)

        # check the constant parts as <0|pauli|0>, can only be 0 or 1
        # so we can do a fast return of one of them is not Z
        for i in not_in_u:
            pauli = paulistring[i]
            if pauli.upper() != "Z":
                return 0.0

        # make measurement instruction
        measure = QCircuit()
        if len(qubits) == 0:
            # no measurement instructions for a constant term as paulistring
            return paulistring.coeff
        else:
            measure += Measurement(target=qubits)
            #measure += Measurement(name=str(paulistring), target=qubits)
            circuit = self.circuit + self.create_circuit(basis_change +
                                                         measure)
            # run simulators
            counts = self.do_sample(samples=samples,
                                    circuit=circuit,
                                    *args,
                                    **kwargs)
            # compute energy
            E = 0.0
            n_samples = 0
            for key, count in counts.items():
                parity = key.array.count(1)
                sign = (-1)**parity
                E += sign * count
                n_samples += count
            E = E / samples * paulistring.coeff
            return E
예제 #21
0
def hadamard_recursor(gate) -> QCircuit:
    if not isinstance(gate, PowerGateImpl) or gate.name not in [
            'H', 'h', 'hadamard'
    ]:
        return QCircuit.wrap_gate(gate)
    result = QCircuit()
    cl = 0
    if gate.is_controlled():
        cl = len(gate.control)
    if cl == 0:
        return hadamard_base(gate)
    if cl == 1:
        return hadamard_axbxc(gate)

    if cl == 2:
        v = type(gate)(name=gate.name,
                       power=gate.parameter / 2,
                       target=gate.target,
                       control=gate.control[1])
        result += hadamard_axbxc(v)
        result += CNOT(gate.control[0], gate.control[1])
        vdag = type(gate)(name=gate.name,
                          power=gate.parameter / 2,
                          target=gate.target,
                          control=gate.control[1]).dagger()
        result += hadamard_axbxc(vdag)
        result += CNOT(gate.control[0], gate.control[1])
        again = type(gate)(name=gate.name,
                           power=gate.parameter / 2,
                           target=gate.target,
                           control=gate.control[0])
        result += hadamard_axbxc(again)

    else:
        v = type(gate)(name=gate.name,
                       power=gate.parameter / 2,
                       target=gate.target,
                       control=gate.control[-1])
        result += hadamard_axbxc(v)
        result += CNOT(target=gate.control[cl - 1],
                       control=gate.control[0:cl - 1])
        vdag = type(gate)(name=gate.name,
                          power=gate.parameter / 2,
                          target=gate.target,
                          control=gate.control[-1]).dagger()
        result += hadamard_axbxc(vdag)
        result += CNOT(target=gate.control[cl - 1],
                       control=gate.control[0:cl - 1])
        rebuild = type(gate)(name=gate.name,
                             power=gate.parameter / 2,
                             target=gate.target,
                             control=gate.control[:cl - 1])
        result += hadamard_recursor(rebuild)
    return result
예제 #22
0
def change_basis(target, axis, daggered=False):
    if isinstance(axis, str):
        axis = RotationGateImpl.string_to_axis[axis.lower()]

    if axis == 0:
        return H(target=target)
    elif axis == 1 and daggered:
        return Rx(angle=-numpy.pi / 2, target=target)
    elif axis == 1:
        return Rx(angle=numpy.pi / 2, target=target)
    else:
        return QCircuit()
예제 #23
0
def compile_phase(gate) -> QCircuit:
    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)
예제 #24
0
def compile_power_base(gate):
    if not isinstance(gate, PowerGateImpl):
        return QCircuit.wrap_gate(gate)
    power = gate.parameter
    if gate.name in ['H', 'h', 'Hadamard', 'hadamard']:
        return compile_h_power(gate=gate)
    if 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
예제 #25
0
def hadamard_base(gate) -> QCircuit:
    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
예제 #26
0
def do_compile_trotterized_gate(generator, steps, factor, randomize, control):
    assert (generator.is_hermitian())
    circuit = QCircuit()
    factor = factor / steps
    for index in range(steps):
        paulistrings = generator.paulistrings
        if randomize:
            numpy.random.shuffle(paulistrings)
        for ps in paulistrings:
            if len(ps._data) == 0:
                print("ignoring constant term in trotterized gate")
                continue
            coeff = to_float(ps.coeff)
            circuit += ExpPauli(paulistring=ps.naked(),
                                angle=factor * coeff,
                                control=control)

    return circuit
예제 #27
0
def change_basis(target, axis=None, name=None, daggered=False):
    """
    helper function; returns circuit that performs change of basis.
    Parameters
    ----------
    target:
        the qubit having its basis changed
    axis:
        The axis of rotation to shift into.
    daggered: bool:
        adjusts the sign of the gate if axis = 1, I.E, change of basis about Y axis.

    Returns
    -------
    QCircuit that performs change of basis on target qubit onto desired axis

    """
    if axis is None and name is None:
        raise TequilaException('axis or name must be given.')

    if name:
        name = name.lower()
        if name in ['h', 'hadamard'] and daggered:
            return Ry(angle=numpy.pi / 4, target=target)
        elif name in ['h', 'hadamard']:
            return Ry(angle=-numpy.pi / 4, target=target)
        else:
            name_to_axis = {'rx': 0, 'ry': 1, 'rz': 2}
            axis = name_to_axis.get(name, name)

    if isinstance(axis, str):
        axis = RotationGateImpl.string_to_axis[axis.lower()]

    if axis == 0 and daggered:
        return Ry(angle=numpy.pi / 2, target=target)
    elif axis == 0:
        return Ry(angle=-numpy.pi / 2, target=target)
    elif axis == 1 and daggered:
        return Rx(angle=-numpy.pi / 2, target=target)
    elif axis == 1:
        return Rx(angle=numpy.pi / 2, target=target)
    else:
        return QCircuit()
예제 #28
0
def compile_to_single_control(gate) -> QCircuit:
    """
    break down a gate into a sequence with no more than single-controlled gates.
    Parameters
    ----------
    gate:
        the gate.

    Returns
    -------
        A QCircuit; the result of compilation.
    """
    if not gate.is_controlled:
        return QCircuit.wrap_gate(gate)
    cl = len(gate.control)
    target = gate.target
    control = gate.control
    if cl <= 1:
        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,
                            generator=gate.make_generator())
        partial = compile_power_gate(gate=new)
        back += compile_to_single_control(gate=partial)
    elif isinstance(gate, RotationGateImpl):
        partial = compile_controlled_rotation(gate=gate)
        back += compile_to_single_control(gate=partial)
    elif isinstance(gate, PhaseGateImpl):
        partial = compile_controlled_phase(gate=gate)
        back += compile_to_single_control(gate=partial)
    else:
        print(gate)
        raise TequilaException('frankly, what the f**k is this gate?')
    return back
예제 #29
0
def compile_multitarget(gate, variables=None) -> QCircuit:
    """
    If a gate is 'trivially' multitarget, split it into single target gates.
    Parameters
    ----------
    gate:
        the gate in question
    variables:
        Todo: Jakob plz write

    Returns
    -------
    QCircuit, the result of compilation.
    """
    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
예제 #30
0
def compile_toffoli(gate) -> QCircuit:
    """
    break down a toffoli gate into a sequence of CNOT and single qubit gates.
    Parameters
    ----------
    gate:
        the gate.

    Returns
    -------
        A QCircuit; the result of compilation.
    """

    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)