Skip to content

Commit

Permalink
feat: [QILI-48] Implement platform, backend and settings classes (#4)
Browse files Browse the repository at this point in the history
* chore: 📝 Update requirements

Add qibo and pyyaml requirements

* chore: 🔊 Add raise_error function in config.py file

* feat: ✨ Add AbstractPlatform class.

* style: 🎨 Remove long line

* feat: ✨ Add HardwareCircuit class

* feat: ✨ Add QililabBackend class

* feat: ✨ Add gates.py file

* refactor: ♻️ Remove useless raise_error

* docs: 📝 Update docs of backend and platform classes

Add description of attributes

* feat: ✨ Add I, X, Y, Z gates.

* test: 🧪 Add backend tests

* refactor: ♻️ Remove dummy files and examples

* feat: ✨ Add QiliPlatform class.

* feat: ✨ Add Settings class.

* feat: ✨ Add SettingsLoader class.

* chore: 🔧 Add types-PyYAML to dev-requirements.txt

* ci: configure codecov

* refactor: ♻️ Create one python file for each gate

* fix: 🐛 Remove dummy import

* refactor: ♻️ Change file name

* test: 🧪 Add settings_manager tests. Fix backend tests.

* refactor: ♻️ Change class name

SettingsLoader to SettingsManager

* feat: ✨ Add platform and instrument setting files

* refactor: ♻️ Change gates file names

* build: 🔧 Add typeguard to requirements

* refactor: ♻️ Delete useless methods.

* refactor: ♻️ Change gate name in __init__.

* refactor: ♻️ Remove useless methods

* refactor: ♻️ Remove raise_error

* feat: ✨ Change SettingsManager to singleton

* feat: ✨ Add PlatformSettings class

* feat: ✨ Add AbstractSettings and SettingsLoader classes

* feat: ✨ Add QubitCalibrationSettings class

* refactor: ♻️ Remove Settings class

* refactor: ♻️ Move instrument settings file to single yaml file

* test: 🧪 Update backend and settings_manager tests.

* fix: 🐛 Add init file

* style: 🎨 Remove unused import

* refactor: ♻️ Change classes to dataclass

* style: 🎨 Remove unused import

* ci: 👷 Install requirements.txt before code quality check

* ci: 👷 Add MANIFEST.in file to install yaml files

* ci: 👷 Modify MANIFEST.in file

* fix: 🐛 Call __post_init__() of AbstractPlatform

* refactor: ♻️ Remove SettingsLoader class

* docs: 📝 Remove unused argument docs

* fix: 🐛 Add ClassVar to class variables inside a dataclass

* style: 🎨 Disable sort when dumping yaml file

* feat: ✨ Add buses in PlatformSettings

* style: 🎨 Declare platform attribute instead of setting it to None

* refactor: ♻️ Change settings files structure

* refactor: ♻️ Change platform class name

* refactor: ♻️ Remove raise error

* feat: ✨ Add PlatformBuilder. Add relative imports to __init__.py files.

* refactor: ♻️ Move settings loading to PlatformBuilder

* style: 🎨 Log message when instantiating SettingsManager class

* feat: ✨ Make PlatformBuilder a singleton

* docs: 📝 Add docs

* style: 🎨 Delete unused imports.

* style: 🎨 Delete unused imports.

* style: 🎨 Use match case statement.

* refactor: ♻️ Add SettingsHashTable

* Remove imports from __init__ to avoid circular imports

* refactor: ♻️ Remove typing of current class

* refactor: ♻️ Move all instrument files inside instrument/ folder

* feat: ✨ Add Singleton metaclass

* ci: 👷 Check with pylint only staged files

* refactor: ♻️ Use platform-specific settings

Move all the settings of a specific platform inside the same folder

* style: 🎨 Solve pylint issues.

* refactor: ♻️ Move settings category inside yaml file

* refactor: ♻️ Add category attribute to AbstractSettings

* refactor: ♻️ Remove 'abstract' from any file or class.

Solves comment https://github.com/qilimanjaro-tech/qililab/pull/4\#discussion_r841469545

* refactor: ♻️ Change name PB to PLATFORM_BUILDER

* refactor: ♻️ Remove dataclass from HardwareCircuit

* refactor: ♻️ Change name SM to SETTINGS_MANAGER

* refactor: ♻️ Rename 'platform' to 'platform_name'

* refactor: ♻️ Add constants.py file

* refactor: ♻️ Add DEFAULT_SETTINGS_FOLDERNAME to constants.py file

* refactor: ♻️ Use full name for variables

* docs: 📝 Delete TODO

* style: 🎨 Change settings type

* style: 🎨 Remove typing lsit

* refactor: ♻️ Check that dict has key before deleting it

* test: 🧪 Split tests

* fix: 🐛 Change backend attributes after parent init.

* chore: 📝 Add load_platform example

* refactor: ♻️ Remove dependency from qibo

* style: 🎨 Add entry points

* chore: 📝 Add load_platform example using PLATFORM_BUILDER

* docs: 📝 Fix typo in docs

Co-authored-by: Albert Solana <iamtxena@gmail.com>
  • Loading branch information
amitjansc and iamtxena authored Apr 5, 2022
1 parent 432cbe8 commit fc93b43
Show file tree
Hide file tree
Showing 41 changed files with 638 additions and 118 deletions.
1 change: 1 addition & 0 deletions .github/workflows/pull_request_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
run: |
python -m pip install -U pip
python -m pip install -r dev-requirements.txt
python -m pip install -r requirements.txt
- name: Code Quality
run: |
Expand Down
6 changes: 2 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ repos:
hooks:
- id: mypy
args: [--no-strict-optional, --ignore-missing-imports]
additional_dependencies: [types-PyYAML==6.0.5]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
Expand Down Expand Up @@ -59,10 +60,7 @@ repos:
entry: pylint
language: system
types: [python]
args: [
"src",
"-E", # Only check for errors
]
args: ["-E"] # Only check for errors

- repo: https://github.com/executablebooks/mdformat
rev: 0.7.14 # Use the ref you want to point at
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
recursive-include src *.yml
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ tomli==2.0.1
tomlkit==0.10.0
tornado==6.1
traitlets==5.1.1
types-PyYAML==6.0.5
typing-extensions==4.1.1
uc-micro-py==1.0.1
urllib3==1.26.9
Expand Down
61 changes: 0 additions & 61 deletions examples/example.ipynb

This file was deleted.

10 changes: 0 additions & 10 deletions examples/example.py

This file was deleted.

27 changes: 27 additions & 0 deletions examples/load_platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import qibo

from qililab import PLATFORM_BUILDER

# FIXME: Need to add backend in qibo's profiles.yml file
backend = {
"name": "qililab",
"driver": "qililab.backend.QililabBackend",
"minimum_version": "0.0.1.dev0",
"is_hardware": True,
}
qibo.K.profile["backends"].append(backend)
# ------------------------------------------------------


def load_platform() -> None:
"""Load the platform 'platform_0' from the settings folder."""
# Using qibo (needed when using qibo circuits)
qibo.set_backend(backend="qililab", platform="platform_0")
print(f"Platform name: {qibo.K.platform}")
# Using PLATFORM_BUILDER
platform = PLATFORM_BUILDER.build(name="platform_0")
print(f"Platform name: {platform}")


if __name__ == "__main__":
load_platform()
7 changes: 5 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# here goes your library dependencies to be installed
# with the exact version
# example:
# scipy==1.8.0
# example:
# scipy==1.8.0
qibo==0.1.7
pyyaml==6.0
typeguard==2.13.3
4 changes: 3 additions & 1 deletion src/qililab/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
__version__ = "0.0.0"

from .qililab import Qililab
from .circuit import HardwareCircuit
from .gates import I, X, Y, Z
from .platforms import PLATFORM_BUILDER
62 changes: 62 additions & 0 deletions src/qililab/backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from dataclasses import dataclass
from typing import ClassVar, Type

from qibo.backends.numpy import NumpyBackend

from qililab import gates
from qililab.circuit import HardwareCircuit
from qililab.platforms import PLATFORM_BUILDER
from qililab.platforms.platform import Platform


@dataclass
class QililabBackend(NumpyBackend):
"""Hardware backend used to execute circuits on specified lab platforms
Attributes:
name (str): Name of the backend.
is_hardware (bool): Flag used by Qibo to identify a hardware backend.
platform (object): Platform object describing the lab setup.
"""

name: str
is_hardware: bool

def __init__(self) -> None:
super().__init__()
self.platform: Platform
self.name = "qililab"
self.is_hardware = True

def set_platform(self, platform: str) -> None:
"""Set platform for controlling quantum devices.
Args:
name (str): Name of the platform.
"""
self.platform = PLATFORM_BUILDER.build(name=platform)

def get_platform(self) -> str:
"""
Returns:
str: Platform name.
"""
return str(self.platform)

def circuit_class(self, accelerators: dict = None, density_matrix: bool = False) -> Type[HardwareCircuit]:
"""
Returns:
Type[HardwareCircuit]: Circuit class used to create circuit model.
"""
if accelerators is not None:
raise NotImplementedError("Hardware backend does not support multi-GPU configuration.")
if density_matrix:
raise NotImplementedError("Hardware backend does not support density matrix simulation.")

return HardwareCircuit

def create_gate(self, cls, *args, **kwargs) -> object:
"""Create gate object"""

return getattr(gates, cls.__name__)(*args, **kwargs)
18 changes: 18 additions & 0 deletions src/qililab/circuit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from dataclasses import dataclass

from numpy import ndarray


@dataclass
class HardwareCircuit:
"""Class used to create circuit model.
Args:
nqubits (int): Number of qubits.
"""

nqubits: int

def execute(self, initial_state: ndarray = None, nshots: int = None):
"""Executes a pulse sequence"""
raise NotImplementedError
2 changes: 2 additions & 0 deletions src/qililab/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DEFAULT_PLATFORM_FILENAME = "platform"
DEFAULT_SETTINGS_FOLDERNAME = "qili"
4 changes: 4 additions & 0 deletions src/qililab/gates/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .i import I
from .x import X
from .y import Y
from .z import Z
17 changes: 17 additions & 0 deletions src/qililab/gates/hardware_gate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import sys
from abc import ABC, abstractmethod


class HardwareGate(ABC):
"""Abstract Base Class of a hardware gate."""

module = sys.modules[__name__] # used to avoid maximum recursion depth with qibo gates

# TODO: Replace 'object' with PulseSequence class
@abstractmethod
def to_sequence(self, sequence: object) -> None:
"""Translates the gate to pulses and adds them to the given PulseSequence.
Args:
sequence (PulseSequence): Class containing the sequence of pulses to be applied.
"""
22 changes: 22 additions & 0 deletions src/qililab/gates/i.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from dataclasses import dataclass

from qililab.gates.hardware_gate import HardwareGate


@dataclass
class I(HardwareGate): # noqa: E742
"""Identity gate
Args:
q (int): Index of the qubit to which the gate is applied.
"""

q: int

def to_sequence(self, sequence: object) -> None:
"""Translates the gate to pulses and adds them to the given PulseSequence.
Args:
sequence (PulseSequence): Class containing the sequence of pulses to be applied.
"""
raise NotImplementedError
22 changes: 22 additions & 0 deletions src/qililab/gates/x.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from dataclasses import dataclass

from qililab.gates.hardware_gate import HardwareGate


@dataclass
class X(HardwareGate):
"""X gate
Args:
q (int): Index of the qubit to which the gate is applied.
"""

q: int

def to_sequence(self, sequence: object) -> None:
"""Translates the gate to pulses and adds them to the given PulseSequence.
Args:
sequence (PulseSequence): Class containing the sequence of pulses to be applied.
"""
raise NotImplementedError
22 changes: 22 additions & 0 deletions src/qililab/gates/y.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from dataclasses import dataclass

from qililab.gates.hardware_gate import HardwareGate


@dataclass
class Y(HardwareGate):
"""Y gate
Args:
q (int): Index of the qubit to which the gate is applied.
"""

q: int

def to_sequence(self, sequence: object) -> None:
"""Translates the gate to pulses and adds them to the given PulseSequence.
Args:
sequence (PulseSequence): Class containing the sequence of pulses to be applied.
"""
raise NotImplementedError
22 changes: 22 additions & 0 deletions src/qililab/gates/z.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from dataclasses import dataclass

from qililab.gates.hardware_gate import HardwareGate


@dataclass
class Z(HardwareGate):
"""Z gate
Args:
q (int): Index of the qubit to which the gate is applied.
"""

q: int

def to_sequence(self, sequence: object) -> None:
"""Translates the gate to pulses and adds them to the given PulseSequence.
Args:
sequence (PulseSequence): Class containing the sequence of pulses to be applied.
"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions src/qililab/platforms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .platform import Platform
from .platform_builder import PlatformBuilder

PLATFORM_BUILDER = PlatformBuilder()
24 changes: 24 additions & 0 deletions src/qililab/platforms/platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from dataclasses import dataclass

from qililab.settings.settings import Settings


@dataclass
class Platform:
"""Platform object that describes setup used to control quantum devices.
Args:
name (str): Name of the platform.
settings (Settings): Dataclass containing the settings of the platform.
"""

name: str
settings: Settings

def __str__(self) -> str:
"""String representation of the platform
Returns:
str: Name of the platform
"""
return self.name
Loading

0 comments on commit fc93b43

Please # to comment.