diff --git a/docs/source/apidoc/backend.rst b/docs/source/apidoc/backend.rst new file mode 100644 index 000000000..263b35ce2 --- /dev/null +++ b/docs/source/apidoc/backend.rst @@ -0,0 +1,32 @@ +************************ +Backend Interfaces +************************ + +QPU +---- + +.. autoclass:: pulser.QPUBackend + :members: + + +Emulators +---------- + +Local +^^^^^^^ +.. autoclass:: pulser_simulation.QutipBackend + :members: + +Remote +^^^^^^^^^^ +.. autoclass:: pulser_pasqal.EmuTNBackend + :members: + +.. autoclass:: pulser_pasqal.EmuFreeBackend + :members: + + +Remote backend connection +--------------------------- + +.. autoclass:: pulser_pasqal.PasqalCloud diff --git a/docs/source/apidoc/cloud.rst b/docs/source/apidoc/cloud.rst deleted file mode 100644 index af977455e..000000000 --- a/docs/source/apidoc/cloud.rst +++ /dev/null @@ -1,9 +0,0 @@ -************************ -Pasqal Cloud connection -************************ - -PasqalCloud ----------------------- - -.. autoclass:: pulser_pasqal.PasqalCloud - :members: diff --git a/docs/source/apidoc/pulser.rst b/docs/source/apidoc/pulser.rst index 4ac1d617f..82533cce0 100644 --- a/docs/source/apidoc/pulser.rst +++ b/docs/source/apidoc/pulser.rst @@ -6,4 +6,4 @@ API Reference core simulation - cloud + backend diff --git a/docs/source/index.rst b/docs/source/index.rst index 955f57596..6e953fa98 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -61,6 +61,12 @@ computers and simulators, check the pages in :doc:`review`. review +.. toctree:: + :maxdepth: 2 + :caption: Backend Execution + + tutorials/backends + .. toctree:: :maxdepth: 2 :caption: Classical Simulation diff --git a/docs/source/tutorials/backends.nblink b/docs/source/tutorials/backends.nblink new file mode 100644 index 000000000..02acdbc43 --- /dev/null +++ b/docs/source/tutorials/backends.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../tutorials/advanced_features/Backends for Sequence Execution.ipynb" +} \ No newline at end of file diff --git a/pulser-core/pulser/__init__.py b/pulser-core/pulser/__init__.py index 128bde91a..9dccecc5b 100644 --- a/pulser-core/pulser/__init__.py +++ b/pulser-core/pulser/__init__.py @@ -18,3 +18,5 @@ from pulser.pulse import Pulse from pulser.register import Register, Register3D from pulser.sequence import Sequence + +from pulser.backend import QPUBackend # isort: skip diff --git a/pulser-core/pulser/backend/__init__.py b/pulser-core/pulser/backend/__init__.py index ac8e7e552..65c4f1ff5 100644 --- a/pulser-core/pulser/backend/__init__.py +++ b/pulser-core/pulser/backend/__init__.py @@ -12,3 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. """Classes for backend execution.""" + +from pulser.backend.config import EmulatorConfig +from pulser.backend.noise_model import NoiseModel +from pulser.backend.qpu import QPUBackend diff --git a/pulser-core/pulser/backend/config.py b/pulser-core/pulser/backend/config.py index eb7f27cfb..6a30f2862 100644 --- a/pulser-core/pulser/backend/config.py +++ b/pulser-core/pulser/backend/config.py @@ -24,7 +24,7 @@ EVAL_TIMES_LITERAL = Literal["Full", "Minimal", "Final"] -@dataclass +@dataclass(frozen=True) class BackendConfig: """The base backend configuration. @@ -35,7 +35,7 @@ class BackendConfig: backend_options: dict[str, Any] = field(default_factory=dict) -@dataclass +@dataclass(frozen=True) class EmulatorConfig(BackendConfig): """The configuration for emulator backends. diff --git a/pulser-core/pulser/backend/noise_model.py b/pulser-core/pulser/backend/noise_model.py index ca862394a..98b376354 100644 --- a/pulser-core/pulser/backend/noise_model.py +++ b/pulser-core/pulser/backend/noise_model.py @@ -24,7 +24,7 @@ ] -@dataclass +@dataclass(frozen=True) class NoiseModel: """Specifies the noise model parameters for emulation. diff --git a/pulser-core/pulser/backend/qpu.py b/pulser-core/pulser/backend/qpu.py index f2a141d3f..ef3d11751 100644 --- a/pulser-core/pulser/backend/qpu.py +++ b/pulser-core/pulser/backend/qpu.py @@ -24,7 +24,7 @@ class QPUBackend(RemoteBackend): """Backend for sequence execution on a QPU.""" - def run(self, job_params: list[JobParams] = []) -> RemoteResults: + def run(self, job_params: list[JobParams] | None = None) -> RemoteResults: """Runs the sequence on the remote QPU and returns the result. Args: diff --git a/pulser-core/pulser/backend/remote.py b/pulser-core/pulser/backend/remote.py index 0741dcf49..39cbc5044 100644 --- a/pulser-core/pulser/backend/remote.py +++ b/pulser-core/pulser/backend/remote.py @@ -58,12 +58,20 @@ class RemoteResults(Results): the results. connection: The remote connection over which to get the submission's status and fetch the results. + jobs_order: An optional list of job IDs (as stored by the connection) + used to order the results. """ - def __init__(self, submission_id: str, connection: RemoteConnection): + def __init__( + self, + submission_id: str, + connection: RemoteConnection, + jobs_order: list[str] | None = None, + ): """Instantiates a new collection of remote results.""" self._submission_id = submission_id self._connection = connection + self._jobs_order = jobs_order @property def results(self) -> tuple[Result, ...]: @@ -79,7 +87,9 @@ def __getattr__(self, name: str) -> Any: status = self.get_status() if status == SubmissionStatus.DONE: self._results = tuple( - self._connection._fetch_result(self._submission_id) + self._connection._fetch_result( + self._submission_id, self._jobs_order + ) ) return self._results raise RemoteResultsError( @@ -102,7 +112,9 @@ def submit( pass @abstractmethod - def _fetch_result(self, submission_id: str) -> typing.Sequence[Result]: + def _fetch_result( + self, submission_id: str, jobs_order: list[str] | None + ) -> typing.Sequence[Result]: """Fetches the results of a completed submission.""" pass @@ -116,8 +128,8 @@ def _get_submission_status(self, submission_id: str) -> SubmissionStatus: pass def fetch_available_devices(self) -> dict[str, Device]: - """Fetches the available devices through this connection.""" - raise NotImplementedError( + """Fetches the devices available through this connection.""" + raise NotImplementedError( # pragma: no cover "Unable to fetch the available devices through this " "remote connection." ) diff --git a/pulser-pasqal/pulser_pasqal/__init__.py b/pulser-pasqal/pulser_pasqal/__init__.py index 793a9ceac..6f9c57bf3 100644 --- a/pulser-pasqal/pulser_pasqal/__init__.py +++ b/pulser-pasqal/pulser_pasqal/__init__.py @@ -16,5 +16,6 @@ from pasqal_cloud import BaseConfig, EmulatorType, Endpoints from pulser_pasqal._version import __version__ +from pulser_pasqal.backends import EmuFreeBackend, EmuTNBackend from pulser_pasqal.job_parameters import JobParameters, JobVariables from pulser_pasqal.pasqal_cloud import PasqalCloud diff --git a/pulser-pasqal/pulser_pasqal/backends.py b/pulser-pasqal/pulser_pasqal/backends.py index 4dbf68456..56dfb0b15 100644 --- a/pulser-pasqal/pulser_pasqal/backends.py +++ b/pulser-pasqal/pulser_pasqal/backends.py @@ -24,9 +24,7 @@ from pulser.backend.remote import JobParams, RemoteBackend, RemoteResults from pulser_pasqal.pasqal_cloud import PasqalCloud -DEFAULT_CONFIG_EMU_TN = EmulatorConfig( - evaluation_times="Final", sampling_rate=0.1 -) +DEFAULT_CONFIG_EMU_TN = EmulatorConfig(evaluation_times="Final") DEFAULT_CONFIG_EMU_FREE = EmulatorConfig( evaluation_times="Final", sampling_rate=0.25 ) @@ -62,29 +60,24 @@ def run( """Executes on the emulator backend through the Pasqal Cloud. Args: - job_params: An optional list of parameters for each job to execute. - Must be provided only when the sequence is parametrized as - a list of mappings, where each mapping contains one mapping - of variable names to values under the 'variables' field. + job_params: A list of parameters for each job to execute. Each + mapping must contain a defined 'runs' field specifying + the number of times to run the same sequence. If the sequence + is parametrized, the values for all the variables necessary + to build the sequence must be given in it's own mapping, for + each job, under the 'variables' field. Returns: The results, which can be accessed once all sequences have been successfully executed. """ - needs_build = ( - self._sequence.is_parametrized() - or self._sequence.is_register_mappable() - ) - if job_params is None and needs_build: - raise ValueError( - "When running a sequence that requires building, " - "'job_params' must be provided." - ) - elif job_params and not needs_build: + suffix = f" when executing a sequence on {self.__class__.__name__}." + if not job_params: + raise ValueError("'job_params' must be specified" + suffix) + if any("runs" not in j for j in job_params): raise ValueError( - "'job_params' cannot be provided when running built " - "sequences on an emulator backend." + "All elements of 'job_params' must specify 'runs'" + suffix ) return self._connection.submit( @@ -119,9 +112,9 @@ class EmuTNBackend(PasqalEmulator): - sampling_rate - backend_options: - precision (str): The precision of the simulation. Can be "low", - "normal" or "high". Defaults to "normal". + "normal" or "high". Defaults to "normal". - max_bond_dim (int): The maximum bond dimension of the Matrix - Product State (MPS). Defaults to 500. + Product State (MPS). Defaults to 500. All other parameters should not be changed from their default values. @@ -142,8 +135,8 @@ class EmuFreeBackend(PasqalEmulator): Configurable fields in EmulatorConfig: - backend_options: - - with_noise (bool): Whether to add noise to the simulation. - Defaults to False. + - with_noise (bool): Whether to add noise to the simulation. + Defaults to False. All other parameters should not be changed from their default values. diff --git a/pulser-pasqal/pulser_pasqal/pasqal_cloud.py b/pulser-pasqal/pulser_pasqal/pasqal_cloud.py index 95178f010..1173e472d 100644 --- a/pulser-pasqal/pulser_pasqal/pasqal_cloud.py +++ b/pulser-pasqal/pulser_pasqal/pasqal_cloud.py @@ -15,10 +15,13 @@ from __future__ import annotations import copy +import json import warnings from dataclasses import fields -from typing import Any, Optional, Type +from typing import Any, Optional, Type, cast +import backoff +import numpy as np import pasqal_cloud from pasqal_cloud.device.configuration import ( BaseConfig, @@ -35,6 +38,7 @@ SubmissionStatus, ) from pulser.devices import Device +from pulser.json.abstract_repr.deserializer import deserialize_device from pulser.result import Result, SampledResult from pulser_pasqal.job_parameters import JobParameters @@ -43,6 +47,29 @@ pasqal_cloud.EmulatorType.EMU_TN: EmuTNConfig, } +MAX_CLOUD_ATTEMPTS = 5 + +backoff_decorator = backoff.on_exception( + backoff.fibo, Exception, max_tries=MAX_CLOUD_ATTEMPTS, max_value=60 +) + + +def _make_json_compatible(obj: Any) -> Any: + """Makes an object compatible with JSON serialization. + + For now, simply converts Numpy arrays to lists, but more can be added + as needed. + """ + + class NumpyEncoder(json.JSONEncoder): + def default(self, o: Any) -> Any: + if isinstance(o, np.ndarray): + return o.tolist() + return json.JSONEncoder.default(self, o) + + # Serializes with the custom encoder and then deserializes back + return json.loads(json.dumps(obj, cls=NumpyEncoder)) + class PasqalCloud(RemoteConnection): """Manager of the connection to PASQAL's cloud platform. @@ -51,9 +78,9 @@ class PasqalCloud(RemoteConnection): QPUs. Args: - username: your username in the PASQAL cloud platform. - password: the password for your PASQAL cloud platform account. - group_id: the group_id associated to the account. + username: Your username in the PASQAL cloud platform. + password: The password for your PASQAL cloud platform account. + project_id: The project ID associated to the account. kwargs: Additional arguments to provide to the pasqal_cloud.SDK() """ @@ -61,14 +88,15 @@ def __init__( self, username: str = "", password: str = "", - group_id: str = "", + project_id: str = "", **kwargs: Any, ): """Initializes a connection to the Pasqal cloud platform.""" + project_id_ = project_id or kwargs.pop("group_id", "") self._sdk_connection = pasqal_cloud.SDK( username=username, password=password, - group_id=group_id, + project_id=project_id_, **kwargs, ) @@ -86,7 +114,9 @@ def submit(self, sequence: Sequence, **kwargs: Any) -> RemoteResults: sequence.measure(bases[0]) emulator = kwargs.get("emulator", None) - job_params: list[JobParams] = kwargs.get("job_params", []) + job_params: list[JobParams] = _make_json_compatible( + kwargs.get("job_params", []) + ) if emulator is None: available_devices = self.fetch_available_devices() # TODO: Could be better to check if the devices are @@ -97,6 +127,7 @@ def submit(self, sequence: Sequence, **kwargs: Any) -> RemoteResults: "of the devices currently available through the remote " "connection." ) + # TODO: Validate the register layout if sequence.is_parametrized() or sequence.is_register_mappable(): for params in job_params: @@ -106,29 +137,60 @@ def submit(self, sequence: Sequence, **kwargs: Any) -> RemoteResults: configuration = self._convert_configuration( config=kwargs.get("config", None), emulator=emulator ) - - batch = self._sdk_connection.create_batch( + create_batch_fn = backoff_decorator(self._sdk_connection.create_batch) + batch = create_batch_fn( serialized_sequence=sequence.to_abstract_repr(), jobs=job_params or [], # type: ignore[arg-type] emulator=emulator, configuration=configuration, wait=False, - fetch_results=False, ) - return RemoteResults(batch.id, self) + jobs_order = [] + if job_params: + for job_dict in job_params: + for job in batch.jobs.values(): + if ( + job.id not in jobs_order + and job_dict["runs"] == job.runs + and job_dict.get("variables", None) == job.variables + ): + jobs_order.append(job.id) + break + else: + raise RuntimeError( + f"Failed to find job ID for {job_dict}." + ) + + return RemoteResults(batch.id, self, jobs_order or None) + + @backoff_decorator + def fetch_available_devices(self) -> dict[str, Device]: + """Fetches the devices available through this connection.""" + abstract_devices = self._sdk_connection.get_device_specs_dict() + return { + name: cast(Device, deserialize_device(dev_str)) + for name, dev_str in abstract_devices.items() + } - def _fetch_result(self, submission_id: str) -> tuple[Result, ...]: + def _fetch_result( + self, submission_id: str, jobs_order: list[str] | None + ) -> tuple[Result, ...]: # For now, the results are always sampled results - batch = self._sdk_connection.get_batch( - id=submission_id, fetch_results=True - ) + get_batch_fn = backoff_decorator(self._sdk_connection.get_batch) + batch = get_batch_fn(id=submission_id) seq_builder = Sequence.from_abstract_repr(batch.sequence_builder) reg = seq_builder.get_register(include_mappable=True) all_qubit_ids = reg.qubit_ids meas_basis = seq_builder.get_measurement_basis() results = [] - for job in batch.jobs.values(): + + jobs = ( + (batch.jobs[job_id] for job_id in jobs_order) + if jobs_order + else batch.jobs.values() + ) + for job in jobs: vars = job.variables size: int | None = None if vars and "qubits" in vars: @@ -143,11 +205,10 @@ def _fetch_result(self, submission_id: str) -> tuple[Result, ...]: ) return tuple(results) + @backoff_decorator def _get_submission_status(self, submission_id: str) -> SubmissionStatus: """Gets the status of a submission from its ID.""" - batch = self._sdk_connection.get_batch( - id=submission_id, fetch_results=False - ) + batch = self._sdk_connection.get_batch(id=submission_id) return SubmissionStatus[batch.status] def _convert_configuration( diff --git a/pulser-pasqal/requirements.txt b/pulser-pasqal/requirements.txt index f636822df..067102a0b 100644 --- a/pulser-pasqal/requirements.txt +++ b/pulser-pasqal/requirements.txt @@ -1,2 +1,2 @@ -pasqal-cloud ~= 0.2.3 -pydantic < 2.0 +pasqal-cloud ~= 0.3.3 +backoff ~= 2.2 \ No newline at end of file diff --git a/pulser-simulation/pulser_simulation/__init__.py b/pulser-simulation/pulser_simulation/__init__.py index d35b82d4b..9964e23ff 100644 --- a/pulser-simulation/pulser_simulation/__init__.py +++ b/pulser-simulation/pulser_simulation/__init__.py @@ -14,5 +14,6 @@ """Classes for classical emulation of a Sequence.""" from pulser_simulation._version import __version__ +from pulser_simulation.qutip_backend import QutipBackend from pulser_simulation.simconfig import SimConfig from pulser_simulation.simulation import QutipEmulator, Simulation diff --git a/tests/test_backend.py b/tests/test_backend.py index aa4fab5bb..1fb282e87 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -220,7 +220,9 @@ def __init__(self): def submit(self, sequence, **kwargs) -> RemoteResults: return RemoteResults("abcd", self) - def _fetch_result(self, submission_id: str) -> typing.Sequence[Result]: + def _fetch_result( + self, submission_id: str, jobs_order: list[str] | None + ) -> typing.Sequence[Result]: return ( SampledResult( ("q0", "q1"), diff --git a/tests/test_pasqal.py b/tests/test_pasqal.py index d80e59017..ae670acf4 100644 --- a/tests/test_pasqal.py +++ b/tests/test_pasqal.py @@ -13,11 +13,13 @@ # limitations under the License. from __future__ import annotations +import copy import dataclasses from pathlib import Path from typing import Any from unittest.mock import MagicMock, patch +import numpy as np import pytest from pasqal_cloud.device.configuration import EmuFreeConfig, EmuTNConfig @@ -31,6 +33,7 @@ ) from pulser.devices import Chadoq2 from pulser.register import Register +from pulser.register.special_layouts import SquareLatticeLayout from pulser.result import SampledResult from pulser.sequence import Sequence from pulser_pasqal import BaseConfig, EmulatorType, Endpoints, PasqalCloud @@ -56,7 +59,7 @@ class CloudFixture: @pytest.fixture def seq(): - reg = Register.square(2, spacing=10, prefix="q") + reg = SquareLatticeLayout(5, 5, 5).make_mappable_register(10) return Sequence(reg, test_device) @@ -64,51 +67,45 @@ def seq(): def mock_job(): @dataclasses.dataclass class MockJob: + runs = 10 variables = {"t": 100, "qubits": {"q0": 1, "q1": 2, "q2": 4, "q3": 3}} result = {"00": 5, "11": 5} + def __post_init__(self) -> None: + self.id = str(np.random.randint(10000)) + return MockJob() @pytest.fixture def mock_batch(mock_job, seq): - with pytest.warns(UserWarning): - seq_ = seq.build() - seq_.declare_channel("rydberg_global", "rydberg_global") - seq_.measure() + seq_ = copy.deepcopy(seq) + seq_.declare_channel("rydberg_global", "rydberg_global") + seq_.measure() @dataclasses.dataclass class MockBatch: id = "abcd" status = "DONE" - jobs = {"job1": mock_job} + jobs = {mock_job.id: mock_job} sequence_builder = seq_.to_abstract_repr() return MockBatch() @pytest.fixture -def fixt(monkeypatch, mock_batch): +def fixt(mock_batch): with patch("pasqal_cloud.SDK", autospec=True) as mock_cloud_sdk_class: pasqal_cloud_kwargs = dict( username="abc", password="def", - group_id="ghi", + project_id="ghi", endpoints=Endpoints(core="core_url"), webhook="xyz", ) pasqal_cloud = PasqalCloud(**pasqal_cloud_kwargs) - with pytest.raises(NotImplementedError): - pasqal_cloud.fetch_available_devices() - - monkeypatch.setattr( - PasqalCloud, - "fetch_available_devices", - lambda _: {test_device.name: test_device}, - ) - mock_cloud_sdk_class.assert_called_once_with(**pasqal_cloud_kwargs) mock_cloud_sdk = mock_cloud_sdk_class.return_value @@ -117,6 +114,9 @@ def fixt(monkeypatch, mock_batch): mock_cloud_sdk.create_batch = MagicMock(return_value=mock_batch) mock_cloud_sdk.get_batch = MagicMock(return_value=mock_batch) + mock_cloud_sdk.get_device_specs_dict = MagicMock( + return_value={test_device.name: test_device.to_abstract_repr()} + ) yield CloudFixture( pasqal_cloud=pasqal_cloud, mock_cloud_sdk=mock_cloud_sdk @@ -152,11 +152,17 @@ def test_submit(fixt, parametrized, emulator, seq, mock_job): ): fixt.pasqal_cloud.submit(seq2, job_params=[dict(runs=10)]) + assert fixt.pasqal_cloud.fetch_available_devices() == { + test_device.name: test_device + } if parametrized: with pytest.raises( TypeError, match="Did not receive values for variables" ): - fixt.pasqal_cloud.submit(seq, job_params=[{"runs": 100}]) + fixt.pasqal_cloud.submit( + seq.build(qubits={"q0": 1, "q1": 2, "q2": 4, "q3": 3}), + job_params=[{"runs": 10}], + ) assert not seq.is_measured() config = EmulatorConfig( @@ -175,7 +181,16 @@ def test_submit(fixt, parametrized, emulator, seq, mock_job): == sdk_config ) - job_params = [{"runs": 10, "variables": {"t": 100}}] + job_params = [ + { + "runs": 10, + "variables": { + "t": np.array(100), # Check that numpy array is converted + "qubits": {"q0": 1, "q1": 2, "q2": 4, "q3": 3}, + }, + } + ] + remote_results = fixt.pasqal_cloud.submit( seq, job_params=job_params, @@ -192,20 +207,41 @@ def test_submit(fixt, parametrized, emulator, seq, mock_job): emulator=emulator, configuration=sdk_config, wait=False, - fetch_results=False, ) ) + job_params[0]["runs"] = 1 + with pytest.raises(RuntimeError, match="Failed to find job ID"): + # Job runs don't match MockJob + fixt.pasqal_cloud.submit( + seq, + job_params=job_params, + emulator=emulator, + config=config, + ) + + job_params[0]["runs"] = {10} + with pytest.raises( + TypeError, match="Object of type set is not JSON serializable" + ): + # Check that the decoder still fails on unsupported types + fixt.pasqal_cloud.submit( + seq, + job_params=job_params, + emulator=emulator, + config=config, + ) + assert isinstance(remote_results, RemoteResults) assert remote_results.get_status() == SubmissionStatus.DONE fixt.mock_cloud_sdk.get_batch.assert_called_once_with( - id=remote_results._submission_id, fetch_results=False + id=remote_results._submission_id ) fixt.mock_cloud_sdk.get_batch.reset_mock() results = remote_results.results fixt.mock_cloud_sdk.get_batch.assert_called_with( - id=remote_results._submission_id, fetch_results=True + id=remote_results._submission_id ) assert results == ( SampledResult( @@ -264,25 +300,30 @@ def test_emulators_run(fixt, seq, emu_cls, parametrized: bool): emu = emu_cls(seq, fixt.pasqal_cloud) - bad_kwargs = {} if parametrized else {"job_params": [{"runs": 100}]} - err_msg = ( - "'job_params' must be provided" - if parametrized - else "'job_params' cannot be provided" - ) - with pytest.raises(ValueError, match=err_msg): - emu.run(**bad_kwargs) + with pytest.raises(ValueError, match="'job_params' must be specified"): + emu.run() - good_kwargs = ( - {"job_params": [{"variables": {"t": 100}}]} if parametrized else {} - ) + with pytest.raises(ValueError, match="must specify 'runs'"): + emu.run(job_params=[{}]) + + good_kwargs = { + "job_params": [ + { + "runs": 10, + "variables": { + "t": 100, + "qubits": {"q0": 1, "q1": 2, "q2": 4, "q3": 3}, + }, + } + ] + } remote_results = emu.run(**good_kwargs) assert isinstance(remote_results, RemoteResults) sdk_config: EmuTNConfig | EmuFreeConfig if isinstance(emu, EmuTNBackend): emulator_type = EmulatorType.EMU_TN - sdk_config = EmuTNConfig() + sdk_config = EmuTNConfig(dt=1.0) else: emulator_type = EmulatorType.EMU_FREE sdk_config = EmuFreeConfig() @@ -293,7 +334,6 @@ def test_emulators_run(fixt, seq, emu_cls, parametrized: bool): emulator=emulator_type, configuration=sdk_config, wait=False, - fetch_results=False, ) diff --git a/tutorials/advanced_features/Backends for Sequence Execution.ipynb b/tutorials/advanced_features/Backends for Sequence Execution.ipynb new file mode 100644 index 000000000..00170c733 --- /dev/null +++ b/tutorials/advanced_features/Backends for Sequence Execution.ipynb @@ -0,0 +1,457 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6f230abe", + "metadata": {}, + "source": [ + "# Backend Execution of Pulser Sequences" + ] + }, + { + "cell_type": "markdown", + "id": "ae508ab2", + "metadata": {}, + "source": [ + "When the time comes to execute a Pulser sequence, there are many options: one can choose to execute it on a QPU or on an emulator, which might happen locally or remotely. All these options are accessible through an unified interface we call a `Backend`. \n", + "\n", + "This tutorial is a step-by-step guide on how to use the different backends for Pulser sequence execution." + ] + }, + { + "cell_type": "markdown", + "id": "a7601ae9", + "metadata": {}, + "source": [ + "## 1. Choosing the type of backend\n", + "\n", + "Although the backend interface nearly doesn't change between backends, some will unavoidably enforce more restrictions on the sequence being executed or require extra steps. In particular, there are two questions to answer:\n", + "\n", + "1. **Is it local or remote?** Execution on remote backends requires a working remote connection. For now, this is only available through `pulser_pasqal.PasqalCloud`.\n", + "2. **Is it a QPU or an Emulator?** For QPU execution, there are extra constraints on the sequence to take into account.\n", + "\n", + "### 1.1. Starting a remote connection\n", + "\n", + "For remote backend execution, start by ensuring that you have access and start a remote connection. For `PasqalCloud`, we could start one by running:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "ef3cc2eb", + "metadata": {}, + "outputs": [], + "source": [ + "from pulser_pasqal import PasqalCloud\n", + "\n", + "connection = PasqalCloud(\n", + " username=USERNAME, # Your username or email address for the Pasqal Cloud Platform\n", + " project_id=PROJECT_ID, # The ID of the project associated to your account\n", + " password=PASSWORD, # The password for your Pasqal Cloud Platform account\n", + " **kwargs\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "29cff577", + "metadata": {}, + "source": [ + "### 1.2. Preparation for execution on `QPUBackend`\n", + "\n", + "Sequence execution on a QPU is done through the `QPUBackend`, which is a remote backend. Therefore, it requires a remote backend connection, which should be open from the start due to two additional QPU constraints:\n", + "\n", + "1. The `Device` must be chosen among the options available at the moment, which can be found through `connection.fetch_available_devices()`.\n", + "2. The `Register` must be defined from one of the register layouts calibrated for the chosen `Device`, which are found under `Device.calibrated_register_layouts`. Check out [this tutorial](reg_layouts.nblink) for more information on how to define a `Register` from a `RegisterLayout`.\n", + "\n", + "On the contrary, execution on emulator backends imposes no further restriction on the device and the register. We will stick to emulator backends in this tutorial, so we will forego the requirements of QPU backends in the following steps." + ] + }, + { + "cell_type": "markdown", + "id": "35a4f10c", + "metadata": {}, + "source": [ + "## 2. Creating the Pulse Sequence" + ] + }, + { + "cell_type": "markdown", + "id": "122a3c37", + "metadata": {}, + "source": [ + "The next step is to create the sequence that we want to execute. Here, we make a sequence with a variable duration combining a Blackman waveform in amplitude and a ramp in detuning. Since it will be executed on an emulator, we can create the register we want and choose a `VirtualDevice` that does not impose hardware restrictions (like the `MockDevice`)." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "4548fedd", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "from pulser import Sequence, Pulse, Register\n", + "from pulser.devices import MockDevice\n", + "from pulser.waveforms import BlackmanWaveform, RampWaveform" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "57e088c6", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABp0AAAF8CAYAAAA9/HMGAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAADJFElEQVR4nOzdd3jb5b3+8bf2sizJezt770kIISFsCITRNARaxoEOuuF3WqDnlDIP7enpbg+0FCinpaxAwp4hAwgjezlxth3vLdmyLQ/p94dikUAgCbYjO7lf16VL0lePvs9HwXjo1vN5DJFIJIKIiIiIiIiIiIiIiIhINxjjXYCIiIiIiIiIiIiIiIj0fwqdREREREREREREREREpNsUOomIiIiIiIiIiIiIiEi3KXQSERERERERERERERGRblPoJCIiIiIiIiIiIiIiIt2m0ElERERERERERERERES6TaGTiIiIiIiIiIiIiIiIdJtCJxEREREREREREREREek2hU4iIiIiIiIiIiIiIiLSbQqdREREREREREREREREpNvM8S5A4qehoYFNmzbh9/uJRCLdPp/RaMTr9TJp0iRcLlcPVCgiIiIiIiIiIiIiIv2FQqdT0Icffsh9997Dm2+9RXt7R4+f32G3cdFFF3PX3XczZsyYHj+/iIiIiIiIiIiIiIj0PYZITyxxkX7jvffe44Lzz2Vwajs3ntnJuWMhOQGMPdBosTMM1QF4dSM8vNJEQ1si7yxfydixY7t/chERERERERERERER6dMUOp0CwuEwZWVlOBwORgwfyug0P6/8exiXvffmrGuCuf9lotU2gI8+XofBYOi9yURERERERERERERE5JhFIhEaGxvJysrC2BOrUg5S6HQKKCkpITc3N3Z/7X0weWDvz/vKBpj3P70/j4iIiIiIiIiIiIiIHL8DBw6Qk5PTY+fTnk6nALfbDcBNN93Emy/8nUkDen4fpyM5dyy47EZ+csfP+dGPfnTMz3vuuee48sore68wEREREREREREREZFTWCAQIDc3N5Yf9BSFTqeArtZ2gUCAASkRTlSnO6sZspJMBAIBEhMTj/l5drv9uMaLiIiIiIiIiIiIiMjx6+mtcXquUZ/0eR0dHVjNJ7abos0M7e3tx/WcwYMH91I1IiIiIiIiIiIiIiLSWxQ6SZ+TnZ0d7xJEREREREREREREROQ4KXSSPmfVqlXxLkFERERERERERERERI6TQic5bn9ZBqN+HO8qRERERERERERERESkL1HoJMetphEKy3vv/HPmzOm9k4uIiIiIiIiIiIiISK9Q6CR9TnFxcbxLEBERERERERERERGR46TQSfqcvXv3xrsEERERERERERERERE5TgqdpM8xm83xLkFERERERERERERERI6TQifpcxYsWBDvEkRERERERERERERE5DhpSYkA8JtXj33s+zt7rw6A5557jiuvvLJ3JxERERERERERERERkR6l0Kkf6Ozs5K677uKf//wnFRUVZGVlcf311/Of//mfGAyGHpnj3/91fON7ZtYja2tr68Wzi4iIiIiIiIiIiIhIb1Do1A/88pe/5MEHH+Txxx9n9OjRrF27lhtuuAGPx8MPfvCDHplj+X/0yGl6RH5+frxLEBERERERERERERGR46TQqR9YvXo18+fP5+KLLwZgwIABPPnkk3z88cc9NsfskT12qm4bPHhwvEsQEREREREREREREZHjZIx3AXJ0p59+OsuWLWPnzuhmSps2beK9997jwgsvPOL4UChEIBA47NKTPt4D336kR095mHfeeaf3Ti4iIiIiIiIiIiIiIr1CK536gdtvv51AIMCIESMwmUx0dnZy//33c8011xxx/AMPPMDdd9/dozXUNsL/vQeProCC0uixh27s0SlERERERERERERERKQfU+jUDzzzzDM88cQT/Otf/2L06NFs3LiRH/3oR2RlZXHdddd9Zvwdd9zBrbfeGrsfCATIzc097nkjEXh9EzyyAl7eCG0dMCAFbr0IrpzajRd0FGeccUbvnVxERERERERERERERHqFQqd+4Mc//jG33347V111FQBjx46lqKiIBx544Iihk81mw2azfen59lZFVzQ9/i6U1UOCHdo74E/XwXfO/dKnPWZVVVVfKiQTEREREREREREREZH4UejUDzQ3N2M0Hr79lslkIhwO99gcrW3w7Efw6EpYtQPMJrh4Alx/JgzNgNG3QYa3x6b7Qjt37mTy5MknZjIREREREREREREREekRCp36gUsuuYT777+fvLw8Ro8ezYYNG/jNb37Dv/3bv/XYHBnfhcYWmJAPv/s6XH06JLujj+2p7LFpRERERERERERERETkJKXQqR/44x//yM9+9jO+853vUFVVRVZWFt/61re48847e2yOQAsMSY/u13TFVHBYe+zUx23RokXxm1xERERERERERERERL4U49GHSLy53W5+97vfUVRUREtLC3v27OG+++7Dau25ZOjP14PHCV9/EDK+Azc9DO/u6LHTH5cXXnghPhOLiIiIiIiIiIiIiMiXppVOAsDN50Qvm4rgkRXwr9Xw2EoYkArnjQXDCaylubn5BM4mIiIiIhJ/kUiEUEeIUHuIzkgnneEjXA45HolEMBqNmAwmjEYjRkP0YjKaDrttMpqwmW3YLXbMJv35JyIiIiIivUt/dchhxufDH66D/7kGlqyJBlAPL4cIcP9SOFALl0+BvJTeqyEnJ6f3Ti4iIiIi0k2t7a3UBeuoC9bR0NxAoDVAY2sj/hZ/9H5LAH+rn0BL9HhjayPBUJDWjlZC7SFa2ltiAVNbRxuhjhBtnW1fOGdXkGQ0GDEajRgwECFCOByOXkfCRCLR6y86h9VkxWo+eDFZsVlsWM1WHBYHLpsLl9WF2+6OXRLtibjtbrwOL4mORDxODz6njyRXEkmuJLwOLxazpaf/iUVEREREpJ9S6CRHZDXDwhnRS3ENPLoSHn8Xbvkn3PpPmDwQPr63d+YeNWpU75xYRERERORTwuEw9c31VPgrqAhUUOGvoMxfRqW/kppgDbVNtYcFTA0tDbS2twLgtDpxWV3YLXbsFjs2sy16sdhit61mK16nl9SEVMwmM2ajGYvJ8sltswWz4eC1yYzJYIqtVjpsFZPxk87ohiP0IYgQid3uDHdGQ6hwhI5wBx3hDto72umIRG93dH5yrDPSSXtnO+0d7YQ6QrR3ttPS3oK/xU9bRxttnW20dbTR2t4ave5opbmtmabWplhQ5rK6SHQk4nV48Tq9+Jw+khOSSU9MJ9OTSZY3i0xPJmmJaaQnpuNz+jAYTmQvBREREREROVEUOslR5aXAXVdGL29tia5+emFd78335ptvsmjRot6bQEREREROepFIhOrGag7UH+BA3QGKa4spaSihrKGMykAllYFKqhqrqG2qpSPcgdPqxOPwxFb2uGwuHBYHdqudvKQ8hmcMx2V14bQ6cVgduKwubBYbJqMJs9Eca3VnNpqjoZHxkBZ3h4RHfV04Eo6FVp3hTsLh8Oe2+2tua6Yp1ESwLUhLWwvNbc20tLXQ0t5CZaCSvdV7aQo10RhqpLGlEX9rNMgyG80kuZJISUghLTGNLG8Web488pPzGZAygFxfLjm+HBIdiQqnRERERET6GYVOclzOHRu91AfjXYmIiIiInMqCoSD7a/ZzoP4AxXXF7K3eS1FtEcV1xZQ2lFLhryDUESLRnkhyQnIsUEqwJeB1esn2ZuO2uXE73LGQqWsFksV48NpkwWw0YzaZ+0Vg1BOMBiNGU/dea2e48/AVVZ3tdHR20NbRRlOoiYbmhmgY1dpIU6iJmsYa9lbvjbUnrA/W09rRitPqjK2WyvZmk5eUx8DUgQxLG8ag1EHkJeWptZ+IiIiISB+j0EmOqj4IH+2GxlaYNAAGp4PP1XvzzZgxo/dOLiIiIiL9QiQSoTJQyZ7qPeyp2sPOyp3srNrJ3qq9FNUVUdNUg8PiIDkhGa/TG9tzKC8pjzHZY6LH7F5cdldsHyOLyRK7NhvNWkXTS0zGaItAm9l21LGRSLQFYFcrv642f4GWALXBWvzNfhpaovtmfbD3A17b+hq1wVpqmmqIRCKkJ6aTn5RPfko+Q1KHMCx9GMPShzEwdSBp7jT9NxYREREROcEUOknM71+Hv6+K7uf07bPhhtnw+Cr4/uMQDH0y7ptz4cF/6706/H5/751cRERERPqMSCRCTVMNO8p3sL1iOwVlBeyq3MXemmiw1NLWQrIrmVR3KkmuJJKcSYzIHMHpg08nOSGZRHtibP8kqzkaLNnM0ZZ30j8YDAYsJgsWkwUXn//Jto7ODto62wh1hAh1hGhta6UyUPnJnltNdbxZ/SZPrXmK2qZaGloacFgc5CfnMyRtCMMzhjMmawyjs0YzPGM4iY7EE/gqRUREREROHQqdjmL58uUsW7aM999/n5KSEmpqanA6naSmpjJ27Fhmz57NvHnzyMjIiHep3fL0B3DLP8FiArsFbnoYOsPw7UdhVDacPRraO+G1TfDXd2DigGj41BsKCgoYP35875xcRERERE64js4O9tXsY0fFDgrKCthaupUdFTvYVbULf4uflIQUMhIzouGSM4nTB5/OvPHzSHYmk2BPwGa2xcIlhUqnJrMp2ubQaXXGjg1IGRC73dHZEQukulZKVQQqqGmqobqxmvd2v8fSDUupClTRGGokOSGZwSmDGZo+lJGZIxmTPYYxWWMYmDIQo/HUaKUoIiIiItIbFDodQTAY5A9/+AMPP/wwRUVFRCIRAOx2O0lJSbS0tLB161Y2b97ME088gcVi4ZJLLuGWW25h5syZca7+y3lwGQzPhPd/Hm2d929/hR/+A2aPhDdvh6627q1tMO1OeGRF74VOIiIiItI/hcNh9tbsZUvJFjYe2MjGAxvZXr6dfTX7MBgMZHoySUtMIzUhlREZIzhjyBmkuFNw2904LA7sFjt2ix2r2XrK7KEkPaMrlHLZoqulMj2ZDM8YDkA4Eqa1vZVQe4iW9hbqgnWUNZRR3VhNRaCCbWXb+N8V/0tVoAqzycyQ1CGMzBzJuJxxTMybyPic8WT7stWqT0RERETkGCh0+pSHHnqIu+++m8rKSsaNG8e9997LjBkzmDJlCm63OzYuEomwa9cuPvroI958801eeOEFlixZwvz58/n1r3/NwIED4/gqjl9hOfzwfEhKiN7/0QXw+Ltw/axPAicAuxWumQn3Le29WhYsWNB7JxcRERGRHlEVqGJL6RY2H9jM+uL1bCndws7KnbR3tpPjyyHDk0FGYgZnDj2TKyddSXJCMi6bKxYsOSwOrViSE8JoMOK0OnFanfjwkeXNYkz2GADaO9tpbW+ltb2VplATJfUllPvLqQxU8tz65/jz8j9T1ViF0+pkWPowRmWOYnzueCbnT2ZC7gR8Ll+cX52IiIiISN+i0OlTvv/977No0SJ+8pOfMGbMmM8dZzAYGDZsGMOGDePrX/86LS0tPPHEEzzwwAP84x//4M477zyBVXdflR+yD/l7KdMbvc46wt9Q2T5oDn32eE95/fXXmTdvXu9NICIiIiLHLBwOs7tqN+uL17Nm3xrWFq9lW+k2aoO1pCemk+XJIt2TzriccZw78lzSEtNw2Vw4rU4c1ujqJa1akr6qaz8pt91NqjuVgSnRDw92hjtpaW+hpa0Ff7OfA/UHqPBXUOYvY+OBjfzitV9QG6wly5vF6KzRTMqbxPSB05kyYAo5vhytihIRERGRU5ZCp0/Ztm0bw4YNO+7nORwObrrpJm644QaKi4t7obLeFeHwFU1dt4/0t1Jv//3U2NjYuxOIiIiIyBF1dHawvXw7G4o38NG+j1hXtI4tpVvo6OwgLzmPbG82mZ5MxmaPJdOTSaI9MbaCxGHVyiU5eZiMJhJsCSTYEkh1pzIkfQgQXRnV0tZCc3szNY01FNUUUeov5Z0d7/CPD/9Bhb8Ct93N6KzRjM8dz7SB05g+cDrD0ofp/w8REREROSUodPqULxM4HcpkMvW71npdjhgwnfgyyMjIiMOsIiIiIqeWznAnBWUFfLzvYz7c+yHritZRUF6A0WCMBkyebAalDmLm4JlkeDJIsCfgtDpxWV1YzVat5JBTksVkweKwkOhIJCMxgzHZY4hEIrFVUfXN9RTVFlFaX8rmks28sfUNShpKMBlMjM4azdQBUzl9yOmcMeQM8pPz9f+RiIiIiJx0FDp9SZFIhN27d2O328nNzY13OT3i9qfggRejtzvD0cDppr+By3b4OH9z79YxadKk3p1ARERE5BRUUlfCx/s/5v3d7/Ph3g/ZeGAjkUiEgSkDyfHlMCZ7DOeOOpdUdypuuzsaMNlcWEyWeJcu0qcZDIbYir/khGSGpEVXRYU6QjSHmmlsbWR/7X6K64rZXLqZV7e8SklDCW6bm/G545k6YCqzhs5ixuAZpLpT4/xqRERERES6R6HTUTz//PMsXbqU3//+9/h80Q2O9u/fzyWXXEJBQQEACxYs4IknnsBk6r/tEvKSoyudGlsPOZYC4cjhxwCMxuhjveXVV19l0aJFvTeBiIiIyEmusbWRtfvX8sHeD1i9ZzVr962luqmaXF8ueUl55CXlcdrA08jwZOC2u3HZXAqYRHqYzWzDZrbhc/nIS84DoK2jjWAoSENLA3uq9lBcV8zKnSv554f/pCJQQaYnk4m5E5k+aDqzh81m2sBpOKyOOL8SEREREZFjp9DpKB588EEqKytjgRPALbfcwrZt25g7dy61tbU8++yznH322XzjG9+IY6Xds//38a5ARERERL6MSCTCnuo9vL/7fVYUrmD1ntXsqtxFSkIKA1IGkO3N5vJJl5OblIvX4Y0FTDaz7egnF5EeZTVbsZqt+Fw+BqZE27K3trcSDAWpaqxiT9UeSupLeH798/zmrd8QDAUZlTmKGYNnMHv4bOYMm0OmNzPOr0JERERE5PMpdDqKgoICLrzwwtj9xsZGXnnlFRYuXMiTTz5Je3s7EydO5NFHH+3XoVNfMnXq1HiXICIiItJntXW0saF4A+/teo8VO1fw4d4PaWhuYHDqYAYkD2Dm4JksnLKQ5IRkEmwJJNgTcFgc2jtGpI+yW+zYLXaSE5IZmTmScCQca8tXXFfMnuo9bC3dyitbXqG0vpQsbxZTBkzhzKFnMnfEXMbmjMVk7L9dN0RERETk5KLQ6Sjq6urIyMiI3X/vvffo6OiItX+zWCyce+65PPHEE/EqsVccqIUtB6L7N3mcMDYXcpNPzNytra1HHyQiIiJyimhobuCDPR+wcudKVu1axYbiDVhNVganDiYvKY+FUxeS48vB4/Dgsrlw29yYTfo1X6S/MhqMJNijgXGmN5Ppg6bT1tFGU6iJ6kA1hZWFFNcV8/C7D/MfS/8Do8HIhNwJzBwyk3NGnsMZQ87AaXPG+2WIiIiIyClKf40eRWJiIrW1tbH7y5cvx2g0MmvWrNgxi8VCMBiMR3k97p1tcPtTsG7fZx+bPBB+cRXMHd27NWzZsoUxY8b07iQiIiIifVRVoIpVu1bx9va3WVm4ksKKQjI8GQxMGUh+Uj4zB88k05OJ2+HGbXPjtDq1iknkJGc1W0kyJ5HkSmJ45nDCkTDBUBB/s5891XvYW7OX5TuW88h7jxBoCTAmewyzhs7i3FHnMmf4HNx2d7xfgoiIiIicIhQ6HcWIESN46aWXuO+++zCZTPzrX/9i8uTJh+3xVFRURHp6ehyr7Bl/WQbf/TtEIjBjaDRkSnRAoAXW74fVO+G8X8D/3gDfnBvvakVERERODrGQqeBtlhcuZ1flLvKT8xmcOpgZg2bw1SlfJTkhGbc9GjLZLNqLSeRUZzQYo98T7G5yknI4c9iZtLS30NjSSFFtEbuqd/HRvo946uOnqA3WMipzFGcMPYNzR57L3JFz8Tq98X4JIiIiInKSUuh0FD/4wQ9YsGABOTk5sRVN991332FjPvzwQyZNmhSnCnvGpiL43uMwJgf+9V0YlfPZMQUl8LUHo8HUaUNgXF7v1HL55Zf3zolFRERE+oAvCplOH3w610y/hiRXUuwNZYvJEu+SRaSPMxgMOK1OnFYn6Z50pg2aRqgjFN0XqraYwspCNh3YxJINS6hurGZo+lDOGBINoc4dfS5JrqR4vwQREREROUkodDqKK6+8kj//+c888sgjAFx11VVcf/31scdXrlxJIBDgggsuiFOFPePXr0JyArzzH5CUcOQxo3Lg7Ttg1E/gN6/C37/dO7WsWLGi3/97ioiIiHSpbqxm5c6VvL39bZbvOELINO2aT1Yy2bUfk4j0DJvZhi3BRkpCCpPyJ9HW0UZjayMH6g+ws2InhRWFvLblNSoCFQzPGM6cYXO4aNxFnDX8LFw2V7zLFxEREZF+Sn/RHoObb76Zm2+++YiPzZ49m/r6+hNcUc9buR1uOPPzA6cuSQlw/Znw5Oreq+Vk+PcUERGRU1dzqJl3d73LG9ve4I1tb7CjYgf5SfkMSh3EzMEzuWb6NSS7FDKJyIllNVtJTkgmOSGZCbkTYiFUSX0J28u3s754Pc+sfQZ/i58JuRM4a8RZXDz2Yk4ffDoWs1ZcioiIiMix0V+4PeA//uM/2LNnD0899VSvzVFaWsptt93Ga6+9RnNzM0OGDOGxxx5jypQpPXL+ygAMyzy2scMzo+N7S0pKSu+dXERERKSHdYY7WVe0jje3vclrW19jzf41JDmTGJ4xnKkDprJgygKSXEkk2hNJdCSqXZ6I9AmHhlDjc8cT6ggRaAmwr2Yf28u38/b2t3lo5UN0dHYwbeA0zh55NvPGzmN87niMRmO8yxcRERGRPkqh01Hcc889X/h4R0cHTz31FBUVFb1WQ319PTNnzuSss87itddeIzU1lV27duHz+XpsjgQb1DUd29i6puj43jJjxozeO7mIiIhIN0UiEXZX7eatgrd4betrrNq5iggRRmSMYFDKIGYNnUV6Yjpep5dEeyJWszXeJYuIHJXNbCPVnUqqO5VpA6fR2t5KQ3MDhRWFFFYW8vSap/mvV/8Lu8XO6YNP54LRF3DZxMvITcqNd+kiIiIi0ocodDqKu+666wsfNxgMACxatKjXavjlL39Jbm4ujz32WOzYwIEDe3SO8fnw3Br4fxcffezza2BcXo9Of5iXXnqpV/89RURERI5XTWMNb29/m9e2vsay7cuoaqxiePpwBqcO5vrTrycvKY9EZyIeuweH1RHvckVEus1usZPhySDDk8GZw86kua2ZumAd28u3s7NyJ39Y9gd+9PSPyE/OZ+6IucwfP59zRp2j74EiIiIipziFTkexfPnyIx5vbW1l586d/PnPf6ajo4Nf//rXvVbDiy++yPnnn8+CBQtYuXIl2dnZfOc73+Eb3/jGEceHQiFCoVDsfiBw9F54154BN/wV7lwM93zl88fd9Rx8uBse/eZxvwwRERGRfqMz3MmafWt4dcurvLzlZTYd2MSA5AEMTR/KvHHzyE/Ox+v04nF4cNlcGA1qNSUiJy+DwYDL5sJlc5GblMvZI8+mKdREhb+CLaVbKCgrYOmGpQRaA0wdMJXzR5/PZRMuY2zO2NgHNUVERETk1GCIRCKReBfRnwUCAcaOHcv06dN55plnemUOu90OwK233sqCBQtYs2YNP/zhD3nooYe47rrrPjP+rrvu4u677/7M8SuuuILArqW8dXv4M49FInD+L2DZNjhtCNx0FkzMB48T/M2wfj88siIaOM0dDW/eDsfyt8PYOyzMvexmfv/73x/z692xYwcjRow45vEiIiIiPaG8oZw3tr3BS5tfYtn2ZUQiEUZljWJw6mAGpQ4iJSEFr8OL2+7GbNJnt0REurR3ttPQ3MDuqt0UlBWwu3o3uyp34XF6mD1sNpeMv4R54+aR5EqKd6kiIiIiclAgEMDj8eD3+0lMTOyx8yp06gHf+c53+Oc//3lMK4q+DKvVypQpU1i9enXs2A9+8APWrFnDBx988JnxR1rplJub+4WhE0BzCL71CDyxGo6UJ0WARTPgLzdCgv3YalfoJCIiIn1Ve0c7q/es5pUtr/DqllfZXr6dwamDGZY+jEGpg8hLyoutZrJbjvGXHxERobmtmerGaraUbmFn5U52Ve6i3F/O6KzRnDvqXC6beBkzBs1QgC8iIiISR70VOuk3vB5gsViwWCy9dv7MzExGjRp12LGRI0fy3HPPHXG8zWbDZrMd9zxOG/zjO/CTedH9nbYegEALJDpgTC5cMbV393LqsmHDBoVOIiIi0iuKa4t5betrvLz5ZZYXLsdqsjIqcxST8yezYPICUtzR1UwJ9gS1zBMR+ZKcVif5yfnkJ+fTGe4k0BqguLaYLaVbWFG4gr+u+isGg4E5w+Ywf8J85k+YT4o7Jd5li4iIiEgPUOjUTaFQiFdffZXLLrus1+aYOXMmhYWFhx3buXMn+fn5vTLf2Lzo5fM89QH837vw6k96ZXoRERGRHtPR2cHqPat5YeMLvLz5ZfZW72VY+jCGpQ/jG2d8gxxfDj6XD4/Dg9VsjXe5IiInHZPRhM/pw+f0MT53PK3trdQF69hWto3t5du5+6W7+eY/vsnY7LFcOPZCvjL5K0zKm6S9oERERET6KYVOR/F///d/RzweiUQoKyvjiSeewO/3M3ny5M+Mvfbaa3ukhltuuYXTTz+d//qv/+KrX/0qH3/8MX/961/561//2iPnP157KuGNzb13/ksuuaT3Ti4iIiInvdqmWl7f+jpLNy7lzW1vYjQaGZs9lpmDZ/K1075GkitJq5lEROLEbrGT5c0iy5vF3BFzaWxtZH/NfjaXbOaVza/w27d+S6IjkbNHnM3lEy/n4nEX47K54l22iIiIiBwj7el0FEaj8YifsPr0P9uhYyKRCAaDgc7Ozh6r4+WXX+aOO+5g165dDBw4kFtvvZVvfOMbx/Tcrt6MR9vT6VjdvxTuXAyd/zz62C+zp9Nbb73Fueee++ULFBERkVNKJBJhW9k2Xtr0Ei9sfIG1+9eSn5LPyIyRsb2ZfE4fHqcHm/n4WxCLiMiJ0dLWQnVTNZsObGJHxQ4KKwqpb65n6oCpzBs3jwWTFzAkfUi8yxQRERE5KWhPpzh59NFH+8Sy/nnz5jFv3rx4l3FC1NTUxLsEERER6eNa21tZUbiCpRuX8vKml6lpqmF01miGpQ/jnJHnkOHJwOPwkOhI1GomEZF+wmF1kJeUR15SHheNvQh/i5+dlTvZUrKFx1c/zs9e+Bk5vhzOH3U+V066kjkj5qg1qoiIiEgfo9DpCP73f/+X+fPnk52dzfXXXx/vck45Pp8v3iWIiIhIH1TWUMYrm19hyYYlrChcgdvuZnTWaC4aexEDUwaS5ErC5/ThsDriXaqIiHSTyWgiyZXEaYNOY/rA6QTbgpT7y9l8YDObSjbx9Nqn6ejsYM7wOVw56Uoun3Q5Xqc33mWLiIiInPIUOh3B9773Pb7//e8zadIkLrvsMi699FLGjh0b77JOGXPmzIl3CSIiItIHRCIRNh3YxJINS1i6cSnbSrcxNH0oIzJG8J053yHbm43P5cPj8GA26ddaEZGTlcFgIMGWwNC0oQxNG0pbRxt1wToKygrYWrqVO1+8k2/84xtMyZ/C/AnzWTh1IYNSB8W7bBEREZFTkv46P4I1a9awdOlSXnzxRX72s59x5513MmDAgFgANWvWLIzGk6tNy/Nrjn3stpLeqwNgyZIlLFq0qHcnERERkT6pvaOdVbtW8fz653lh4wvUBesYmz2W8TnjuWLiFaQkpOB1ekmwJ6htnojIKcpqtpLhySDDk8Hs4bMJtAbYU7WHzSWb+b8P/o+fvfAzBqYM5KKxF3HVlKuYPmj6Sfc3vIiIiEhfpdDpCCZPnszkyZO599572b9/P0uWLOHFF1/kD3/4A7/73e9ISkpi3rx5zJ8/n/POOw+n0xnvkrvtK7+HY925KsKxjxURERE5mkBLgNe3vs5z65/j9a2vYzaZGZs9lgvHXsjg1MH4nD61zRMRkSMyGU34nD6mDJjC5PzJBNuClDWUsaF4A+/teo+/vfs3HFYH5408j69M+QoXjb0Iu8Ue77JFRERETloKnY5iwIAB3HLLLdxyyy3U1dXx8ssvs3TpUhYvXszjjz+O3W7n7LPP5vLLL2fevHmkpaXFu+Qv5bFvxruCT6iVoYiIyMmvtL6UFza+wHPrn+PdXe+S6clkdNZorjv9OvKS8khyJeF1erGYLPEuVURE+omuNnzD0ocxLH0YoY4Q1U3VbCreREF5Ad/6x7dobG3kzKFnctnEy1gwZQGp7tR4ly0iIiJyUjFEIpFIvIvoj0KhEG+99RYvvPACL7/8MpWVlRiNRk477TTee++9eJd3mEAggMfj4YorriCwaylv3R4+YXOPvcPC3Mtu5ve///0xP2f37t0MGTKkF6sSERGREy0SibC1dCtLNizh+fXPs7V0K8MyhjEycyRD04aS5c3C6/TicXjUNk9ERHpcR2cHDc0NbC/fzpayLewo30FxXTETcidwybhLuGraVYzIHBHvMkVEREROmK7cwO/3k5iY2GPn1UqnL8lmszFv3jzmzZtHJBLhww8/jO0DJd2zZs0ahU4iIiIngY7ODt7b/R7Pr3+epRuXUt1YzZisMYzJGsNlEy8jzZ2Gz+nDZXNhMKh5r4iI9B6zyUyKO4VZ7lnMHDqTxtZGimqL2FC8gcXrF/Nfr/0Xub5cLhl/CYumLWLawGn62SQiIiLyJSh06gEGg4EZM2YwY8YMfvnLX8a7nC+tvB4MBsjwRu+3tsH/vv3ZcbnJsGD6CS1NRERE+onmUDNvbHuDZ9c9y2tbXsNgMDA2eyznjTqPwamDSXIlkeRK0n4aIiISN0aDEY/Dw7iccYzLGUcwFKTcX876ovW8u+td/rLqL3gdXi4ccyFXTbuKuSPmYjbp7RMRERGRY6HfmgSAwjIYczvctwBuuyR6LBiCf/8XGIBDezCajTAhH4Zm9E4tF110Ue+cWERERHqFv9nPK1te4ek1T/NWwVv4XD7GZY/ja6d9jfzkfHxOHz6XT/sziYhIn+SyuRiSNoQhaUMItYeoaqxifdF6tpVvY8FDC8AA5408j4VTF3LxuItxWB3xLllERESkzzqu0On//u//emzia6+9tsfO1ZP+7d/+7Us9z2Aw8Mgjj/RwNSfOY6sgyQW3XPjZx/7nGpg0IHo7HIav/AEeXQEPXNU7taxfv56zzjqrd04uIiIiPaK6sZqlG5byzNpnWLlzJTm+HMZmj+U7c75Dtjcbn8uH1+nFZDTFu1QREZFjZrPYyE3KJTcpl4vGXURdUx2bSjaxpXQL33niOzQ+2siZQ89kweQFfGXKV/A6vfEuWURERKRPOa7Q6frrr++RnsYGg6HPhk5///vfj3jcYDAQiUQ+93h/D53e2QaXTgLrEb4ixufB7JGf3F94Gizb1nu1VFRU9N7JRURE5Es7UHeAJeuX8PTap/l438cMSh3E6KzR3HrurWR5s0hyJeG2uzEajPEuVUREpNssJgvpnnTO85zH2SPPpqG5gYKyAjaVbOLul+/m5iduZtrAaVwx6QoWTV1Eli8r3iWLiIiIxN1xhU55eXkn/Uaa+/btO+x+OBzmhz/8IR9++CE//OEPmTVrFunp6VRWVrJq1Sr+8Ic/MGPGDH7729/GqeKesasCrpt1bGNHZMJTH/ReLW63u/dOLiIiIsdlV+UuFq9bzLNrn2Vz6WZGZoxkZOZIbr/wdjI8GficPhJsCSf974giInJqMxlNJCckM2vYLGYOnUljayM7K3eyoXgDD654kJ8s/gljs8cyf8J8rpl+DcMyhsW7ZBEREZG4OK7Qaf/+/b1URt+Rn59/2P1f/OIXfPTRR2zatInMzMzY8eHDh3PmmWdyww03MHHiRBYvXsxPfvKTE11ujwmGIOFT+3n7XLDlFzAw9fDjiY7o+N5ywQUX9N7JRURE5AtFIhG2lG7h2bXP8uy6Z9lbvZfRWaMZmTmS+RPmk56Yjs/lw2l1xrtUERGRuDAajHgcHqYOmMqU/Ck0hZooqi1iXdE6Fq9bzH+9+l/kJ+dzybhLuPq0q5mSP0UfzhAREZFTxnGFTqeiRx55hK9+9auHBU6Hys7O5qtf/SoPP/xwvw6dvC4obzj8mNEIo3M+O7bCD55efJ/p2WefZdGiRb03gYiIiBwmHA7z8b6PeWbtMzy//nmqGqsYmz2WaQOn8bXpXyMtMQ2f04fdYj/6yURERE4hBoMBt93NmOwxjMkeQ3NbM6UNpawvWs/KXSt5aNVDeJ1e5o2dx9XTrubM4Wdqv0MRERE5qSl0OoqSkhLs9i9+g8Vut1NSUnKCKuodY3PhzS1w+6VHH/vmluh4ERER6b86Ojt4d9e7PLPmGZZuXEpTqIlxOeM4e+TZDE0fSkpCCj6nD6vZGu9SRURE+g2n1cnQtKEMTRtKa3srVY1VrC9az5bSLcz/3/mYjWYuGHMBi6Yu4vwx5+vnrIiIiJx0FDodRU5ODkuWLOHee+89YvjU3NzMkiVLyMk5wpKgfuTKqfD9x+HFdXDp5M8ft3QtrNwOf7q+92oZNWpU751cRETkFBZqD/H29rd5es3TvLT5JQwYGJczjksnXMrQtKEkuZLwOr1YTJZ4lyoiItLv2S128pLyyEvK46KxF1HTVMPGAxvZVraN6x67jrbONs4ZeQ4Lpyzk0gmX4rK54l2yiIiISLf1aOhUUlLC6tWrKSkpIRgMEolEPnfsnXfe2ZNT95qbbrqJO+64g5kzZ3LnnXdyxhlnkJycTG1tLe+++y733HMP+/fv54EHHoh3qcfk8/6T3DgH/vQmfPWP8JN5cONsyD9kL6eiavjbCvjVKzAyG/5t9jHO9yVq9Hg8X+JZIiIiciRNrU28vu11nvr4KV7f9jouq4txOeO4Zto1DEoZRFJCNGhSqx8REZHeYzVbyfJmkeXN4txR51IfrGdL6Ra2lm7llmdu4frHrmf2sNksmLKAr0z+Cj6XL94li4iIiHwphsgXJUPHqKamhm9/+9ssXbr0C4MmiG5ObTAY6Ozs7O60J0Q4HOYb3/gGjz32WGzjT6PRSDgcBqKv54YbbuBvf/tbn90YNBAI4PF4+NrXvsauj57iw7s6jjhubxVc/CsoLAcDkOiIXgIt0UsEGJEJr/4EBqQe8RSfMeAWC9fc9GPuv//+Y673ySef1J5OIiIi3VAfrOfFTS/y9JqneWfHO6S6UxmbPZZh6cMYkDyApIQkPA4PRoMx3qWKiIic0jrDndQH69lRsYPNpZspKCugtKGU6QOnc+WkK1k0bRGZ3iPvMS0iIiLSHV25gd/vJzExscfO2+2VTsFgkDlz5rB9+3asVivjx4/n448/xmq1Mm3aNCoqKti9ezcASUlJjB07tttFn0hGo5FHHnmEa6+9lscff5zNmzfj9/vxeDyMHz+er3/968yZMyfeZR6TIUOG8PziMM0hcNo++/igNNhwPzy8HBZ/DNtKoLwhGjzNGgFfmQY3zQH7MbacLquH4up2hg0b1pMvQ0RERI6gwl/Bkg1LeGbNM7y3+z3ykvMYkzWG78/9PrlJuSS5knDb3QqaRERE+hCT0USKO4Uz3GcwY/AMAi0BdlfvZtOBTTy08iF+vPjHjM8Zz+WTLufqaVczOG1wvEsWERER+ULdXun03//939x+++2MGDGCZcuWkZmZidFoJCMjg7KyMgCKioq47bbbWLx4Mffffz+33XZbjxQvx6YrsVy/fj2TJk3in9+Ba2b2/rz/8wr89FkzlZVV+HzH3hqgtraW5OTkXqxMRETk5LC/Zj/Pr3+eZ9Y+w9r9axmaPpTRWaMZmjaUHF8OPpePBFtCn12NLSIiIkcWjoQJtAQoqitiU/Emtldsp7CikMGpg5k/YT7XTL+GsTlj9TNeREREvrTeWunU7dBpxowZfPzxxzz//PPMnz8f4DOhU5err76ap59+mjfffJOzzz67O9PKcTj0i+eqhQt4d+UyXrylk7NG9858kQgsWQtX/cnA1752LY8+9vfjev67777LrFmzeqc4ERGRfm5H+Q4Wr1vMM2ufoaC8gNGZoxmZOZKhaUPJ9GbGgiYRERE5OUQiERpbGylrKGPjgY1sL99OQXkB6YnpXDL+Eq6edjWnDToNo1GrmUVEROTY9dnQyefzEQgEaG5uxmaL9mwzGo0kJydTXV192Nh9+/YxePBgLr30UpYuXdqdaeOis7OTmpoaQqHQER/Py8s7wRUdm0O/eEwmE/MuvpAVK99ldK6Z88Z0kOSCnvjdtDMM1QF4dbOZPRUdXHH5ZTz19DNYLJbjOo/2dBIREflEJBJhQ/EGFq9bzOJ1iymuK2ZM9hhGZoxkaPpQUt2pJLmScFqd8S5VREREelkkEiEYClIRqGBTySZ2lO9ga+lWnDYnF4+9mKunXc2c4XOwmI/v73ARERE59fTZ0MnhcOByuaipqYkdczqdRCIRWlpaPjPe5/PhcDg+swqqL1u3bh0//elPWbVqFW1tbUccYzAY6OjoOMGVHZtPf/GEQiHeeOMNnn32WT764D38AT/d+yqIMhoNeD1eZs2ey4IFC5g7dy5m8/FvG/bCCy/EVs2JiIicisLhMKv3rObZdc/y/PrnqQvWMS5nHCMyRjA0bSjJCckkuZKwW+zxLlVERETiKBgKUtNUw+aSzWwv387W0q1EiHDeqPNYNG0RF4y5AIfVEe8yRUREpA/qs6HTgAEDqK2tpbGxMXYsPz+fkpISioqKyMnJiR3v7OzE4XBgMBg+d7VQX7Nx40ZOP/10zGYzZ511Fi+99BLjx48nIyOD9evXU11dzZw5c8jPz+exxx7r9Xp+8YtfcMcdd/DDH/6Q3/3ud8f0nN764hEREZGe097RzoqdK3h27bMs3biUto42xueMZ1j6MAalDiIlIQWfy4fNbIt3qSIiItIHNbc1U9tUS0F5QSyAamxtZO6IuSycupBLx1+Kx+mJd5kiIiLSR/RWbnD8y1A+JS8vjwMHDlBVVUVaWhoAEyZMoKSkhCVLlvD9738/NvbFF1+ko6OD7Ozs7k57wtx7770AfPTRR4wcORKj0cjll1/OnXfeSUtLC//v//0/Fi9ezKOPPtrrtaxZs4a//OUvjBs3rtfniie11xMRkVNFS1sLbxa8ybNrn+XlzS9jMVkYlzOOr0z6CgNTBpLkSsLn8mExqUWOiIiIfDGn1YkzyUluUi5zhs2hNlhLYUUhBeUF/MeS/+DGx29k5pCZLJyykCsmXUFaYlq8SxYREZGTULdDpxkzZvD+++/z7rvvcuWVVwKwcOFCXnrpJe644w5aW1uZMGECmzZt4r777sNgMHDhhRd2u/AT5b333uPSSy9l5MiRsWNdi8McDgd/+tOfWL16NT/96U/517/+1Wt1NDU1cc011/Dwww9z33339do8IiIi0rsCLQFe2fwKz6x7hje3vYnH4WF8znium3EduUm50aDJ6cNs6vavaSIiInKKsllsZHmzyPJmMXPITOqa69hbvZdtZdv4nzf/h+/963tMzp/MgikL+OqUr5KX3Df3qBYREZH+p9vvZlxxxRX86le/4h//+EcsdFq0aBF/+9vfWLFiBbfffntsbCQSISMjg7vuuqu7054wfr+fQYMGxe5bLBaamppi941GI3PmzOHJJ5/s1Tq++93vcvHFF3POOeccNXQKhUKHtS8MBAK9WltPGzZsWLxLEBER6VHVjdW8uPFFnln7DMsLl5Pjy2FM1hi+PfvbZHuySUpIwuv0YjKa4l2qiIiInGSsZisZiRlkJGYwdcBUGpob2F+7n4KyAh59/1Fuf/52RmaM5CuTv8JXp36VkZkjj35SERERkc/R7dBp+vTphMPhw44ZDAZeeeUV7rvvPp5++mkOHDiAx+Phggsu4L777iMrK6u7054waWlp1NfXx+5nZGSwa9euw8a0trbS3NzcazU89dRTrF+/njVr1hzT+AceeIC777671+rpbV1tGkVERPqzA3UHeH798yxet5gP937I4NTBjM4aza3n3EqGN4MkZxKJjkQFTSIiInLCWEwWUt2ppLpTmZg7kYaWBkrrS9laupWlG5Zy/6v3k+vL5YpJV7Bw6kIm50/GYDDEu2wRERHpRwyRrl5xckQXXHABbW1tvPPOOwBcffXVLF26lGXLljFjxgy2b9/OzJkzGTx48DGHQsfjwIEDTJkyhbfeeiu2l9OcOXOYMGECv/vd7474nCOtdMrNze3xDcF6i/Z0EhGR/mpnxU6eW/8cz657li0lWxiVOYpRWaMYkjaEVHcqPqePREciRoMx3qWKiIiIxHSGO/G3+KloqGBb+TYKKwrZWrYVj8PD/AnzuWrqVZwx9Ax9WEZEROQkEggE8Hg8PZ4bKHQ6ij/+8Y/ccsstHDhwgMzMTDZt2sRpp51GW1sbSUlJ1NfXEw6Hee6557j88st7fP6lS5dy+eWXYzJ98otdZ2cnBoMBo9FIKBQ67LEj6a0vnt6i0ElERPqLSCTCxgMbeX798zy77ln2Vu9lXM44RmWMYlDqIFLcKficPtx2tz4lLCIiIv1COBLG3+KnOlDN9vLt7KjcwdbSrZgMJi4adxFXTb2Kc0aeg81ii3epIiIi0g39KnTq7Oykrq4OgKSkpKOGIn1Ze3s7dXV1+Hw+rFYrAKtXr+b+++9n79695Ofn8/3vf5+LL764V+ZvbGykqKjosGM33HADI0aM4LbbbmPMmDFHPUd/C50qKytJT0+PdxkiIiJHFA6H+WDvByxet5jn1j1HbbCW8TnjGZExgkGpg0hyJeFz+XBZXQqaREREpF+LRCI0tjZS01hDYWUhOyp2sKV0Cy1tLZw3+jwWTl3IxWMvJsGeEO9SRURE5Dj1+dApGAzy0EMP8dRTT7F582Y6OjoAMJvNjBs3jquuuopvfetbJCToF5HuOlp7vU/rb6HT6tWrOf300+NdhoiISEx7Rzsrdq5g8drFLNm4hFB7iIl5ExmWPoyBKQPxOX34XD6cVme8SxURERHpFZFIhGAoSG2wlt1Vu9levp1tZduobqxmzvA5LJy6kPkT5pOckBzvUkVEROQY9OnQaePGjVx++eUUFxfzeaczGAzk5eXx/PPPM3HixO5OecKYTCauuuoqnnjiiXiXEnOyh05qryciIn1Bc6iZNwveZPG6xby06SWsZivjc8YzPGM4+cn5eJ1ekpxJai0jIiIip6Tmtmbqg/Xsqd7D9vLtbC/fTlFdETMGzWDB5AVcOflKsn3Z8S5TREREPkdv5Qbm7p6gvLycc845h7q6OqxWK1/5yleYO3cu2dnRXyxKS0tZvnw5ixcvpqioiHPPPZfNmzeTlZXV7eJPhMTERHJzc+NdxmFWrFgR7xJ6VVcbQxERkRPN3+znlS2v8MzaZ3hz25v4XD7G54zn+tOvJzcpF5/Th9fpxWrWzyoRERE5tTmtTpxWJ9m+bKYNnEZ9cz1FNUUUVBTw4MoHufWZWxmXM44rJ1/JwqkLGZI2JN4li4iIyAnQ7ZVON998M3/5y1/Iz8/ntddeY8SIEUccV1hYyAUXXEBxcTHf/OY3efDBB7sz7Qlz/vnnYzQaee211+JdypfW31Y6iYiInEhlDWW8uPFFFq9fzKqdq8jx5TAmewzD0oeRmZhJUkISXocXs6nbn9UREREROem1dbTR0NxASX0J28q2UVhRyPaK7QxKGcTlEy/nqmlXMS5nnPa+FBERibM+214vPz+fkpIS3njjDc4555wvHPv2229z3nnnkZOTQ3FxcXemPWE++OAD5syZw8MPP8y1114b73K+lP4WOj377LMsWLAg3mWIiMhJKhKJsKNiB0s2LOH5dc+z8cBGhmcMZ2TmSIakDSHTk4nP6SPRkYjJaIp3uSIiIiL9VkdnBw0tDZQ3lFNQXsCOih1sK9tGakIq8yfM56ppVzFj0AyMRmO8SxURETnl9NnQyW63YzabaWpqOqbxCQkJdHZ20tLS0p1pT5h77rmH999/n7fffptJkyYxdepU0tPTP/OJHIPBwM9+9rM4VfnF+lvopD2dRESkp3WGO/lw74cs2bCEJeuXUNpQytjssYzIGMGglEGkJqbic/pw29361K2IiIhIL+gMdxJoCVAZqGR7+XZ2VOxga+lWbBYbF4+7mEVTFzF3xFwsZku8SxURETkl9NnQKTc3l0AggN/vP6bxiYmJeL3efrPS6Vg/bWMwGOjs7Ozlar6c/hY6ffTRR0yfPj3eZYiISD/X0tbCsu3LeH7987y0+SXaOtqYkDuBoelDGZQyCJ8ruj9Tgi0h3qWKiIiInFIikQiNrY3UNtWytWwrhRWFbCndQke4g/NGnceiaYu4cMyFOG3OeJcqIiJy0uqt3KDbmxOcffbZ/OMf/2DdunVMnjz5C8euXbuWpqYmrrzyyu5Oe8IsX7483iWccvLy8uJdgoiI9FN1wTpe2fwKi9ct5u3tb5NoT2RczjgWTllIXnIeXqcXn9OH3WKPd6kiIiIipyyDwUCiI5FERyIDUwdy9sizqWmqYUf5DraXb+e7//ou/hY/c4bN4atTv8rlEy/H6/TGu2wRERE5Bt1e6bR7924mTZrEkCFDeOutt0hOTj7iuLq6Os455xz27t3L2rVrGTJkSHemlePQ31Y6qb2eiIgcj/01+1m6cSnPr3+eD/Z8wIDkAYzKGsWQ1CFkebNiK5osJrVqEREREenrQu0h6oJ1FFYVsq10GwVlBZT7y5kxeAZfmfwVFk5dSHpierzLFBER6ff6RHu9z2uJ9+GHH/Ktb30Li8XCzTffzFlnnUV2djYApaWlLF++nIceeoj29nb+8pe/MH36dK1mOYEUOomIyMkkEomw6cAmlmxYwnPrn6OwopBRWaMYmTGSwamDY/szeRweTEZTvMsVERERkS+pvbMdf4ufPZV72FS6ie3l29lXs48JuROYP2E+C6cuZHjG8HiXKSIi0i/1idDJZOqZN24MBgMdHR09cq6edsEFF3DvvfcyderU435uMBjkj3/8I263m+9+97u9UN2X099Cp9LS0lhoKSIiAtDa3sryHctZunEpL296mfrmesbmjGVE+ggGpw0m2ZWM1+nFbXdjMBjiXa6IiIiI9LBwJEygJcD+2v1sKN5AYUUhOyt3ku3N5oIxF/DVKV/lzGFnYjZ1eycJERGRU0Kf2NOpm534evw8vaG6uprTTjuNM888k2uvvZYrrrgCj8fzhc/58MMP+ec//8lTTz1FS0sLjz/++Amq9uSk0ElERAAq/BW8svkVlmxYwjs73iHRnsjo7NHMGzePASkDSHIl4XV6cVq1wbSIiIjIyc5oMOJ1epngnMD4nPEE24JU+CvYVLKJjQc28uTHTxKJRDhrxFlcMekKLh1/KT6XL95li4iInHKOa6VTUVFRj02cn5/fY+fqaY8//jh33303+/fvx2g0Mnz4cCZPnkx6ejper5fW1lbq6uooLCxk7dq1NDY2YjKZuOqqq7jvvvv6XOvA/rbSSe31REROTV1t817c9CIvbHyBTQc2MTR9KCMyRjAodRDZ3my8Tq/2ZxIRERGRw4TaQ9QGa9lWFt0DqrCykHJ/OZPzJnPphEtZMHkBwzKGxbtMERGRPqVPtNc7lUQiEV599VUee+wxVqxYQV1d3WfGGI1Gxo0bx+WXX85NN91EZmZmHCo9uv4WOj399NMsXLgw3mWIiMgJ0NU274WNL/DS5peoD9YzNnssw9KHMSh1EMkJ0bZ5ifZE7c8kIiIiIkfV0dmBv8XP3uq9bC3dSmFltA1fji+HC8dcyIIpC5g1dJba8ImIyClPoVOcbd++nZKSEmpra3E4HKSmpjJ69Oijtt7rC/pb6CQiIie3I7XNG5M9hiFpQxiQPACP04PP6cNlc8W7VBERERHpxyKRCI2tjVQEKthcspnCikK2l28nQoS5I+ZyxcQruHTCpXid3niXKiIicsL1q9CpqKiIqqoqANLS0vp0K71TQX8LnZ5//nmuuOKKeJchIiI9JBwOs+HABl7Z/Eqsbd6Q9CGMzBgZa5vncXjwOr1YzdZ4lysiIiIiJ6nW9lbqmurYVn6wDV9FIeWBcqbkT2HeuHlcOelKRmSOwGAwxLtUERGRXtdbuUGPrSUuLy/ngQce4KmnnqK2tvawx5KTk7n66qu57bbb+mwLOuk7QqFQvEsQEZFuqg/W81bBW7y06SVe3/Y6zW3NjM4azcjMkVw89mJS3al4nV7cdrfa5omIiIjICWG32MnyZZHly+Ks4WdF2/DV7GVLyRae/PhJ7nn5HtLcaZwz8hwum3gZ5406D6fNGe+yRURE+pUeWen0/vvvc9lll1FXV8fnnc5gMJCcnMzSpUs5/fTTuzulHIf+ttLp/fffZ+bMmfEuQ0REjkMkEmHTgU28uvVVXtr0Emv2ryHXl8uIjBEMSh1EXlIeXqcXr9OL06o/3EVERESk74hEIgRDQaoaq9hcspmdlTsprCikoaWB0wadxsVjL+bKyVcyJG1IvEsVERHpMX22vV5VVRUjR46kvr6exMREvv3tb3PuueeSk5MDQElJCW+//TZ/+ctfaGhoICkpiYKCAtLS0nrkBcjR9bfQqbq6mtTU1HiXISIiRxFoCfD29rd5adNLvLb1NQItAcZkj2Fo2lAGpgwkxZ2C1+HF4/Boo2YRERER6TfaOtpoaG5gd9VuCsoK2Fm1k91Vu8n0ZnLeqPO4fOLlnD3ybOwWe7xLFRER+dL6bOh022238atf/YoRI0bw1ltvkZ2dfcRxZWVlnHPOORQWFvLjH/+YX/ziF92ZVo5DfwudnnzySRYtWhTvMkRE5FMikQjbyrbx6pboaqYP935IljcrtjdTflI+ic5EvA4vLptLvfBFREREpN8LR8I0tTZRGahkc+lmdlXuorCikKZQEzMGz2DeuHlcMfEKBqYOjHepIiIix6XPhk5jxoxh+/btrFq16qgt0d5//31mzZrFqFGj2Lp1a3emleOg0ElERL6shuYG3tnxDq9ueZXXtrxGbbCW0VmjGZY+jIEpA0lzp+FxevA4PFhMlniXKyIiIiLSq0IdIRqCDeyq2sW2sm3srtrN7urd5PnyOGfUOcyfMJ+zhp+lvaBERKTP67OhU0JCAkajkUAgcEzj3W43AI2Njd2ZVo5DfwudiouLycvLi3cZIiKnpI7ODtbsX8MbW9/g1a2vsr54PTneHIamD2Vw6mDyk/OjezNpNZOIiIiInOK6VkGVB8rZUrKFXZW72Fm5k0BrgKkDpnLe6POYP34+43PH6/dmERHpc3orN4jLBgvdzLn6nEAgQENDg4KSHlJTU6N/SxGRE2hf9T7eLHiTV7e8yvLC5RgwMCprFMPSh3HeqPNIdaficXhIdCRqNZOIiIiIyEFGg5FERyKJjkSGpw8/bC+oHRU7eG7dczzw6gO4bC7mDJvDxeMu5uJxF5OemB7v0kVERHpNt0OnAQMGsH37dj788ENOO+20Lxz7wQcfEAwGGTVqVHenPWFefPFFHnvsMT7++GPq6urw+XyMGjWKRYsWcf3112Mymfjtb3/LPffcQ2dnZ7zLPSkUFhYyadKkeJchInLSCrQEWFG4gte3vs4b296guK6Y4RnDGZo2lBvPuJEsbxaJ9kS8Ti9Oq9qCiIiIiIgcC6vZSlpiGmmJacwYPIOmUBO1TbUUlBewu2o39758L9/4v28wNG0o54w8h0snXMqZw87EbrHHu3QREZEe0+3Q6cILL6SgoIBvfvObLFu2jNTU1COOq6qq4pvf/CYGg4GLLrqou9P2uqamJq655hpefvnlw1ZmVVRUUFFRwfLly/nTn/7EU089FccqRUREjq4z3Mn6ovW8vvV1Xt36Kmv3ryXDk8HwjOGcPeJs8pLz8Dq90U9p2hMxGU3xLllEREREpF8zGAy47W7cdjcDUgbQ0dlBoDVAaUMpBWUFrCtax78+/hfNbc1MGziNC0ZfwKUTLmV01mi14hMRkX6t23s6VVZWMnLkSPx+Pz6fj5tvvpmzzz6b7OxsAEpKSli2bBl/+ctfqK2txev1sn37dtLT+/ZS4ksuuYRXXnmFKVOmcNtttzFr1ix8Ph+lpaWsX7+eP//5zyxfvpyMjAxmz57NM88802dXOvW3PZ3C4TBGozHeZYiI9FuRSIRdlbtYtmMZb2x7g5WFK+kMdzIycyRD0oYwIHkAqe7UWCsQm9kW75JFRERERE4pLW0tNLREW/EVVhSyp3oPu6p24bF7mDV0FuePPp+Lxl5ETlJOvEsVEZGTVG/lBt0OnQBWrlzJ5ZdfTkNDw+d+GiMSieD1elm6dClnnnlmd6fsVUuXLuWKK67g6quv5vHHH8dkOvInvv/5z3/yzW9+k1AoBKDQqYe8+OKLXHrppfEuQ0SkXympK2HZjmW8VfAWy7Yvoy5Yx7D0YQxOHUxuUi65Sbl4HB48Dg9Oq1OfnhQRERER6SPCkTDBUJCaphoKygrYU72HPdV7KKotIseXw+xhs7lgzAWcN+o8Utwp8S5XREROEn06dILoiqb777+fZ599lrq6usMeS0pKYuHChfz0pz+NrYDqy+bPn8+HH37Ivn37cDq/eC+Ll156ifnz52MwGHotdHrggQd4/vnn2bFjBw6Hg9NPP51f/vKXDB8+/Jie399CpyeffJJFixbFuwwRkT6tprGG5YXLeavgLd7e/jbFtcUMSRvCkLQh5Cblkp+UH1vJlGBLUMs8EREREZF+oqOzg8bWRioDlWwv387emr3sqd5DWUMZQ9OGMmfEHC4acxFnjTgLt90d73JFRKSf6vOh06H27dtHVVUVAGlpaQwcOLCnp+hVWVlZXHDBBTz66KPHNP7Xv/41W7du5bHHHuuVei644AKuuuoqpk6dSkdHBz/96U/ZunUrBQUFuFyuoz6/v4VOq1at6vOr4URETrTG1kZW7VzF2wVv89b2t9hevp385HyGpg0lPymfvOQ8PA5PbF8ms6nb2zaKiIiIiEgf0NbRFt0Pqr6UHRU72F+zn11Vu6hpqmFczjjmjpjLRWMvYuaQmdgt9niXKyIi/US/Cp36O5vNxo9//GPuu+++eJdyRNXV1aSlpbFy5cojhjOhUCjW8g+iXzy5ubn9JnSqq6sjKSkp3mWIiMRVY2sjq3evZnnhcpZtX8aGAxtId6czNH0oA1MGkp+Uj8/li4VMVrM13iWLiIiIiMgJ0NreSqAlQFFtEYWVheyr2ceuql00tzUzOW8ys4fP5vxR53Pa4NMUQomIyOfqrdBJH4M+Ao/HQ3V19TGPX7x4MQUFBdx55529WNUn/H4/wOcGMw888AB33333CamlN7zxxhtqrycip5yG5gbe2/UeywuX886Od9hSuoXUhFSGpA1heMZwzht1Hqnu1FjIZLPY4l2yiIiIiIjEgd1ix26xk5aYxtSBU2lua8bf4mdP1R52Ve7izW1v8uCKB2lpa2FC7gTOHHYm5406j5lDZuK0ffE2EiIiIt2llU5HcN5557Fjxw727NmDxWL5wrEffPABZ555JuFwuNf2dDpUOBzm0ksvpaGhgffee++IY/r7Sift6SQip4LaplpW7VzF8h3LWV64nILyAjI9mQxJG0J+Uj45STmkJqTitrtJdCTqE4oiIiIiInJUkUiElvYW/M3+6F5QVXvYX7ufPdV7aGxtZGzOWM4ceibnjT6PWUNnaU8oEZFTWJ9or2cy9cwm5AaDgY6Ojh45V2947LHHuPHGG7nlllv49a9//bnjVq1axYIFC6iursZgMJyQ0Onmm2/mtdde47333iMnJ+eYntPf9nTau3cvgwYNincZIiI9qjJQycrClSwvXM6KwhUUVhSSl5THoLRB0ZDJl0OyKxm33Y3b7sZhdcS7ZBERERER6ecODaGKaovYXb2botoi9lTvoS5Yx+is0cwaOotzR53LnOFz8Dq98S5ZREROkD4ROhmNxp6Z9AQFNF9WZ2cnp59+OmvXrmX+/Pn853/+J5MmTQKiK402b97M//7v//L4449jtVqZOXMmb731Vq+/pu9973u88MILrFq1ioEDBx7z8/pb6LR582bGjRsX7zJERL60SCRCYUUhq/esZuXOlby/+332Vu9lYMpABqUOIteXS15yHj6nLxYyaSWTiIiIiIj0tq4QqrG1kQO1B9hZtZOiuiL2Vu+lurGaYenDOG3QacwePpuzhp9FXlIeBoMh3mWLiEgv6BOh08qVK3ts4tmzZ/fYuXpDRUUFF198MRs2bMBgMOB0OvF4PFRVVdHZ2UkkEiErK4tnnnmGt956i3vuuafXQqdIJML3v/99lixZwooVKxg6dOhxPb+/hU5qryci/U1reytr96/lvd3vsXLnSj7a+xHBUJDBaYPJT8on25dNXtLhIZPVbI132SIiIiIiIrS2t9LY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ERGR7vv0Fi7d1e3QacWKFbHbXcV9evHUkY4bDAbuvPNOzj77bB5//HEyMzO7W8pJy2q1MnnyZJYtW8Zll10GRIOZZcuW8b3vfS++xfWCwYMHx7sEERERERERERERERE5Tt0OnX7+85/T3t7Ogw8+SH19PXl5ecyePZvs7GwASktLWbVqFUVFRSQlJfHtb3+bpqYm1q5dy+rVq1m2bBnnn38+H3/8MXa7vdsv6GR16623ct111zFlyhSmTZvG7373O4LBIDfccEO8S+txXV87IiIiIiIiIiIiIiLSf3Q7dPqP//gPzjnnHFpbW/n73//Otddee8Rx//jHP/j2t7/Nxx9/zOuvv47RaGTlypVcdtllbNu2jYcffpjvf//73S3npLVw4UKqq6u58847qaioYMKECbz++uukp6fHu7Qet2rVKhYtWhTvMkRERERERERERERE5DgYu3uC3/72t7z77rv84Q9/+NzACeDrX/86f/jDH1i2bBm///3vAZg9eza/+MUviEQiPPfcc90t5aT3ve99j6KiIkKhEB999BHTp0+Pd0kiIiIiIiIiIiIiIiIAGCKf3oDpOE2YMIHt27fT2NiI1Wr9wrGhUIjExERGjRrFhg0bAPD7/SQlJZGUlER1dXV3SpHPEQgE8Hg8+P1+EhMT413OUZWXl2uPLxERERERERERERGRXtJbuUG3Vzrt2bOHhISEowZOADabjYSEBHbv3h075vF48Hq9BAKB7pYiJ4ni4uJ4lyAiIiIiIiIiIiIiIsep26GT2WymoaGB8vLyo44tLy+noaEBs/nwraSam5vxeDzdLUVOEnv37o13CSIiIiIiIiIiIiIicpy6HTpNmjQJgNtuu+2oY2+//XYikUjsOQCVlZWEQiHS09O7W4qcJD4dSoqIiIiIiIiIiIiISN/X7dDpBz/4AZFIhCeeeIILL7yQd999l46OjtjjHR0drFq1iosuuoh//vOfGAwGfvCDH8Qef/311wGYPn16d0uRk8SCBQviXYKIiIiIiIiIiIiIiBynbodO8+fP59ZbbyUSifDmm28yZ84cEhISyM7OJicnh4SEBM466yzeeOMNIpEIP/rRj5g/f37s+WvWrGH8+PFcdtll3S1FThLPPfdcvEsQEREREREREREREZHj1CN9zP7nf/6HKVOmcOedd7J7927a2to+s8fTkCFDuPvuu1m0aNFhx//0pz/1RAlyEmlra4t3CSIiIiIiIiIiIiIicpx6bPOcq666iquuuoqNGzeyfv16qqurAUhNTWXSpElMmDChp6aSk1x+fn68SxARERERERERERERkePU7dDpnnvuAeCGG24gNzeXCRMmKGD6AnfddRd33333YceGDx/Ojh07Pvc5zz77LD/72c/Yv38/Q4cO5Ze//CUXXXRRb5caN4MHD453CSIiIiIiIiIiIiIicpy6vafT3XffzX333UdGRkZP1HNKGD16NOXl5bHLe++997ljV69ezaJFi7jxxhvZsGEDl112GZdddhlbt249gRWfWO+88068SxARERERERERERERkePU7dApJSWFxMRELBZLT9RzSjCbzWRkZMQuKSkpnzv297//PRdccAE//vGPGTlyJPfeey+TJk3SXlgiIiIiIiIiIiIiItKndLu93vjx43nnnXeora0lOTm5J2o66e3atYusrCzsdjszZszggQceIC8v74hjP/jgA2699dbDjp1//vksXbr0c88fCoUIhUKx+4FAoEfqPlHOOOOMeJcgIiIiIiIiIiIiIv1AJBKhpamNhsog/qog9ZVBGiqaqCtrpK68iRt/cy6uRHu8yzxldDt0+ta3vsXbb7/Nb37zG+6///6eqOmkNn36dP7+978zfPhwysvLufvuu5k1axZbt27F7XZ/ZnxFRQXp6emHHUtPT6eiouJz53jggQc+s29Uf1JVVUVubm68yxARERERERERERGROIhEIgQbWqMBUmWQhsom6iuD1JU1Ul/eRH1FkIaqJvzVzQRqWmhv7cBkNuLy2nAm2rAnWHG4rdgTrOxZX8G4OQPi/ZJOGd0Ona688kpuvfVWfvGLX9De3s5PfvKTL2wXd6q78MILY7fHjRvH9OnTyc/P55lnnuHGG2/skTnuuOOOw1ZHBQKBfhXi7Ny5k8mTJ8e7DBERERERERERERHpIeFwhMba5sOCpLryJurKmmioiIZKDVVBAtVBGmtb6GgPY7GZcHntONxWHF1BksuKI8GCJy3tk2MJVuwuC2arCZPFhNlixGQ2Ul/ehMXW7RhEjkO3/7Xnzp0LgMvl4te//jW//e1vGTJkCGlpaZhMpiM+x2AwsGzZsu5OfVLwer0MGzaM3bt3H/HxjIwMKisrDztWWVlJRkbG557TZrNhs9l6tE4RERER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DI4+h07jxo3TihUrlMlk5HQ6t3puOp1We3u7xo8f39fL9puf/vSnev/99zVv3rxBud4zzzzT4/H999+v2tpaLV26VNOmTdvi6ywWi+rr6we6vCHhySef1IknnljuMgAAAAAAAPqsI5NTdF0hQOoMkwpj7doLQdLauCLr44ptSCgeTsk0VQiNgl0hUqH7yKFgrVd1OwTl8hvyFMMlp8fRswup244km4P9SACAwdXn0Omkk07SZZddpgcffFBnnnnmVs/93//9X3V0dOikk07q62U/l6uvvnqrz2ezWc2bN08tLS2DUk9votGoJKmysnKr57W3t2vMmDHK5/Paa6+99Itf/EK77bZbr+em02ml0+nS41gs1n8FAwAAAAAAbOdSiQ5F1rYrui6hyNp2hVvaix1Jhd9H1sYVXR9XdENCyVhGFovkDhjyBgy5A065fIbcPocMj0PVzX417lJV2I9UDJmcLnuvIZLdYZXVTpAEABi6LKZpmn15g46ODs2cOVOvvvqq7rzzTp122mm9nvfggw/q7LPP1j777KMFCxbIbu9z3vWZrNatz5bt/D/oE088UX/4wx8GvJ5N5fN5HXXUUYpEIlq8ePEWz1uyZInee+897b777opGo7rxxhu1aNEivf3222pqatrs/CuvvFJXXXXVZsej0agCgUC/foaBsHz58iHVDQcAAAAAAEY20zSVbMv0GGsXWRvXxuJYu3BL12i72Iak0okOWW0WeYKGPAGjML7O37UfyfA4ZHidpeNun0N2w94tPOq5J8lmZz8SAAyET99r1fipTZowdfOfo2/vYrGYgsFgv+cG2xQ6balzKJ1O64477lAsFlNzc7NmzJhR2vG0evVqLVy4UKtWrVIwGNT3vvc9OZ1OXXHFFf3zCbZi4cKFvR5PpVL697//rdtvv13ZbFb/+Mc/VFdXN+D1bOqcc87RX//6Vy1evLjX8GhLOjo6NGHCBJ144om65pprNnu+t06n5uZmQicAAAAAALDdME1T7eFUoROpGCKFW9q1cXVb6feRdXHF1icU25BQRzonm90qb4VLnkBnWGTI8Dnk8jrk8jjk8hbH3fmdcnmdshu2UoBU2pNU7FCy2giSAKDcCJ22bEiETlbr1tt3O99q03N6O57L5bap0IEQi8U0adIk7bfffnrkkUcG9drnnXeeHn/8cS1atEhjx47d5tcf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cqVmz55dlvoAAAAAANumI5NTdH28W5AUL461K+xHCre0K7q+MNauPZySmTfl8jrkCRpy+41C55HPKZfPoUCNWzVjAqUuJbfPKafHUQiRunUhdd+TRJAEAAAAbFmfO506ZbNZPfHEE7r77rv197//Xfl8vuzdT/l8XmeddZbuu+++0uJUq9WqfD4vqTCH+4wzztDvfve7Eb1Ydbh1Om3cuFFVVVXlLgMAAADAIEknO7pCpM79SGvaS6PtImvjpSApEU1LkjwBoxgkdYZIhf1Ihtchl8dRDJIMufxOOV32HgFS9z1JNrt1RP99EAAAYHtGp9OWDVRu0G+hU3erVq3SPffco/vvv1+rV68uXMhiKVv308KFC/XAAw/ozTffVDQaVTAY1B577KFTTjlFM2bMGLQ6ymW4hU4vvPCCDjrooHKXAQAAAOALMk1TyfZMj7F2XR1Jhf1IkXVxRdcVgqRUvEMWq0XeYDFI8hWCJKMzSOo21s7tM+T2O2Q37KXuox57korHAAAAAEKnLRtWoVOnfD6vv/zlL/rd736np59+Wrlcrkf309lnn60DDjhgoC4/pN1+++264YYb1NLSoj322EO33Xab9t133y2e/+ijj+ryyy/XypUrtfPOO+v666/XYYcd9rmuNdxCJ3Y6AQAAAEOPaZqKR1IKdwuSwi3xUjdSuCWuyLrO0XZJdaSystmt8gQNeQOFjiO3v9iR5OkeJBnFgMkhh9PeNcquW4hkd1hltREkAQAAYNsQOm3ZkN3ptDVWq1VHHnmkHA6HNm7cqCVLlsg0TaVSKT300EOaM2eOpkyZoltuuUX77LPPQJYypDz88MO6+OKLddddd2m//fbTLbfcolmzZmnFihWqra3d7PwXX3xRJ554ombPnq0jjjhCc+bM0dFHH63XXntNEydOLMMnGFgej6fcJQAAAADbhXzeVNvGRI8gqTDWrl3hNW0Kd461Wx9X28aksh152Z02eSsMeQJGaReSy+uU2+dQsLZW7mKQ5PIXupTsTlup+6h7iGSzEyQBAAAAI82AdTqtWbNG9957r37/+9/ro48+UudlDjzwQB1//PH629/+pr/+9a/K5/NyOBz6v//7vwEddZfL5bRhwwal0+lenx89evSAXXtT++23n/bZZx/95je/kVToCGtubtb555+vSy65ZLPzv/nNbyoej+upp54qHZsy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V12lSCTyuV9zww03aObMmQMWOEnS2Wefrddee03PPvvsgF0DAAAAwPBD6AQAAAAAI8S6dev0l7/8Rd/4xjcG9DoTJkzQxIkTdf/99w/odQAAAAAML4ROAAAAADAEXXnllfrRj34kSRo7dqwsFossFotWrly5xdf85S9/UTab1cEHH9zj+P333y+LxaJ//OMfuvjii1VTUyOv16tjjjlG69ev73Huq6++qlmzZqm6ulput1tjx47Vt7/97c2u9V//9V968sknxcR2AAAAAJ3s5S4AAAAAALC5Y489Vv/+9781d+5c3XzzzaqurpYk1dTUbPE1L774oqqqqjRmzJhenz///PMVCoX085//XCtXrtQtt9yi8847Tw8//LCkQqfUIYccopqaGl1yySWqqKjQypUr9ac//Wmz95o8ebJuvvlmvf3225o4cWI/fGIAAAAAwx2hEwAAAAAMQbvvvrv22msvzZ07V0cffbR22GGHz3zN8uXLt3peVVWV/va3v8lisUiS8vm8br31VkWjUQWDQb344osKh8P629/+pr333rv0umuvvXaz9xo3bpwk6Z133iF0AgAAACCJ8XoAAAAAMGJs3LhRoVBoi89/5zvfKQVOknTQQQcpl8vpo48+kiRVVFRIkp566il1dHRs9Vqd19mwYUMfqwYAAAAwUhA6AQAAAMAIsrUdS6NHj+7xuDM4CofDkqTp06fruOOO01VXXaXq6mp9/etf13333ad0Or3F63QPsQAAAABs3widAAAAAGCEqKqqKgVIvbHZbL0e7x4g/fGPf9SSJUt03nnnafXq1fr2t7+tyZMnq729vcdrOq/TuWsKAAAAAAidAAAAAGCI2tYuovHjx+vDDz/s83WnTJmi6667Tq+++qoeeughvf3225o3b16PczqvM2HChD5fDwAAAMDIQOgEAAAAAEOU1+uVJEUikc91/tSpUxUOh/XBBx98oeuFw+HNxvPtueeekrTZiL2lS5cqGAxqt912+0LXAgAAADDy2MtdAAAAAACgd5MnT5Yk/fSnP9UJJ5wgh8OhI488shRGberwww+X3W7X3//+d33nO9/Z5us98MADuuOOO3TMMcdoxx13VFtbm+655x4FAgEddthhPc6dP3++jjzySHY6AQAAACghdAIAAACAIWqfffbRNddco7vuukvPPPOM8vm8Pvzwwy2GTnV1dTrssMP0yCOPfKHQafr06frnP/+pefPmae3atQoGg9p333310EMPaezYsaXzli9frmXLlumWW275oh8NAAAAwAhkMTednQAAAAAAGLZeeOEFzZgxQ8uXL9fOO+88INe48MILtWjRIi1dupROJwAAAAAlhE4AAAAAMMIceuihampq0j333NPv771x40aNGTNGjzzyyGYj9wAAAABs3widAAAAAAAAAAAA0GfWchcAAAAAAAAAAACA4Y/QCQAAAAAAAAAAAH1G6AQAAAAAAAAAAIA+I3QCAAAAAAAAAABAnxE6AQAAAAAAAAAAoM8InQAAAAAAAAAAANBnhE4AAAAAAAAAAADoM0InAAAAAAAAAAAA9BmhEwAAAAAAAAAAAPqM0AkAAAAAAAAAAAB99v8BxnBRMMkPEOIAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "reg = Register({\"q0\": (-5, 0), \"q1\": (5, 0)})\n", + "\n", + "seq = Sequence(reg, MockDevice)\n", + "seq.declare_channel(\"rydberg_global\", \"rydberg_global\")\n", + "t = seq.declare_variable(\"t\", dtype=int)\n", + "\n", + "amp_wf = BlackmanWaveform(t, np.pi)\n", + "det_wf = RampWaveform(t, -5, 5)\n", + "seq.add(Pulse(amp_wf, det_wf, 0), \"rydberg_global\")\n", + "\n", + "# We build with t=1000 so that we can draw it\n", + "seq.build(t=1000).draw()" + ] + }, + { + "cell_type": "markdown", + "id": "deb625b6", + "metadata": {}, + "source": [ + "## 3. Starting the backend" + ] + }, + { + "cell_type": "markdown", + "id": "953eab2e", + "metadata": {}, + "source": [ + "It is now time to select and initialize the backend. Currently, these are the available backends (but bear in mind that the list may grow in the future):\n", + "\n", + " - **Local**: \n", + " - `QutipBackend` (from `pulser_simulation`): Uses `QutipEmulator` to emulate the sequence execution locally.\n", + " - **Remote**:\n", + " - `QPUBackend` (from `pulser`): Executes on a QPU through a remote connection.\n", + " - `EmuFreeBackend` (from `pulser_pasqal`): Emulates the sequence execution using free Hamiltonian time evolution (similar to `QutipBackend`, but runs remotely). \n", + " - `EmuTNBackend` (from `pulser_pasqal`): Emulates the sequence execution using a tensor network simulator." + ] + }, + { + "cell_type": "markdown", + "id": "438c3cca", + "metadata": {}, + "source": [ + "Instead of choosing one, here we will import the three emulator backends so that we can compare them." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c508a2d8", + "metadata": {}, + "outputs": [], + "source": [ + "from pulser_simulation import QutipBackend\n", + "from pulser_pasqal import EmuFreeBackend, EmuTNBackend" + ] + }, + { + "cell_type": "markdown", + "id": "365ed331", + "metadata": {}, + "source": [ + "Upon creation, all backends require the sequence they will execute. Emulator backends also accept, optionally, a configuration given as an instance of the `EmulatorConfig` class. This class allows for setting all the parameters available in `QutipEmulator` and is forward looking, meaning that it envisions that these options will at some point be availabe on other emulator backends. This also means that trying to change parameters in the configuration of a backend that does not support them yet will raise an error.\n", + "\n", + "Even so, `EmulatorConfig` also has a dedicated `backend_options` for options specific to each backend, which are detailed in the [backends' docstrings](../apidoc/backend.rst)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "37b68469", + "metadata": {}, + "outputs": [], + "source": [ + "from pulser.backend import EmulatorConfig" + ] + }, + { + "cell_type": "markdown", + "id": "21f506c5", + "metadata": {}, + "source": [ + "With `QutipBackend`, we have free reign over the configuration. In this example, we will:\n", + " \n", + "- Change the `sampling_rate`\n", + "- Include measurement errors using a custom `NoiseModel`\n", + "\n", + "On the other hand, `QutipBackend` does not support parametrized sequences. Since it is running locally, they can always be built externally before being given to the backend. Therefore, we will build the sequence (with `t=2000`) before we give it to the backend." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "6f64a5af", + "metadata": {}, + "outputs": [], + "source": [ + "from pulser.backend import NoiseModel\n", + "\n", + "config = EmulatorConfig(\n", + " sampling_rate=0.1,\n", + " noise_model=NoiseModel(\n", + " noise_types=(\"SPAM\",),\n", + " p_false_pos=0.01,\n", + " p_false_neg=0.004,\n", + " state_prep_error=0.0,\n", + " ),\n", + ")\n", + "\n", + "qutip_bknd = QutipBackend(seq.build(t=2000), config=config)" + ] + }, + { + "cell_type": "markdown", + "id": "e74755e3", + "metadata": {}, + "source": [ + "Currently, the remote emulator backends are still quite limited in the number of parameters they allow to be changed. Furthermore, the default configuration of a given backend does not necessarily match that of `EmulatorConfig()`, so it's important to start from the correct default configuration. Here's how to do that for the `EmuTNBackend`:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "0889e0ba", + "metadata": {}, + "outputs": [], + "source": [ + "from dataclasses import replace\n", + "\n", + "emu_tn_default = EmuTNBackend.default_config\n", + "# This will create a new config with a different sampling rate\n", + "# All other parameters remain the same\n", + "emu_tn_config = replace(emu_tn_default, sampling_rate=0.5)" + ] + }, + { + "cell_type": "markdown", + "id": "21f4ee21", + "metadata": {}, + "source": [ + "We will stick to the default configuration for `EmuFreeBackend`, but the process to create a custom configuration would be identical. To know which parameters can be changed, consult the backend's docstring." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "59d5e3ca", + "metadata": {}, + "outputs": [], + "source": [ + "free_bknd = EmuFreeBackend(seq, connection=connection)\n", + "tn_bknd = EmuTNBackend(seq, connection=connection, config=emu_tn_config)" + ] + }, + { + "cell_type": "markdown", + "id": "50729b54", + "metadata": {}, + "source": [ + "Note also that the remote backends require an open connection upon initialization. This would also be the case for `QPUBackend`." + ] + }, + { + "cell_type": "markdown", + "id": "51cce28c", + "metadata": {}, + "source": [ + "## 4. Executing the Sequence" + ] + }, + { + "cell_type": "markdown", + "id": "f4590ab7", + "metadata": {}, + "source": [ + "Once the backend is created, executing the sequence is always done through the backend's `run()` method.\n", + "\n", + "For the `QutipBackend`, all arguments are optional and are the same as the ones in `QutipEmulator`. On the other hand, remote backends all require `job_params` to be specified. `job_params` are given as a list of dictionaries, each containing the number of runs and the values for the variables of the parametrized sequence (if any). The sequence is then executed with the parameters specified within each entry of `job_params`." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "22e8f95b", + "metadata": {}, + "outputs": [], + "source": [ + "# Local execution, returns the same results as QutipEmulator\n", + "qutip_results = qutip_bknd.run()\n", + "\n", + "# Remote execution, requires job_params\n", + "job_params = [\n", + " {\"runs\": 100, \"variables\": {\"t\": 1000}},\n", + " {\"runs\": 50, \"variables\": {\"t\": 2000}},\n", + "]\n", + "free_results = free_bknd.run(job_params=job_params)\n", + "tn_results = tn_bknd.run(job_params=job_params)" + ] + }, + { + "cell_type": "markdown", + "id": "4421eb27", + "metadata": {}, + "source": [ + "## 5. Retrieving the Results" + ] + }, + { + "cell_type": "markdown", + "id": "8289b06f", + "metadata": {}, + "source": [ + "For the `QutipBackend` the results are identical to those of `QutipEmulator`: a sequence of individual `QutipResult` objects, one for each evaluation time. As usual we can, for example, get the final state:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "c920679c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "Quantum object: dims = [[2, 2], [1, 1]], shape = (4, 1), type = ket $ \\\\ \\left(\\begin{matrix}(-0.380-0.157j)\\\\(0.035+0.593j)\\\\(0.035+0.593j)\\\\(-0.235-0.263j)\\\\\\end{matrix}\\right)$" + ], + "text/plain": [ + "Quantum object: dims = [[2, 2], [1, 1]], shape = (4, 1), type = ket\n", + "Qobj data =\n", + "[[-0.38024396-0.15656328j]\n", + " [ 0.03529282+0.59329452j]\n", + " [ 0.03529282+0.59329452j]\n", + " [-0.23481812-0.26320141j]]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qutip_results[-1].state" + ] + }, + { + "cell_type": "markdown", + "id": "2618a789", + "metadata": {}, + "source": [ + "For remote backends, the object returned is a `RemoteResults` instance, which uses the connection to fetch the results once they are ready. To check the status of the submission, we can run:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "d24593f4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "free_results.get_status()" + ] + }, + { + "cell_type": "markdown", + "id": "763e011c", + "metadata": {}, + "source": [ + "When the submission states shows as `DONE`, the results can be accessed. In this case, they are a sequence of `SampledResult` objects, one for each entry in `job_params` in the same order. For example, we can retrieve the bitstring counts or even plot an histogram with the results:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "738de317", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'00': 5, '01': 13, '10': 26, '11': 56}\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(free_results[0].bitstring_counts)\n", + "free_results[0].plot_histogram()" + ] + }, + { + "cell_type": "markdown", + "id": "579c9417", + "metadata": {}, + "source": [ + "The same could be done with the results from `EmuTNBackend` or even from `QPUBackend`, as they all share the same format." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pulser-dev", + "language": "python", + "name": "pulser-dev" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}