Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QNEBE-901] Remote hardware backend support #89

Merged
merged 3 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ command_line = -m pytest -s --junitxml=report.xml

[report]
show_missing = True
; fail_under = 100
fail_under = 75
exclude_lines =
if __name__ == .__main__.:
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 QuTech
Copyright (c) 2024 QuTech

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
22 changes: 15 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Quantum Network Explorer ADK

The QNE-ADK is a Quantum Network Explorer - Application Development Kit that allows you to create your own applications and experiments and run them on a simulator.
The QNE-ADK is a Quantum Network Explorer - Application Development Kit that allows you to create your own applications
and experiments and run them on a simulator.
bpopescu-qutech marked this conversation as resolved.
Show resolved Hide resolved

## Local development

With the ADK you can create your own application from scratch using the ``qne application create`` command
(see section 'Commands' below for more information about the individual commands). An application directory is created with all the necessary files for you to configure.
(see section 'Commands' below for more information about the individual commands). An application directory is created
with all the necessary files for you to configure.
When configuring an application, you specify the different roles and what types of inputs your
application uses. In addition, you write the functionality of your application using the NetQASM library.

Expand Down Expand Up @@ -34,10 +36,13 @@ A copy of a working application is made to your application directory and can be
for application development.

## Prerequisites
- A modern Linux or macOS (10 or 11) 64-bit (x86_64) operating system. If you don’t have Linux or macOS you could run it via virtualization, e.g. using VirtualBox. If you have Windows 10 or 11 you can also use the [Bash on Ubuntu](https://docs.microsoft.com/en-us/windows/wsl/) subsystem.
- A modern Linux or macOS (10 or 11) 64-bit (x86_64) operating system. If you don’t have Linux or macOS you could run
it via virtualization, e.g. using VirtualBox. If you have Windows 10 or 11 you can also use the [Bash on Ubuntu](https://docs.microsoft.com/en-us/windows/wsl/)
subsystem.
- A [virtual environment](https://docs.python.org/3/library/venv.html) should be created and activated before creating an application.
- Python version 3.8 or higher.
- NetQASM makes use of SquidASM for which you need credentials in order to use it. These credentials can be obtained by registering on the forum of [NetSquid](https://forum.netsquid.org/).
- NetQASM makes use of SquidASM for which you need credentials in order to use it. These credentials can be obtained by
registering on the forum of [NetSquid](https://forum.netsquid.org/).

## Installation
To install all the required packages, execute the following command:
Expand All @@ -46,16 +51,19 @@ To install all the required packages, execute the following command:
pip install qne-adk
```

After installing the qne-adk, you can install SquidASM. Replace '{netsquid-user-name}' and '{netsquid-password}' with the credentials you registered on [NetSquid](https://forum.netsquid.org/):
After installing the qne-adk, you can install SquidASM. Replace '{netsquid-user-name}' and '{netsquid-password}' with
the credentials you registered on [NetSquid](https://forum.netsquid.org/):

```
pip install squidasm --extra-index-url=https://{netsquid-user-name}:{netsquid-password}@pypi.netsquid.org
```

Now everything should be setup and ready in order to create your own applications and experiments and run them on the simulator!
Now everything should be setup and ready in order to create your own applications and experiments and run them on the
simulator!

## Commands
The QNE-ADK uses various commands to create and run your applications and experiments. All the commands are listed below:
The QNE-ADK uses various commands to create and run your applications and experiments. All the commands are listed
below:

<!--- QNE APPLICATION LIST --->
<details closed>
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# -- Project information -----------------------------------------------------

project = 'Quantum Network Explorer Application Development Kit'
copyright = '2022, QuTech'
copyright = '2024, QuTech'
author = 'QuTech'

# -- General configuration ---------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/json_examples/experiment_complete_example.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"backend": {
"location": "local",
"type": "local_netsquid"
"type": "NetSquid simulator"
},
"description": "teleport experiment description",
"number_of_rounds": 1,
Expand Down
2 changes: 1 addition & 1 deletion docs/json_examples/experiment_meta_example.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"backend": {
"location": "local",
"type": "local_netsquid"
"type": "NetSquid simulator"
},
"description": "teleport experiment description",
"number_of_rounds": 1,
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
""" Quantum Network Explorer ADK

Copyright (c) 2022 QuTech
Copyright (c) 2024 QuTech

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
52 changes: 32 additions & 20 deletions src/adk/api/local_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from adk.managers.roundset_manager import RoundSetManager
from adk.generators.network_generator import FullyConnectedNetworkGenerator
from adk.parsers.output_converter import OutputConverter
from adk.settings import BASE_DIR
from adk.settings import BASE_DIR, DEFAULT_BACKEND_TYPE
from adk.type_aliases import (AppConfigType, AppResultType, ApplicationType, ApplicationDataType, app_configNetworkType,
app_configApplicationType, AssetType, assetApplicationType, assetNetworkType,
ErrorDictType, ExperimentDataType, ResultType,
Expand Down Expand Up @@ -591,7 +591,7 @@ def validate_application(self, application_name: str, application_path: Path) ->
application_path: Path of where the application is located

returns:
Returns empty list when all validations passes
Returns empty list when all validations pass
Returns dict containing error messages of the validations that failed
"""
error_dict: ErrorDictType = utils.get_empty_errordict()
Expand Down Expand Up @@ -990,7 +990,7 @@ def __create_experiment(self, experiment_name: str, application_name: str, local
},
"backend": {
"location": "local" if local else "remote",
"type": "local_netsquid" if local else "remote_netsquid"
"type": DEFAULT_BACKEND_TYPE
},
"description": f"description of {experiment_name} here",
"number_of_rounds": 1,
Expand Down Expand Up @@ -1298,9 +1298,9 @@ def get_experiment_round_set(self, experiment_path: Path) -> Optional[str]:
The round set from the experiment.json
"""
if not self.is_experiment_local(experiment_path):
experiment_data = self.get_experiment_data(experiment_path)
if "round_set" in experiment_data["meta"]:
return cast(str, experiment_data["meta"]["round_set"])
experiment_meta = self.get_experiment_meta(experiment_path)
if "round_set" in experiment_meta:
return cast(str, experiment_meta["round_set"])
return None

@staticmethod
Expand Down Expand Up @@ -1565,7 +1565,7 @@ def get_results(experiment_path: Path) -> List[ResultType]:
result = output_converter.convert(round_number=1)
return [result]

def validate_experiment(self, experiment_path: Path) -> ErrorDictType:
def validate_experiment(self, experiment_path: Path, error_dict: ErrorDictType) -> None:
"""
Validates the experiment by checking:
- if the structure is correct and consists of an experiment.json
Expand All @@ -1577,19 +1577,14 @@ def validate_experiment(self, experiment_path: Path) -> ErrorDictType:

Args:
experiment_path: The location of the experiment

Returns:
Dictionary containing lists of error, warning and info messages of the validations that failed
error_dict: Dictionary containing error and warning messages of the validations that failed
"""
local = self.is_experiment_local(experiment_path=experiment_path)
error_dict: ErrorDictType = utils.get_empty_errordict()

self._validate_experiment_json(experiment_path=experiment_path, error_dict=error_dict)
if local:
self._validate_experiment_input(experiment_path=experiment_path, error_dict=error_dict)

return error_dict

def _validate_experiment_json(self, experiment_path: Path, error_dict: ErrorDictType) -> None:
"""
This function validates if experiment.json contains valid json and if it passes schema validation.
Expand All @@ -1606,13 +1601,8 @@ def _validate_experiment_json(self, experiment_path: Path, error_dict: ErrorDict
if not valid:
error_dict["error"].append(message)
else:
# Check if experiment is local or remote
experiment_data = self.get_experiment_data(experiment_path)
# location is required field in schema
location = experiment_data["meta"]["backend"]["location"].strip().lower()
if location not in ["local", "remote"]:
error_dict["warning"].append(f"In file '{experiment_json_file}': only 'local' or 'remote' is supported "
f"for property 'location'")
self._validate_experiment_backend(experiment_json_file, experiment_data, error_dict)
# slug is now also a required field
experiment_network_slug = experiment_data["asset"]["network"]["slug"]
# Check if the chosen network exists
Expand Down Expand Up @@ -1690,6 +1680,28 @@ def _validate_application_roles(self, experiment_path: Path, error_dict: ErrorDi
error_dict["error"].append(f"In file '{experiment_path / 'experiment.json'}': role '{role}' is not"
f" valid for the application")

def _validate_experiment_backend(self, experiment_file_path: Path, experiment_data: Dict[str, Any], error_dict:
ErrorDictType) -> None:
"""
Validate if the backend properties are valid. Backend property location must be local or remote.

Args:
experiment_file_path: The location of the experiment.json file
experiment_data: contents of the experiment.json file
error_dict: Dictionary containing error and warning messages of the validations that failed
"""
# Check if experiment backend location is local or remote
# location is required field in schema
location = experiment_data["meta"]["backend"]["location"].strip().lower()
if location not in ["local", "remote"]:
error_dict["warning"].append(f"In file '{experiment_file_path}': only 'local' or 'remote' is supported "
f"for backend property 'location'")
if location == "local":
# local backend must be default backend
if experiment_data["meta"]["backend"]["type"].strip().lower() != DEFAULT_BACKEND_TYPE.strip().lower():
error_dict["warning"].append(f"In file '{experiment_file_path}': local backend must "
f"be {DEFAULT_BACKEND_TYPE}")

def _validate_experiment_nodes(self, experiment_file_path: Path, experiment_data: Dict[str, Any], error_dict:
ErrorDictType) -> None:
"""
Expand All @@ -1704,7 +1716,7 @@ def _validate_experiment_nodes(self, experiment_file_path: Path, experiment_data
"""
experiment_network_slug = experiment_data["asset"]["network"]["slug"]

# Check if the amount of nodes are valid for this network
# Check if the amount of nodes is valid for this network
experiment_nodes = experiment_data["asset"]["network"]["nodes"]

all_network_nodes = self._get_network_nodes()
Expand Down
11 changes: 9 additions & 2 deletions src/adk/api/qne_client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime, timezone
from functools import lru_cache
import re
from pathlib import Path
from typing import Any, cast, Dict, List, Optional, Tuple, Union
Expand Down Expand Up @@ -432,10 +433,11 @@ def partial_update_asset(self, asset_url: str, asset: AssetType) -> AssetType:
response = self._action('partialUpdateAsset', id=asset_id, asset=params)
return cast(AssetType, response)

def list_default_backendtypes(self) -> List[BackendTypeType]:
def list_default_backendtypes(self) -> BackendTypeType:
response = self._action('listDefaultBackendTypes')
return cast(List[BackendTypeType], response)
return cast(BackendTypeType, response)

@lru_cache
def list_backendtypes(self) -> List[BackendTypeType]:
response = self._action('listBackendTypes')
return cast(List[BackendTypeType], response)
Expand All @@ -454,6 +456,11 @@ def retrieve_backend(self, backend_url: str) -> BackendType:
response = self._action('retrieveBackend', id=backend_id)
return cast(BackendType, response)

def list_backends_networks(self) -> List[Any]:
bpopescu-qutech marked this conversation as resolved.
Show resolved Hide resolved
response = self._action('listBackendsNetworks')
return cast(List[Any], response)


def list_experiments(self) -> List[ExperimentType]:
response = self._action('listExperiments')
return cast(List[ExperimentType], response)
Expand Down
Loading
Loading