Skip to content

Commit 0b5d099

Browse files
authored
circuit->executor->sampler (#224)
* circuit->executor->sampler
1 parent bedc24e commit 0b5d099

33 files changed

+5925
-107
lines changed

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ pecos-qsim = { version = "0.1.1", path = "crates/pecos-qsim" }
115115
pecos-qasm = { version = "0.1.1", path = "crates/pecos-qasm" }
116116
pecos-phir-json = { version = "0.1.1", path = "crates/pecos-phir-json" }
117117
pecos-engines = { version = "0.1.1", path = "crates/pecos-engines" }
118+
pecos-experimental = { version = "0.1.1", path = "crates/pecos-experimental" }
118119
pecos-phir = { version = "0.1.1", path = "crates/pecos-phir" }
119120
pecos-qec = { version = "0.1.1", path = "crates/pecos-qec" }
120121
pecos-rng = { version = "0.1.1", path = "crates/pecos-rng" }

Justfile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ validate-cuda:
7777
# Build PECOS (profile: debug, release, native)
7878
build profile="debug": installreqs build-selene
7979
cargo run -p pecos --features cli -- python build --profile {{profile}}
80-
# Build FFI crates if tools available
81-
cargo run -p pecos --features cli -- julia build --profile {{profile}} 2>/dev/null || true
82-
cargo run -p pecos --features cli -- go build --profile {{profile}} 2>/dev/null || true
80+
# Build FFI crates if tools available (- prefix ignores errors)
81+
-cargo run -p pecos --features cli -- julia build --profile {{profile}}
82+
-cargo run -p pecos --features cli -- go build --profile {{profile}}
8383

8484
# Build and install Selene plugins for development
8585
build-selene:
@@ -114,9 +114,9 @@ build-selene:
114114
# Build PECOS with CUDA support
115115
build-cuda profile="debug": installreqs
116116
cargo run -p pecos --features cli -- python build --profile {{profile}} --cuda
117-
# Build FFI crates if tools available
118-
cargo run -p pecos --features cli -- julia build --profile {{profile}} 2>/dev/null || true
119-
cargo run -p pecos --features cli -- go build --profile {{profile}} 2>/dev/null || true
117+
# Build FFI crates if tools available (- prefix ignores errors)
118+
-cargo run -p pecos --features cli -- julia build --profile {{profile}}
119+
-cargo run -p pecos --features cli -- go build --profile {{profile}}
120120

121121
# Convenience aliases
122122
build-debug: (build "debug")

crates/pecos-engines/src/shot_results/data.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,42 @@ impl Data {
252252
_ => None,
253253
}
254254
}
255+
256+
/// Convert the Data to a JSON value
257+
#[must_use]
258+
pub fn to_json_value(&self) -> JsonValue {
259+
match self {
260+
Self::U8(v) => JsonValue::from(*v),
261+
Self::U16(v) => JsonValue::from(*v),
262+
Self::U32(v) => JsonValue::from(*v),
263+
Self::U64(v) => JsonValue::from(*v),
264+
Self::I8(v) => JsonValue::from(*v),
265+
Self::I16(v) => JsonValue::from(*v),
266+
Self::I32(v) => JsonValue::from(*v),
267+
Self::I64(v) => JsonValue::from(*v),
268+
Self::F32(v) => serde_json::Number::from_f64(f64::from(*v))
269+
.map_or(JsonValue::Null, JsonValue::Number),
270+
Self::F64(v) => {
271+
serde_json::Number::from_f64(*v).map_or(JsonValue::Null, JsonValue::Number)
272+
}
273+
Self::String(v) => JsonValue::from(v.clone()),
274+
Self::Bool(v) => JsonValue::from(*v),
275+
Self::BigInt(v) => JsonValue::from(v.to_string()),
276+
Self::Bytes(v) => JsonValue::Array(v.iter().map(|&b| JsonValue::from(b)).collect()),
277+
Self::BitVec(bv) => {
278+
// Convert BitVec to decimal integer
279+
let mut value = 0u64;
280+
for (i, bit) in bv.iter().enumerate() {
281+
if *bit && i < 64 {
282+
value |= 1u64 << i;
283+
}
284+
}
285+
JsonValue::from(value)
286+
}
287+
Self::Json(v) => v.clone(),
288+
Self::Vec(v) => JsonValue::Array(v.iter().map(Data::to_json_value).collect()),
289+
}
290+
}
255291
}
256292

257293
// Implement Display trait for Data instead of inherent to_string method

crates/pecos-engines/src/shot_results/data_vec.rs

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ pub enum DataVec {
7373
BitVec(Vec<BitVec<u8, Lsb0>>),
7474
/// Vector of JSON values
7575
Json(Vec<JsonValue>),
76+
/// Vector of nested Data vectors (for tuples, arrays, etc.)
77+
Vec(Vec<Vec<Data>>),
7678
}
7779

7880
impl DataVec {
@@ -96,6 +98,7 @@ impl DataVec {
9698
Self::Bytes(v) => v.len(),
9799
Self::BitVec(v) => v.len(),
98100
Self::Json(v) => v.len(),
101+
Self::Vec(v) => v.len(),
99102
}
100103
}
101104

@@ -127,6 +130,7 @@ impl DataVec {
127130
(Self::Bytes(v), Data::Bytes(val)) => v.push(val),
128131
(Self::BitVec(v), Data::BitVec(val)) => v.push(val),
129132
(Self::Json(v), Data::Json(val)) => v.push(val),
133+
(Self::Vec(v), Data::Vec(val)) => v.push(val),
130134
_ => {
131135
return Err(PecosError::Processing(
132136
"Data type mismatch when pushing to DataVec".to_string(),
@@ -158,6 +162,7 @@ impl DataVec {
158162
Self::Bytes(v) => v.get(index).map(|val| Data::Bytes(val.clone())),
159163
Self::BitVec(v) => v.get(index).map(|val| Data::BitVec(val.clone())),
160164
Self::Json(v) => v.get(index).map(|val| Data::Json(val.clone())),
165+
Self::Vec(v) => v.get(index).map(|val| Data::Vec(val.clone())),
161166
}
162167
}
163168

@@ -190,13 +195,7 @@ impl DataVec {
190195
Data::Bytes(_) => Self::Bytes(Vec::with_capacity(data.len())),
191196
Data::BitVec(_) => Self::BitVec(Vec::with_capacity(data.len())),
192197
Data::Json(_) => Self::Json(Vec::with_capacity(data.len())),
193-
Data::Vec(_) => {
194-
// For nested vectors, we need to create a nested DataVec
195-
// For now, return an error as this is complex to handle
196-
return Err(PecosError::Processing(
197-
"Cannot create DataVec from nested vectors".to_string(),
198-
));
199-
}
198+
Data::Vec(_) => Self::Vec(Vec::with_capacity(data.len())),
200199
};
201200

202201
// Push all elements, checking for type consistency
@@ -277,6 +276,15 @@ impl DataVec {
277276
.collect(),
278277
),
279278
Self::Json(v) => JsonValue::Array(v.clone()),
279+
Self::Vec(v) => JsonValue::Array(
280+
v.iter()
281+
.map(|inner| {
282+
JsonValue::Array(
283+
inner.iter().map(super::data::Data::to_json_value).collect(),
284+
)
285+
})
286+
.collect(),
287+
),
280288
}
281289
}
282290

@@ -308,6 +316,7 @@ impl DataVec {
308316
DataVecType::Bytes => Self::Bytes(Vec::new()),
309317
DataVecType::BitVec => Self::BitVec(Vec::new()),
310318
DataVecType::Json => Self::Json(Vec::new()),
319+
DataVecType::Vec => Self::Vec(Vec::new()),
311320
}
312321
}
313322

@@ -331,6 +340,7 @@ impl DataVec {
331340
Self::Bytes(_) => DataVecType::Bytes,
332341
Self::BitVec(_) => DataVecType::BitVec,
333342
Self::Json(_) => DataVecType::Json,
343+
Self::Vec(_) => DataVecType::Vec,
334344
}
335345
}
336346
}
@@ -370,6 +380,8 @@ pub enum DataVecType {
370380
BitVec,
371381
/// JSON value type
372382
Json,
383+
/// Nested vector type (for tuples, arrays, etc.)
384+
Vec,
373385
}
374386

375387
impl DataVecType {
@@ -393,11 +405,7 @@ impl DataVecType {
393405
Data::Bytes(_) => Self::Bytes,
394406
Data::BitVec(_) => Self::BitVec,
395407
Data::Json(_) => Self::Json,
396-
Data::Vec(_) => {
397-
// For nested vectors, we can't determine a single type
398-
// This is a limitation of the current type system
399-
Self::Json // Use Json as a fallback for complex types
400-
}
408+
Data::Vec(_) => Self::Vec,
401409
}
402410
}
403411
}
@@ -565,4 +573,46 @@ mod tests {
565573
panic!("Expected Json variant");
566574
}
567575
}
576+
577+
#[test]
578+
fn test_vec_support() {
579+
// Test nested vectors (e.g., tuple outputs from HUGR)
580+
let vec1 = vec![Data::Bool(true), Data::Bool(false)];
581+
let vec2 = vec![Data::Bool(false), Data::Bool(true)];
582+
583+
let data = vec![Data::Vec(vec1.clone()), Data::Vec(vec2.clone())];
584+
let data_vec = DataVec::from_data_vec(data).unwrap();
585+
586+
assert_eq!(data_vec.len(), 2);
587+
assert_eq!(data_vec.data_type(), DataVecType::Vec);
588+
589+
if let DataVec::Vec(ref vecs) = data_vec {
590+
assert_eq!(vecs[0], vec1);
591+
assert_eq!(vecs[1], vec2);
592+
} else {
593+
panic!("Expected Vec variant");
594+
}
595+
596+
// Test JSON serialization
597+
let json = data_vec.to_json_array();
598+
assert!(json.is_array());
599+
let arr = json.as_array().unwrap();
600+
assert_eq!(arr.len(), 2);
601+
assert_eq!(arr[0], serde_json::json!([true, false]));
602+
assert_eq!(arr[1], serde_json::json!([false, true]));
603+
}
604+
605+
#[test]
606+
fn test_vec_roundtrip() {
607+
// Test roundtrip conversion for Vec variant
608+
let original = vec![
609+
Data::Vec(vec![Data::I32(1), Data::I32(2)]),
610+
Data::Vec(vec![Data::I32(3), Data::I32(4)]),
611+
];
612+
613+
let data_vec = DataVec::from_data_vec(original.clone()).unwrap();
614+
let converted_back = data_vec.to_data_vec();
615+
616+
assert_eq!(original, converted_back);
617+
}
568618
}

crates/pecos-engines/src/shot_results/shot_map_formatter.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ impl<'a> ShotMapDisplay<'a> {
166166
DataVec::Bytes(v) => v.get(index).map(|x| format!("{x:?}")),
167167
DataVec::BitVec(v) => v.get(index).map(|x| self.format_bitvec(x)),
168168
DataVec::Json(v) => v.get(index).map(std::string::ToString::to_string),
169+
DataVec::Vec(v) => v.get(index).map(|inner| {
170+
let items: Vec<String> =
171+
inner.iter().map(std::string::ToString::to_string).collect();
172+
format!("[{}]", items.join(", "))
173+
}),
169174
}
170175
}
171176
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
name = "pecos-experimental"
3+
version.workspace = true
4+
edition.workspace = true
5+
readme.workspace = true
6+
authors.workspace = true
7+
homepage.workspace = true
8+
repository.workspace = true
9+
license.workspace = true
10+
keywords.workspace = true
11+
categories.workspace = true
12+
description = "Experimental APIs for PECOS - unstable, may change without notice."
13+
publish = false
14+
15+
[lib]
16+
crate-type = ["rlib"]
17+
18+
[dependencies]
19+
# Can depend on any internal crate - this is the staging area
20+
pecos-core.workspace = true
21+
pecos-rng.workspace = true
22+
pecos-qsim.workspace = true
23+
pecos-quantum.workspace = true
24+
wide.workspace = true
25+
26+
[lints]
27+
workspace = true

0 commit comments

Comments
 (0)