def test_qpu_run(): config = PyquilConfig() if config.qpu_url and config.qpu_compiler_url: g = nx.Graph() g.add_node(0) device = NxDevice(g) qc = QuantumComputer( name="pyQuil test QC", qam=QPU(endpoint=config.qpu_url, user="******"), device=device, compiler=QPUCompiler( quilc_endpoint=config.quilc_url, qpu_compiler_endpoint=config.qpu_compiler_url, device=device, ), ) bitstrings = qc.run_and_measure(program=Program(X(0)), trials=1000) assert bitstrings[0].shape == (1000, ) assert np.mean(bitstrings[0]) > 0.8 bitstrings = qc.run(qc.compile(Program(X(0)))) assert bitstrings.shape == (0, 0) else: pytest.skip( "QPU or compiler-server not available; skipping QPU run test.")
def test_qpu_reengage_when_invalid(): config = PyquilConfig() engagement = Engagement( server_public_key=b"abc123", client_public_key=b"abc123", client_secret_key=b"abc123", expires_at=9999999999.0, qpu_endpoint="tcp://fake.qpu:50053", qpu_compiler_endpoint="tcp://fake.compiler:5555", ) assert engagement.is_valid() session = get_session(config=config) config._engagement_requested = True config.get_engagement = lambda: engagement qpu = QPU(session=session) assert qpu._client_engagement is None assert qpu._get_client_auth_config() is not None assert qpu._client_engagement is engagement # By expiring the previous engagement, we expect QPU to attempt to re-engage engagement.expires_at = 0.0 assert not engagement.is_valid() new_engagement = Engagement( server_public_key=b"abc12345", client_public_key=b"abc12345", client_secret_key=b"abc12345", expires_at=9999999999.0, qpu_endpoint="tcp://fake.qpu:50053", qpu_compiler_endpoint="tcp://fake.compiler:5555", ) config.get_engagement = lambda: new_engagement new_auth_config = qpu._get_client_auth_config() assert new_auth_config is not None assert new_auth_config.client_public_key == new_engagement.client_public_key assert qpu._client_engagement is new_engagement new_engagement.expires_at = 0.0 config.get_engagement = lambda: None assert qpu._get_client_auth_config() is None
def test_qpu_run(forest: ForestConnection): devices = get_devices(async_endpoint=forest.async_endpoint, api_key=forest.api_key, user_id=forest.user_id, as_dict=True) for name, dev in devices.items(): if not dev.is_online: continue # TODO: gh-372. No way to query whether a device is available for running pytest.xfail("Please fix after gh-372") qpu = QPU(connection=forest, device_name=name) bitstrings = qpu.run( quil_program=Program(X(0), MEASURE(0, 0)), classical_addresses=[0], trials=1000, ) assert bitstrings.shape == (1000, 1) assert np.mean(bitstrings) > 0.8
def test_run_expects_executable(): # https://github.com/rigetti/pyquil/issues/740 # This test might need some more knowledgeable eyes. Not sure how # to best mock a qpu. qc = get_qc('1q-qvm') qc.qam = QPU(endpoint='tcp://not-needed:00000', user="******") p = Program(X(0)) with pytest.raises(TypeError): result = qc.run(p)
def mock_qpu(): return QPU(endpoint='tcp://not-needed:00000', user="******")
def test_qpu_does_not_engage_without_session(): qpu = QPU(endpoint="tcp://fake.qpu:50052") assert qpu._get_client_auth_config() is None
def test_qpu_not_engaged_error(): with pytest.raises(ValueError): QPU()
def get_qc(name: str, *, as_qvm: bool = None, noisy: bool = None, connection: ForestConnection = None): """ 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("8Q-Agave-noisy-qvm") >>> qc = get_qc("8Q-Agave", 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-generic-qvm") >>> qc = get_qc("9q-generic", as_qvm=True) Redundant flags are acceptable, but conflicting flags will raise an exception:: >>> qc = get_qc("9q-generic-qvm") # qc is fully specified by its name >>> qc = get_qc("9q-generic-qvm", as_qvm=True) # redundant, but ok >>> qc = get_qc("9q-generic-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() name, as_qvm, noisy = _parse_name(name, as_qvm, noisy) if name == '9q-generic': if not as_qvm: raise ValueError( "The device '9q-generic' is only available as a QVM") nineq_square = nx.convert_node_labels_to_integers( nx.grid_2d_graph(3, 3)) nineq_device = NxDevice(topology=nineq_square) if noisy: noise_model = decoherance_noise_with_asymmetric_ro( nineq_device.get_isa()) else: noise_model = None return QuantumComputer(name='9q-generic-qvm', qam=QVM(connection=connection, noise_model=noise_model), device=nineq_device) # At least based off a real device. device = get_devices(as_dict=True)[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 controling noise models on QVMs.") return QuantumComputer(name=name, qam=QPU(device_name=name, connection=connection), device=device) if noisy: noise_model = device.noise_model name = "{name}-noisy-qvm".format(name=name) else: noise_model = None name = "{name}-qvm".format(name=name) return QuantumComputer(name=name, qam=QVM(connection=connection, noise_model=noise_model), device=device)
def test_qpu_not_engaged_error(): with pytest.raises(RuntimeError): qpu = QPU(None)