示例#1
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)