Skip to content

Commit

Permalink
update: auto set coupling map on backends
Browse files Browse the repository at this point in the history
  • Loading branch information
erichulburd committed Feb 11, 2022
1 parent 8d0ace7 commit ed1bab1
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 25 deletions.
46 changes: 36 additions & 10 deletions qiskit_rigetti/_qcs_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from qiskit.circuit import Measure
from qiskit.providers import BackendV1, Options, Provider
from qiskit.providers.models import QasmBackendConfiguration
from qiskit.transpiler import CouplingMap

from ._qcs_job import RigettiQCSJob

Expand Down Expand Up @@ -102,7 +103,8 @@ def __init__(
engagement_manager: EngagementManager,
backend_configuration: QasmBackendConfiguration,
provider: Optional[Provider],
qc: QuantumComputer,
auto_set_coupling_map: bool = True,
qc: Optional[QuantumComputer] = None,
**fields: Any,
) -> None:
"""
Expand All @@ -113,19 +115,40 @@ def __init__(
engagement_manager: QPU engagement manager.
backend_configuration: Backend configuration.
provider: Parent provider.
qc: Parent provider.
auto_set_coupling_map: When `True`, this will set the `QasmBackendConfiguration`
`coupling_map` based on the `QuantumComputer` topology if the existing
`coupling_map` is empty.
fields: Keyword arguments for the values to use to override the default options.
"""
super().__init__(backend_configuration, provider, **fields)
self._compiler_timeout = compiler_timeout
self._execution_timeout = execution_timeout
self._client_configuration = client_configuration
self._engagement_manager = engagement_manager
self._qc: Optional[QuantumComputer] = qc
self._qc = qc
self._auto_set_coupling_map = auto_set_coupling_map

@classmethod
def _default_options(cls) -> Options:
return Options(shots=None)

def _load_qc_if_necessary(self):
configuration: QasmBackendConfiguration = self.configuration()
if self._qc is None:
self._qc = get_qc(
configuration.backend_name,
compiler_timeout=self._compiler_timeout,
execution_timeout=self._execution_timeout,
client_configuration=self._client_configuration,
engagement_manager=self._engagement_manager,
)

def _set_coupling_map_based_on_qc_topology(self):
self._load_qc_if_necessary()
configuration: QasmBackendConfiguration = self.configuration()
configuration.coupling_map = get_coupling_map_from_qc_topology(self._qc)

def run(
self,
run_input: Union[QuantumCircuit, List[QuantumCircuit]],
Expand All @@ -150,14 +173,10 @@ def run(

run_input = [_prepare_circuit(circuit) for circuit in run_input]

if self._qc is None:
self._qc = get_qc(
self.configuration().backend_name,
compiler_timeout=self._compiler_timeout,
execution_timeout=self._execution_timeout,
client_configuration=self._client_configuration,
engagement_manager=self._engagement_manager,
)
self._load_qc_if_necessary()
configuration: QasmBackendConfiguration = self.configuration()
if not configuration.coupling_map and self._auto_set_coupling_map:
self._set_coupling_map_based_on_qc_topology()

return RigettiQCSJob(
job_id=str(uuid4()),
Expand All @@ -167,3 +186,10 @@ def run(
backend=self,
configuration=self.configuration(),
)


def get_coupling_map_from_qc_topology(qc: QuantumComputer) -> CouplingMap:
g = qc.quantum_processor.qubit_topology()
h = g.to_directed()
cm = h.edges()
return CouplingMap(cm)
2 changes: 1 addition & 1 deletion qiskit_rigetti/_qcs_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def __init__(
configuration: Configuration from parent backend
"""
super().__init__(backend, job_id)

self._status = JobStatus.INITIALIZING
self._circuits = circuits
self._options = options
Expand Down
23 changes: 9 additions & 14 deletions qiskit_rigetti/_qcs_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@

import httpx
from pyquil import get_qc
from pyquil.api import QuantumComputer, EngagementManager
from pyquil.api import EngagementManager
from qcs_api_client.client import build_sync_client, QCSClientConfiguration
from qiskit.providers import ProviderV1
from qiskit.providers.models import QasmBackendConfiguration
from qiskit.transpiler import CouplingMap

from ._qcs_backend import RigettiQCSBackend
from ._qcs_backend import RigettiQCSBackend, get_coupling_map_from_qc_topology


class RigettiQCSProvider(ProviderV1):
Expand Down Expand Up @@ -105,9 +104,9 @@ def get_simulator(self, *, num_qubits: int, noisy: bool = False) -> RigettiQCSBa
client_configuration=self._client_configuration,
engagement_manager=self._engagement_manager,
)
cm = _convert_coupling(qc)
configuration = _configuration(name, num_qubits, local=local, simulator=True, coupling_map=cm)
return RigettiQCSBackend(
configuration = _configuration(name, num_qubits, local=local, simulator=True)
configuration.coupling_map = get_coupling_map_from_qc_topology(qc)
backend = RigettiQCSBackend(
compiler_timeout=self._compiler_timeout,
execution_timeout=self._execution_timeout,
client_configuration=self._client_configuration,
Expand All @@ -117,14 +116,16 @@ def get_simulator(self, *, num_qubits: int, noisy: bool = False) -> RigettiQCSBa
qc=qc,
)

return backend

def _get_quantum_processors(self) -> Dict[str, Any]:
with build_sync_client(configuration=self._client_configuration) as qcs_client: # type: httpx.Client
return cast(
Dict[str, Any], qcs_client.get("https://forest-server.qcs.rigetti.com/devices").json()["devices"]
)


def _configuration(name: str, num_qubits: int, local: bool, simulator: bool, coupling_map: CouplingMap) -> QasmBackendConfiguration:
def _configuration(name: str, num_qubits: int, local: bool, simulator: bool) -> QasmBackendConfiguration:
return QasmBackendConfiguration(
backend_name=name,
backend_version="",
Expand All @@ -137,12 +138,6 @@ def _configuration(name: str, num_qubits: int, local: bool, simulator: bool, cou
open_pulse=False,
memory=False,
max_shots=10000,
coupling_map=coupling_map,
coupling_map=[],
max_experiments=8,
)

def _convert_coupling(qc: QuantumComputer) -> CouplingMap:
g = qc.quantum_processor.qubit_topology()
h = g.to_directed()
cm = h.edges()
return CouplingMap(cm)
7 changes: 7 additions & 0 deletions tests/test_qcs_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ def test_run__no_measurments(backend: RigettiQCSBackend):
execute(circuit, backend, shots=10)


def test_run__backend_coupling_map():
backend = RigettiQCSProvider().get_simulator(num_qubits=3)
assert backend.configuration().coupling_map
edges = list(backend.configuration().coupling_map.get_edges())
assert [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] == sorted(edges)


@pytest.fixture
def backend():
return RigettiQCSProvider().get_simulator(num_qubits=3)
Expand Down

0 comments on commit ed1bab1

Please sign in to comment.