Skip to content

Commit

Permalink
fix: pyright diagnotics (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
kahojyun authored Oct 12, 2024
1 parent f9cfcf4 commit 42daf4e
Show file tree
Hide file tree
Showing 8 changed files with 407 additions and 362 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,8 @@ jobs:
run: cargo fmt --check
- name: Cargo clippy
run: cargo clippy --all-targets
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install uv
uses: astral-sh/setup-uv@v2
uses: astral-sh/setup-uv@v3
- name: Sync project
run: uv sync --locked
- name: Pytest
Expand Down
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.12
3.9
11 changes: 8 additions & 3 deletions bosing.pyi
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# ruff: noqa: PLR0913
from collections.abc import Iterable, Mapping, Sequence
from typing import ClassVar, Literal, Self, TypeAlias, final
from typing import ClassVar, Literal, final

import numpy as np
import numpy.typing as npt
from typing_extensions import Self, TypeAlias

@final
class Channel:
Expand All @@ -14,7 +16,7 @@ class Channel:
*,
delay: float = ...,
align_level: int = ...,
iq_matrix: npt.ArrayLike | None = ...,
iq_matrix: npt.ArrayLike | Sequence[Sequence[float]] | None = ...,
offset: npt.ArrayLike | None = ...,
iir: npt.ArrayLike | None = ...,
fir: npt.ArrayLike | None = ...,
Expand Down Expand Up @@ -64,7 +66,10 @@ class Hann(Shape):
@final
class Interp(Shape):
def __new__(
cls, knots: Iterable[float], controls: Iterable[float], degree: float
cls,
knots: Iterable[float],
controls: Iterable[float],
degree: float,
) -> Self: ...
@property
def knots(self) -> Sequence[float]: ...
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# ruff: noqa: INP001, D100
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
Expand Down
23 changes: 16 additions & 7 deletions examples/schedule_stress.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""An example of using bosing to generate a pulse sequence."""

import time
from collections.abc import Sequence
from itertools import cycle

import numpy as np
Expand All @@ -19,15 +20,19 @@
)


def get_biquad(amp, tau, fs):
def get_biquad(
amp: Sequence[float],
tau: Sequence[float],
fs: float,
) -> np.ndarray:
z = [-1 / (t * (1 + a)) for (a, t) in zip(amp, tau)]
p = [-1 / t for t in tau]
k = np.prod([1 + a for a in amp])
z, p, k = signal.bilinear_zpk(z, p, k, fs)
return signal.zpk2sos(p, z, 1 / k)


def gen_n(n: int):
def gen_n(n: int) -> None:
t0 = time.perf_counter()
nxy = 64
nu = 2 * nxy
Expand All @@ -37,7 +42,11 @@ def gen_n(n: int):
channels = (
{
f"xy{i}": Channel(
3e6 * i, 2e9, 100000, iq_matrix=[[1, 0.1], [0.1, 1]], offset=[0.1, 0.2]
3e6 * i,
2e9,
100000,
iq_matrix=[[1.0, 0.1], [0.1, 1.0]],
offset=[0.1, 0.2],
)
for i in range(nxy)
}
Expand All @@ -58,16 +67,16 @@ def gen_n(n: int):
*(
Play(f"m{i}", "hann", 0.1, 30e-9, plateau=1e-6, frequency=20e6 * i)
for i in range(nm)
)
),
)
c_group = Stack().with_children(
*(Play(f"u{i}", "halfcos", 0.01 * (i + 1), 50e-9) for i in range(nu))
*(Play(f"u{i}", "halfcos", 0.01 * (i + 1), 50e-9) for i in range(nu)),
)
x_group = Stack().with_children(
*(
Play(f"xy{i}", "hann", 0.01 * (i + 1), 50e-9, drag_coef=5e-10)
for i in range(nxy)
)
),
)

schedule = Stack(duration=50e-6).with_children(
Expand All @@ -94,7 +103,7 @@ def gen_n(n: int):
print(f"Time: {t1-t0:.3f}s")


def main():
def main() -> None:
for i in cycle(range(349, 350)):
print(i)
gen_n(i)
Expand Down
33 changes: 28 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name = "bosing"
dynamic = ["version"]
description = "Waveform generator for pulse sequences in quantum computing"
readme = "README.md"
requires-python = ">=3.8"
requires-python = ">=3.9"
keywords = []
authors = [{ name = "kaho", email = "kaho0769@qq.com" }]
classifiers = [
Expand All @@ -30,16 +30,15 @@ Source = "https://github.com/kahojyun/Bosing"
features = ["pyo3/extension-module"]

[tool.uv]
environments = ["python_version>='3.10'"]
dev-dependencies = [
"mypy>=1.11.2",
"ruff>=0.6.7",
"sphinx>=8.0.2",
"furo>=2024.8.6",
"matplotlib>=3.9.2",
"scipy>=1.14.1",
"taskipy>=1.13.0",
"pytest>=8.3.3",
"scipy>=1.13.1",
"furo>=2024.8.6",
"sphinx>=7.4.7",
]
cache-keys = [
{ file = "src/**/*.rs" },
Expand All @@ -62,3 +61,27 @@ test_rs = "cargo test"
stubtest = "stubtest bosing --allowlist stubtest-allowlist.txt"
makedocs = "sphinx-build -M html docs docs/_build"
cleandocs = "sphinx-build -M clean docs docs/_build"

[tool.ruff.lint]
select = ["ALL"]
ignore = ["COM812", "ISC001"]
isort.known-first-party = ["bosing"]
[tool.ruff.lint.per-file-ignores]
"examples/*.py" = ["INP", "D", "T201"]
"tests/*.py" = ["INP", "D", "S101"]
[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.basedpyright]
include = ["examples", "tests", "docs"]
exclude = ["**/node_modules", "**/__pycache__", "docs/_build"]
[[tool.basedpyright.executionEnvironments]]
root = "examples"
reportAny = "none"
reportMissingTypeStubs = "none"
reportUnknownArgumentType = "none"
reportUnknownVariableType = "none"
reportUnknownMemberType = "none"
reportUnknownParameterType = "none"
reportUnusedCallResult = "none"
reportMissingTypeArgument = "none"
89 changes: 57 additions & 32 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
from typing import TYPE_CHECKING

import numpy as np

import bosing

if TYPE_CHECKING:
from numpy.typing import NDArray


def test_basic():
channels = {"xy0": bosing.Channel(100e6, 2e9, 100000)}
def test_basic() -> None:
length = 100000
channels = {"xy0": bosing.Channel(100e6, 2e9, length)}
shapes = {"hann": bosing.Hann()}
schedule = bosing.Stack(duration=49.9e-6).with_children(
bosing.Play("xy0", "hann", 0.1, 100e-9)
bosing.Play("xy0", "hann", 0.1, 100e-9),
)
result = bosing.generate_waveforms(channels, shapes, schedule)
assert "xy0" in result
w = result["xy0"]
assert w.shape == (2, 100000)
w = w[0] + 1j * w[1]
assert w.shape == (2, length)
w: NDArray[np.float64] = w[0] + 1j * w[1]
assert w[0] == 0
assert w[-1] == 0
assert np.any(w != 0)
assert np.any(w != 0) # pyright: ignore[reportAny]


def test_mixing():
def test_mixing() -> None:
shapes = {"hann": bosing.Hann()}
schedule = bosing.Stack(duration=500e-9).with_children(
bosing.Play(
Expand All @@ -32,50 +38,69 @@ def test_mixing():
bosing.Barrier(duration=10e-9),
)
freq = 30e6
length = 1000
sample_rate = 2e9

channels = {"xy": bosing.Channel(freq, 2e9, 1000)}
channels = {"xy": bosing.Channel(freq, sample_rate, length)}
result = bosing.generate_waveforms(channels, shapes, schedule)
w1 = result["xy"]
w1 = w1[0] + 1j * w1[1]
w1: NDArray[np.float64] = w1[0] + 1j * w1[1]

channels = {"xy": bosing.Channel(0, 2e9, 1000)}
channels = {"xy": bosing.Channel(0, sample_rate, length)}
result = bosing.generate_waveforms(channels, shapes, schedule)
w2 = result["xy"]
w2 = w2[0] + 1j * w2[1]
w2 = w2 * np.exp(1j * (2 * np.pi * freq * np.arange(1000) / 2e9))
w2: NDArray[np.float64] = w2[0] + 1j * w2[1]
w2 = w2 * np.exp(1j * (2 * np.pi * freq * np.arange(length) / sample_rate))

assert np.allclose(w1, w2)


def test_states():
def test_states() -> None:
length = 1000
base_freq0 = 100e6
base_freq1 = 50e6
phase_shift = 0.1
freq_shift = 10e6
duration = 500e-9
gap = 10e-9
shift_instant = duration - gap
channels = {
"xy0": bosing.Channel(100e6, 2e9, 1000),
"xy1": bosing.Channel(50e6, 2e9, 1000),
"xy0": bosing.Channel(base_freq0, 2e9, length),
"xy1": bosing.Channel(base_freq1, 2e9, length),
}
schedule = bosing.Stack(duration=500e-9).with_children(
schedule = bosing.Stack(duration=duration).with_children(
bosing.Play("xy0", "hann", 0.3, 100e-9),
bosing.Play("xy1", "hann", 0.5, 200e-9),
bosing.ShiftPhase("xy0", 0.1),
bosing.ShiftFreq("xy1", 10e6),
bosing.Barrier(duration=10e-9),
bosing.ShiftPhase("xy0", phase_shift),
bosing.ShiftFreq("xy1", freq_shift),
bosing.Barrier(duration=gap),
)
shapes = {"hann": bosing.Hann()}
_, states = bosing.generate_waveforms_with_states(
channels, shapes, schedule, states=None
channels,
shapes,
schedule,
states=None,
)
assert states["xy0"].base_freq == 100e6
assert states["xy0"].base_freq == base_freq0
assert states["xy0"].delta_freq == 0
assert states["xy0"].phase == 0.1
assert states["xy1"].base_freq == 50e6
assert states["xy1"].delta_freq == 10e6
assert states["xy1"].phase_at(490e-9) == 50e6 * 490e-9
shifted_states = {n: s.with_time_shift(500e-9) for n, s in states.items()}
assert states["xy0"].phase == phase_shift
assert states["xy1"].base_freq == base_freq1
assert states["xy1"].delta_freq == freq_shift
assert states["xy1"].phase_at(shift_instant) == base_freq1 * shift_instant
shifted_states = {n: s.with_time_shift(duration) for n, s in states.items()}
_, states = bosing.generate_waveforms_with_states(
channels, shapes, schedule, states=shifted_states
channels,
shapes,
schedule,
states=shifted_states,
)
assert states["xy0"].base_freq == 100e6
assert states["xy0"].base_freq == base_freq0
assert states["xy0"].delta_freq == 0
assert states["xy0"].phase == 0.2 + 100e6 * 500e-9
assert states["xy1"].base_freq == 50e6
assert states["xy1"].delta_freq == 20e6
assert states["xy1"].phase_at(490e-9) == 50e6 * 490e-9 + 60e6 * 500e-9
assert states["xy0"].phase == phase_shift * 2 + base_freq0 * duration
assert states["xy1"].base_freq == base_freq1
assert states["xy1"].delta_freq == freq_shift * 2
assert (
states["xy1"].phase_at(shift_instant)
== base_freq1 * shift_instant + (base_freq1 + freq_shift) * duration
)
Loading

0 comments on commit 42daf4e

Please sign in to comment.