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

fix: pyright diagnotics #196

Merged
merged 4 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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