Exemplo n.º 1
0
def tk_to_pyquil(circ: Union[Circuit,PhysicalCircuit]) -> Program:
    """
       Convert a :math:`\\mathrm{t|ket}\\rangle` :py:class:`Circuit` to a :py:class:`pyquil.Program` .
    
    :param circ: A circuit to be converted

    :return: The converted circuit
    """
    p = Program()
    ro = p.declare('ro', 'BIT', circ.n_qubits)
    for command in circ:
        op = command.op
        optype = op.get_type()
        if optype == OpType.Input or optype == OpType.Output:
            continue
        elif optype == OpType.Measure:
            p += Measurement(Qubit(command.qubits[0]), ro[int(op.get_desc())])
            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
        params = []
        for par in op.get_params():
            try:
                params.append(par.evalf()*PI)
            except:
                params.append(par*PI)
        g = Gate(gatetype, params, [Qubit(q) for q in command.qubits])
        p += g
    return p
def test_exponentiate_identity():
    q = QubitPlaceholder.register(11)
    mapping = {qp: Qubit(i) for i, qp in enumerate(q)}
    generator = PauliTerm("I", q[1], 0.0)
    para_prog = exponential_map(generator)
    prog = para_prog(1)
    result_prog = Program().inst()
    assert address_qubits(prog,
                          mapping) == address_qubits(result_prog, mapping)

    generator = PauliTerm("I", q[1], 1.0)
    para_prog = exponential_map(generator)
    prog = para_prog(1)
    result_prog = Program().inst(
        [X(q[0]), PHASE(-1.0, q[0]),
         X(q[0]), PHASE(-1.0, q[0])])
    assert address_qubits(prog,
                          mapping) == address_qubits(result_prog, mapping)

    generator = PauliTerm("I", q[10], 0.08)
    para_prog = exponential_map(generator)
    prog = para_prog(1)
    result_prog = Program().inst(
        [X(q[0]), PHASE(-0.08, q[0]),
         X(q[0]), PHASE(-0.08, q[0])])
    assert address_qubits(prog,
                          mapping) == address_qubits(result_prog, mapping)
Exemplo n.º 3
0
def DELAY(*args) -> Union[DelayFrames, DelayQubits]:
    """
    Produce a DELAY instruction.

    Note: There are two variants of DELAY. One applies to specific frames on some
    qubit, e.g. `DELAY 0 "rf" "ff" 1.0` delays the `"rf"` and `"ff"` frames on 0.
    It is also possible to delay all frames on some qubits, e.g. `DELAY 0 1 2 1.0`.

    :param args: A list of delay targets, ending with a duration.
    :returns: A DelayFrames or DelayQubits instance.
    """
    if len(args) < 2:
        raise ValueError(
            "Expected DELAY(t1,...,tn, duration). In particular, there "
            "must be at least one target, as well as a duration."
        )
    targets, duration = args[:-1], args[-1]
    if not isinstance(duration, (Expression, Real)):
        raise TypeError("The last argument of DELAY must be a real or parametric duration.")

    if all(isinstance(t, Frame) for t in targets):
        return DelayFrames(targets, duration)
    elif all(isinstance(t, (int, Qubit, FormalArgument)) for t in targets):
        targets = [Qubit(t) if isinstance(t, int) else t for t in targets]
        return DelayQubits(targets, duration)
    else:
        raise TypeError(
            "DELAY targets must be either (i) a list of frames, or "
            "(ii) a list of qubits / formal arguments. "
            f"Got {args}."
        )
Exemplo n.º 4
0
def test_rewrite_arithmetic_mixed_mutations():
    fdefn = DefFrame(
        frame=Frame([Qubit(0)], "rf"),
        center_frequency=10.0,
        sample_rate=20.0,
    )
    prog = Program(
        fdefn,
        "DECLARE theta REAL",
        'SET-FREQUENCY 0 "rf" theta',
        'SET-PHASE 0 "rf" theta',
        'SET-SCALE 0 "rf" theta',
    )

    response = rewrite_arithmetic(prog)

    assert response == RewriteArithmeticResponse(
        original_memory_descriptors={
            "theta": ParameterSpec(length=1, type="REAL")
        },
        recalculation_table={
            ParameterAref(index=0, name="__P1"): "(theta[0] - 10.0)/20.0",
            ParameterAref(index=1, name="__P1"): "theta[0]/(2*pi)",
            ParameterAref(index=2, name="__P1"): "theta[0]/8",
        },
        quil=Program(
            fdefn,
            "DECLARE __P1 REAL[3]",
            "DECLARE theta REAL[1]",
            'SET-FREQUENCY 0 "rf" __P1[0]',
            'SET-PHASE 0 "rf" __P1[1]',
            'SET-SCALE 0 "rf" __P1[2]',
        ).out(),
    )
Exemplo n.º 5
0
def FENCE(*qubits: Union[int, Qubit, FormalArgument]) -> Union[FenceAll, Fence]:
    """
    Produce a FENCE instruction.

    Note: If no qubits are specified, then this is interpreted as a global FENCE.

    :params qubits: A list of qubits or formal arguments.
    :returns: A Fence or FenceAll instance.
    """
    if qubits:
        return Fence([Qubit(t) if isinstance(t, int) else t for t in qubits])
    else:
        return FenceAll()
Exemplo n.º 6
0
def RESET(qubit_index=None):
    """
    Reset all qubits or just a specific qubit at qubit_index.

    :param Optional[int] qubit_index: The address of the qubit to reset.
        If None, reset all qubits.
    :returns: A Reset or ResetQubit Quil AST expression corresponding to a global or targeted
        reset, respectively.
    :rtype: Union[Reset, ResetQubit]
    """
    if qubit_index is not None:
        return ResetQubit(Qubit(qubit_index))
    else:
        return Reset()
Exemplo n.º 7
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
Exemplo n.º 8
0
def get_default_qubit_mapping(
        program: Program) -> Dict[Union[Qubit, QubitPlaceholder], Qubit]:
    """
    Takes a program which contains qubit placeholders and provides a mapping to the integers
    0 through N-1.

    The output of this function is suitable for input to :py:func:`address_qubits`.

    :param program: A program containing qubit placeholders
    :return: A dictionary mapping qubit placeholder to an addressed qubit from 0 through N-1.
    """
    fake_qubits, real_qubits, qubits = _what_type_of_qubit_does_it_use(program)
    if real_qubits:
        warnings.warn(
            "This program contains integer qubits, so getting a mapping doesn't make sense."
        )
        # _what_type_of_qubit_does_it_use ensures that if real_qubits is True, then qubits contains
        # only real Qubits, not QubitPlaceholders. Help mypy figure this out with cast.
        return {q: cast(Qubit, q) for q in qubits}
    return {qp: Qubit(i) for i, qp in enumerate(qubits)}
def tk_to_pyquil(
    tkcirc: Circuit,
    active_reset: bool = False,
    return_used_bits: bool = False
) -> Union[Program, Tuple[Program, List[Bit]]]:
    """
       Convert a tket :py:class:`Circuit` to a :py:class:`pyquil.Program` .

    :param tkcirc: A circuit to be converted

    :return: The converted circuit
    """
    p = Program()
    qregs = set()
    for qb in tkcirc.qubits:
        if len(qb.index) != 1:
            raise NotImplementedError(
                "PyQuil registers must use a single index")
        qregs.add(qb.reg_name)
    if len(qregs) > 1:
        raise NotImplementedError(
            "Cannot convert circuit with multiple quantum registers to pyQuil")
    creg_sizes: Dict = {}
    for b in tkcirc.bits:
        if len(b.index) != 1:
            raise NotImplementedError(
                "PyQuil registers must use a single index")
        if (b.reg_name
                not in creg_sizes) or (b.index[0] >= creg_sizes[b.reg_name]):
            creg_sizes.update({b.reg_name: b.index[0] + 1})
    cregmap = {}
    for reg_name, size in creg_sizes.items():
        name = reg_name
        if name == "c":
            name = "ro"
        quil_reg = p.declare(name, "BIT", size)
        cregmap.update({reg_name: quil_reg})
    for sym in tkcirc.free_symbols():
        p.declare(str(sym), "REAL")
    if active_reset:
        p.reset()
    measures = []
    measured_qubits: List[Qubit] = []
    used_bits: List[Bit] = []
    for command in tkcirc:
        op = command.op
        optype = op.type
        if optype == OpType.Measure:
            qb = Qubit_(command.args[0].index[0])
            if qb in measured_qubits:
                raise NotImplementedError("Cannot apply gate on qubit " +
                                          qb.__repr__() + " after measurement")
            bit = command.args[1]
            b = cregmap[bit.reg_name][bit.index[0]]
            measures.append(Measurement(qb, b))
            measured_qubits.append(qb)
            used_bits.append(bit)
            continue
        elif optype == OpType.Barrier:
            continue  # pyQuil cannot handle barriers
        qubits = [Qubit_(qb.index[0]) for qb in command.args]
        for qb in qubits:
            if qb in measured_qubits:
                raise NotImplementedError("Cannot apply gate on qubit " +
                                          qb.__repr__() + " after measurement")
        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
        params = [param_to_pyquil(p) for p in op.params]
        g = Gate(gatetype, params, qubits)
        p += g
    for m in measures:
        p += m
    if return_used_bits:
        return p, used_bits
    return p
Exemplo n.º 10
0
def address_qubits(
    program: Program,
    qubit_mapping: Optional[Dict[QubitPlaceholder, Union[Qubit, int]]] = None
) -> Program:
    """
    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: List[AbstractInstruction] = []
    for instr in program:
        # Remap qubits on Gate, Measurement, and ResetQubit instructions
        if isinstance(instr, Gate):
            remapped_qubits = [qubit_mapping[q] for q in instr.qubits]
            gate = Gate(instr.name, instr.params, remapped_qubits)
            gate.modifiers = instr.modifiers
            result.append(gate)
        elif isinstance(instr, Measurement):
            result.append(
                Measurement(qubit_mapping[instr.qubit], instr.classical_reg))
        elif isinstance(instr, ResetQubit):
            result.append(ResetQubit(qubit_mapping[instr.qubit]))
        elif isinstance(instr, Pragma):
            new_args: List[Union[Qubit, int, str]] = []
            for arg in instr.args:
                # Pragmas can have arguments that represent things besides qubits, so here we
                # make sure to just look up the QubitPlaceholders.
                if isinstance(arg, QubitPlaceholder):
                    new_args.append(qubit_mapping[arg])
                else:
                    new_args.append(arg)
            result.append(
                Pragma(instr.command, new_args, instr.freeform_string))
        # Otherwise simply add it to the result
        else:
            result.append(instr)

    new_program = program.copy()
    new_program._instructions = result

    return new_program