Example #1
0
def test_http_compilation_failure(compiler):
    device_name = "test_device"
    mock_url = "http://mock-qpu-compiler"

    config = PyquilConfig(TEST_CONFIG_PATHS)
    session = get_session(config=config)
    mock_adapter = requests_mock.Adapter()
    session.mount("http://", mock_adapter)

    headers = {
        # access token from ./data/user_auth_token_valid.json.
        "Authorization": "Bearer secret"
    }

    mock_adapter.register_uri(
        "POST",
        f"{mock_url}/devices/{device_name}/get_version_info",
        status_code=200,
        json={},
        headers=headers,
    )

    mock_adapter.register_uri(
        "POST",
        f"{mock_url}/devices/{device_name}/native_quilt_to_binary",
        status_code=500,
        json={"message": "test compilation failed"},
        headers=headers,
    )

    mock_adapter.register_uri(
        "POST",
        f"{mock_url}/devices/{device_name}/get_quilt_calibrations",
        status_code=200,
        json=CALIBRATIONS_RESPONSE,
        headers=headers,
    )

    device = Device(name="not_actually_device_name",
                    raw={
                        "device_name": device_name,
                        "isa": DUMMY_ISA_DICT
                    })

    compiler = QPUCompiler(
        quilc_endpoint=session.config.quilc_url,
        qpu_compiler_endpoint=mock_url,
        device=device,
        session=session,
    )

    native_quil = compiler.quil_to_native_quil(simple_program())

    try:
        compiler.native_quil_to_executable(native_quil)
    except UserMessageError as e:
        assert "test compilation failed" in str(e)
Example #2
0
def test_compile_with_quilt_calibrations(compiler):
    device_name = "test_device"
    mock_url = "http://mock-qpu-compiler"

    config = PyquilConfig(TEST_CONFIG_PATHS)
    session = get_session(config=config)
    mock_adapter = requests_mock.Adapter()
    session.mount("http://", mock_adapter)

    headers = {
        # access token from ./data/user_auth_token_valid.json.
        "Authorization": "Bearer secret"
    }
    mock_adapter.register_uri(
        "POST",
        f"{mock_url}/devices/{device_name}/get_version_info",
        status_code=200,
        json={},
        headers=headers,
    )

    mock_adapter.register_uri(
        "POST",
        f"{mock_url}/devices/{device_name}/native_quilt_to_binary",
        status_code=200,
        json=SIMPLE_RESPONSE,
        headers=headers,
    )

    device = Device(name="not_actually_device_name",
                    raw={
                        "device_name": device_name,
                        "isa": DUMMY_ISA_DICT
                    })
    compiler = QPUCompiler(
        quilc_endpoint=session.config.quilc_url,
        qpu_compiler_endpoint=mock_url,
        device=device,
        session=session,
    )

    program = simple_program()
    q = FormalArgument("q")
    defn = DefCalibration(
        "H", [], [q],
        [RZ(math.pi / 2, q),
         RX(math.pi / 2, q),
         RZ(math.pi / 2, q)])
    cals = [defn]
    program._calibrations = cals
    # this should more or less pass through
    compilation_result = compiler.quil_to_native_quil(program, protoquil=True)
    assert compilation_result.calibrations == cals
    assert program.calibrations == cals
    assert compilation_result == program
Example #3
0
def test_http_compilation(compiler):
    device_name = "test_device"
    mock_url = "http://mock-qpu-compiler"

    config = PyquilConfig(TEST_CONFIG_PATHS)
    session = get_session(config=config)
    mock_adapter = requests_mock.Adapter()
    session.mount("http://", mock_adapter)

    headers = {
        # access token from ./data/user_auth_token_valid.json.
        "Authorization": "Bearer secret"
    }
    mock_adapter.register_uri(
        "POST",
        f"{mock_url}/devices/{device_name}/get_version_info",
        status_code=200,
        json={},
        headers=headers,
    )

    mock_adapter.register_uri(
        "POST",
        f"{mock_url}/devices/{device_name}/native_quil_to_binary",
        status_code=200,
        json=SIMPLE_RESPONSE,
        headers=headers,
    )

    device = Device(
        name="not_actually_device_name", raw={"device_name": device_name, "isa": DUMMY_ISA_DICT}
    )
    compiler = QPUCompiler(
        quilc_endpoint=session.config.quilc_url,
        qpu_compiler_endpoint=mock_url,
        device=device,
        session=session,
    )

    compilation_result = compiler.native_quil_to_executable(
        compiler.quil_to_native_quil(simple_program())
    )

    assert isinstance(compilation_result, BinaryExecutableResponse)
    assert compilation_result.program == SIMPLE_RESPONSE["program"]
Example #4
0
def test_invalid_protocol():
    device_name = "test_device"
    mock_url = "not-http-or-tcp://mock-qpu-compiler"

    config = PyquilConfig(TEST_CONFIG_PATHS)
    session = get_session(config=config)
    mock_adapter = requests_mock.Adapter()
    session.mount("", mock_adapter)
    device = Device(
        name="not_actually_device_name", raw={"device_name": device_name, "isa": DUMMY_ISA_DICT}
    )

    with pytest.raises(UserMessageError):
        QPUCompiler(
            quilc_endpoint=session.config.quilc_url,
            qpu_compiler_endpoint=mock_url,
            device=device,
            session=session,
        )
Example #5
0
def get_qc(name: str,
           *,
           as_qvm: bool = None,
           noisy: bool = None,
           connection: ForestConnection = None) -> QuantumComputer:
    """
    Get a quantum computer.

    A quantum computer is an object of type :py:class:`QuantumComputer` and can be backed
    either by a QVM simulator ("Quantum/Quil Virtual Machine") or a physical Rigetti QPU ("Quantum
    Processing Unit") made of superconducting qubits.

    You can choose the quantum computer to target through a combination of its name and optional
    flags. There are multiple ways to get the same quantum computer. The following are equivalent::

        >>> qc = get_qc("Aspen-0-12Q-A-noisy-qvm")
        >>> qc = get_qc("Aspen-0-12Q-A", as_qvm=True, noisy=True)

    and will construct a simulator of the 8q-agave chip with a noise model based on device
    characteristics. We also provide a means for constructing generic quantum simulators that
    are not related to a given piece of Rigetti hardware::

        >>> qc = get_qc("9q-square-qvm")
        >>> qc = get_qc("9q-square", as_qvm=True)

    Finally, you can get request a QVM with "no" topology of a given number of qubits
    (technically, it's a fully connected graph among the given number of qubits) with::

        >>> qc = get_qc("5q-qvm") # or "6q-qvm", or "34q-qvm", ...

    Redundant flags are acceptable, but conflicting flags will raise an exception::

        >>> qc = get_qc("9q-square-qvm") # qc is fully specified by its name
        >>> qc = get_qc("9q-square-qvm", as_qvm=True) # redundant, but ok
        >>> qc = get_qc("9q-square-qvm", as_qvm=False) # Error!

    Use :py:func:`list_quantum_computers` to retrieve a list of known qc names.

    This method is provided as a convenience to quickly construct and use QVM's and QPU's.
    Power users may wish to have more control over the specification of a quantum computer
    (e.g. custom noise models, bespoke topologies, etc.). This is possible by constructing
    a :py:class:`QuantumComputer` object by hand. Please refer to the documentation on
    :py:class:`QuantumComputer` for more information.

    :param name: The name of the desired quantum computer. This should correspond to a name
        returned by :py:func:`list_quantum_computers`. Names ending in "-qvm" will return
        a QVM. Names ending in "-noisy-qvm" will return a QVM with a noise model. Otherwise,
        we will return a QPU with the given name.
    :param as_qvm: An optional flag to force construction of a QVM (instead of a QPU). If
        specified and set to ``True``, a QVM-backed quantum computer will be returned regardless
        of the name's suffix
    :param noisy: An optional flag to force inclusion of a noise model. If
        specified and set to ``True``, a quantum computer with a noise model will be returned
        regardless of the name's suffix. The noise model for QVM's based on a real QPU
        is an empirically parameterized model based on real device noise characteristics.
        The generic QVM noise model is simple T1 and T2 noise plus readout error. See
        :py:func:`decoherance_noise_with_asymmetric_ro`.
    :param connection: An optional :py:class:ForestConnection` object. If not specified,
        the default values for URL endpoints, ping time, and status time will be used. Your
        user id and API key will be read from ~/.pyquil_config. If you deign to change any
        of these parameters, pass your own :py:class:`ForestConnection` object.
    :return:
    """
    if connection is None:
        connection = ForestConnection()

    full_name = name
    name, as_qvm, noisy = _parse_name(name, as_qvm, noisy)

    ma = re.fullmatch(r'(\d+)q', name)
    if ma is not None:
        n_qubits = int(ma.group(1))
        if not as_qvm:
            raise ValueError("Please name a valid device or run as a QVM")
        return _get_unrestricted_qvm(connection=connection,
                                     noisy=noisy,
                                     n_qubits=n_qubits)

    if name == '9q-generic' or name == '9q-square':
        if name == '9q-generic':
            warnings.warn("Please prefer '9q-square' instead of '9q-generic'",
                          DeprecationWarning)

        if not as_qvm:
            raise ValueError(
                "The device '9q-square' is only available as a QVM")
        return _get_9q_square_qvm(connection=connection, noisy=noisy)

    device = get_lattice(name)
    if not as_qvm:
        if noisy is not None and noisy:
            warnings.warn(
                "You have specified `noisy=True`, but you're getting a QPU. This flag "
                "is meant for controlling noise models on QVMs.")
        return QuantumComputer(name=full_name,
                               qam=QPU(endpoint=pyquil_config.qpu_url,
                                       user=pyquil_config.user_id),
                               device=device,
                               compiler=QPUCompiler(
                                   endpoint=pyquil_config.compiler_url,
                                   device=device))

    if noisy:
        noise_model = device.noise_model
    else:
        noise_model = None

    return QuantumComputer(name=full_name,
                           qam=QVM(connection=connection,
                                   noise_model=noise_model),
                           device=device,
                           compiler=_get_qvm_compiler_based_on_endpoint(
                               device=device,
                               endpoint=connection.compiler_endpoint))
Example #6
0
def get_qc(name: str,
           *,
           as_qvm: bool = None,
           noisy: bool = None,
           connection: ForestConnection = None) -> QuantumComputer:
    """
    Get a quantum computer.

    A quantum computer is an object of type :py:class:`QuantumComputer` and can be backed
    either by a QVM simulator ("Quantum/Quil Virtual Machine") or a physical Rigetti QPU ("Quantum
    Processing Unit") made of superconducting qubits.

    You can choose the quantum computer to target through a combination of its name and optional
    flags. There are multiple ways to get the same quantum computer. The following are equivalent::

        >>> qc = get_qc("Aspen-1-16Q-A-noisy-qvm")
        >>> qc = get_qc("Aspen-1-16Q-A", as_qvm=True, noisy=True)

    and will construct a simulator of an Aspen-1 lattice with a noise model based on device
    characteristics. We also provide a means for constructing generic quantum simulators that
    are not related to a given piece of Rigetti hardware::

        >>> qc = get_qc("9q-square-qvm")
        >>> qc = get_qc("9q-square", as_qvm=True)

    Finally, you can get request a QVM with "no" topology of a given number of qubits
    (technically, it's a fully connected graph among the given number of qubits) with::

        >>> qc = get_qc("5q-qvm") # or "6q-qvm", or "34q-qvm", ...

    These less-realistic, fully-connected QVMs will also be more lenient on what types of programs
    they will ``run``. Specifically, you do not need to do any compilation. For the other, realistic
    QVMs you must use :py:func:`qc.compile` or :py:func:`qc.compiler.native_quil_to_executable`
    prior to :py:func:`qc.run`.

    The Rigetti QVM must be downloaded from https://www.rigetti.com/forest and run as a server
    alongside your python program. To use pyQuil's built-in QVM, replace all ``"-qvm"`` suffixes
    with ``"-pyqvm"``::

        >>> qc = get_qc("5q-pyqvm")

    Redundant flags are acceptable, but conflicting flags will raise an exception::

        >>> qc = get_qc("9q-square-qvm") # qc is fully specified by its name
        >>> qc = get_qc("9q-square-qvm", as_qvm=True) # redundant, but ok
        >>> qc = get_qc("9q-square-qvm", as_qvm=False) # Error!

    Use :py:func:`list_quantum_computers` to retrieve a list of known qc names.

    This method is provided as a convenience to quickly construct and use QVM's and QPU's.
    Power users may wish to have more control over the specification of a quantum computer
    (e.g. custom noise models, bespoke topologies, etc.). This is possible by constructing
    a :py:class:`QuantumComputer` object by hand. Please refer to the documentation on
    :py:class:`QuantumComputer` for more information.

    :param name: The name of the desired quantum computer. This should correspond to a name
        returned by :py:func:`list_quantum_computers`. Names ending in "-qvm" will return
        a QVM. Names ending in "-pyqvm" will return a :py:class:`PyQVM`. Names ending in
        "-noisy-qvm" will return a QVM with a noise model. Otherwise, we will return a QPU with
        the given name.
    :param as_qvm: An optional flag to force construction of a QVM (instead of a QPU). If
        specified and set to ``True``, a QVM-backed quantum computer will be returned regardless
        of the name's suffix
    :param noisy: An optional flag to force inclusion of a noise model. If
        specified and set to ``True``, a quantum computer with a noise model will be returned
        regardless of the name's suffix. The noise model for QVMs based on a real QPU
        is an empirically parameterized model based on real device noise characteristics.
        The generic QVM noise model is simple T1 and T2 noise plus readout error. See
        :py:func:`~pyquil.noise.decoherence_noise_with_asymmetric_ro`.
    :param connection: An optional :py:class:`ForestConnection` object. If not specified,
        the default values for URL endpoints will be used. If you deign to change any
        of these parameters, pass your own :py:class:`ForestConnection` object.
    :return: A pre-configured QuantumComputer
    """
    # 1. Parse name, check for redundant options, canonicalize names.
    prefix, qvm_type, noisy = _parse_name(name, as_qvm, noisy)
    del as_qvm  # do not use after _parse_name
    name = _canonicalize_name(prefix, qvm_type, noisy)

    # 2. Check for unrestricted {n}q-qvm
    ma = re.fullmatch(r'(\d+)q', prefix)
    if ma is not None:
        n_qubits = int(ma.group(1))
        if qvm_type is None:
            raise ValueError("Please name a valid device or run as a QVM")
        return _get_unrestricted_qvm(name=name,
                                     connection=connection,
                                     noisy=noisy,
                                     n_qubits=n_qubits,
                                     qvm_type=qvm_type)

    # 3. Check for "9q-square" qvm
    if prefix == '9q-generic' or prefix == '9q-square':
        if prefix == '9q-generic':
            warnings.warn("Please prefer '9q-square' instead of '9q-generic'",
                          DeprecationWarning)

        if qvm_type is None:
            raise ValueError(
                "The device '9q-square' is only available as a QVM")
        return _get_9q_square_qvm(name=name,
                                  connection=connection,
                                  noisy=noisy,
                                  qvm_type=qvm_type)

    # 4. Not a special case, query the web for information about this device.
    device = get_lattice(prefix)
    if qvm_type is not None:
        # 4.1 QVM based on a real device.
        return _get_qvm_based_on_real_device(name=name,
                                             device=device,
                                             noisy=noisy,
                                             connection=connection,
                                             qvm_type=qvm_type)
    else:
        # 4.2 A real device
        if noisy is not None and noisy:
            warnings.warn(
                "You have specified `noisy=True`, but you're getting a QPU. This flag "
                "is meant for controlling noise models on QVMs.")
        return QuantumComputer(
            name=name,
            qam=QPU(endpoint=pyquil_config.qpu_url,
                    user=pyquil_config.user_id),
            device=device,
            compiler=QPUCompiler(
                quilc_endpoint=pyquil_config.quilc_url,
                qpu_compiler_endpoint=pyquil_config.qpu_compiler_url,
                device=device,
                name=prefix))