Пример #1
0
def test_XY():
    for theta in np.linspace(-2 * np.pi, 2 * np.pi):
        p = Program(XY(theta, 0, 1))
        u1 = program_unitary(p, n_qubits=2)
        u2 = program_unitary(basic_compile(p), n_qubits=2)
        assert equal_up_to_global_phase(u1, u2, atol=1e-12)

        p = Program(XY(theta, 1, 0))
        u1 = program_unitary(p, n_qubits=2)
        u2 = program_unitary(basic_compile(p), n_qubits=2)
        assert equal_up_to_global_phase(u1, u2, atol=1e-12)
Пример #2
0
def _ISWAP(q0: QubitLike, q1: QubitLike) -> Program:
    """
    An ISWAP as an XY(pi). Of course, assumes XY is available.
    """
    p = Program()
    p += XY(np.pi, q0, q1)
    return p
Пример #3
0
def basic_compile(program: Program) -> Program:
    """
    A rudimentary but predictable compiler.

    No rewiring or optimization is done by this compilation step. There may be
    some gates that are not yet supported. Gates defined in the input program
    are included without change in the output program.

    :param program: A program to be compiled to native quil with simple
        replacements.
    :return: A program with some of the input non-native quil gates replaced
        with basic native quil gate implementations.
    """
    new_prog = Program()
    new_prog.num_shots = program.num_shots
    new_prog.inst(program.defined_gates)

    for inst in program:
        if isinstance(inst, Gate):
            if inst.name == "CCNOT":
                new_prog += _CCNOT(*inst.qubits)
            elif inst.name == "CNOT":
                new_prog += _CNOT(*inst.qubits)
            # NB: we haven't implemented CPHASE00/01/10
            elif inst.name == "CPHASE":
                angle_param = inst.params[0]
                new_prog += _CPHASE(angle_param, *inst.qubits)
            elif inst.name == "CZ":
                new_prog += CZ(*inst.qubits)  # remove dag modifiers
            elif inst.name == "H":
                new_prog += _H(inst.qubits[0])
            elif inst.name == "I":
                new_prog += I(inst.qubits[0])  # remove dag modifiers
            elif inst.name == "ISWAP":
                new_prog += _ISWAP(*inst.qubits)  # remove dag modifiers
            elif inst.name == "PHASE":
                angle_param = inst.params[0]
                new_prog += _PHASE(angle_param, inst.qubits[0])
            elif inst.name == "RX":
                angle_param = inst.params[0]
                if is_magic_angle(inst.params[0]):
                    # in case dagger
                    new_prog += RX(angle_param, inst.qubits[0])
                else:
                    new_prog += _RX(angle_param, inst.qubits[0])
            elif inst.name == "RY":
                angle_param = inst.params[0]
                new_prog += _RY(angle_param, inst.qubits[0])
            elif inst.name == "RZ":
                # in case dagger
                angle_param = inst.params[0]
                new_prog += RZ(angle_param, inst.qubits[0])
            elif inst.name == "S":
                new_prog += _S(inst.qubits[0])
            # NB: we haven't implemented CSWAP or PSWAP
            elif inst.name == "SWAP":
                new_prog += _SWAP(*inst.qubits)
            elif inst.name == "T":
                new_prog += _T(inst.qubits[0])
            elif inst.name == "X":
                new_prog += _X(inst.qubits[0])
            elif inst.name == "XY":
                angle_param = inst.params[0]
                new_prog += XY(angle_param, *inst.qubits)
            elif inst.name == "Y":
                new_prog += _Y(inst.qubits[0])
            elif inst.name == "Z":
                new_prog += _Z(inst.qubits[0])
            elif inst.name in [gate.name for gate in new_prog.defined_gates]:
                new_prog += inst
            else:
                raise ValueError(f"Unknown gate instruction {inst}")
        else:
            new_prog += inst

    new_prog.native_quil_metadata = {  # type: ignore[assignment]
        "final_rewiring": None,
        "gate_depth": None,
        "gate_volume": None,
        "multiqubit_gate_depth": None,
        "program_duration": None,
        "program_fidelity": None,
        "topological_swaps": 0,
    }
    return new_prog
Пример #4
0
def basic_compile(program: Program):
    """
    A rudimentary but predictable compiler.

    No rewiring or optimization is done by this compilation step. There may be some gates that
    are not yet supported. Gates defined in the input program are included without change in the
    output program.

    :param program: a program to be compiled to native quil with simple replacements.
    :return: a program with some of the input non-native quil gates replaced with basic native quil
        gate implementations.
    """
    new_prog = Program()
    new_prog.num_shots = program.num_shots
    new_prog.inst(program.defined_gates)

    daggered_defgates = []

    for inst in program:
        if isinstance(inst, Gate):
            # TODO: this is only a stopgap while the noisy QVM does not support modifiers.
            # dagger this gate if odd number of daggers. Ignore controlled for now.
            needs_dagger = inst.modifiers.count('DAGGER') % 2 == 1
            angle_param = None
            if len(inst.params) > 0:
                angle_param = inst.params[0]
                if needs_dagger:
                    angle_param = -angle_param

            if 'CONTROLLED' in inst.modifiers:
                raise ValueError("Controlled gates are not currently supported.")

            if inst.name == 'CZ':
                new_prog += CZ(*inst.qubits)  # remove dag modifiers
            elif inst.name == 'XY':
                new_prog += XY(angle_param, *inst.qubits)
            elif inst.name == 'I':
                new_prog += I(inst.qubits[0])  # remove dag modifiers
            elif inst.name == 'RZ':
                # in case dagger
                new_prog += RZ(angle_param, inst.qubits[0])
            elif inst.name == 'RX':
                if is_magic_angle(inst.params[0]):
                    # in case dagger
                    new_prog += RX(angle_param, inst.qubits[0])
                else:
                    new_prog += _RX(angle_param, inst.qubits[0])
            elif inst.name == 'RY':
                new_prog += _RY(angle_param, inst.qubits[0])
            elif inst.name == 'CNOT':
                new_prog += _CNOT(*inst.qubits)
            elif inst.name == 'CCNOT':
                new_prog += _CCNOT(*inst.qubits)
            elif inst.name == 'SWAP':
                new_prog += _SWAP(*inst.qubits)
            elif inst.name == 'T':
                new_prog += _T(inst.qubits[0], needs_dagger)
            elif inst.name == "H":
                new_prog += _H(inst.qubits[0])
            elif inst.name == "X":
                new_prog += _X(inst.qubits[0])
            elif inst.name in [gate.name for gate in new_prog.defined_gates]:
                if needs_dagger and inst.name not in daggered_defgates:
                    new_prog.defgate(inst.name + 'DAG', inst.matrix.T.conj())
                    daggered_defgates.append(inst.name)
                new_prog += inst
            else:
                raise ValueError(f"Unknown gate instruction {inst}")

        else:
            new_prog += inst

    new_prog.native_quil_metadata = {
        'final_rewiring': None,
        'gate_depth': None,
        'gate_volume': None,
        'multiqubit_gate_depth': None,
        'program_duration': None,
        'program_fidelity': None,
        'topological_swaps': 0,
    }
    return new_prog