Skip to content

Commit c8619a2

Browse files
committed
2 parents 9393d2d + 9f3116f commit c8619a2

File tree

26 files changed

+1285
-14
lines changed

26 files changed

+1285
-14
lines changed

.github/workflows/docs.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: Deploy Documentation
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
tags:
8+
- "v*"
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
pages: write
14+
id-token: write
15+
16+
# Serialize the entire workflow (build + deploy) to prevent race conditions.
17+
# If two runs trigger concurrently (e.g. a push to main and a tag), the second
18+
# queues until the first finishes. This ensures the gh-pages checkout always
19+
# reflects the latest deployed state.
20+
concurrency:
21+
group: pages
22+
cancel-in-progress: false
23+
24+
jobs:
25+
deploy:
26+
runs-on: ubuntu-latest
27+
environment:
28+
name: github-pages
29+
url: ${{ steps.deployment.outputs.page_url }}
30+
steps:
31+
- uses: actions/checkout@v6
32+
with:
33+
fetch-depth: 0
34+
35+
- uses: dtolnay/rust-toolchain@stable
36+
37+
- uses: Swatinem/rust-cache@v2
38+
39+
- uses: extractions/setup-just@v3
40+
41+
- name: Install uv
42+
uses: astral-sh/setup-uv@v7
43+
with:
44+
version: "0.5.1"
45+
46+
- name: Download existing site from gh-pages
47+
uses: actions/checkout@v6
48+
with:
49+
ref: gh-pages
50+
path: target/site
51+
continue-on-error: true
52+
53+
# actions/checkout creates a .git/ directory inside target/site.
54+
# Remove it so deploy-pages doesn't upload git metadata — the full
55+
# site replacement only needs the built files, not the repo history.
56+
- name: Remove git metadata from site checkout
57+
run: rm -rf target/site/.git
58+
59+
- name: Determine version
60+
id: version
61+
run: |
62+
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
63+
echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
64+
else
65+
echo "version=dev" >> "$GITHUB_OUTPUT"
66+
fi
67+
68+
- name: Build versioned documentation
69+
run: just doc-deploy ${{ steps.version.outputs.version }}
70+
71+
- name: Upload Pages artifact
72+
uses: actions/upload-pages-artifact@v3
73+
with:
74+
path: target/site
75+
76+
- name: Deploy to GitHub Pages
77+
id: deployment
78+
uses: actions/deploy-pages@v4

CLAUDE.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ just coverage # Run Python tests with coverage + generate XML report
4343
just coverage-run # Run Python tests only
4444
just coverage-html # Generate HTML coverage report
4545
just demo # Run all demo scripts
46-
just doc # Serve mkdocs locally
46+
just doc # Build and open documentation site in browser
47+
just doc-all # Build documentation site (book + Rust API)
48+
just doc-book # Build mdBook only
49+
just doc-rust # Build Rust API docs only
50+
just doc-deploy <ver> # Deploy versioned docs (e.g. dev, v0.5.0)
51+
just install-mdbook # Install pinned mdBook version
4752
just test-python # Run Python tests via pytest
4853

4954
# Rust
@@ -70,7 +75,9 @@ Direct test run: `uv run coverage run -m pytest python/tests`
7075

7176
## Linting & Formatting
7277

73-
Pre-commit hooks enforce all checks. The CI lint pipeline runs:
78+
Pre-commit hooks enforce all checks. When hooks must be bypassed (e.g. committing on orphan branches like `gh-pages` that lack `.pre-commit-config.yaml`), use `git commit -n`.
79+
80+
The CI lint pipeline runs:
7481

7582
### Python
7683
- **isort** (profile=black, src_paths=python/bloqade)
@@ -111,7 +118,8 @@ bloqade-lanes/
111118
├── Cargo.toml # Rust workspace root
112119
├── Cargo.lock
113120
├── pyproject.toml # Maturin build config + Python project metadata
114-
├── justfile # Task automation
121+
├── justfile # Task automation (pinned tool versions + all recipes)
122+
├── book.toml # mdBook configuration
115123
├── crates/ # Rust workspace
116124
│ ├── bloqade-lanes-bytecode-core/ # Pure Rust: bytecode format, arch spec, validation
117125
│ ├── bloqade-lanes-bytecode-python/ # PyO3 bindings (cdylib → _native module)
@@ -139,8 +147,12 @@ bloqade-lanes/
139147
│ ├── bytecode/ # Bytecode-specific tests
140148
│ └── ... # Tests mirror python/bloqade/lanes structure
141149
├── tests/ # Rust integration tests
150+
├── docs/
151+
│ ├── src/ # mdBook source (SUMMARY.md, arch/, bytecode/)
152+
│ ├── theme/ # Custom mdBook theme assets (version-switcher.js)
153+
│ └── scripts/ # Documentation deploy scripts (deploy_docs.py)
142154
├── examples/ # Architecture specs and sample bytecode programs
143-
├── scripts/ # Build/test utility scripts
155+
├── scripts/ # Build/test utility scripts (non-docs)
144156
├── demo/ # Python demo scripts
145157
└── dist-data/ # Staged artifacts for wheel packaging (gitignored)
146158
```

book.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[book]
2+
title = "Bloqade Lanes"
3+
authors = ["QuEra Computing"]
4+
language = "en"
5+
src = "docs/src"
6+
7+
[build]
8+
build-dir = "target/book"
9+
10+
[output.html]
11+
git-repository-url = "https://github.com/QuEraComputing/bloqade-lanes"
12+
edit-url-template = "https://github.com/QuEraComputing/bloqade-lanes/edit/main/{path}"
13+
# Note: version-switcher.js is injected by deploy_docs.py for deployed builds only.
14+
# Local builds (just doc / just doc-all) do not include the version switcher.

crates/bloqade-lanes-bytecode-core/src/arch/addr.rs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,48 @@
1+
//! Bit-packed address types for bytecode instructions.
2+
//!
3+
//! These types encode device-level addresses into compact integer
4+
//! representations used in the 16-byte instruction format.
5+
6+
/// Atom movement direction along a transport bus.
17
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28
#[repr(u8)]
39
pub enum Direction {
10+
/// Movement from source to destination (value 0).
411
Forward = 0,
12+
/// Movement from destination to source (value 1).
513
Backward = 1,
614
}
715

16+
/// Type of transport bus used for an atom move operation.
817
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
918
#[repr(u8)]
1019
pub enum MoveType {
20+
/// Moves atoms between sites within a word (value 0).
1121
SiteBus = 0,
22+
/// Moves atoms between words (value 1).
1223
WordBus = 1,
1324
}
1425

26+
/// Bit-packed atom location address (word + site).
27+
///
28+
/// Encodes `word_id` (16 bits) and `site_id` (16 bits) into a 32-bit word.
29+
///
30+
/// Layout: `[word_id:16][site_id:16]`
1531
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1632
pub struct LocationAddr {
1733
pub word_id: u32,
1834
pub site_id: u32,
1935
}
2036

2137
impl LocationAddr {
22-
// Layout: [word_id:16][site_id:16]
38+
/// Encode to a 32-bit packed integer.
39+
///
40+
/// Layout: `[word_id:16][site_id:16]`
2341
pub fn encode(&self) -> u32 {
2442
((self.word_id as u16 as u32) << 16) | (self.site_id as u16 as u32)
2543
}
2644

45+
/// Decode a 32-bit packed integer into a `LocationAddr`.
2746
pub fn decode(bits: u32) -> Self {
2847
Self {
2948
word_id: (bits >> 16) & 0xFFFF,
@@ -32,6 +51,14 @@ impl LocationAddr {
3251
}
3352
}
3453

54+
/// Bit-packed lane address for atom move operations.
55+
///
56+
/// Encodes direction (1 bit), move type (1 bit), word_id (16 bits),
57+
/// site_id (16 bits), and bus_id (16 bits) across two 32-bit data words.
58+
///
59+
/// Layout:
60+
/// - data0: `[word_id:16][site_id:16]`
61+
/// - data1: `[dir:1][mt:1][pad:14][bus_id:16]`
3562
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3663
pub struct LaneAddr {
3764
pub direction: Direction,
@@ -42,9 +69,7 @@ pub struct LaneAddr {
4269
}
4370

4471
impl LaneAddr {
45-
// Layout across two u32 words:
46-
// data0: [word_id:16][site_id:16]
47-
// data1: [dir:1][mt:1][pad:14][bus_id:16]
72+
/// Encode to two 32-bit data words `(data0, data1)`.
4873
pub fn encode(&self) -> (u32, u32) {
4974
let data0 = ((self.word_id as u16 as u32) << 16) | (self.site_id as u16 as u32);
5075
let data1 = ((self.direction as u32) << 31)
@@ -53,11 +78,13 @@ impl LaneAddr {
5378
(data0, data1)
5479
}
5580

81+
/// Encode to a single 64-bit packed integer (`data0 | (data1 << 32)`).
5682
pub fn encode_u64(&self) -> u64 {
5783
let (d0, d1) = self.encode();
5884
(d0 as u64) | ((d1 as u64) << 32)
5985
}
6086

87+
/// Decode two 32-bit data words into a `LaneAddr`.
6188
pub fn decode(data0: u32, data1: u32) -> Self {
6289
let direction = if (data1 >> 31) & 1 == 0 {
6390
Direction::Forward
@@ -78,22 +105,29 @@ impl LaneAddr {
78105
}
79106
}
80107

108+
/// Decode a 64-bit packed integer into a `LaneAddr`.
81109
pub fn decode_u64(bits: u64) -> Self {
82110
Self::decode(bits as u32, (bits >> 32) as u32)
83111
}
84112
}
85113

114+
/// Bit-packed zone address.
115+
///
116+
/// Encodes a zone identifier (16 bits) into a 32-bit value.
117+
///
118+
/// Layout: `[pad:16][zone_id:16]`
86119
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87120
pub struct ZoneAddr {
88121
pub zone_id: u32,
89122
}
90123

91124
impl ZoneAddr {
92-
// Layout: [pad:16][zone_id:16]
125+
/// Encode to a 32-bit packed integer.
93126
pub fn encode(&self) -> u32 {
94127
self.zone_id as u16 as u32
95128
}
96129

130+
/// Decode a 32-bit packed integer into a `ZoneAddr`.
97131
pub fn decode(bits: u32) -> Self {
98132
Self {
99133
zone_id: bits & 0xFFFF,
@@ -163,6 +197,19 @@ mod tests {
163197
assert_eq!(LaneAddr::decode(data0, data1), addr);
164198
}
165199

200+
#[test]
201+
fn test_lane_addr_u64_round_trip() {
202+
let addr = LaneAddr {
203+
direction: Direction::Backward,
204+
move_type: MoveType::WordBus,
205+
word_id: 1,
206+
site_id: 0,
207+
bus_id: 0,
208+
};
209+
let packed = addr.encode_u64();
210+
assert_eq!(LaneAddr::decode_u64(packed), addr);
211+
}
212+
166213
#[test]
167214
fn test_zone_addr_round_trip() {
168215
let addr = ZoneAddr { zone_id: 42 };

crates/bloqade-lanes-bytecode-core/src/arch/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
//! Architecture specification types, address encoding, and validation.
2+
//!
3+
//! This module defines the physical topology of a Bloqade quantum device:
4+
//! words, grids, transport buses, zones, and the `ArchSpec` that ties them
5+
//! together. It also provides bit-packed address types used by bytecode
6+
//! instructions and comprehensive structural validation.
7+
//!
8+
//! # Key types
9+
//!
10+
//! - [`ArchSpec`] — top-level device specification (loadable from JSON)
11+
//! - [`Word`], [`Grid`], [`Bus`], [`Zone`] — building blocks
12+
//! - [`LocationAddr`], [`LaneAddr`], [`ZoneAddr`] — bit-packed addresses
13+
//! - [`Direction`], [`MoveType`] — transport enums
14+
115
pub mod addr;
216
pub mod query;
317
pub mod types;

crates/bloqade-lanes-bytecode-core/src/arch/query.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//! Arch spec queries: JSON loading, position lookup, lane resolution,
2+
//! and group-level address validation.
3+
14
use std::collections::HashSet;
25
use std::fmt;
36

@@ -7,6 +10,7 @@ use super::addr::{LaneAddr, LocationAddr, MoveType};
710
use super::types::{ArchSpec, Bus, Word};
811
use super::validate::ArchSpecError;
912

13+
/// Error returned when loading an arch spec from JSON fails.
1014
#[derive(Debug, Error)]
1115
pub enum ArchSpecLoadError {
1216
#[error("JSON parse error: {0}")]

0 commit comments

Comments
 (0)