Ejemplo n.º 1
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.º 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_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.º 4
0
    def __init__(self,
                 abstract_circuit: QCircuit,
                 variables,
                 noise=None,
                 device=None,
                 qubit_map=None,
                 optimize_circuit=True,
                 *args,
                 **kwargs):
        """

        Parameters
        ----------
        abstract_circuit: QCircuit:
            the circuit which is to be rendered in the backend language.
        variables:
            values for the variables of abstract_circuit
        noise: optional:
            noise to apply to abstract circuit.
        device: optional:
            device on which to sample (or emulate sampling) abstract circuit.
        qubit_map: dictionary:
            a qubit map which maps the abstract qubits in the abstract_circuit to the qubits on the backend
            there is no need to initialize the corresponding backend types
            the dictionary should simply be {int:int} (preferred) or {int:name}
            if None the default will map to qubits 0 ... n_qubits -1 in the backend
        optimize_circuit: bool:
            whether or not to attempt backend depth optimization. Defaults to true.
        args
        kwargs
        """

        self._input_args = {
            "abstract_circuit": abstract_circuit,
            "variables": variables,
            "noise": noise,
            "qubit_map": qubit_map,
            "optimize_circuits": optimize_circuit,
            "device": device,
            **kwargs
        }

        self.no_translation = False
        self._variables = tuple(abstract_circuit.extract_variables())

        compiler_arguments = self.compiler_arguments
        if noise is not None:
            compiler_arguments["cc_max"] = True
            compiler_arguments["controlled_phase"] = True
            compiler_arguments["controlled_rotation"] = True
            compiler_arguments["hadamard_power"] = True

        # compile the abstract_circuit
        c = compiler.Compiler(**compiler_arguments)

        if qubit_map is None:
            qubit_map = {q: i for i, q in enumerate(abstract_circuit.qubits)}
        elif not qubit_map == {
                q: i
                for i, q in enumerate(abstract_circuit.qubits)
        }:
            warnings.warn(
                "reveived custom qubit_map = {}\n"
                "This is not fully integrated and might result in unexpected behaviour!"
                .format(qubit_map), TequilaWarning)

            if len(qubit_map) > abstract_circuit.max_qubit() + 1:
                raise TequilaException(
                    "Custom qubit_map has too many qubits {} vs {}".format(
                        len(qubit_map),
                        abstract_circuit.max_qubit() + 1))
            if max(qubit_map.keys()) > abstract_circuit.max_qubit():
                raise TequilaException(
                    "Custom qubit_map tries to assign qubit {} but we only have {}"
                    .format(max(qubit_map.keys()),
                            abstract_circuit.max_qubit()))

        # qubit map is initialized to have BackendQubits as values (they carry number and instance attributes)
        self.qubit_map = self.make_qubit_map(qubit_map)

        # pre-compilation (still an abstract ciruit, but with gates decomposed depending on backend requirements)
        compiled = c(abstract_circuit)
        self.abstract_circuit = compiled

        self.noise = noise
        self.check_device(device)
        self.device = self.retrieve_device(device)

        # translate into the backend object
        self.circuit = self.create_circuit(abstract_circuit=compiled,
                                           variables=variables)

        if optimize_circuit and noise is None:
            self.circuit = self.optimize_circuit(circuit=self.circuit)