1# Copyright 2018 The Cirq Developers 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15import functools 16import itertools 17 18import numpy as np 19import pytest 20 21import cirq 22from cirq.testing import ( 23 EqualsTester, 24 assert_allclose_up_to_global_phase, 25) 26 27_bools = (False, True) 28_paulis = (cirq.X, cirq.Y, cirq.Z) 29 30 31def _assert_not_mirror(gate) -> None: 32 trans_x = gate.transform(cirq.X) 33 trans_y = gate.transform(cirq.Y) 34 trans_z = gate.transform(cirq.Z) 35 right_handed = ( 36 trans_x.flip ^ trans_y.flip ^ trans_z.flip ^ (trans_x.to.relative_index(trans_y.to) != 1) 37 ) 38 assert right_handed, 'Mirrors' 39 40 41def _assert_no_collision(gate) -> None: 42 trans_x = gate.transform(cirq.X) 43 trans_y = gate.transform(cirq.Y) 44 trans_z = gate.transform(cirq.Z) 45 assert trans_x.to != trans_y.to, 'Collision' 46 assert trans_y.to != trans_z.to, 'Collision' 47 assert trans_z.to != trans_x.to, 'Collision' 48 49 50def _all_rotations(): 51 for ( 52 pauli, 53 flip, 54 ) in itertools.product(_paulis, _bools): 55 yield cirq.PauliTransform(pauli, flip) 56 57 58def _all_rotation_pairs(): 59 for px, flip_x, pz, flip_z in itertools.product(_paulis, _bools, _paulis, _bools): 60 if px == pz: 61 continue 62 yield cirq.PauliTransform(px, flip_x), cirq.PauliTransform(pz, flip_z) 63 64 65def _all_clifford_gates(): 66 for trans_x, trans_z in _all_rotation_pairs(): 67 yield cirq.SingleQubitCliffordGate.from_xz_map(trans_x, trans_z) 68 69 70@pytest.mark.parametrize('pauli,flip_x,flip_z', itertools.product(_paulis, _bools, _bools)) 71def test_init_value_error(pauli, flip_x, flip_z): 72 with pytest.raises(ValueError): 73 cirq.SingleQubitCliffordGate.from_xz_map((pauli, flip_x), (pauli, flip_z)) 74 75 76@pytest.mark.parametrize('trans_x,trans_z', _all_rotation_pairs()) 77def test_init_from_xz(trans_x, trans_z): 78 gate = cirq.SingleQubitCliffordGate.from_xz_map(trans_x, trans_z) 79 assert gate.transform(cirq.X) == trans_x 80 assert gate.transform(cirq.Z) == trans_z 81 _assert_not_mirror(gate) 82 _assert_no_collision(gate) 83 84 85@pytest.mark.parametrize( 86 'trans1,trans2,from1', 87 ( 88 (trans1, trans2, from1) 89 for trans1, trans2, from1 in itertools.product(_all_rotations(), _all_rotations(), _paulis) 90 if trans1.to != trans2.to 91 ), 92) 93def test_init_from_double_map_vs_kwargs(trans1, trans2, from1): 94 from2 = cirq.Pauli.by_relative_index(from1, 1) 95 from1_str, from2_str = (str(frm).lower() + '_to' for frm in (from1, from2)) 96 gate_kw = cirq.SingleQubitCliffordGate.from_double_map(**{from1_str: trans1, from2_str: trans2}) 97 gate_map = cirq.SingleQubitCliffordGate.from_double_map({from1: trans1, from2: trans2}) 98 # Test initializes the same gate 99 assert gate_kw == gate_map 100 101 # Test initializes what was expected 102 assert gate_map.transform(from1) == trans1 103 assert gate_map.transform(from2) == trans2 104 _assert_not_mirror(gate_map) 105 _assert_no_collision(gate_map) 106 107 108@pytest.mark.parametrize( 109 'trans1,from1', 110 ((trans1, from1) for trans1, from1 in itertools.product(_all_rotations(), _paulis)), 111) 112def test_init_from_double_invalid(trans1, from1): 113 from2 = cirq.Pauli.by_relative_index(from1, 1) 114 # Test throws on invalid arguments 115 with pytest.raises(ValueError): 116 cirq.SingleQubitCliffordGate.from_double_map({from1: trans1, from2: trans1}) 117 118 119@pytest.mark.parametrize('trans,frm', itertools.product(_all_rotations(), _paulis)) 120def test_init_from_single_map_vs_kwargs(trans, frm): 121 from_str = str(frm).lower() + '_to' 122 # pylint: disable=unexpected-keyword-arg 123 gate_kw = cirq.SingleQubitCliffordGate.from_single_map(**{from_str: trans}) 124 gate_map = cirq.SingleQubitCliffordGate.from_single_map({frm: trans}) 125 assert gate_kw == gate_map 126 127 128@pytest.mark.parametrize( 129 'trans,frm', 130 ( 131 (trans, frm) 132 for trans, frm in itertools.product(_all_rotations(), _paulis) 133 if trans.to != frm 134 ), 135) 136def test_init_90rot_from_single(trans, frm): 137 gate = cirq.SingleQubitCliffordGate.from_single_map({frm: trans}) 138 assert gate.transform(frm) == trans 139 _assert_not_mirror(gate) 140 _assert_no_collision(gate) 141 # Check that it decomposes to one gate 142 assert len(gate.decompose_rotation()) == 1 143 # Check that this is a 90 degree rotation gate 144 assert ( 145 gate.merged_with(gate).merged_with(gate).merged_with(gate) == cirq.SingleQubitCliffordGate.I 146 ) 147 # Check that flipping the transform produces the inverse rotation 148 trans_rev = cirq.PauliTransform(trans.to, not trans.flip) 149 gate_rev = cirq.SingleQubitCliffordGate.from_single_map({frm: trans_rev}) 150 assert gate ** -1 == gate_rev 151 152 153@pytest.mark.parametrize( 154 'trans,frm', 155 ( 156 (trans, frm) 157 for trans, frm in itertools.product(_all_rotations(), _paulis) 158 if trans.to == frm and trans.flip 159 ), 160) 161def test_init_180rot_from_single(trans, frm): 162 gate = cirq.SingleQubitCliffordGate.from_single_map({frm: trans}) 163 assert gate.transform(frm) == trans 164 _assert_not_mirror(gate) 165 _assert_no_collision(gate) 166 # Check that it decomposes to one gate 167 assert len(gate.decompose_rotation()) == 1 168 # Check that this is a 180 degree rotation gate 169 assert gate.merged_with(gate) == cirq.SingleQubitCliffordGate.I 170 171 172@pytest.mark.parametrize( 173 'trans,frm', 174 ( 175 (trans, frm) 176 for trans, frm in itertools.product(_all_rotations(), _paulis) 177 if trans.to == frm and not trans.flip 178 ), 179) 180def test_init_ident_from_single(trans, frm): 181 gate = cirq.SingleQubitCliffordGate.from_single_map({frm: trans}) 182 assert gate.transform(frm) == trans 183 _assert_not_mirror(gate) 184 _assert_no_collision(gate) 185 # Check that it decomposes to zero gates 186 assert len(gate.decompose_rotation()) == 0 187 # Check that this is an identity gate 188 assert gate == cirq.SingleQubitCliffordGate.I 189 190 191@pytest.mark.parametrize( 192 'pauli,sqrt,expected', 193 ( 194 (cirq.X, False, cirq.SingleQubitCliffordGate.X), 195 (cirq.Y, False, cirq.SingleQubitCliffordGate.Y), 196 (cirq.Z, False, cirq.SingleQubitCliffordGate.Z), 197 (cirq.X, True, cirq.SingleQubitCliffordGate.X_sqrt), 198 (cirq.Y, True, cirq.SingleQubitCliffordGate.Y_sqrt), 199 (cirq.Z, True, cirq.SingleQubitCliffordGate.Z_sqrt), 200 ), 201) 202def test_init_from_pauli(pauli, sqrt, expected): 203 gate = cirq.SingleQubitCliffordGate.from_pauli(pauli, sqrt=sqrt) 204 assert gate == expected 205 206 207def test_pow(): 208 assert cirq.SingleQubitCliffordGate.X ** -1 == cirq.SingleQubitCliffordGate.X 209 assert cirq.SingleQubitCliffordGate.H ** -1 == cirq.SingleQubitCliffordGate.H 210 assert cirq.SingleQubitCliffordGate.X_sqrt == cirq.SingleQubitCliffordGate.X ** 0.5 211 assert cirq.SingleQubitCliffordGate.Y_sqrt == cirq.SingleQubitCliffordGate.Y ** 0.5 212 assert cirq.SingleQubitCliffordGate.Z_sqrt == cirq.SingleQubitCliffordGate.Z ** 0.5 213 assert cirq.SingleQubitCliffordGate.X_nsqrt == cirq.SingleQubitCliffordGate.X ** -0.5 214 assert cirq.SingleQubitCliffordGate.Y_nsqrt == cirq.SingleQubitCliffordGate.Y ** -0.5 215 assert cirq.SingleQubitCliffordGate.Z_nsqrt == cirq.SingleQubitCliffordGate.Z ** -0.5 216 assert cirq.SingleQubitCliffordGate.X_sqrt ** -1 == cirq.SingleQubitCliffordGate.X_nsqrt 217 assert cirq.inverse(cirq.SingleQubitCliffordGate.X_nsqrt) == ( 218 cirq.SingleQubitCliffordGate.X_sqrt 219 ) 220 with pytest.raises(TypeError): 221 _ = cirq.SingleQubitCliffordGate.Z ** 0.25 222 223 224def test_init_from_quarter_turns(): 225 eq = cirq.testing.EqualsTester() 226 eq.add_equality_group( 227 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 0), 228 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Y, 0), 229 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Z, 0), 230 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 4), 231 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Y, 4), 232 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Z, 4), 233 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 8), 234 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Y, 8), 235 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Z, 8), 236 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, -4), 237 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Y, -4), 238 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Z, -4), 239 ) 240 eq.add_equality_group( 241 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 1), 242 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 5), 243 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 9), 244 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, -3), 245 ) 246 eq.add_equality_group( 247 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Y, 1), 248 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Y, 5), 249 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Y, 9), 250 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Y, -3), 251 ) 252 eq.add_equality_group( 253 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Z, 1), 254 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Z, 5), 255 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Z, 9), 256 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.Z, -3), 257 ) 258 eq.add_equality_group( 259 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 2), 260 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 6), 261 ) 262 eq.add_equality_group( 263 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 3), 264 cirq.SingleQubitCliffordGate.from_quarter_turns(cirq.X, 7), 265 ) 266 267 268@pytest.mark.parametrize('gate', _all_clifford_gates()) 269def test_init_from_quarter_turns_reconstruct(gate): 270 new_gate = functools.reduce( 271 cirq.SingleQubitCliffordGate.merged_with, 272 ( 273 cirq.SingleQubitCliffordGate.from_quarter_turns(pauli, qt) 274 for pauli, qt in gate.decompose_rotation() 275 ), 276 cirq.SingleQubitCliffordGate.I, 277 ) 278 assert gate == new_gate 279 280 281def test_init_invalid(): 282 with pytest.raises(ValueError): 283 cirq.SingleQubitCliffordGate.from_single_map() 284 with pytest.raises(ValueError): 285 cirq.SingleQubitCliffordGate.from_single_map({}) 286 with pytest.raises(ValueError): 287 cirq.SingleQubitCliffordGate.from_single_map( 288 {cirq.X: (cirq.X, False)}, y_to=(cirq.Y, False) 289 ) 290 with pytest.raises(ValueError): 291 cirq.SingleQubitCliffordGate.from_single_map( 292 {cirq.X: (cirq.X, False), cirq.Y: (cirq.Y, False)} 293 ) 294 with pytest.raises(ValueError): 295 cirq.SingleQubitCliffordGate.from_double_map() 296 with pytest.raises(ValueError): 297 cirq.SingleQubitCliffordGate.from_double_map({}) 298 with pytest.raises(ValueError): 299 cirq.SingleQubitCliffordGate.from_double_map({cirq.X: (cirq.X, False)}) 300 with pytest.raises(ValueError): 301 cirq.SingleQubitCliffordGate.from_double_map(x_to=(cirq.X, False)) 302 with pytest.raises(ValueError): 303 cirq.SingleQubitCliffordGate.from_single_map( 304 {cirq.X: (cirq.Y, False), cirq.Y: (cirq.Z, False), cirq.Z: (cirq.X, False)} 305 ) 306 with pytest.raises(ValueError): 307 cirq.SingleQubitCliffordGate.from_single_map( 308 {cirq.X: (cirq.X, False), cirq.Y: (cirq.X, False)} 309 ) 310 311 312def test_eq_ne_and_hash(): 313 eq = EqualsTester() 314 for trans_x, trans_z in _all_rotation_pairs(): 315 gate_gen = lambda: cirq.SingleQubitCliffordGate.from_xz_map(trans_x, trans_z) 316 eq.make_equality_group(gate_gen) 317 318 319@pytest.mark.parametrize( 320 'gate,rep', 321 ( 322 (cirq.SingleQubitCliffordGate.I, 'cirq.SingleQubitCliffordGate(X:+X, Y:+Y, Z:+Z)'), 323 (cirq.SingleQubitCliffordGate.H, 'cirq.SingleQubitCliffordGate(X:+Z, Y:-Y, Z:+X)'), 324 (cirq.SingleQubitCliffordGate.X, 'cirq.SingleQubitCliffordGate(X:+X, Y:-Y, Z:-Z)'), 325 (cirq.SingleQubitCliffordGate.X_sqrt, 'cirq.SingleQubitCliffordGate(X:+X, Y:+Z, Z:-Y)'), 326 ), 327) 328def test_repr(gate, rep): 329 assert repr(gate) == rep 330 331 332@pytest.mark.parametrize( 333 'gate,trans_y', 334 ( 335 (cirq.SingleQubitCliffordGate.I, (cirq.Y, False)), 336 (cirq.SingleQubitCliffordGate.H, (cirq.Y, True)), 337 (cirq.SingleQubitCliffordGate.X, (cirq.Y, True)), 338 (cirq.SingleQubitCliffordGate.Y, (cirq.Y, False)), 339 (cirq.SingleQubitCliffordGate.Z, (cirq.Y, True)), 340 (cirq.SingleQubitCliffordGate.X_sqrt, (cirq.Z, False)), 341 (cirq.SingleQubitCliffordGate.X_nsqrt, (cirq.Z, True)), 342 (cirq.SingleQubitCliffordGate.Y_sqrt, (cirq.Y, False)), 343 (cirq.SingleQubitCliffordGate.Y_nsqrt, (cirq.Y, False)), 344 (cirq.SingleQubitCliffordGate.Z_sqrt, (cirq.X, True)), 345 (cirq.SingleQubitCliffordGate.Z_nsqrt, (cirq.X, False)), 346 ), 347) 348def test_y_rotation(gate, trans_y): 349 assert gate.transform(cirq.Y) == trans_y 350 351 352@pytest.mark.parametrize( 353 'gate,gate_equiv', 354 ( 355 (cirq.SingleQubitCliffordGate.I, cirq.X ** 0), 356 (cirq.SingleQubitCliffordGate.H, cirq.H), 357 (cirq.SingleQubitCliffordGate.X, cirq.X), 358 (cirq.SingleQubitCliffordGate.Y, cirq.Y), 359 (cirq.SingleQubitCliffordGate.Z, cirq.Z), 360 (cirq.SingleQubitCliffordGate.X_sqrt, cirq.X ** 0.5), 361 (cirq.SingleQubitCliffordGate.X_nsqrt, cirq.X ** -0.5), 362 (cirq.SingleQubitCliffordGate.Y_sqrt, cirq.Y ** 0.5), 363 (cirq.SingleQubitCliffordGate.Y_nsqrt, cirq.Y ** -0.5), 364 (cirq.SingleQubitCliffordGate.Z_sqrt, cirq.Z ** 0.5), 365 (cirq.SingleQubitCliffordGate.Z_nsqrt, cirq.Z ** -0.5), 366 ), 367) 368def test_decompose(gate, gate_equiv): 369 q0 = cirq.NamedQubit('q0') 370 mat = cirq.Circuit(gate(q0)).unitary() 371 mat_check = cirq.Circuit( 372 gate_equiv(q0), 373 ).unitary() 374 assert_allclose_up_to_global_phase(mat, mat_check, rtol=1e-7, atol=1e-7) 375 376 377@pytest.mark.parametrize( 378 'gate,gate_equiv', 379 ( 380 (cirq.SingleQubitCliffordGate.I, cirq.X ** 0), 381 (cirq.SingleQubitCliffordGate.H, cirq.H), 382 (cirq.SingleQubitCliffordGate.X, cirq.X), 383 (cirq.SingleQubitCliffordGate.Y, cirq.Y), 384 (cirq.SingleQubitCliffordGate.Z, cirq.Z), 385 (cirq.SingleQubitCliffordGate.X_sqrt, cirq.X ** 0.5), 386 (cirq.SingleQubitCliffordGate.X_nsqrt, cirq.X ** -0.5), 387 (cirq.SingleQubitCliffordGate.Y_sqrt, cirq.Y ** 0.5), 388 (cirq.SingleQubitCliffordGate.Y_nsqrt, cirq.Y ** -0.5), 389 (cirq.SingleQubitCliffordGate.Z_sqrt, cirq.Z ** 0.5), 390 (cirq.SingleQubitCliffordGate.Z_nsqrt, cirq.Z ** -0.5), 391 ), 392) 393def test_known_matrix(gate, gate_equiv): 394 assert cirq.has_unitary(gate) 395 mat = cirq.unitary(gate) 396 mat_check = cirq.unitary(gate_equiv) 397 assert_allclose_up_to_global_phase(mat, mat_check, rtol=1e-7, atol=1e-7) 398 399 400@pytest.mark.parametrize('gate', _all_clifford_gates()) 401def test_inverse(gate): 402 assert gate == cirq.inverse(cirq.inverse(gate)) 403 404 405@pytest.mark.parametrize('gate', _all_clifford_gates()) 406def test_inverse_matrix(gate): 407 q0 = cirq.NamedQubit('q0') 408 mat = cirq.Circuit(gate(q0)).unitary() 409 mat_inv = cirq.Circuit(cirq.inverse(gate)(q0)).unitary() 410 assert_allclose_up_to_global_phase(mat, mat_inv.T.conj(), rtol=1e-7, atol=1e-7) 411 412 413def test_commutes_notimplemented_type(): 414 with pytest.raises(TypeError): 415 cirq.commutes(cirq.SingleQubitCliffordGate.X, 'X') 416 assert cirq.commutes(cirq.SingleQubitCliffordGate.X, 'X', default='default') == 'default' 417 418 419@pytest.mark.parametrize( 420 'gate,other', itertools.product(_all_clifford_gates(), _all_clifford_gates()) 421) 422def test_commutes_single_qubit_gate(gate, other): 423 q0 = cirq.NamedQubit('q0') 424 gate_op = gate(q0) 425 other_op = other(q0) 426 mat = cirq.Circuit( 427 gate_op, 428 other_op, 429 ).unitary() 430 mat_swap = cirq.Circuit( 431 other_op, 432 gate_op, 433 ).unitary() 434 commutes = cirq.commutes(gate, other) 435 commutes_check = cirq.allclose_up_to_global_phase(mat, mat_swap) 436 assert commutes == commutes_check 437 438 # Test after switching order 439 mat_swap = cirq.Circuit( 440 gate.equivalent_gate_before(other)(q0), 441 gate_op, 442 ).unitary() 443 assert_allclose_up_to_global_phase(mat, mat_swap, rtol=1e-7, atol=1e-7) 444 445 446@pytest.mark.parametrize('gate', _all_clifford_gates()) 447def test_parses_single_qubit_gate(gate): 448 assert gate == cirq.read_json(json_text=(cirq.to_json(gate))) 449 450 451@pytest.mark.parametrize( 452 'gate,pauli,half_turns', 453 itertools.product(_all_clifford_gates(), _paulis, (1.0, 0.25, 0.5, -0.5)), 454) 455def test_commutes_pauli(gate, pauli, half_turns): 456 # TODO(#4328) cirq.X**1 should be _PauliX instead of XPowGate 457 pauli_gate = pauli if half_turns == 1 else pauli ** half_turns 458 q0 = cirq.NamedQubit('q0') 459 mat = cirq.Circuit( 460 gate(q0), 461 pauli_gate(q0), 462 ).unitary() 463 mat_swap = cirq.Circuit( 464 pauli_gate(q0), 465 gate(q0), 466 ).unitary() 467 commutes = cirq.commutes(gate, pauli_gate) 468 commutes_check = np.allclose(mat, mat_swap) 469 assert commutes == commutes_check, f"gate: {gate}, pauli {pauli}" 470 471 472def test_to_clifford_tableau_util_function(): 473 474 tableau = cirq.ops.clifford_gate._to_clifford_tableau( 475 x_to=cirq.PauliTransform(to=cirq.X, flip=False), 476 z_to=cirq.PauliTransform(to=cirq.Z, flip=False), 477 ) 478 assert tableau == cirq.CliffordTableau(num_qubits=1, initial_state=0) 479 480 tableau = cirq.ops.clifford_gate._to_clifford_tableau( 481 x_to=cirq.PauliTransform(to=cirq.X, flip=False), 482 z_to=cirq.PauliTransform(to=cirq.Z, flip=True), 483 ) 484 assert tableau == cirq.CliffordTableau(num_qubits=1, initial_state=1) 485 486 tableau = cirq.ops.clifford_gate._to_clifford_tableau( 487 rotation_map={ 488 cirq.X: cirq.PauliTransform(to=cirq.X, flip=False), 489 cirq.Z: cirq.PauliTransform(to=cirq.Z, flip=False), 490 } 491 ) 492 assert tableau == cirq.CliffordTableau(num_qubits=1, initial_state=0) 493 494 tableau = cirq.ops.clifford_gate._to_clifford_tableau( 495 rotation_map={ 496 cirq.X: cirq.PauliTransform(to=cirq.X, flip=False), 497 cirq.Z: cirq.PauliTransform(to=cirq.Z, flip=True), 498 } 499 ) 500 assert tableau == cirq.CliffordTableau(num_qubits=1, initial_state=1) 501 502 with pytest.raises(ValueError): 503 cirq.ops.clifford_gate._to_clifford_tableau() 504 505 506@pytest.mark.parametrize( 507 'gate,sym,exp', 508 ( 509 (cirq.SingleQubitCliffordGate.I, 'I', 1), 510 (cirq.SingleQubitCliffordGate.H, 'H', 1), 511 (cirq.SingleQubitCliffordGate.X, 'X', 1), 512 (cirq.SingleQubitCliffordGate.X_sqrt, 'X', 0.5), 513 (cirq.SingleQubitCliffordGate.X_nsqrt, 'X', -0.5), 514 ( 515 cirq.SingleQubitCliffordGate.from_xz_map((cirq.Y, False), (cirq.X, True)), 516 '(X^-0.5-Z^0.5)', 517 1, 518 ), 519 ), 520) 521def test_text_diagram_info(gate, sym, exp): 522 assert cirq.circuit_diagram_info(gate) == cirq.CircuitDiagramInfo( 523 wire_symbols=(sym,), exponent=exp 524 ) 525 526 527def test_from_unitary(): 528 def _test(clifford_gate): 529 u = cirq.unitary(clifford_gate) 530 result_gate = cirq.SingleQubitCliffordGate.from_unitary(u) 531 assert result_gate == clifford_gate 532 533 _test(cirq.SingleQubitCliffordGate.I) 534 _test(cirq.SingleQubitCliffordGate.H) 535 _test(cirq.SingleQubitCliffordGate.X) 536 _test(cirq.SingleQubitCliffordGate.Y) 537 _test(cirq.SingleQubitCliffordGate.Z) 538 _test(cirq.SingleQubitCliffordGate.X_nsqrt) 539 540 541def test_from_unitary_with_phase_shift(): 542 u = np.exp(0.42j) * cirq.unitary(cirq.SingleQubitCliffordGate.Y_sqrt) 543 gate = cirq.SingleQubitCliffordGate.from_unitary(u) 544 545 assert gate == cirq.SingleQubitCliffordGate.Y_sqrt 546 547 548def test_from_unitary_not_clifford(): 549 # Not a single-qubit gate. 550 u = cirq.unitary(cirq.CNOT) 551 assert cirq.SingleQubitCliffordGate.from_unitary(u) is None 552 553 # Not an unitary matrix. 554 u = 2 * cirq.unitary(cirq.X) 555 assert cirq.SingleQubitCliffordGate.from_unitary(u) is None 556 557 # Not a Clifford gate. 558 u = cirq.unitary(cirq.T) 559 assert cirq.SingleQubitCliffordGate.from_unitary(u) is None 560 561 562@pytest.mark.parametrize('trans_x,trans_z', _all_rotation_pairs()) 563def test_to_phased_xz_gate(trans_x, trans_z): 564 gate = cirq.SingleQubitCliffordGate.from_xz_map(trans_x, trans_z) 565 actual_phased_xz_gate = gate.to_phased_xz_gate()._canonical() 566 expect_phased_xz_gates = cirq.PhasedXZGate.from_matrix(cirq.unitary(gate)) 567 568 assert np.isclose(actual_phased_xz_gate.x_exponent, expect_phased_xz_gates.x_exponent) 569 assert np.isclose(actual_phased_xz_gate.z_exponent, expect_phased_xz_gates.z_exponent) 570 assert np.isclose( 571 actual_phased_xz_gate.axis_phase_exponent, expect_phased_xz_gates.axis_phase_exponent 572 ) 573 574 575def test_from_xz_to_clifford_tableau(): 576 seen_tableau = [] 577 for trans_x, trans_z in _all_rotation_pairs(): 578 tableau = cirq.SingleQubitCliffordGate.from_xz_map(trans_x, trans_z).clifford_tableau 579 tableau_number = sum(2 ** i * t for i, t in enumerate(tableau.matrix().ravel())) 580 tableau_number = tableau_number * 4 + 2 * tableau.rs[0] + tableau.rs[1] 581 seen_tableau.append(tableau_number) 582 # Satisfy the symplectic property 583 assert sum(tableau.matrix()[0, :2] * tableau.matrix()[1, 1::-1]) % 2 == 1 584 585 # Should not have any duplication. 586 assert len(set(seen_tableau)) == 24 587