def test_rowsum(): # Note: rowsum should not apply on two rows that anti-commute each other. t = cirq.CliffordTableau(num_qubits=2) # XI * IX ==> XX t._rowsum(0, 1) assert t.destabilizers()[0] == cirq.DensePauliString('XX', coefficient=1) # IX * ZI ==> ZX t._rowsum(1, 2) assert t.destabilizers()[1] == cirq.DensePauliString('ZX', coefficient=1) # ZI * IZ ==> ZZ t._rowsum(2, 3) assert t.stabilizers()[0] == cirq.DensePauliString('ZZ', coefficient=1) t = cirq.CliffordTableau(num_qubits=2) _S(t, 0) # Table now are [YI, IX, ZI, IZ] _CNOT(t, 0, 1) # Table now are [YX, IX, ZI, ZZ] # YX * ZZ ==> XY t._rowsum(0, 3) assert t.destabilizers()[0] == cirq.DensePauliString('XY', coefficient=1) # ZZ * XY ==> YX t._rowsum(3, 0) assert t.stabilizers()[1] == cirq.DensePauliString('YX', coefficient=1)
def test_clifford_decompose_two_qubits(): """Two random instance for two qubits decomposition.""" qubits = cirq.LineQubit.range(2) args = cirq.CliffordTableauSimulationState( tableau=cirq.CliffordTableau(num_qubits=2), qubits=qubits, prng=np.random.RandomState() ) cirq.act_on(cirq.H, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.CNOT, args, qubits=[qubits[0], qubits[1]], allow_decompose=False) expect_circ = cirq.Circuit(cirq.H(qubits[0]), cirq.CNOT(qubits[0], qubits[1])) ops = cirq.decompose_clifford_tableau_to_operations(qubits, args.tableau) circ = cirq.Circuit(ops) assert_allclose_up_to_global_phase(cirq.unitary(expect_circ), cirq.unitary(circ), atol=1e-7) qubits = cirq.LineQubit.range(2) args = cirq.CliffordTableauSimulationState( tableau=cirq.CliffordTableau(num_qubits=2), qubits=qubits, prng=np.random.RandomState() ) cirq.act_on(cirq.H, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.CNOT, args, qubits=[qubits[0], qubits[1]], allow_decompose=False) cirq.act_on(cirq.H, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.S, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.X, args, qubits=[qubits[1]], allow_decompose=False) expect_circ = cirq.Circuit( cirq.H(qubits[0]), cirq.CNOT(qubits[0], qubits[1]), cirq.H(qubits[0]), cirq.S(qubits[0]), cirq.X(qubits[1]), ) ops = cirq.decompose_clifford_tableau_to_operations(qubits, args.tableau) circ = cirq.Circuit(ops) assert_allclose_up_to_global_phase(cirq.unitary(expect_circ), cirq.unitary(circ), atol=1e-7)
def test_x_act_on_tableau(): with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(cirq.X, DummySimulationState(), qubits=()) original_tableau = cirq.CliffordTableau(num_qubits=5, initial_state=31) flipped_tableau = cirq.CliffordTableau(num_qubits=5, initial_state=23) state = cirq.CliffordTableauSimulationState( tableau=original_tableau.copy(), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), ) cirq.act_on(cirq.X**0.5, state, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.X**0.5, state, [cirq.LineQubit(1)], allow_decompose=False) assert state.log_of_measurement_results == {} assert state.tableau == flipped_tableau cirq.act_on(cirq.X, state, [cirq.LineQubit(1)], allow_decompose=False) assert state.log_of_measurement_results == {} assert state.tableau == original_tableau cirq.act_on(cirq.X**3.5, state, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.X**3.5, state, [cirq.LineQubit(1)], allow_decompose=False) assert state.log_of_measurement_results == {} assert state.tableau == flipped_tableau cirq.act_on(cirq.X**2, state, [cirq.LineQubit(1)], allow_decompose=False) assert state.log_of_measurement_results == {} assert state.tableau == flipped_tableau foo = sympy.Symbol('foo') with pytest.raises(TypeError, match="Failed to act action on state"): cirq.act_on(cirq.X**foo, state, [cirq.LineQubit(1)])
def test_to_clifford_tableau_util_function(): tableau = cirq.ops.clifford_gate._to_clifford_tableau( x_to=cirq.PauliTransform(to=cirq.X, flip=False), z_to=cirq.PauliTransform(to=cirq.Z, flip=False), ) assert tableau == cirq.CliffordTableau(num_qubits=1, initial_state=0) tableau = cirq.ops.clifford_gate._to_clifford_tableau( x_to=cirq.PauliTransform(to=cirq.X, flip=False), z_to=cirq.PauliTransform(to=cirq.Z, flip=True), ) assert tableau == cirq.CliffordTableau(num_qubits=1, initial_state=1) tableau = cirq.ops.clifford_gate._to_clifford_tableau( rotation_map={ cirq.X: cirq.PauliTransform(to=cirq.X, flip=False), cirq.Z: cirq.PauliTransform(to=cirq.Z, flip=False), } ) assert tableau == cirq.CliffordTableau(num_qubits=1, initial_state=0) tableau = cirq.ops.clifford_gate._to_clifford_tableau( rotation_map={ cirq.X: cirq.PauliTransform(to=cirq.X, flip=False), cirq.Z: cirq.PauliTransform(to=cirq.Z, flip=True), } ) assert tableau == cirq.CliffordTableau(num_qubits=1, initial_state=1) with pytest.raises(ValueError): cirq.ops.clifford_gate._to_clifford_tableau()
def test_stabilizers(): # Note: the stabilizers are not unique for one state. We just use the one # produced by the tableau algorithm. # 1. Final state is |1>: Stabalized by -Z. t = cirq.CliffordTableau(num_qubits=1, initial_state=1) stabilizers = t.stabilizers() assert len(stabilizers) == 1 assert stabilizers[0] == cirq.DensePauliString('Z', coefficient=-1) # 2. EPR pair -- Final state is |00> + |11>: Stabalized by XX and ZZ. t = cirq.CliffordTableau(num_qubits=2) _H(t, 0) _CNOT(t, 0, 1) stabilizers = t.stabilizers() assert len(stabilizers) == 2 assert stabilizers[0] == cirq.DensePauliString('XX', coefficient=1) assert stabilizers[1] == cirq.DensePauliString('ZZ', coefficient=1) # 3. Uniform distribution: Stablized by XI and IX. t = cirq.CliffordTableau(num_qubits=2) _H(t, 0) _H(t, 1) stabilizers = t.stabilizers() assert len(stabilizers) == 2 assert stabilizers[0] == cirq.DensePauliString('XI', coefficient=1) assert stabilizers[1] == cirq.DensePauliString('IX', coefficient=1)
def test_clifford_gate_from_tableau(): t = cirq.CliffordGate.X.clifford_tableau assert cirq.CliffordGate.from_clifford_tableau(t) == cirq.CliffordGate.X t = cirq.CliffordGate.H.clifford_tableau assert cirq.CliffordGate.from_clifford_tableau(t) == cirq.CliffordGate.H t = cirq.CliffordGate.CNOT.clifford_tableau assert cirq.CliffordGate.from_clifford_tableau(t) == cirq.CliffordGate.CNOT with pytest.raises( ValueError, match='Input argument has to be a CliffordTableau instance.'): cirq.SingleQubitCliffordGate.from_clifford_tableau(123) with pytest.raises( ValueError, match="The number of qubit of input tableau should be 1"): t = cirq.CliffordTableau(num_qubits=2) cirq.SingleQubitCliffordGate.from_clifford_tableau(t) with pytest.raises(ValueError): t = cirq.CliffordTableau(num_qubits=1) t.xs = np.array([1, 1]).reshape(2, 1) t.zs = np.array([1, 1 ]).reshape(2, 1) # This violates the sympletic property. cirq.CliffordGate.from_clifford_tableau(t) with pytest.raises( ValueError, match="Input argument has to be a CliffordTableau instance."): cirq.CliffordGate.from_clifford_tableau(1)
def test_clifford_gate_act_on_large_case(): n, num_ops = 50, 1000 # because we don't need unitary, it is fast. gate_candidate = [ cirq.X, cirq.Y, cirq.Z, cirq.H, cirq.S, cirq.CNOT, cirq.CZ ] for seed in range(10): prng = np.random.RandomState(seed) t1 = cirq.CliffordTableau(num_qubits=n) t2 = cirq.CliffordTableau(num_qubits=n) qubits = cirq.LineQubit.range(n) args1 = cirq.ActOnCliffordTableauArgs(tableau=t1, qubits=qubits, prng=prng, log_of_measurement_results={}) args2 = cirq.ActOnCliffordTableauArgs(tableau=t2, qubits=qubits, prng=prng, log_of_measurement_results={}) ops = [] for _ in range(num_ops): g = prng.randint(len(gate_candidate)) indices = (prng.randint(n), ) if g < 5 else prng.choice( n, 2, replace=False) cirq.act_on(gate_candidate[g], args1, qubits=[qubits[i] for i in indices], allow_decompose=False) ops.append(gate_candidate[g].on(*[qubits[i] for i in indices])) compiled_gate = cirq.CliffordGate.from_op_list(ops, qubits) cirq.act_on(compiled_gate, args2, qubits) assert args1.tableau == args2.tableau
def test_pad_tableau(): tableau = cirq.CliffordTableau(num_qubits=1) padded_tableau = cirq.ops.clifford_gate._pad_tableau( tableau, num_qubits_after_padding=2, axes=[0]) assert padded_tableau == cirq.CliffordTableau(num_qubits=2) tableau = cirq.CliffordTableau(num_qubits=1, initial_state=1) padded_tableau = cirq.ops.clifford_gate._pad_tableau( tableau, num_qubits_after_padding=1, axes=[0]) assert padded_tableau == cirq.CliffordGate.X.clifford_tableau # Tableau for H # [0 1 0] # [1 0 0] tableau = cirq.CliffordGate.H.clifford_tableau padded_tableau = cirq.ops.clifford_gate._pad_tableau( tableau, num_qubits_after_padding=2, axes=[0]) # fmt: off np.testing.assert_equal( padded_tableau.matrix().astype(np.int64), np.array([[0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]]), ) # fmt: on np.testing.assert_equal(padded_tableau.rs.astype(np.int64), np.zeros(4)) # The tableau of H again but pad for another ax tableau = cirq.CliffordGate.H.clifford_tableau padded_tableau = cirq.ops.clifford_gate._pad_tableau( tableau, num_qubits_after_padding=2, axes=[1]) # fmt: off np.testing.assert_equal( padded_tableau.matrix().astype(np.int64), np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]]), ) # fmt: on np.testing.assert_equal(padded_tableau.rs.astype(np.int64), np.zeros(4))
def test_destabilizers(): # Note: Like stablizers, the destabilizers are not unique for one state, too. # We just use the one produced by the tableau algorithm. # Under the clifford tableau algorithm, there are several properties that the # destablizers have to satisfy: # 1. destablizers[i] anti-commutes with stablizers[i] # 2. destablizers[i] commutes with destablizers[j] for j!= i # 3. destablizers[i] commutes with stablizers[j] for j!= i # 1. Final state is |1>: Stabalized by -Z. t = cirq.CliffordTableau(num_qubits=1, initial_state=1) destabilizers = t.destabilizers() assert len(destabilizers) == 1 assert destabilizers[0] == cirq.DensePauliString('X', coefficient=1) # 2. EPR pair -- Final state is |00> + |11>: Stabalized by XX and ZZ. t = cirq.CliffordTableau(num_qubits=2) _H(t, 0) _CNOT(t, 0, 1) destabilizers = t.destabilizers() assert len(destabilizers) == 2 assert destabilizers[0] == cirq.DensePauliString('ZI', coefficient=1) assert destabilizers[1] == cirq.DensePauliString('IX', coefficient=1) # 3. Uniform distribution: Stablized by XI and IX. t = cirq.CliffordTableau(num_qubits=2) _H(t, 0) _H(t, 1) destabilizers = t.destabilizers() assert len(destabilizers) == 2 assert destabilizers[0] == cirq.DensePauliString('ZI', coefficient=1) assert destabilizers[1] == cirq.DensePauliString('IZ', coefficient=1)
def test_x_act_on_tableau(): with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(cirq.X, object()) original_tableau = cirq.CliffordTableau(num_qubits=5, initial_state=31) flipped_tableau = cirq.CliffordTableau(num_qubits=5, initial_state=23) args = cirq.ActOnCliffordTableauArgs( tableau=original_tableau.copy(), axes=[1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(cirq.X**0.5, args, allow_decompose=False) cirq.act_on(cirq.X**0.5, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau cirq.act_on(cirq.X, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == original_tableau cirq.act_on(cirq.X**3.5, args, allow_decompose=False) cirq.act_on(cirq.X**3.5, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau cirq.act_on(cirq.X**2, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau foo = sympy.Symbol('foo') with pytest.raises(TypeError, match="Failed to act action on state"): cirq.act_on(cirq.X**foo, args)
def test_unitary_fallback(): class UnitaryXGate(cirq.testing.SingleQubitGate): def _unitary_(self): return np.array([[0, 1], [1, 0]]) class UnitaryYGate(cirq.Gate): def _qid_shape_(self) -> Tuple[int, ...]: return (2, ) def _unitary_(self): return np.array([[0, -1j], [1j, 0]]) original_tableau = cirq.CliffordTableau(num_qubits=3) args = cirq.CliffordTableauSimulationState( tableau=original_tableau.copy(), qubits=cirq.LineQubit.range(3), prng=np.random.RandomState(), ) cirq.act_on(UnitaryXGate(), args, [cirq.LineQubit(1)]) assert args.tableau == cirq.CliffordTableau(num_qubits=3, initial_state=2) args = cirq.CliffordTableauSimulationState( tableau=original_tableau.copy(), qubits=cirq.LineQubit.range(3), prng=np.random.RandomState(), ) cirq.act_on(UnitaryYGate(), args, [cirq.LineQubit(1)]) expected_args = cirq.CliffordTableauSimulationState( tableau=original_tableau.copy(), qubits=cirq.LineQubit.range(3), prng=np.random.RandomState(), ) cirq.act_on(cirq.Y, expected_args, [cirq.LineQubit(1)]) assert args.tableau == expected_args.tableau
def test_clifford_gate_act_on_small_case(): # Note this is also covered by the `from_op_list` one, etc. qubits = cirq.LineQubit.range(5) args = cirq.CliffordTableauSimulationState( tableau=cirq.CliffordTableau(num_qubits=5), qubits=qubits, prng=np.random.RandomState() ) expected_args = cirq.CliffordTableauSimulationState( tableau=cirq.CliffordTableau(num_qubits=5), qubits=qubits, prng=np.random.RandomState() ) cirq.act_on(cirq.H, expected_args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.CliffordGate.H, args, qubits=[qubits[0]], allow_decompose=False) assert args.tableau == expected_args.tableau cirq.act_on(cirq.CNOT, expected_args, qubits=[qubits[0], qubits[1]], allow_decompose=False) cirq.act_on(cirq.CliffordGate.CNOT, args, qubits=[qubits[0], qubits[1]], allow_decompose=False) assert args.tableau == expected_args.tableau cirq.act_on(cirq.H, expected_args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.CliffordGate.H, args, qubits=[qubits[0]], allow_decompose=False) assert args.tableau == expected_args.tableau cirq.act_on(cirq.S, expected_args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.CliffordGate.S, args, qubits=[qubits[0]], allow_decompose=False) assert args.tableau == expected_args.tableau cirq.act_on(cirq.X, expected_args, qubits=[qubits[2]], allow_decompose=False) cirq.act_on(cirq.CliffordGate.X, args, qubits=[qubits[2]], allow_decompose=False) assert args.tableau == expected_args.tableau
def test_clifford_decompose_by_reconstruction(): """Validate the decomposition of random Clifford Tableau by reconstruction. This approach can validate large number of qubits compared with the unitary one. """ n, num_ops = 100, 500 gate_candidate = [cirq.X, cirq.Y, cirq.Z, cirq.H, cirq.S, cirq.CNOT, cirq.CZ] for seed in range(10): prng = np.random.RandomState(seed) t = cirq.CliffordTableau(num_qubits=n) qubits = cirq.LineQubit.range(n) expect_circ = cirq.Circuit() args = cirq.CliffordTableauSimulationState(tableau=t, qubits=qubits, prng=prng) for _ in range(num_ops): g = prng.randint(len(gate_candidate)) indices = (prng.randint(n),) if g < 5 else prng.choice(n, 2, replace=False) cirq.act_on( gate_candidate[g], args, qubits=[qubits[i] for i in indices], allow_decompose=False ) expect_circ.append(gate_candidate[g].on(*[qubits[i] for i in indices])) ops = cirq.decompose_clifford_tableau_to_operations(qubits, args.tableau) reconstruct_t = cirq.CliffordTableau(num_qubits=n) reconstruct_args = cirq.CliffordTableauSimulationState( tableau=reconstruct_t, qubits=qubits, prng=prng ) for op in ops: cirq.act_on(op.gate, reconstruct_args, qubits=op.qubits, allow_decompose=False) assert t == reconstruct_t
def test_tableau_then_with_bad_input(): t1 = cirq.CliffordTableau(1) t2 = cirq.CliffordTableau(2) with pytest.raises(ValueError, match="Mismatched number of qubits of two tableaux: 1 vs 2."): t1.then(t2) with pytest.raises(TypeError): t1.then(cirq.X)
def test_measurement(): repetitions = 500 prng = np.random.RandomState(seed=123456) # 1. The final state is |0> res = [] for _ in range(repetitions): t = cirq.CliffordTableau(num_qubits=1) res.append(t._measure(q=0, prng=prng)) assert all(res) == 0 # 2. The final state is |1> res = [] for _ in range(repetitions): t = cirq.CliffordTableau(num_qubits=1, initial_state=1) res.append(t._measure(q=0, prng=prng)) assert all(res) == 1 # 3. EPR pair -- The final state is |00> + |11> res = [] for _ in range(repetitions): t = cirq.CliffordTableau(num_qubits=2) _H(t, 0) _CNOT(t, 0, 1) res.append(2 * t._measure(q=0, prng=prng) + t._measure(q=1, prng=prng)) assert set(res) == set([0, 3]) assert sum(np.asarray(res) == 0) >= (repetitions / 2 * 0.9) assert sum(np.asarray(res) == 3) >= (repetitions / 2 * 0.9) # 4. Uniform distribution -- The final state is |00> + |01> + |10> + |11> res = [] for _ in range(repetitions): t = cirq.CliffordTableau(num_qubits=2) _H(t, 0) _H(t, 1) res.append(2 * t._measure(q=0, prng=prng) + t._measure(q=1, prng=prng)) assert set(res) == set([0, 1, 2, 3]) assert sum(np.asarray(res) == 0) >= (repetitions / 4 * 0.9) assert sum(np.asarray(res) == 1) >= (repetitions / 4 * 0.9) assert sum(np.asarray(res) == 2) >= (repetitions / 4 * 0.9) assert sum(np.asarray(res) == 3) >= (repetitions / 4 * 0.9) # 5. To cover usage of YY case. The final state is: # 0.5|00⟩ + 0.5j|01⟩ + 0.5j|10⟩ - 0.5|11⟩ res = [] for _ in range(repetitions): t = cirq.CliffordTableau(num_qubits=2) _H(t, 0) _H(t, 1) # [ZI, IZ, XI, IX] _CNOT(t, 0, 1) # [ZI, ZZ, XX, IX] _S(t, 0) # [ZI, ZZ, YX, IX] _S(t, 1) # [ZI, ZZ, YY, IY] res.append(2 * t._measure(q=0, prng=prng) + t._measure(q=1, prng=prng)) assert set(res) == set([0, 1, 2, 3]) assert sum(np.asarray(res) == 0) >= (repetitions / 4 * 0.9) assert sum(np.asarray(res) == 1) >= (repetitions / 4 * 0.9) assert sum(np.asarray(res) == 2) >= (repetitions / 4 * 0.9) assert sum(np.asarray(res) == 3) >= (repetitions / 4 * 0.9)
def test_pad_tableau_bad_input(): with pytest.raises( ValueError, match="Input axes of padding should match with the number of qubits" ): tableau = cirq.CliffordTableau(num_qubits=3) cirq.ops.clifford_gate._pad_tableau(tableau, num_qubits_after_padding=4, axes=[1, 2]) with pytest.raises( ValueError, match='The number of qubits in the input tableau should not be larger than' ): tableau = cirq.CliffordTableau(num_qubits=3) cirq.ops.clifford_gate._pad_tableau(tableau, num_qubits_after_padding=2, axes=[0, 1, 2])
def test_z_h_act_on_tableau(): with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(cirq.Z, DummyActOnArgs(), qubits=()) with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(cirq.H, DummyActOnArgs(), qubits=()) original_tableau = cirq.CliffordTableau(num_qubits=5, initial_state=31) flipped_tableau = cirq.CliffordTableau(num_qubits=5, initial_state=23) args = cirq.ActOnCliffordTableauArgs( tableau=original_tableau.copy(), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(cirq.H, args, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.Z ** 0.5, args, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.Z ** 0.5, args, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.H, args, [cirq.LineQubit(1)], allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau cirq.act_on(cirq.H, args, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.Z, args, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.H, args, [cirq.LineQubit(1)], allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == original_tableau cirq.act_on(cirq.H, args, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.Z ** 3.5, args, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.Z ** 3.5, args, [cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.H, args, [cirq.LineQubit(1)], allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau cirq.act_on(cirq.Z ** 2, args, [cirq.LineQubit(1)], allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau cirq.act_on(cirq.H ** 2, args, [cirq.LineQubit(1)], allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau foo = sympy.Symbol('foo') with pytest.raises(TypeError, match="Failed to act action on state"): cirq.act_on(cirq.Z ** foo, args, [cirq.LineQubit(1)]) with pytest.raises(TypeError, match="Failed to act action on state"): cirq.act_on(cirq.H ** foo, args, [cirq.LineQubit(1)]) with pytest.raises(TypeError, match="Failed to act action on state"): cirq.act_on(cirq.H ** 1.5, args, [cirq.LineQubit(1)])
def test_clifford_decompose_by_unitary(): """Validate the decomposition of random Clifford Tableau by unitary matrix. Due to the exponential growth in dimension, it cannot validate very large number of qubits. """ n, num_ops = 5, 20 gate_candidate = [cirq.X, cirq.Y, cirq.Z, cirq.H, cirq.S, cirq.CNOT, cirq.CZ] for seed in range(100): prng = np.random.RandomState(seed) t = cirq.CliffordTableau(num_qubits=n) qubits = cirq.LineQubit.range(n) expect_circ = cirq.Circuit() args = cirq.CliffordTableauSimulationState(tableau=t, qubits=qubits, prng=prng) for _ in range(num_ops): g = prng.randint(len(gate_candidate)) indices = (prng.randint(n),) if g < 5 else prng.choice(n, 2, replace=False) cirq.act_on( gate_candidate[g], args, qubits=[qubits[i] for i in indices], allow_decompose=False ) expect_circ.append(gate_candidate[g].on(*[qubits[i] for i in indices])) ops = cirq.decompose_clifford_tableau_to_operations(qubits, args.tableau) circ = cirq.Circuit(ops) circ.append(cirq.I.on_each(qubits)) expect_circ.append(cirq.I.on_each(qubits)) assert_allclose_up_to_global_phase(cirq.unitary(expect_circ), cirq.unitary(circ), atol=1e-7)
def test_act_on_tableau(phase): original_tableau = cirq.CliffordTableau(0) args = cirq.ActOnCliffordTableauArgs(original_tableau.copy(), np.random.RandomState(), {}) cirq.act_on(cirq.global_phase_operation(phase), args, allow_decompose=False) assert args.tableau == original_tableau
def test_gate_act_on_tableau(phase): original_tableau = cirq.CliffordTableau(0) args = cirq.ActOnCliffordTableauArgs(original_tableau.copy(), np.random.RandomState(), {}) cirq.act_on(cirq.GlobalPhaseGate(phase), args, qubits=(), allow_decompose=False) assert args.tableau == original_tableau
def test_tableau_initial_state_string(num_qubits): for i in range(2 ** num_qubits): t = cirq.CliffordTableau(initial_state=i, num_qubits=num_qubits) splitted_represent_string = str(t).split('\n') assert len(splitted_represent_string) == num_qubits for n in range(num_qubits): sign = '- ' if i >> (num_qubits - n - 1) & 1 else '+ ' expected_string = sign + 'I ' * n + 'Z ' + 'I ' * (num_qubits - n - 1) assert splitted_represent_string[n] == expected_string
def test_clifford_decompose_one_qubit(): """Two random instance for one qubit decomposition.""" qubits = cirq.LineQubit.range(1) args = cirq.ActOnCliffordTableauArgs( tableau=cirq.CliffordTableau(num_qubits=1), qubits=qubits, prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(cirq.X, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.H, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.S, args, qubits=[qubits[0]], allow_decompose=False) expect_circ = cirq.Circuit(cirq.X(qubits[0]), cirq.H(qubits[0]), cirq.S(qubits[0])) ops = cirq.decompose_clifford_tableau_to_operations(qubits, args.tableau) circ = cirq.Circuit(ops) assert_allclose_up_to_global_phase(cirq.unitary(expect_circ), cirq.unitary(circ), atol=1e-7) qubits = cirq.LineQubit.range(1) args = cirq.ActOnCliffordTableauArgs( tableau=cirq.CliffordTableau(num_qubits=1), qubits=qubits, prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(cirq.Z, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.H, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.S, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.H, args, qubits=[qubits[0]], allow_decompose=False) cirq.act_on(cirq.X, args, qubits=[qubits[0]], allow_decompose=False) expect_circ = cirq.Circuit( cirq.Z(qubits[0]), cirq.H(qubits[0]), cirq.S(qubits[0]), cirq.H(qubits[0]), cirq.X(qubits[0]), ) ops = cirq.decompose_clifford_tableau_to_operations(qubits, args.tableau) circ = cirq.Circuit(ops) assert_allclose_up_to_global_phase(cirq.unitary(expect_circ), cirq.unitary(circ), atol=1e-7)
def test_cz_act_on_equivalent_to_h_cx_h_tableau(): args1 = cirq.ActOnCliffordTableauArgs( tableau=cirq.CliffordTableau(num_qubits=2), qubits=cirq.LineQubit.range(2), prng=np.random.RandomState(), log_of_measurement_results={}, ) args2 = cirq.ActOnCliffordTableauArgs( tableau=cirq.CliffordTableau(num_qubits=2), qubits=cirq.LineQubit.range(2), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(cirq.S, args=args1, qubits=[cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.S, args=args2, qubits=[cirq.LineQubit(1)], allow_decompose=False) # Args1 uses H*CNOT*H cirq.act_on(cirq.H, args=args1, qubits=[cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.CNOT, args=args1, qubits=cirq.LineQubit.range(2), allow_decompose=False) cirq.act_on(cirq.H, args=args1, qubits=[cirq.LineQubit(1)], allow_decompose=False) # Args2 uses CZ cirq.act_on(cirq.CZ, args=args2, qubits=cirq.LineQubit.range(2), allow_decompose=False) assert args1.tableau == args2.tableau
def test_unitary_fallback(): class UnitaryXGate(cirq.Gate): def _num_qubits_(self) -> int: return 1 def _unitary_(self): return np.array([[0, 1], [1, 0]]) class UnitaryYGate(cirq.Gate): def _qid_shape_(self) -> Tuple[int, ...]: return (2, ) def _unitary_(self): return np.array([[0, -1j], [1j, 0]]) original_tableau = cirq.CliffordTableau(num_qubits=3) args = cirq.ActOnCliffordTableauArgs( tableau=original_tableau.copy(), qubits=cirq.LineQubit.range(3), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(UnitaryXGate(), args, [cirq.LineQubit(1)]) assert args.tableau == cirq.CliffordTableau(num_qubits=3, initial_state=2) args = cirq.ActOnCliffordTableauArgs( tableau=original_tableau.copy(), qubits=cirq.LineQubit.range(3), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(UnitaryYGate(), args, [cirq.LineQubit(1)]) expected_args = cirq.ActOnCliffordTableauArgs( tableau=original_tableau.copy(), qubits=cirq.LineQubit.range(3), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(cirq.Y, expected_args, [cirq.LineQubit(1)]) assert args.tableau == expected_args.tableau
def test_validate_tableau(): num_qubits = 4 for i in range(2 ** num_qubits): t = cirq.CliffordTableau(initial_state=i, num_qubits=num_qubits) assert t._validate() t = cirq.CliffordTableau(num_qubits=2) assert t._validate() _H(t, 0) assert t._validate() _X(t, 0) assert t._validate() _Z(t, 1) assert t._validate() _CNOT(t, 0, 1) assert t._validate() _CNOT(t, 1, 0) assert t._validate() t.xs = np.zeros((4, 2)) assert t._validate() == False
def test_act_on_clifford_tableau(): a, b = [cirq.LineQubit(3), cirq.LineQubit(1)] m = cirq.measure(a, b, key='out', invert_mask=(True, ), confusion_map={(1, ): np.array([[0, 1], [1, 0]])}) # The below assertion does not fail since it ignores non-unitary operations cirq.testing.assert_all_implemented_act_on_effects_match_unitary(m) args = cirq.CliffordTableauSimulationState( tableau=cirq.CliffordTableau(num_qubits=5, initial_state=0), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 1]} args = cirq.CliffordTableauSimulationState( tableau=cirq.CliffordTableau(num_qubits=5, initial_state=8), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 0]} args = cirq.CliffordTableauSimulationState( tableau=cirq.CliffordTableau(num_qubits=5, initial_state=10), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), ) cirq.act_on(m, args) datastore = cast(cirq.ClassicalDataDictionaryStore, args.classical_data) out = cirq.MeasurementKey('out') assert args.log_of_measurement_results == {'out': [0, 0]} assert datastore.records[out] == [(0, 0)] cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [0, 0]} assert datastore.records[out] == [(0, 0), (0, 0)]
def test_cz_act_on_equivalent_to_h_cx_h_tableau(): state1 = cirq.CliffordTableauSimulationState( tableau=cirq.CliffordTableau(num_qubits=2), qubits=cirq.LineQubit.range(2), prng=np.random.RandomState(), ) state2 = cirq.CliffordTableauSimulationState( tableau=cirq.CliffordTableau(num_qubits=2), qubits=cirq.LineQubit.range(2), prng=np.random.RandomState(), ) cirq.act_on(cirq.S, sim_state=state1, qubits=[cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.S, sim_state=state2, qubits=[cirq.LineQubit(1)], allow_decompose=False) # state1 uses H*CNOT*H cirq.act_on(cirq.H, sim_state=state1, qubits=[cirq.LineQubit(1)], allow_decompose=False) cirq.act_on(cirq.CNOT, sim_state=state1, qubits=cirq.LineQubit.range(2), allow_decompose=False) cirq.act_on(cirq.H, sim_state=state1, qubits=[cirq.LineQubit(1)], allow_decompose=False) # state2 uses CZ cirq.act_on(cirq.CZ, sim_state=state2, qubits=cirq.LineQubit.range(2), allow_decompose=False) assert state1.tableau == state2.tableau
def test_cannot_act(): class NoDetails: pass args = cirq.ActOnCliffordTableauArgs( tableau=cirq.CliffordTableau(num_qubits=3), axes=[1], prng=np.random.RandomState(), log_of_measurement_results={}) with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(NoDetails(), args)
def test_unitary_fallback(): class UnitaryXGate(cirq.Gate): def num_qubits(self) -> int: return 1 def _unitary_(self): return np.array([[0, 1], [1, 0]]) class UnitaryYGate(cirq.Gate): def num_qubits(self) -> int: return 1 def _unitary_(self): return np.array([[0, -1j], [1j, 0]]) original_tableau = cirq.CliffordTableau(num_qubits=3) args = cirq.ActOnCliffordTableauArgs(tableau=original_tableau.copy(), axes=[1], prng=np.random.RandomState(), log_of_measurement_results={}) cirq.act_on(UnitaryXGate(), args) assert args.tableau == cirq.CliffordTableau(num_qubits=3, initial_state=2) args = cirq.ActOnCliffordTableauArgs(tableau=original_tableau.copy(), axes=[1], prng=np.random.RandomState(), log_of_measurement_results={}) cirq.act_on(UnitaryYGate(), args) expected_args = cirq.ActOnCliffordTableauArgs( tableau=original_tableau.copy(), axes=[1], prng=np.random.RandomState(), log_of_measurement_results={}) cirq.act_on(cirq.Y, expected_args) assert args.tableau == expected_args.tableau
def test_act_on_clifford_tableau(): a, b = cirq.LineQubit.range(2) m = cirq.measure(a, b, key='out', invert_mask=(True, )) # The below assertion does not fail since it ignores non-unitary operations cirq.testing.assert_all_implemented_act_on_effects_match_unitary(m) with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(m, object()) args = cirq.ActOnCliffordTableauArgs( tableau=cirq.CliffordTableau(num_qubits=5, initial_state=0), axes=[3, 1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 0]} args = cirq.ActOnCliffordTableauArgs( tableau=cirq.CliffordTableau(num_qubits=5, initial_state=8), axes=[3, 1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 1]} args = cirq.ActOnCliffordTableauArgs( tableau=cirq.CliffordTableau(num_qubits=5, initial_state=10), axes=[3, 1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [0, 1]} with pytest.raises(ValueError, match="already logged to key"): cirq.act_on(m, args)