Skip to content

Commit c15cc3d

Browse files
add a discussion section in rotation_synthesis/README.md about digits of precision and add a parameter to control global phase of to_quirk
1 parent 24d83c5 commit c15cc3d

6 files changed

Lines changed: 34 additions & 26 deletions

File tree

qualtran/rotation_synthesis/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,15 @@ expected number of T gates is 18.982
116116
>>> 'actual diamond distance: %e'%mixed_fallback.diamond_norm_distance_to_rz(theta, config)
117117
'actual diamond distance: 5.397363e-10'
118118
```
119+
120+
## Effect of digits of precision
121+
The number of digits of precision used (i.e. rs.with_dps(digits_of_precision)) affects the result of the synthesis as follows:
122+
123+
- very low => A math error will be raised by one of the checks|
124+
- low => A valid solution may be missed, in other words you get either a solution that has more T gates or None|
125+
- just right => A correct solution that has a number of T gates on par with the current state of the art|
126+
- high => same solution as above but in more time|
127+
128+
Essentially, the code will either return a valid synthesis or None. If the code returns a result then it may be improved by increasing the number of digits of precision and if the code returns None then we need to increase the number of digits of precisions or `max_n` or both.
129+
130+
As a rule of thumb, the number of digits of precision should be close to $9\log_10{1/\epsilon}$. This works for large $epsilon$ and is an upperbound for very small $\epsilon$, for example for $\epsilon=10^{-50}$ we need 400 digits and for $\epsilon=10^{-100}$ we need 800 digits.

qualtran/rotation_synthesis/channels/channel.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ def to_cirq(self, fmt: str = "xz", qs: Optional[Sequence[cirq.Qid]] = None) -> c
132132
q = cirq.q(0)
133133
return cirq.Circuit(ctr.to_cirq(self.to_matrix(), fmt, q))
134134

135-
def to_quirk(self, fmt: str = "xz", allow_global_phase: bool = False) -> str:
135+
def to_quirk(self, fmt: str = "xz", allow_global_phase: bool = True) -> str:
136136
"""Retruns a quirk link representing the channel operation.
137137
138138
Args:
139139
fmt: The gates to use (see the documentation of to_sequence).
140140
allow_global_phase: whether the result can have a global phase or not.
141-
If this is set then each gate (except H) gets replaced by SU2 version:
141+
If this is False, then each gate (except H) gets replaced by SU2 version:
142142
- S -> Rz(pi/2)
143143
- T -> Rz(pi/4)
144144
- X -> Rx(-pi)
@@ -286,13 +286,13 @@ def to_cirq(self, fmt: str = "xz", qs: Optional[Sequence[cirq.Qid]] = None) -> c
286286
),
287287
)
288288

289-
def to_quirk(self, fmt: str = "xz", allow_global_phase: bool = False) -> str:
289+
def to_quirk(self, fmt: str = "xz", allow_global_phase: bool = True) -> str:
290290
"""Retruns a quirk link representing the channel operation.
291291
292292
Args:
293293
fmt: The gates to use (see the documentation of to_sequence).
294294
allow_global_phase: whether the result can have a global phase or not.
295-
If this is set then each gate (except H) gets replaced by SU2 version:
295+
If this is False then each gate (except H) gets replaced by SU2 version:
296296
- S -> Rz(pi/2)
297297
- T -> Rz(pi/4)
298298
- X -> Rx(-pi)

qualtran/rotation_synthesis/matrix/clifford_t_repr.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ def _xyz_sequence(matrix: su2_ct.SU2CliffordT) -> tuple[str, ...]:
5252
]
5353

5454

55-
def _xz_sequence(matrix: su2_ct.SU2CliffordT, use_hs: bool = True, prv: str = 'dummy') -> Optional[tuple[str, ...]]:
56-
# if use_hs:
57-
# matrix = matrix.reduce()
55+
def _xz_sequence(
56+
matrix: su2_ct.SU2CliffordT, use_hs: bool = True, prv: str = 'dummy'
57+
) -> Optional[tuple[str, ...]]:
5858
if matrix.det() == 2:
5959
return clifford(matrix)
6060
cliffords = [su2_ct.ISqrt2]
@@ -64,7 +64,8 @@ def _xz_sequence(matrix: su2_ct.SU2CliffordT, use_hs: bool = True, prv: str = 'd
6464
candidates = []
6565
pref = prv.removesuffix('*')
6666
for name, t in _T_list:
67-
if name.startswith(pref): continue
67+
if name.startswith(pref):
68+
continue
6869
for c in cliffords:
6970
new = c.adjoint() @ matrix
7071
new = t.adjoint() @ new
@@ -138,14 +139,14 @@ def _to_quirk_name(name: str, allow_global_phase: bool = False) -> str:
138139
if name == "H":
139140
return "\"H\""
140141
if name in ("X", "Y", "Z"):
141-
return '{"id":"R%sft","arg":"-pi"}'%(name.lower())
142+
return '{"id":"R%sft","arg":"-pi"}' % (name.lower())
142143
if name == "S":
143144
return '{"id":"Rzft","arg":"pi/2"}'
144145
if name == "S*":
145146
return '{"id":"Rzft","arg":"-pi/2"}'
146147
if name.startswith("T"):
147148
angle = ['pi/4', '-pi/4'][name.endswith('*')]
148-
return '{"id":"R%sft","arg":"%s"}'%(name[1].lower(), angle)
149+
return '{"id":"R%sft","arg":"%s"}' % (name[1].lower(), angle)
149150
raise ValueError(f"{name=} is not supported")
150151

151152

@@ -165,7 +166,9 @@ def to_cirq(
165166
return tuple(_CIRQ_GATE_MAP[g](q) for g in to_sequence(matrix, fmt))
166167

167168

168-
def to_quirk(matrix: su2_ct.SU2CliffordT, fmt: str, allow_global_phase: bool = False) -> tuple[str, ...]:
169+
def to_quirk(
170+
matrix: su2_ct.SU2CliffordT, fmt: str, allow_global_phase: bool = False
171+
) -> tuple[str, ...]:
169172
"""Retruns a representation of the matrix as a sequence of quirk symbols.
170173
171174
Args:
@@ -184,8 +187,8 @@ def to_quirk(matrix: su2_ct.SU2CliffordT, fmt: str, allow_global_phase: bool = F
184187
A tuple quirk symbols.
185188
"""
186189
sequence = to_sequence(matrix, fmt)
187-
phase_correction = ()
190+
phase_correction = tuple[str, ...]()
188191
if not allow_global_phase:
189-
phase = sum(g=='H' for g in sequence) % 4
192+
phase = sum(g == 'H' for g in sequence) % 4
190193
phase_correction = ('"Z^½"', '"X"', '"Z^½"', '"X"') * phase
191194
return phase_correction + tuple(_to_quirk_name(name, allow_global_phase) for name in sequence)

qualtran/rotation_synthesis/matrix/clifford_t_repr_test.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,10 @@ def test_to_xyz_seq(g):
4141
got = su2_ct.SU2CliffordT.from_sequence(seq)
4242
assert got == g
4343

44-
def reduce(g: su2_ct.SU2CliffordT):
45-
import qualtran.rotation_synthesis.rings.zsqrt2 as z2
46-
import qualtran.rotation_synthesis.rings.zw as zw
47-
if not(g.det() > 2 * z2.LAMBDA_KLIUCHNIKOV):
48-
return g
49-
if not all(v.is_divisible_by(zw.LAMBDA_KLIUCHNIKOV) for v in g.matrix.flat):
50-
return g
51-
return reduce(su2_ct.SU2CliffordT([[v//zw.LAMBDA_KLIUCHNIKOV for v in r] for r in g.matrix]))
5244

5345
@pytest.mark.parametrize("g", _make_random_su(50, 5, random_cliffords=True, seed=0))
54-
def test_to_xz_seq(g):
55-
g = reduce(g)
46+
def test_to_xz_seq(g: su2_ct.SU2CliffordT):
47+
g = g.rescale()
5648
seq = ctr.to_sequence(g, 'xz')
5749
assert not any('Ty' in g for g in seq)
5850
first_t = None

qualtran/rotation_synthesis/matrix/su2_ct.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,12 @@ def rescale(self) -> 'SU2CliffordT':
221221
while u.det() > 2 * zsqrt2.LAMBDA_KLIUCHNIKOV:
222222
if not all(a.is_divisible_by(zw.LAMBDA_KLIUCHNIKOV) for a in u.matrix.flat):
223223
break
224-
u = SU2CliffordT(
224+
new_u = SU2CliffordT(
225225
[[x // zw.LAMBDA_KLIUCHNIKOV for x in row] for row in u.matrix], u.gates
226226
)
227+
if not new_u.is_valid():
228+
break
229+
u = new_u
227230
return u
228231

229232
def num_t_gates(self) -> int:

qualtran/rotation_synthesis/protocols/clifford_t_synthesis.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ def _solve(
6262
m = n
6363
real_bound_fn = protocol.make_real_bound_fn(m, config)
6464
if not real_bound_fn(p):
65-
# if verbose:
66-
# print('skip', p)
6765
bad += new
6866
if verbose and bad % 10**5 == 0:
6967
print(f"at {n=}", "seen", bad, "out of", total, "points, ratio =", bad / total)

0 commit comments

Comments
 (0)