microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.25.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/paulimer/tests/pauli_test.rs

204lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use core::fmt;
5use std::str::FromStr;
6
7use paulimer::quantum_core::{x, y, z};
8use paulimer::{
9 bits::MutableBitView,
10 pauli::{
11 commutes_with, generic::PhaseExponent, DensePauli, DensePauliProjective, Pauli,
12 PauliBinaryOps, PauliUnitary, Phase, SparsePauli, SparsePauliProjective,
13 },
14};
15use proptest::prelude::*;
16use rand::thread_rng;
17
18proptest! {
19 #[test]
20 fn from_bits(pauli in arbitrary_pauli(1000)) {
21 let from_bits = PauliUnitary::from_bits(pauli.x_bits().clone(), pauli.z_bits().clone(), pauli.xz_phase_exponent());
22 assert_eq!(pauli.x_bits(), from_bits.x_bits());
23 assert_eq!(pauli.z_bits(), from_bits.z_bits());
24 assert_eq!(pauli.xz_phase_exponent(), from_bits.xz_phase_exponent());
25 assert_eq!(pauli, from_bits);
26 }
27
28 #[test]
29 fn from_references(pauli in arbitrary_pauli(1000)) {
30 let from_reference = PauliUnitary::from_bits(pauli.x_bits().as_slice(), pauli.z_bits().as_slice(), pauli.xz_phase_exponent());
31 assert_eq!(pauli.x_bits(), from_reference.x_bits());
32 assert_eq!(pauli.z_bits(), from_reference.z_bits());
33 assert_eq!(pauli.xz_phase_exponent(), from_reference.xz_phase_exponent());
34 assert_eq!(pauli, from_reference);
35 }
36
37 #[test]
38 fn is_hermitian(pauli in arbitrary_pauli(1000)) {
39 let square = pauli.clone() * &pauli;
40 let expect_hermitian = square.xz_phase_exponent().value() == 0;
41 assert_eq!(pauli.is_order_two(), expect_hermitian);
42 }
43
44 #[test]
45 fn commutes_with_matches_explicit_commutator((left, right) in equal_length_paulis(1)) {
46 let leftright = left.clone() * &right;
47 let rightleft = right.clone() * &left;
48 let expect_commutes_with = leftright == rightleft;
49 assert_eq!(commutes_with(&left,&right), expect_commutes_with);
50 }
51
52 #[test]
53 fn cayley_table(length in 1..1000usize, mut index in 0..999usize) {
54 index %= length;
55 let zeros = vec![false; length];
56 let mut bits = zeros.clone();
57 bits[index] = true;
58 let identity = PauliUnitary::from_bits(zeros.clone(), zeros.clone(), 0u8);
59 let i = &PauliUnitary::from_bits(zeros.clone(), zeros.clone(), 1u8);
60 let neg = &PauliUnitary::from_bits(zeros.clone(), zeros.clone(), 2u8);
61 let x = &PauliUnitary::from_bits(bits.clone(), zeros.clone(), 0u8);
62 let z = &PauliUnitary::from_bits(zeros.clone(), bits.clone(), 0u8);
63 let y = &PauliUnitary::from_bits(bits.clone(), bits.clone(), 1u8);
64
65 assert_eq!(x.clone() * x, identity);
66 assert_eq!(y.clone() * y, identity);
67 assert_eq!(z.clone() * z, identity);
68
69 assert_eq!(x * x, identity);
70 assert_eq!(y * y, identity);
71 assert_eq!(z * z, identity);
72
73 assert_eq!(z.clone() * x, y.clone() * i);
74 assert_eq!(x.clone() * z, y.clone() * i * neg);
75 assert_eq!(y.clone() * z, x.clone() * i);
76 assert_eq!(z.clone() * y, x.clone() * i * neg);
77 assert_eq!(x.clone() * y, z.clone() * i);
78 assert_eq!(y.clone() * x, z.clone() * i * neg);
79
80 assert_eq!(z * x, i * y );
81 assert_eq!(x * z, -i * y );
82 assert_eq!(y * z, i * x);
83 assert_eq!(z * y, -i * x);
84 assert_eq!(x * y, i * z );
85 assert_eq!(y * x, -i * z);
86
87 assert_eq!(i * x * z, y);
88 }
89
90 #[test]
91 fn unsigned_int_paulis(index in 0..32usize) {
92 let one_bit = 1u32 << index;
93 let zero_bit = 0u32;
94 let x = &PauliUnitary::from_bits(one_bit, zero_bit, 0u8);
95 let z = &PauliUnitary::from_bits(zero_bit, one_bit, 0u8);
96 let y = &PauliUnitary::from_bits(one_bit, one_bit, 1u8);
97 let i = &PauliUnitary::from_bits(zero_bit, zero_bit, 1u8);
98 assert_eq!(i * x * z, y);
99 }
100
101 #[test]
102 fn mul_assign((mut left, right) in equal_length_paulis(1000)) {
103 let product = left.clone() * &right;
104 left *= &right;
105 assert_eq!(left, product);
106 }
107
108 #[test]
109 fn mul_assign_phase(mut pauli in arbitrary_pauli(1000), raw_exponent in 0..4u8) {
110 let original = pauli.clone();
111 let exponent = raw_exponent;
112 pauli *= Phase::from_exponent(exponent);
113 assert_eq!(original.x_bits(), pauli.x_bits());
114 assert_eq!(original.z_bits(), pauli.z_bits());
115 assert_eq!(
116 original.xz_phase_exponent().raw_value().wrapping_add(exponent) % 4u8,
117 pauli.xz_phase_exponent().value()
118 );
119 }
120
121 #[test]
122 fn format_round_trip(pauli in arbitrary_pauli(50)) {
123 let str_sparse = format!("{pauli}");
124 let str_dense = format!("{pauli:#}");
125 test_round_trip::<SparsePauli>(&str_sparse, &str_dense, true);
126 test_round_trip::<DensePauli>(&str_sparse, &str_dense, true);
127 test_round_trip::<SparsePauliProjective>(&str_sparse, &str_dense, false);
128 test_round_trip::<DensePauliProjective>(&str_sparse, &str_dense, false);
129 }
130
131 #[test]
132 fn left_multiply((left, right) in equal_length_paulis(1000)) {
133 let right_product = left.clone() * &right;
134 let left_product = &left * right;
135 assert_eq!(right_product, left_product);
136 }
137
138
139}
140
141prop_compose! {
142 fn arbitrary_pauli(max_dimension: usize)(dimension in 0..max_dimension) -> PauliUnitary<Vec<bool>, u8>{
143 arbitrary_pauli_of_length(dimension)
144 }
145}
146prop_compose! {
147 fn equal_length_paulis(max_dimension: usize)(dimension in 0..max_dimension) -> (PauliUnitary<Vec<bool>, u8>, PauliUnitary<Vec<bool>, u8>){
148 (arbitrary_pauli_of_length(dimension), arbitrary_pauli_of_length(dimension))
149 }
150}
151
152fn arbitrary_pauli_of_length(length: usize) -> PauliUnitary<Vec<bool>, u8> {
153 paulimer::pauli::pauli_random(length, &mut thread_rng())
154}
155
156#[test]
157fn pauli_product_test() {
158 let target: DensePauli = [z(0), z(1)].into();
159 let preimage: DensePauli = [x(0)].into();
160 let mut phase = preimage.xz_phase_exponent().raw_value();
161
162 let (mut x_bits, mut z_bits) = preimage.to_xz_bits();
163 let mut preimage_view = PauliUnitary::<MutableBitView, &mut u8>::from_bits(
164 x_bits.as_view_mut(),
165 z_bits.as_view_mut(),
166 &mut phase,
167 );
168
169 let control: DensePauli = [y(0), x(1)].into();
170 let preimage_r: DensePauli = [-y(1)].into();
171 preimage_view.mul_assign_right(&target);
172 println!("{preimage_view}");
173 preimage_view.mul_assign_left(&control);
174 assert!(preimage_view == preimage_r);
175}
176
177fn test_round_trip<PauliLike: Pauli + FromStr<Err: fmt::Debug> + Eq + fmt::Debug + fmt::Display>(
178 str_sparse: &str,
179 str_dense: &str,
180 with_phases: bool,
181) {
182 let pauli1 = str_sparse.parse::<PauliLike>().expect(str_sparse);
183 let pauli2 = str_dense.parse::<PauliLike>().expect(str_dense);
184 assert_eq!(pauli1, pauli2);
185
186 let str_sparse_1 = format!("{pauli1}");
187 let str_dense_1 = format!("{pauli1:#}");
188
189 let str_sparse_2 = format!("{pauli2}");
190 let str_dense_2 = format!("{pauli2:#}");
191
192 assert_eq!(str_dense_2, str_dense_1);
193 assert_eq!(str_sparse_2, str_sparse_1);
194
195 if with_phases {
196 assert_eq!(str_dense, str_dense_2);
197 assert_eq!(str_sparse, str_sparse_2);
198 }
199
200 let pauli3 = str_sparse_2.parse::<PauliLike>().expect(str_sparse);
201 let pauli4 = str_dense_2.parse::<PauliLike>().expect(str_dense);
202 assert_eq!(pauli1, pauli3);
203 assert_eq!(pauli1, pauli4);
204}
205