コード例 #1
0
def S(qubit: QubitDesignator) -> Gate:
    """Produces the S gate::

        S = [[1, 0],
             [0, 1j]]

    This gate is a single qubit S-gate.

    :param qubit: The qubit apply the gate to.
    :returns: A Gate object.
    """
    return Gate(name="S", params=[], qubits=[unpack_qubit(qubit)])
コード例 #2
0
def H(qubit: QubitDesignator) -> Gate:
    """Produces the Hadamard gate::

        H = (1 / sqrt(2)) * [[1,  1],
                             [1, -1]]

    Produces the H instruction. This gate is a single qubit Hadamard gate.

    :param qubit: The qubit apply the gate to.
    :returns: A Gate object.
    """
    return Gate(name="H", params=[], qubits=[unpack_qubit(qubit)])
コード例 #3
0
def Y(qubit: QubitDesignator) -> Gate:
    """Produces the Y gate::

        Y = [[0, 0 - 1j],
             [0 + 1j, 0]]

    This gate is a single qubit Y-gate.

    :param qubit: The qubit apply the gate to.
    :returns: A Gate object.
    """
    return Gate(name="Y", params=[], qubits=[unpack_qubit(qubit)])
コード例 #4
0
def X(qubit: QubitDesignator) -> Gate:
    """Produces the X ("NOT") gate::

        X = [[0, 1],
             [1, 0]]

    This gate is a single qubit X-gate.

    :param qubit: The qubit apply the gate to.
    :returns: A Gate object.
    """
    return Gate(name="X", params=[], qubits=[unpack_qubit(qubit)])
コード例 #5
0
ファイル: PyQuilListener.py プロジェクト: tim-yit-chen/pyquil
    def exitGate(self, ctx: QuilParser.GateContext):
        gate_name = ctx.name().getText()
        params = list(map(_param, ctx.param()))
        qubits = list(map(_qubit, ctx.qubit()))
        # The Gate.controlled() method *prepends* the CONTROLLED modifier to the gate. But the
        # parser works from the outside-in. Therefore the controlled qubits would be in reverse
        # order. We reverse here to fix that.
        modifiers = [mod.getText() for mod in ctx.modifier()][::-1]
        control_qubits = qubits[0:len(list(filter(lambda str: str == "CONTROLLED", modifiers)))][::-1]
        target_qubits = qubits[len(control_qubits):]

        if gate_name in QUANTUM_GATES:
            if params:
                gate = QUANTUM_GATES[gate_name](*params, *target_qubits)
            else:
                gate = QUANTUM_GATES[gate_name](*target_qubits)
        else:
            gate = Gate(gate_name, params, target_qubits)

        for modifier in modifiers:
            if modifier == "CONTROLLED":
                gate.controlled(control_qubits.pop(0))
            elif modifier == "DAGGER":
                gate.dagger()
            else:
                raise ValueError(f"Unsupported gate modifier {modifier}.")

        self.result.append(gate)
コード例 #6
0
ファイル: gates.py プロジェクト: zero-cooper/pyquil
def RX(angle, qubit):
    """Produces the RX gate::

        RX(phi) = [[cos(phi / 2), -1j * sin(phi / 2)],
                   [-1j * sin(phi / 2), cos(phi / 2)]]

    This gate is a single qubit X-rotation.

    :param angle: The angle to rotate around the x-axis on the bloch sphere.
    :param qubit: The qubit apply the gate to.
    :returns: A Gate object.
    """
    return Gate(name="RX", params=[angle], qubits=[unpack_qubit(qubit)])
コード例 #7
0
def quil_gates(native_gates=None):
    """Generates quil versions of a gate set (the QSCOUT native gates, by default).

    :returns: A mapping of gate names to functions that take classical parameters and
        qubit indices and build pyquil gates.
    :rtype: dict

    .. warning::
        PyQuil simulators will give an error if QSCOUT native gates are passed to them!
    """
    dkt = {}
    if native_gates is None:
        from qscout.v1.std import NATIVE_GATES

        native_gates = NATIVE_GATES

    gates = {}

    for gate in native_gates:
        if gate.ideal_unitary is None:
            continue
        # pyquil expects non-parametrized gates to be matrices and
        # parametrized ones to be functions that return matrices.
        quil_name = gate.name.upper()
        classical_count = len(gate.classical_parameters)
        if classical_count == 0:
            gates[quil_name] = (
                lambda quil_name, classical_count: (lambda *args: Gate(
                    name=quil_name,
                    params=args[:classical_count],
                    qubits=[unpack_qubit(q) for q in args[classical_count:]],
                )))(quil_name, classical_count)
        else:
            gates[quil_name] = (lambda quil_name: (lambda *args: Gate(
                name=quil_name,
                params=[],
                qubits=[unpack_qubit(q) for q in args],
            )))(quil_name)
    return gates
コード例 #8
0
ファイル: PyQuilListener.py プロジェクト: tsatir/pyquil
    def exitGate(self, ctx: QuilParser.GateContext):
        gate_name = ctx.name().getText()
        modifiers = [mod.getText() for mod in ctx.modifier()]
        params = list(map(_param, ctx.param()))
        qubits = list(map(_qubit, ctx.qubit()))

        # The parsed string 'DAGGER CONTROLLED X 0 1' gives
        #   modifiers ['DAGGER', 'CONTROLLED']
        #   qubits    ['0', '1']
        #
        # We will build such gates by applying modifiers from right to left,
        # e.g. X 1 -> CONTROLLED X 0 1 -> DAGGER CONTROLLED X 0 1

        # Some gate modifiers increase the arity of the base gate.
        # The new qubit arguments prefix the old ones.
        modifier_qubits = []
        for m in modifiers:
            if m in ["CONTROLLED", "FORKED"]:
                modifier_qubits.append(qubits[len(modifier_qubits)])

        base_qubits = qubits[len(modifier_qubits):]

        # Each FORKED doubles the number of parameters,
        # e.g. FORKED RX(0.5, 1.5) 0 1 has two.
        forked_offset = len(params) >> modifiers.count("FORKED")
        base_params = params[:forked_offset]

        if gate_name in QUANTUM_GATES:
            if base_params:
                gate = QUANTUM_GATES[gate_name](*base_params, *base_qubits)
            else:
                gate = QUANTUM_GATES[gate_name](*base_qubits)
        else:
            gate = Gate(gate_name, base_params, base_qubits)

        # Track the last param used (for FORKED)
        for modifier in modifiers[::-1]:
            if modifier == "CONTROLLED":
                gate.controlled(modifier_qubits.pop())
            elif modifier == "DAGGER":
                gate.dagger()
            elif modifier == 'FORKED':
                gate.forked(modifier_qubits.pop(),
                            params[forked_offset:(2 * forked_offset)])
                forked_offset *= 2
            else:
                raise ValueError(f"Unsupported gate modifier {modifier}.")

        self.result.append(gate)
コード例 #9
0
ファイル: gates.py プロジェクト: timasq/pyquil
def RY(angle, qubit):
    """Produces the RY instruction.

    RY(phi) = [[cos(phi / 2), -sin(phi / 2)],
               [sin(phi / 2), cos(phi / 2)]]

    This gate is a single qubit Y-rotation.

    :param angle: The angle to rotate around the y-axis on the bloch sphere.
    :param qubit: The qubit apply the gate to.
    :returns: A Gate object.
    """
    return Gate(name="RY", params=[angle], qubits=[unpack_qubit(qubit)])
コード例 #10
0
ファイル: gates.py プロジェクト: timasq/pyquil
def RZ(angle, qubit):
    """Produces the RZ instruction.

    RZ(phi) = [[cos(phi / 2) - 1j * sin(phi / 2), 0]
               [0, cos(phi / 2) + 1j * sin(phi / 2)]]

    This gate is a single qubit Z-rotation.

    :param angle: The angle to rotate around the z-axis on the bloch sphere.
    :param qubit: The qubit apply the gate to.
    :returns: A Gate object.
    """
    return Gate(name="RZ", params=[angle], qubits=[unpack_qubit(qubit)])
コード例 #11
0
ファイル: gates.py プロジェクト: timasq/pyquil
def PHASE(angle, qubit):
    """Produces the PHASE instruction.

    PHASE(phi) = [[1, 0],
                  [0, exp(1j * phi)]]

    This is the same as the RZ gate.

    :param angle: The angle to rotate around the z-axis on the bloch sphere.
    :param qubit: The qubit apply the gate to.
    :returns: A Gate object.
    """
    return Gate(name="PHASE", params=[angle], qubits=[unpack_qubit(qubit)])
コード例 #12
0
ファイル: PyQuilListener.py プロジェクト: greenstick/pyquil
    def exitGate(self, ctx):
        # type: (QuilParser.GateContext) -> None
        gate_name = ctx.name().getText()
        params = list(map(_param, ctx.param()))
        qubits = list(map(_qubit, ctx.qubit()))

        if gate_name in STANDARD_GATES:
            if params:
                self.result.append(STANDARD_GATES[gate_name](*params)(*qubits))
            else:
                self.result.append(STANDARD_GATES[gate_name](*qubits))
        else:
            self.result.append(Gate(gate_name, params, qubits))
コード例 #13
0
def gates_in_isa(isa):
    """
    Generate the full gateset associated with an ISA.

    :param ISA isa: The instruction set architecture for a QPU.
    :return: A sequence of Gate objects encapsulating all gates compatible with the ISA.
    :rtype: Sequence[Gate]
    """
    gates = []
    for q in isa.qubits:
        if q.dead:
            # TODO: dead qubits may in the future lead to some implicit re-indexing
            continue
        if q.type in ["Xhalves"]:
            gates.extend([
                Gate("I", [], [unpack_qubit(q.id)]),
                Gate("RX", [np.pi / 2], [unpack_qubit(q.id)]),
                Gate("RX", [-np.pi / 2], [unpack_qubit(q.id)]),
                Gate("RX", [np.pi], [unpack_qubit(q.id)]),
                Gate("RX", [-np.pi], [unpack_qubit(q.id)]),
                Gate("RZ", [THETA], [unpack_qubit(q.id)]),
            ])
        else:  # pragma no coverage
            raise ValueError("Unknown qubit type: {}".format(q.type))

    for e in isa.edges:
        if e.dead:
            continue
        targets = [unpack_qubit(t) for t in e.targets]
        if e.type in ["CZ", "ISWAP"]:
            gates.append(Gate(e.type, [], targets))
            gates.append(Gate(e.type, [], targets[::-1]))
        elif e.type in ["CPHASE"]:
            gates.append(Gate(e.type, [THETA], targets))
            gates.append(Gate(e.type, [THETA], targets[::-1]))
        else:  # pragma no coverage
            raise ValueError("Unknown edge type: {}".format(e.type))
    return gates
コード例 #14
0
ファイル: kraus.py プロジェクト: ssghost/pyquil
def _noisy_instruction(instruction):
    """
    Translate an ordinary gate instruction into its noisy version, where applicable.

    In an attempt to closely model the QPU, noisy versions of RX(+-pi/2) and CZ are supported;
    I and parametric RZ are returned as-is (noiseless), and other gates are not allowed.
    Pragmas are returned as-is.

    Note: this function doesn't actually define the noisy gates. Please see
    :py:func`add_noise_to_program` for a full solution.

    :param instruction: The instruction
    :return: A noisy version of the instruction
    """
    if not isinstance(instruction, Gate):
        return instruction

    if instruction.name == 'RZ':
        return instruction

    if instruction.name == 'I':
        return instruction

    if instruction.name == 'RX':
        assert len(instruction.params) == 1
        assert len(instruction.qubits) == 1
        if instruction.params[0] == np.pi / 2.0:
            return Gate('noisy-x-plus90', [], instruction.qubits)
        if instruction.params[0] == -np.pi / 2.0:
            return Gate('noisy-x-minus90', [], instruction.qubits)
        raise ValueError("Can't add noise to a parametric gate. "
                         "Try compiling to RX(pi/2) or RX(-pi/2)")

    if instruction.name == 'CZ':
        return Gate('noisy-cz', [], instruction.qubits)

    raise ValueError(
        'Gate {} is not in the native instruction set'.format(instruction))
コード例 #15
0
ファイル: gates.py プロジェクト: vishalbelsare/pyquil
def SWAP(q1: QubitDesignator, q2: QubitDesignator) -> Gate:
    """Produces a SWAP gate which swaps the state of two qubits::

        SWAP = [[1, 0, 0, 0],
                [0, 0, 1, 0],
                [0, 1, 0, 0],
                [0, 0, 0, 1]]


    :param q1: Qubit 1.
    :param q2: Qubit 2.
    :returns: A Gate object.
    """
    return Gate(name="SWAP", params=[], qubits=[unpack_qubit(q) for q in (q1, q2)])
コード例 #16
0
ファイル: gates.py プロジェクト: vishalbelsare/pyquil
def XY(angle: ParameterDesignator, q1: QubitDesignator, q2: QubitDesignator) -> Gate:
    """Produces a parameterized ISWAP gate::

        XY(phi) = [[1,               0,               0, 0],
                   [0,      cos(phi/2), 1j * sin(phi/2), 0],
                   [0, 1j * sin(phi/2),      cos(phi/2), 0],
                   [0,               0,               0, 1]

    :param angle: The angle of the rotation to apply to the population 1 subspace.
    :param q1: Qubit 1.
    :param q2: Qubit 2.
    :returns: A Gate object.
    """
    return Gate(name="XY", params=[angle], qubits=[unpack_qubit(q) for q in (q1, q2)])
コード例 #17
0
def address_qubits(program, qubit_mapping=None):
    """
    Takes a program which contains placeholders and assigns them all defined values.

    Either all qubits must be defined or all undefined. If qubits are
    undefined, you may provide a qubit mapping to specify how placeholders get mapped
    to actual qubits. If a mapping is not provided, integers 0 through N are used.

    This function will also instantiate any label placeholders.

    :param program: The program.
    :param qubit_mapping: A dictionary-like object that maps from :py:class:`QubitPlaceholder`
        to :py:class:`Qubit` or ``int`` (but not both).
    :return: A new Program with all qubit and label placeholders assigned to real qubits and labels.
    """
    fake_qubits, real_qubits, qubits = _what_type_of_qubit_does_it_use(program)
    if real_qubits:
        if qubit_mapping is not None:
            warnings.warn(
                "A qubit mapping was provided but the program does not "
                "contain any placeholders to map!")
        return program

    if qubit_mapping is None:
        qubit_mapping = {qp: Qubit(i) for i, qp in enumerate(qubits)}
    else:
        if all(isinstance(v, Qubit) for v in qubit_mapping.values()):
            pass  # we good
        elif all(isinstance(v, int) for v in qubit_mapping.values()):
            qubit_mapping = {k: Qubit(v) for k, v in qubit_mapping.items()}
        else:
            raise ValueError(
                "Qubit mapping must map to type Qubit or int (but not both)")

    result = []
    for instr in program:
        # Remap qubits on Gate and Measurement instructions
        if isinstance(instr, Gate):
            remapped_qubits = [qubit_mapping[q] for q in instr.qubits]
            result.append(Gate(instr.name, instr.params, remapped_qubits))
        elif isinstance(instr, Measurement):
            result.append(
                Measurement(qubit_mapping[instr.qubit], instr.classical_reg))

        # Otherwise simply add it to the result
        else:
            result.append(instr)

    return Program(result)
コード例 #18
0
ファイル: gates.py プロジェクト: timasq/pyquil
def CPHASE00(angle, control, target):
    """Produces a CPHASE00 instruction.

    CPHASE00(phi) = diag([exp(1j * phi), 1, 1, 1])

    This gate applies to two qubit arguments to produce the variant of the controlled phase
    instruction that affects the state 00.

    :param angle: The input phase angle to apply when both qubits are in the ground state.
    :param control: Qubit 1.
    :param target: Qubit 2.
    :returns: A Gate object.
    """
    qubits = [unpack_qubit(q) for q in (control, target)]
    return Gate(name="CPHASE00", params=[angle], qubits=qubits)
コード例 #19
0
ファイル: gates.py プロジェクト: timasq/pyquil
def CPHASE(angle, control, target):
    """Produces a CPHASE instruction, which is a synonym for CPHASE11.

    CPHASE(phi) = diag([1, 1, 1, exp(1j * phi)])

    This gate applies to two qubit arguments to produce the variant of the controlled phase
    instruction that affects the state 11.

    :param angle: The input phase angle to apply when both qubits are in the excited state.
    :param control: Qubit 1.
    :param target: Qubit 2.
    :returns: A Gate object.
    """
    qubits = [unpack_qubit(q) for q in (control, target)]
    return Gate(name="CPHASE", params=[angle], qubits=qubits)
コード例 #20
0
ファイル: gates.py プロジェクト: timasq/pyquil
def I(qubit):
    """Produces the I instruction.

    I = [1, 0]
        [0, 1]

    This gate is a single qubit identity gate.
    Note that this gate is different that the NOP instruction as noise channels
    are typically still applied during the duration of identity gates. Identities will
    also block parallelization like any other gate.

    :param qubit: The qubit apply the gate to.
    :returns: A Gate object.
    """
    return Gate(name="I", params=[], qubits=[unpack_qubit(qubit)])
コード例 #21
0
def SWAP(q1, q2):
    """Produces a SWAP instruction.

    SWAP = [[1, 0, 0, 0],
            [0, 0, 1, 0],
            [0, 1, 0, 0],
            [0, 0, 0, 1]]

     This gate swaps the state of two qubits.

    :param q1: Qubit 1.
    :param q2: Qubit 2.
    :returns: A Gate object.
    """
    return Gate(name="SWAP", params=[], qubits=[unpack_qubit(q) for q in (q1, q2)])
コード例 #22
0
def tk_to_pyquil(tkcirc: Union[Circuit, PhysicalCircuit],
                 active_reset: bool = False) -> Program:
    """
       Convert a :math:`\\mathrm{t|ket}\\rangle` :py:class:`Circuit` to a :py:class:`pyquil.Program` .
    
    :param tkcirc: A circuit to be converted

    :return: The converted circuit
    """
    circ = tkcirc
    if isinstance(tkcirc, PhysicalCircuit):
        circ = tkcirc._get_circuit()
    p = Program()
    if len(circ.q_regs) != 1:
        raise NotImplementedError(
            "Cannot convert circuit with multiple quantum registers to PyQuil")
    cregmap = {}
    for _, reg in circ.c_regs.items():
        if reg.size() == 0:
            continue
        name = reg.name
        if name == 'c':
            name = 'ro'
        quil_reg = p.declare(name, 'BIT', reg.size())
        cregmap.update({reg: quil_reg})
    if active_reset:
        p.reset()
    for command in circ:
        op = command.op
        qubits = [Qubit(qb.index) for qb in command.qubits]
        optype = op.get_type()
        if optype == OpType.Measure:
            bits = [cregmap[b.reg][b.index] for b in command.bits]
            p += Measurement(*qubits, *bits)
            continue
        try:
            gatetype = _known_quil_gate_rev[optype]
        except KeyError as error:
            raise NotImplementedError(
                "Cannot convert tket Op to pyquil gate: " +
                op.get_name()) from error
        if len(command.controls) != 0:
            raise NotImplementedError(
                "Cannot convert conditional gates from tket to PyQuil")
        params = [float((p * pi).evalf()) for p in op.get_params()]
        g = Gate(gatetype, params, qubits)
        p += g
    return p
コード例 #23
0
ファイル: gates.py プロジェクト: vishalbelsare/pyquil
def ISWAP(q1: QubitDesignator, q2: QubitDesignator) -> Gate:
    """Produces an ISWAP gate::

        ISWAP = [[1, 0,  0,  0],
                 [0, 0,  1j, 0],
                 [0, 1j, 0,  0],
                 [0, 0,  0,  1]]

    This gate swaps the state of two qubits, applying a -i phase to q1 when it
    is in the 1 state and a -i phase to q2 when it is in the 0 state.

    :param q1: Qubit 1.
    :param q2: Qubit 2.
    :returns: A Gate object.
    """
    return Gate(name="ISWAP", params=[], qubits=[unpack_qubit(q) for q in (q1, q2)])
コード例 #24
0
ファイル: gates.py プロジェクト: vishalbelsare/pyquil
def CNOT(control: QubitDesignator, target: QubitDesignator) -> Gate:
    """Produces a controlled-NOT (controlled-X) gate::

        CNOT = [[1, 0, 0, 0],
                [0, 1, 0, 0],
                [0, 0, 0, 1],
                [0, 0, 1, 0]]

    This gate applies to two qubit arguments to produce the controlled-not gate instruction.

    :param control: The control qubit.
    :param target: The target qubit. The target qubit has an X-gate applied to it if the control
        qubit is in the ``|1>`` state.
    :returns: A Gate object.
    """
    return Gate(name="CNOT", params=[], qubits=[unpack_qubit(q) for q in (control, target)])
コード例 #25
0
def CNOT(control, target):
    """Produces a CNOT instruction.

    CNOT = [[1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 0, 1],
            [0, 0, 1, 0]]

    This gate applies to two qubit arguments to produce the controlled-not gate instruction.

    :param control: The control qubit.
    :param target: The target qubit. The target qubit has an X-gate applied to it if the control
        qubit is in the excited state.
    :returns: A Gate object.
    """
    return Gate(name="CNOT", params=[], qubits=[unpack_qubit(q) for q in (control, target)])
コード例 #26
0
ファイル: gates.py プロジェクト: zero-cooper/pyquil
def CPHASE10(angle, control, target):
    """Produces a controlled-phase gate that phases the ``|10>`` state::

        CPHASE10(phi) = diag([1, 1, exp(1j * phi), 1])

    This gate applies to two qubit arguments to produce the variant of the controlled phase
    instruction that affects the state 10.

    :param angle: The input phase angle to apply when q2 is in the ``|1>`` state and q1 is in
        the ``|0>`` state.
    :param control: Qubit 1.
    :param target: Qubit 2.
    :returns: A Gate object.
    """
    qubits = [unpack_qubit(q) for q in (control, target)]
    return Gate(name="CPHASE10", params=[angle], qubits=qubits)
コード例 #27
0
ファイル: gates.py プロジェクト: vishalbelsare/pyquil
def PSWAP(angle: ParameterDesignator, q1: QubitDesignator, q2: QubitDesignator) -> Gate:
    """Produces a parameterized SWAP gate::

        PSWAP(phi) = [[1, 0,             0,             0],
                      [0, 0,             exp(1j * phi), 0],
                      [0, exp(1j * phi), 0,             0],
                      [0, 0,             0,             1]]


    :param angle: The angle of the phase to apply to the swapped states. This phase is applied to
        q1 when it is in the 1 state and to q2 when it is in the 0 state.
    :param q1: Qubit 1.
    :param q2: Qubit 2.
    :returns: A Gate object.
    """
    return Gate(name="PSWAP", params=[angle], qubits=[unpack_qubit(q) for q in (q1, q2)])
コード例 #28
0
def ISWAP(q1, q2):
    """Produces an ISWAP instruction.

    ISWAP = [[1, 0,  0,  0],
             [0, 0,  1j, 0],
             [0, 1j, 0,  0],
             [0, 0,  0,  1]]

    This gate swaps the state of two qubits, applying a -i phase to q1 when it
    is in the excited state and a -i phase to q2 when it is in the ground state.

    :param q1: Qubit 1.
    :param q2: Qubit 2.
    :returns: A Gate object.
    """
    return Gate(name="ISWAP", params=[], qubits=[unpack_qubit(q) for q in (q1, q2)])
コード例 #29
0
ファイル: gates.py プロジェクト: vishalbelsare/pyquil
def CZ(control: QubitDesignator, target: QubitDesignator) -> Gate:
    """Produces a controlled-Z gate::

        CZ = [[1, 0, 0,  0],
              [0, 1, 0,  0],
              [0, 0, 1,  0],
              [0, 0, 0, -1]]


    This gate applies to two qubit arguments to produce the controlled-Z gate instruction.

    :param control: The control qubit.
    :param target: The target qubit. The target qubit has an Z-gate applied to it if the control
        qubit is in the excited state.
    :returns: A Gate object.
    """
    return Gate(name="CZ", params=[], qubits=[unpack_qubit(q) for q in (control, target)])
コード例 #30
0
def PSWAP(angle, q1, q2):
    """Produces a PSWAP instruction.

    PSWAP(phi) = [[1, 0,             0,             0],
                  [0, 0,             exp(1j * phi), 0],
                  [0, exp(1j * phi), 0,             0],
                  [0, 0,             0,             1]]

    This is a parameterized swap gate.

    :param angle: The angle of the phase to apply to the swapped states. This phase is applied to
        q1 when it is in the excited state and to q2 when it is in the ground state.
    :param q1: Qubit 1.
    :param q2: Qubit 2.
    :returns: A Gate object.
    """
    return Gate(name="PSWAP", params=[angle], qubits=[unpack_qubit(q) for q in (q1, q2)])