From a9bf15607cb4b60cf5b1ee43e896ae96d0eed137 Mon Sep 17 00:00:00 2001 From: Agustin Borgna Date: Thu, 4 Jul 2024 17:29:16 +0100 Subject: [PATCH 1/2] Add failing test --- Cargo.toml | 4 + src/lib.rs | 16 ---- tests/data/diagonal-box.json | 137 +++++++++++++++++++++++++++++++++++ tests/data/simple.json | 133 ++++++++++++++++++++++++++++++++++ tests/roundtrip.rs | 26 +++++++ 5 files changed, 300 insertions(+), 16 deletions(-) create mode 100644 tests/data/diagonal-box.json create mode 100644 tests/data/simple.json create mode 100644 tests/roundtrip.rs diff --git a/Cargo.toml b/Cargo.toml index 56ea6ca..d06402d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,8 @@ strum = { workspace = true, features = ["derive"] } [dev-dependencies] pyo3 = { workspace = true } +rstest = { workspace = true } +assert-json-diff = { workspace = true } [features] pyo3 = ["dep:pyo3", "dep:pythonize"] @@ -37,7 +39,9 @@ path = "tests/lib.rs" [workspace.dependencies] pyo3 = "0.21.1" pythonize = "0.21.1" +rstest = "0.21.0" serde = "1.0" serde_json = "1.0" strum = "0.26.2" uuid = "1.4" +assert-json-diff = "2.0.2" diff --git a/src/lib.rs b/src/lib.rs index f529722..5410829 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,19 +10,3 @@ pub mod pytket; pub use circuit_json::SerialCircuit; pub use optype::OpType; - -#[cfg(test)] -mod tests { - use crate::circuit_json::SerialCircuit; - use serde_json::to_string; - #[test] - fn read_json() { - let circ_s = r#"{"bits": [["c", [0]], ["c", [1]]], "commands": [{"args": [["q", [0]]], "op": {"type": "H"}}, {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, {"args": [["q", [0]], ["c", [0]]], "op": {"type": "Measure"}}, {"args": [["q", [1]], ["c", [1]]], "op": {"type": "Measure"}}], "implicit_permutation": [[["q", [0]], ["q", [0]]], [["q", [1]], ["q", [1]]]], "phase": "0.0", "qubits": [["q", [0]], ["q", [1]]]}"#; - let ser: SerialCircuit = serde_json::from_str(circ_s).unwrap(); - - assert_eq!(ser.commands.len(), 4); - - let reser: SerialCircuit = serde_json::from_str(&to_string(&ser).unwrap()[..]).unwrap(); - assert_eq!(ser, reser); - } -} diff --git a/tests/data/diagonal-box.json b/tests/data/diagonal-box.json new file mode 100644 index 0000000..b6e1c2b --- /dev/null +++ b/tests/data/diagonal-box.json @@ -0,0 +1,137 @@ +{ + "bits": [], + "commands": [ + { + "args": [ + [ + "q", + [ + 0 + ] + ], + [ + "q", + [ + 1 + ] + ], + [ + "q", + [ + 2 + ] + ] + ], + "op": { + "box": { + "control_state": 1, + "id": "0dadbfea-5391-41c2-ad71-fb01fdaecddd", + "n_controls": 1, + "op": { + "box": { + "diagonal": [ + [ + [ + 1.0, + 0.0 + ] + ], + [ + [ + 1.0, + 0.0 + ] + ], + [ + [ + 0.7071067811865476, + 0.7071067811865475 + ] + ], + [ + [ + 0.9238795325112867, + 0.3826834323650898 + ] + ] + ], + "id": "919b6c13-b9c4-4ffc-ad1a-660088402d02", + "type": "DiagonalBox", + "upper_triangle": true + }, + "type": "DiagonalBox" + }, + "type": "QControlBox" + }, + "type": "QControlBox" + } + } + ], + "created_qubits": [], + "discarded_qubits": [], + "implicit_permutation": [ + [ + [ + "q", + [ + 0 + ] + ], + [ + "q", + [ + 0 + ] + ] + ], + [ + [ + "q", + [ + 1 + ] + ], + [ + "q", + [ + 1 + ] + ] + ], + [ + [ + "q", + [ + 2 + ] + ], + [ + "q", + [ + 2 + ] + ] + ] + ], + "phase": "0.0", + "qubits": [ + [ + "q", + [ + 0 + ] + ], + [ + "q", + [ + 1 + ] + ], + [ + "q", + [ + 2 + ] + ] + ] +} \ No newline at end of file diff --git a/tests/data/simple.json b/tests/data/simple.json new file mode 100644 index 0000000..855dbaa --- /dev/null +++ b/tests/data/simple.json @@ -0,0 +1,133 @@ +{ + "bits": [ + [ + "c", + [ + 0 + ] + ], + [ + "c", + [ + 1 + ] + ] + ], + "commands": [ + { + "args": [ + [ + "q", + [ + 0 + ] + ] + ], + "op": { + "type": "H" + } + }, + { + "args": [ + [ + "q", + [ + 0 + ] + ], + [ + "q", + [ + 1 + ] + ] + ], + "op": { + "type": "CX" + } + }, + { + "args": [ + [ + "q", + [ + 0 + ] + ], + [ + "c", + [ + 0 + ] + ] + ], + "op": { + "type": "Measure" + } + }, + { + "args": [ + [ + "q", + [ + 1 + ] + ], + [ + "c", + [ + 1 + ] + ] + ], + "op": { + "type": "Measure" + } + } + ], + "implicit_permutation": [ + [ + [ + "q", + [ + 0 + ] + ], + [ + "q", + [ + 0 + ] + ] + ], + [ + [ + "q", + [ + 1 + ] + ], + [ + "q", + [ + 1 + ] + ] + ] + ], + "phase": "0.0", + "qubits": [ + [ + "q", + [ + 0 + ] + ], + [ + "q", + [ + 1 + ] + ] + ] +} \ No newline at end of file diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs new file mode 100644 index 0000000..d7d85cf --- /dev/null +++ b/tests/roundtrip.rs @@ -0,0 +1,26 @@ +//! Roundtrip tests +use assert_json_diff::assert_json_include; +use rstest::rstest; +use serde_json::Value; +use tket_json_rs::SerialCircuit; + +const SIMPLE: &str = include_str!("data/simple.json"); +const DIAGONAL: &str = include_str!("data/diagonal-box.json"); + +#[rstest] +#[case::simple(SIMPLE, 4)] +#[case::diagonal_box(DIAGONAL, 1)] +fn roundtrip(#[case] json: &str, #[case] num_commands: usize) { + let initial_json: Value = serde_json::from_str(json).unwrap(); + let ser: SerialCircuit = serde_json::from_value(initial_json.clone()).unwrap(); + + assert_eq!(ser.commands.len(), num_commands); + + let reencoded_json = serde_json::to_value(&ser).unwrap(); + // Do a partial comparison. The re-encoded circuit does not include "created_qubits" nor "discarded_qubits". + assert_json_include!(actual: initial_json, expected: reencoded_json); + + let reser: SerialCircuit = serde_json::from_value(reencoded_json).unwrap(); + + assert_eq!(ser, reser); +} From c97d380a96291f3fa96ff0b92e89843c5d8140ae Mon Sep 17 00:00:00 2001 From: Agustin Borgna Date: Fri, 5 Jul 2024 08:52:56 +0100 Subject: [PATCH 2/2] fix: Use double precision when encoding matrix values --- src/circuit_json.rs | 2 +- src/opbox.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/circuit_json.rs b/src/circuit_json.rs index 9e50fb5..60d44a7 100644 --- a/src/circuit_json.rs +++ b/src/circuit_json.rs @@ -40,7 +40,7 @@ pub struct Bitstring { /// A 2D matrix. #[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)] #[serde(transparent)] -pub struct Matrix { +pub struct Matrix { /// A 2D vector of complex numbers. pub data: Vec>, } diff --git a/src/opbox.rs b/src/opbox.rs index ae8f30e..794e5a2 100644 --- a/src/opbox.rs +++ b/src/opbox.rs @@ -34,25 +34,25 @@ pub enum OpBox { Unitary1qBox { id: BoxID, /// 2x2 matrix of complex numbers - matrix: [[(f32, f32); 2]; 2], + matrix: [[(f64, f64); 2]; 2], }, /// Two-qubit operation defined as a unitary matrix. Unitary2qBox { id: BoxID, /// 4x4 matrix of complex numbers - matrix: [[(f32, f32); 4]; 4], + matrix: [[(f64, f64); 4]; 4], }, /// Three-qubit operation defined as a unitary matrix. Unitary3qBox { id: BoxID, /// 8x8 matrix of complex numbers - matrix: Box<[[(f32, f32); 8]; 8]>, + matrix: Box<[[(f64, f64); 8]; 8]>, }, /// Two-qubit operation defined in terms of a hermitian matrix and a phase. ExpBox { id: BoxID, /// 4x4 matrix of complex numbers - matrix: [[(f32, f32); 4]; 4], + matrix: [[(f64, f64); 4]; 4], /// Phase of the operation. phase: f64, },