Skip to content

Commit

Permalink
fix: Matrix encoding roundtrip losing precision. Use f64 instead of…
Browse files Browse the repository at this point in the history
… `f32`s. (#48)

Fixes #45. The elements in the encoded matrix where deserialized into
`f32`, which caused a precision loss.
  • Loading branch information
aborgna-q authored Jul 5, 2024
1 parent 60f1c21 commit 35dc198
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 21 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -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"
2 changes: 1 addition & 1 deletion src/circuit_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub struct Bitstring {
/// A 2D matrix.
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)]
#[serde(transparent)]
pub struct Matrix<T = f32> {
pub struct Matrix<T = f64> {
/// A 2D vector of complex numbers.
pub data: Vec<Vec<(T, T)>>,
}
Expand Down
16 changes: 0 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
8 changes: 4 additions & 4 deletions src/opbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down
137 changes: 137 additions & 0 deletions tests/data/diagonal-box.json
Original file line number Diff line number Diff line change
@@ -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
]
]
]
}
133 changes: 133 additions & 0 deletions tests/data/simple.json
Original file line number Diff line number Diff line change
@@ -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
]
]
]
}
26 changes: 26 additions & 0 deletions tests/roundtrip.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 35dc198

Please sign in to comment.