Ejemplo n.º 1
0
    def while_do(self, classical_reg, q_program):
        """
        While a classical register at index classical_reg is 1, loop q_program

        Equivalent to the following construction:

        .. code::

            WHILE [c]:
               instr...
            =>
              LABEL @START
              JUMP-UNLESS @END [c]
              instr...
              JUMP @START
              LABEL @END

        :param int classical_reg: The classical register to check
        :param Program q_program: The Quil program to loop.
        :return: The Quil Program with the loop instructions added.
        :rtype: Program
        """
        label_start = LabelPlaceholder("START")
        label_end = LabelPlaceholder("END")
        self.inst(JumpTarget(label_start))
        self.inst(JumpUnless(target=label_end, condition=classical_reg))
        self.inst(q_program)
        self.inst(Jump(label_start))
        self.inst(JumpTarget(label_end))
        return self
Ejemplo n.º 2
0
def instantiate_labels(instructions):
    """
    Takes an iterable of instructions which may contain label placeholders and assigns
    them all defined values.

    :return: list of instructions with all label placeholders assigned to real labels.
    """
    label_i = 1
    result = []
    label_mapping = dict()
    for instr in instructions:
        if isinstance(instr, Jump) and isinstance(instr.target, LabelPlaceholder):
            new_target, label_mapping, label_i = _get_label(instr.target, label_mapping, label_i)
            result.append(Jump(new_target))
        elif isinstance(instr, JumpConditional) and isinstance(instr.target, LabelPlaceholder):
            new_target, label_mapping, label_i = _get_label(instr.target, label_mapping, label_i)
            cls = instr.__class__  # Make the correct subclass
            result.append(cls(new_target, instr.condition))
        elif isinstance(instr, JumpTarget) and isinstance(instr.label, LabelPlaceholder):
            new_label, label_mapping, label_i = _get_label(instr.label, label_mapping, label_i)
            result.append(JumpTarget(new_label))
        else:
            result.append(instr)

    return result
Ejemplo n.º 3
0
def test_jumps():
    parse_equals("LABEL @test_1", JumpTarget(Label("test_1")))
    parse_equals("JUMP @test_1", Jump(Label("test_1")))
    parse_equals("JUMP-WHEN @test_1 ro[0]",
                 JumpWhen(Label("test_1"), MemoryReference("ro", 0)))
    parse_equals("JUMP-UNLESS @test_1 ro[1]",
                 JumpUnless(Label("test_1"), MemoryReference("ro", 1)))
Ejemplo n.º 4
0
    def if_then(
        self,
        classical_reg: MemoryReferenceDesignator,
        if_program: "Program",
        else_program: Optional["Program"] = None,
    ) -> "Program":
        """
        If the classical register at index classical reg is 1, run if_program, else run
        else_program.

        Equivalent to the following construction:

        .. code::

            IF [c]:
               instrA...
            ELSE:
               instrB...
            =>
              JUMP-WHEN @THEN [c]
              instrB...
              JUMP @END
              LABEL @THEN
              instrA...
              LABEL @END

        :param classical_reg: The classical register to check as the condition
        :param if_program: A Quil program to execute if classical_reg is 1
        :param else_program: A Quil program to execute if classical_reg is 0. This
            argument is optional and defaults to an empty Program.
        :returns: The Quil Program with the branching instructions added.
        """
        else_program = else_program if else_program is not None else Program()

        label_then = LabelPlaceholder("THEN")
        label_end = LabelPlaceholder("END")
        self.inst(
            JumpWhen(target=label_then,
                     condition=unpack_classical_reg(classical_reg)))
        self.inst(else_program)
        self.inst(Jump(label_end))
        self.inst(JumpTarget(label_then))
        self.inst(if_program)
        self.inst(JumpTarget(label_end))
        return self
Ejemplo n.º 5
0
def test_unsupported_ops():
    target = Label("target")
    base_prog = Program(Declare("reg1", "BIT"), Declare("reg2", "BIT"), H(0), JumpTarget(target), CNOT(0, 1))

    bad_ops = [WAIT, Jump(target), MOVE(MemoryReference("reg1"), MemoryReference("reg2"))]

    assert to_latex(base_prog)

    for op in bad_ops:
        prog = base_prog + op
        with pytest.raises(ValueError):
            _ = to_latex(prog)
Ejemplo n.º 6
0
 def def_label(self, label):
     return JumpTarget(label)
Ejemplo n.º 7
0
def test_jumps():
    parse_equals("LABEL @test_1", JumpTarget(Label("test_1")))
    parse_equals("JUMP @test_1", Jump(Label("test_1")))
    parse_equals("JUMP-WHEN @test_1 ro[0]", JumpWhen(Label("test_1"), Addr(0)))
    parse_equals("JUMP-UNLESS @test_1 ro[1]",
                 JumpUnless(Label("test_1"), Addr(1)))
Ejemplo n.º 8
0
 def exitDefLabel(self, ctx):
     # type: (QuilParser.DefLabelContext) -> None
     self.result.append(JumpTarget(_label(ctx.label())))
Ejemplo n.º 9
0
def test_jumps():
    _test("LABEL @test_1", JumpTarget(Label("test_1")))
    _test("JUMP @test_1", Jump(Label("test_1")))
    _test("JUMP-WHEN @test_1 [0]", JumpWhen(Label("test_1"), Addr(0)))
    _test("JUMP-UNLESS @test_1 [1]", JumpUnless(Label("test_1"), Addr(1)))
Ejemplo n.º 10
0
def rewrite_program(raw_prog: Program, qecc: QECC) -> Program:
    if qecc.k != 1:
        raise UnsupportedQECCError("code must have k = 1")

    if raw_prog.defined_gates:
        raise UnsupportedProgramError("does not support DEFGATE")

    # Assign indices to qubit placeholders in the raw program.
    raw_prog = quil.address_qubits(raw_prog)

    new_prog = Program()

    logical_qubits = {
        index: new_logical_qubit(new_prog, qecc,
                                 "logical_qubit_{}".format(index))
        for index in raw_prog.get_qubits(indices=True)
    }

    # Construct ancilla code blocks.
    ancilla_1 = new_logical_qubit(new_prog, qecc, "ancilla_1")
    ancilla_2 = new_logical_qubit(new_prog, qecc, "ancilla_2")

    # Classical scratch BIT registers for gates/measurements.
    scratch_size = max(qecc.n, qecc.measure_scratch_size)
    raw_scratch = new_prog.declare('scratch', 'BIT', scratch_size)
    scratch = MemoryChunk(raw_scratch, 0, raw_scratch.declared_size)
    _initialize_memory(new_prog, raw_scratch,
                       ancilla_1.qubits + ancilla_2.qubits)

    # Classical scratch INTEGER registers.
    raw_scratch_int = new_prog.declare('scratch_int', 'INTEGER', 2)
    scratch_int = MemoryChunk(raw_scratch_int, 0,
                              raw_scratch_int.declared_size)
    _initialize_memory(new_prog, raw_scratch_int,
                       ancilla_1.qubits + ancilla_2.qubits)

    perform_error_correction = _make_error_corrector(new_prog, qecc, ancilla_1,
                                                     ancilla_2)

    # Reset all logical qubits.
    for block in logical_qubits.values():
        qecc.encode_zero(new_prog, block, ancilla_1, scratch)

    for inst in raw_prog.instructions:
        if isinstance(inst, Gate):
            gate_qubits = [
                logical_qubits[index] for index in _gate_qubits(inst)
            ]
            qecc.apply_gate(new_prog, inst.name, *gate_qubits)

            # Perform error correction after every logical gate.
            perform_error_correction(logical_qubits.values())
        elif isinstance(inst, Measurement):
            qubit = logical_qubits[_extract_qubit_index(inst.qubit)]
            # This should really use its own ancilla instead of sharing with the error correction,
            # but we need be extremely conservative with the number of qubits.
            for _ in qecc.measure(new_prog, qubit, 0, inst.classical_reg,
                                  ancilla_1, ancilla_2, scratch, scratch_int):
                # Since measurements are taken multiple times for redundancy, we need to perform
                # rounds of error correction during the measurement routine.
                perform_error_correction(logical_qubits.values())
        elif isinstance(inst, ResetQubit):
            raise NotImplementedError(
                "this instruction is not in the Quil spec")
        elif isinstance(inst, JumpTarget):
            new_prog.inst(JumpTarget(_mangle_label(inst.label)))
        elif isinstance(inst, JumpConditional):
            new_prog.inst(
                type(inst)(_mangle_label(inst.target), inst.condition))
        elif isinstance(inst, Jump):
            new_prog.inst(Jump(_mangle_label(inst.target)))
        elif isinstance(inst, Halt):
            new_prog.append(inst)
        elif isinstance(inst, Wait):
            raise NotImplementedError()
        elif isinstance(inst, Reset):
            for block in logical_qubits.values():
                qecc.encode_zero(new_prog, block.qubits, ancilla_1, scratch)
        elif isinstance(inst, Declare):
            new_prog.inst(inst)
        elif isinstance(inst, Pragma):
            new_prog.inst(inst)
        elif any(
                isinstance(inst, ClassicalInst)
                for ClassicalInst in CLASSICAL_INSTRUCTIONS):
            new_prog.inst(inst)
        else:
            raise UnsupportedProgramError("unsupported instruction: {}", inst)

    return quil.address_qubits(new_prog)