def test_decomposed_fallback(): class Composite(cirq.Gate): def num_qubits(self) -> int: return 1 def _decompose_(self, qubits): yield cirq.X(*qubits) args = cirq.StateVectorSimulationState( available_buffer=np.empty((2, 2, 2), dtype=np.complex64), qubits=cirq.LineQubit.range(3), prng=np.random.RandomState(), initial_state=cirq.one_hot(shape=(2, 2, 2), dtype=np.complex64), dtype=np.complex64, ) cirq.act_on(Composite(), args, [cirq.LineQubit(1)]) np.testing.assert_allclose( args.target_tensor, cirq.one_hot(index=(0, 1, 0), shape=(2, 2, 2), dtype=np.complex64))
def test_decomposed_fallback(): class Composite(cirq.Gate): def num_qubits(self) -> int: return 1 def _decompose_(self, qubits): yield cirq.X(*qubits) args = cirq.ActOnStateVectorArgs( target_tensor=cirq.one_hot(shape=(2, 2, 2), dtype=np.complex64), available_buffer=np.empty((2, 2, 2), dtype=np.complex64), axes=[1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(Composite(), args) np.testing.assert_allclose( args.target_tensor, cirq.one_hot(index=(0, 1, 0), shape=(2, 2, 2), dtype=np.complex64))
def test_reset_act_on(): with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(cirq.ResetChannel(), DummyActOnArgs(), qubits=()) args = cirq.ActOnStateVectorArgs( available_buffer=np.empty(shape=(2, 2, 2, 2, 2), dtype=np.complex64), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), log_of_measurement_results={}, initial_state=cirq.one_hot(index=(1, 1, 1, 1, 1), shape=(2, 2, 2, 2, 2), dtype=np.complex64), dtype=np.complex64, ) cirq.act_on(cirq.ResetChannel(), args, [cirq.LineQubit(1)]) assert args.log_of_measurement_results == {} np.testing.assert_allclose( args.target_tensor, cirq.one_hot(index=(1, 0, 1, 1, 1), shape=(2, 2, 2, 2, 2), dtype=np.complex64), ) cirq.act_on(cirq.ResetChannel(), args, [cirq.LineQubit(1)]) assert args.log_of_measurement_results == {} np.testing.assert_allclose( args.target_tensor, cirq.one_hot(index=(1, 0, 1, 1, 1), shape=(2, 2, 2, 2, 2), dtype=np.complex64), )
def test_reset_act_on(): with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(cirq.ResetChannel(), object()) args = cirq.ActOnStateVectorArgs( target_tensor=cirq.one_hot(index=(1, 1, 1, 1, 1), shape=(2, 2, 2, 2, 2), dtype=np.complex64), available_buffer=np.empty(shape=(2, 2, 2, 2, 2)), axes=[1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(cirq.ResetChannel(), args) assert args.log_of_measurement_results == {} np.testing.assert_allclose( args.target_tensor, cirq.one_hot(index=(1, 0, 1, 1, 1), shape=(2, 2, 2, 2, 2), dtype=np.complex64), ) cirq.act_on(cirq.ResetChannel(), args) assert args.log_of_measurement_results == {} np.testing.assert_allclose( args.target_tensor, cirq.one_hot(index=(1, 0, 1, 1, 1), shape=(2, 2, 2, 2, 2), dtype=np.complex64), )
def test_tagged_act_on(): class YesActOn(cirq.Gate): def _num_qubits_(self) -> int: return 1 def _act_on_(self, args): return True class NoActOn(cirq.Gate): def _num_qubits_(self) -> int: return 1 def _act_on_(self, args): return NotImplemented class MissingActOn(cirq.Operation): def with_qubits(self, *new_qubits): raise NotImplementedError() @property def qubits(self): raise NotImplementedError() q = cirq.LineQubit(1) cirq.act_on(YesActOn()(q).with_tags("test"), object()) with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(NoActOn()(q).with_tags("test"), object()) with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(MissingActOn().with_tags("test"), object())
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_tagged_act_on(): class YesActOn(cirq.Gate): def _num_qubits_(self) -> int: return 1 def _act_on_(self, args, qubits): return True class NoActOn(cirq.Gate): def _num_qubits_(self) -> int: return 1 def _act_on_(self, args, qubits): return NotImplemented class MissingActOn(cirq.Operation): def with_qubits(self, *new_qubits): raise NotImplementedError() @property def qubits(self): pass q = cirq.LineQubit(1) from cirq.protocols.act_on_protocol_test import DummyActOnArgs args = DummyActOnArgs() cirq.act_on(YesActOn()(q).with_tags("test"), args) with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(NoActOn()(q).with_tags("test"), args) with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(MissingActOn().with_tags("test"), args)
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)
def test_probability_comes_up_short_results_in_fallback(): class Short(cirq.Gate): def num_qubits(self) -> int: return 1 def _kraus_(self): return [cirq.unitary(cirq.X) * np.sqrt(0.999), np.eye(2) * 0] mock_prng = mock.Mock() mock_prng.random.return_value = 0.9999 args = cirq.StateVectorSimulationState( available_buffer=np.empty(2, dtype=np.complex64), qubits=cirq.LineQubit.range(1), prng=mock_prng, initial_state=np.array([1, 0], dtype=np.complex64), dtype=np.complex64, ) cirq.act_on(Short(), args, cirq.LineQubit.range(1)) np.testing.assert_allclose(args.target_tensor, np.array([0, 1]))
def test_unitary_fallback_h(): class UnitaryHGate(cirq.Gate): def num_qubits(self) -> int: return 1 def _unitary_(self): return np.array([[1, 1], [1, -1]]) / (2**0.5) args = cirq.ActOnStabilizerCHFormArgs( qubits=cirq.LineQubit.range(3), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(UnitaryHGate(), args, [cirq.LineQubit(1)]) expected_args = cirq.ActOnStabilizerCHFormArgs( qubits=cirq.LineQubit.range(3), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(cirq.H, expected_args, [cirq.LineQubit(1)]) np.testing.assert_allclose(args.state.state_vector(), expected_args.state.state_vector())
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.CliffordTableauSimulationState(tableau=t1, qubits=qubits, prng=prng) args2 = cirq.CliffordTableauSimulationState(tableau=t2, qubits=qubits, prng=prng) ops = [] for _ in range(0, num_ops, 100): 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_act_on_state_vector(): 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]])}) args = cirq.StateVectorSimulationState( available_buffer=np.empty(shape=(2, 2, 2, 2, 2)), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), initial_state=cirq.one_hot(shape=(2, 2, 2, 2, 2), dtype=np.complex64), dtype=np.complex64, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 1]} args = cirq.StateVectorSimulationState( available_buffer=np.empty(shape=(2, 2, 2, 2, 2)), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), initial_state=cirq.one_hot(index=(0, 1, 0, 0, 0), shape=(2, 2, 2, 2, 2), dtype=np.complex64), dtype=np.complex64, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 0]} args = cirq.StateVectorSimulationState( available_buffer=np.empty(shape=(2, 2, 2, 2, 2)), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), initial_state=cirq.one_hot(index=(0, 1, 0, 1, 0), shape=(2, 2, 2, 2, 2), dtype=np.complex64), dtype=np.complex64, ) 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_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.ActOnCliffordTableauArgs(tableau=t, qubits=qubits, prng=prng, log_of_measurement_results={}) 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_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_act_on_state_vector(): a, b = [cirq.LineQubit(3), cirq.LineQubit(1)] m = cirq.measure(a, b, key='out', invert_mask=(True, )) args = cirq.ActOnStateVectorArgs( target_tensor=cirq.one_hot(shape=(2, 2, 2, 2, 2), dtype=np.complex64), available_buffer=np.empty(shape=(2, 2, 2, 2, 2)), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 0]} args = cirq.ActOnStateVectorArgs( target_tensor=cirq.one_hot(index=(0, 1, 0, 0, 0), shape=(2, 2, 2, 2, 2), dtype=np.complex64), available_buffer=np.empty(shape=(2, 2, 2, 2, 2)), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 1]} args = cirq.ActOnStateVectorArgs( target_tensor=cirq.one_hot(index=(0, 1, 0, 1, 0), shape=(2, 2, 2, 2, 2), dtype=np.complex64), available_buffer=np.empty(shape=(2, 2, 2, 2, 2)), qubits=cirq.LineQubit.range(5), 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)
def test_act_on_stabilizer_ch_form(): a, b = [cirq.LineQubit(3), cirq.LineQubit(1)] 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) args = cirq.ActOnStabilizerCHFormArgs( qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), log_of_measurement_results={}, initial_state=0, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 0]} args = cirq.ActOnStabilizerCHFormArgs( qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), log_of_measurement_results={}, initial_state=8, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 1]} args = cirq.ActOnStabilizerCHFormArgs( qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), log_of_measurement_results={}, initial_state=10, ) cirq.act_on(m, args) datastore = cast(cirq.ClassicalDataDictionaryStore, args.classical_data) out = cirq.MeasurementKey('out') assert args.log_of_measurement_results == {'out': [0, 1]} assert datastore.records[out] == [(0, 1)] cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [0, 1]} assert datastore.records[out] == [(0, 1), (0, 1)]
def test_act_on_stabilizer_ch_form(): a, b = [cirq.LineQubit(3), cirq.LineQubit(1)] 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) args = cirq.ActOnStabilizerCHFormArgs( state=cirq.StabilizerStateChForm(num_qubits=5, initial_state=0), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 0]} args = cirq.ActOnStabilizerCHFormArgs( state=cirq.StabilizerStateChForm(num_qubits=5, initial_state=8), qubits=cirq.LineQubit.range(5), prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [1, 1]} args = cirq.ActOnStabilizerCHFormArgs( state=cirq.StabilizerStateChForm(num_qubits=5, initial_state=10), qubits=cirq.LineQubit.range(5), 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)
def test_act_on_qutrit(): a, b = [cirq.LineQid(3, dimension=3), cirq.LineQid(1, dimension=3)] m = cirq.measure( a, b, key='out', invert_mask=(True, ), confusion_map={(1, ): np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]])}, ) args = cirq.StateVectorSimulationState( available_buffer=np.empty(shape=(3, 3, 3, 3, 3)), qubits=cirq.LineQid.range(5, dimension=3), prng=np.random.RandomState(), initial_state=cirq.one_hot(index=(0, 2, 0, 2, 0), shape=(3, 3, 3, 3, 3), dtype=np.complex64), dtype=np.complex64, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [2, 0]} args = cirq.StateVectorSimulationState( available_buffer=np.empty(shape=(3, 3, 3, 3, 3)), qubits=cirq.LineQid.range(5, dimension=3), prng=np.random.RandomState(), initial_state=cirq.one_hot(index=(0, 1, 0, 2, 0), shape=(3, 3, 3, 3, 3), dtype=np.complex64), dtype=np.complex64, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [2, 2]} args = cirq.StateVectorSimulationState( available_buffer=np.empty(shape=(3, 3, 3, 3, 3)), qubits=cirq.LineQid.range(5, dimension=3), prng=np.random.RandomState(), initial_state=cirq.one_hot(index=(0, 2, 0, 1, 0), shape=(3, 3, 3, 3, 3), dtype=np.complex64), dtype=np.complex64, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [0, 0]}
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_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_qutrit(): a, b = cirq.LineQid.range(2, dimension=3) m = cirq.measure(a, b, key='out', invert_mask=(True, )) args = cirq.ActOnStateVectorArgs( target_tensor=cirq.one_hot(index=(0, 2, 0, 2, 0), shape=(3, 3, 3, 3, 3), dtype=np.complex64), available_buffer=np.empty(shape=(3, 3, 3, 3, 3)), axes=[3, 1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [2, 2]} args = cirq.ActOnStateVectorArgs( target_tensor=cirq.one_hot(index=(0, 1, 0, 2, 0), shape=(3, 3, 3, 3, 3), dtype=np.complex64), available_buffer=np.empty(shape=(3, 3, 3, 3, 3)), axes=[3, 1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [2, 1]} args = cirq.ActOnStateVectorArgs( target_tensor=cirq.one_hot(index=(0, 2, 0, 1, 0), shape=(3, 3, 3, 3, 3), dtype=np.complex64), available_buffer=np.empty(shape=(3, 3, 3, 3, 3)), axes=[3, 1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [0, 2]}
def test_act_on_fallback_fails(): args = DummyActOnArgs(fallback_result=NotImplemented) with pytest.raises(TypeError, match='Failed to act'): cirq.act_on(op, args)
def test_act_on_tableau(phase): original_tableau = cirq.CliffordTableau(0) args = cirq.ActOnCliffordTableauArgs(original_tableau.copy(), [], np.random.RandomState(), {}) cirq.act_on(cirq.GlobalPhaseOperation(phase), args, allow_decompose=False) assert args.tableau == original_tableau
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_qubits_should_be_defined_for_operations(): args = DummyActOnArgs() with pytest.raises(ValueError, match='Calls to act_on should'): cirq.act_on(cirq.KrausChannel([np.array([[1, 0], [0, 0]])]), args, qubits=None)
def test_act_on_fallback_succeeds(): args = DummyActOnArgs(fallback_result=True) cirq.act_on(op, args)
def test_act_on_fallback_errors(): args = DummyActOnArgs(fallback_result=False) with pytest.raises( ValueError, match='_act_on_fallback_ must return True or NotImplemented'): cirq.act_on(op, args)
def direct_fidelity_estimation( circuit: cirq.Circuit, qubits: List[cirq.Qid], sampler: cirq.Sampler, n_measured_operators: Optional[int], samples_per_term: int, ): """ Implementation of direct fidelity estimation, as per 'Direct Fidelity Estimation from Few Pauli Measurements' https://arxiv.org/abs/1104.4695 and 'Practical characterization of quantum devices without tomography' https://arxiv.org/abs/1104.3835. Args: circuit: The circuit to run the simulation on. qubits: The list of qubits. sampler: Either a noisy simulator or an engine. n_measured_operators: The total number of Pauli measurements, or None to explore each Pauli state once. samples_per_term: if set to 0, we use the 'sampler' parameter above as a noise (must be of type cirq.DensityMatrixSimulator) and simulate noise in the circuit. If greater than 0, we instead use the 'sampler' parameter directly to estimate the characteristic function. Returns: The estimated fidelity and a log of the run. """ # n_measured_operators is upper-case N in https://arxiv.org/abs/1104.3835 # Number of qubits, lower-case n in https://arxiv.org/abs/1104.3835 n_qubits = len(qubits) clifford_circuit = True qubit_map = {qubits[i]: i for i in range(n_qubits)} clifford_tableau = cirq.CliffordTableau(n_qubits) try: for gate in circuit.all_operations(): tableau_args = clifford.ActOnCliffordTableauArgs( clifford_tableau, [qubit_map[i] for i in gate.qubits], np.random.RandomState(), {}) cirq.act_on(gate, tableau_args) except TypeError: clifford_circuit = False # Computes for every \hat{P_i} of https://arxiv.org/abs/1104.3835 # estimate rho_i and Pr(i). We then collect tuples (rho_i, Pr(i), \hat{Pi}) # inside the variable 'pauli_traces'. if clifford_circuit: # The stabilizers_basis variable only contains basis vectors. For # example, if we have n=3 qubits, then we should have 2**n=8 Pauli # states that we can sample, but the basis will still have 3 entries. We # must flip a coin for each, whether or not to include them. stabilizer_basis: List[ cirq.DensePauliString] = clifford_tableau.stabilizers() pauli_traces = _estimate_pauli_traces_clifford(n_qubits, stabilizer_basis, n_measured_operators) else: pauli_traces = _estimate_pauli_traces_general(qubits, circuit, n_measured_operators) p = np.asarray([x.Pr_i for x in pauli_traces]) if n_measured_operators is None: # Since we enumerate all the possible traces, the probs should add to 1. assert np.isclose(np.sum(p), 1.0, atol=1e-6) p /= np.sum(p) fidelity = 0.0 if samples_per_term == 0: # sigma in https://arxiv.org/abs/1104.3835 if not isinstance(sampler, cirq.DensityMatrixSimulator): raise TypeError( 'sampler is not a cirq.DensityMatrixSimulator but samples_per_term is zero.' ) noisy_simulator = cast(cirq.DensityMatrixSimulator, sampler) noisy_density_matrix = cast( cirq.DensityMatrixTrialResult, noisy_simulator.simulate(circuit)).final_density_matrix if clifford_circuit and n_measured_operators is None: # In case the circuit is Clifford and we compute an exhaustive list of # Pauli traces, instead of sampling we can simply enumerate them because # they all have the same probability. measured_pauli_traces = pauli_traces else: # Otherwise, randomly sample as per probability. measured_pauli_traces = np.random.choice(pauli_traces, size=len(pauli_traces), p=p) trial_results: List[Result] = [] for pauli_trace in measured_pauli_traces: measure_pauli_string: cirq.PauliString = pauli_trace.P_i rho_i = pauli_trace.rho_i if samples_per_term > 0: sigma_i = asyncio.get_event_loop().run_until_complete( estimate_characteristic_function(circuit, measure_pauli_string, qubits, sampler, samples_per_term)) else: sigma_i, _ = compute_characteristic_function( circuit, measure_pauli_string, qubits, noisy_density_matrix) trial_results.append(Result(pauli_trace=pauli_trace, sigma_i=sigma_i)) fidelity += sigma_i / rho_i estimated_fidelity = fidelity / len(pauli_traces) std_dev_estimate: Optional[float] std_dev_bound: Optional[float] if clifford_circuit: std_dev_estimate, std_dev_bound = _estimate_std_devs_clifford( estimated_fidelity, len(measured_pauli_traces)) else: std_dev_estimate, std_dev_bound = None, None dfe_intermediate_result = DFEIntermediateResult( clifford_tableau=clifford_tableau if clifford_circuit else None, pauli_traces=pauli_traces, trial_results=trial_results, std_dev_estimate=std_dev_estimate, std_dev_bound=std_dev_bound, ) return estimated_fidelity, dfe_intermediate_result
def test_z_h_act_on_tableau(): with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(cirq.Z, object()) with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(cirq.H, 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.H, args, allow_decompose=False) cirq.act_on(cirq.Z**0.5, args, allow_decompose=False) cirq.act_on(cirq.Z**0.5, args, allow_decompose=False) cirq.act_on(cirq.H, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau cirq.act_on(cirq.H, args, allow_decompose=False) cirq.act_on(cirq.Z, args, allow_decompose=False) cirq.act_on(cirq.H, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == original_tableau cirq.act_on(cirq.H, args, allow_decompose=False) cirq.act_on(cirq.Z**3.5, args, allow_decompose=False) cirq.act_on(cirq.Z**3.5, args, allow_decompose=False) cirq.act_on(cirq.H, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau cirq.act_on(cirq.Z**2, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == flipped_tableau cirq.act_on(cirq.H**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.Z**foo, args) with pytest.raises(TypeError, match="Failed to act action on state"): cirq.act_on(cirq.H**foo, args) with pytest.raises(TypeError, match="Failed to act action on state"): cirq.act_on(cirq.H**1.5, args)
def test_cz_act_on_tableau(): with pytest.raises(TypeError, match="Failed to act"): cirq.act_on(cirq.Y, object()) original_tableau = cirq.CliffordTableau(num_qubits=5, initial_state=31) args = cirq.ActOnCliffordTableauArgs( tableau=original_tableau.copy(), axes=[0, 1], prng=np.random.RandomState(), log_of_measurement_results={}, ) cirq.act_on(cirq.CZ, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau.stabilizers() == [ cirq.DensePauliString('ZIIII', coefficient=-1), cirq.DensePauliString('IZIII', coefficient=-1), cirq.DensePauliString('IIZII', coefficient=-1), cirq.DensePauliString('IIIZI', coefficient=-1), cirq.DensePauliString('IIIIZ', coefficient=-1), ] assert args.tableau.destabilizers() == [ cirq.DensePauliString('XZIII', coefficient=1), cirq.DensePauliString('ZXIII', coefficient=1), cirq.DensePauliString('IIXII', coefficient=1), cirq.DensePauliString('IIIXI', coefficient=1), cirq.DensePauliString('IIIIX', coefficient=1), ] cirq.act_on(cirq.CZ, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == original_tableau cirq.act_on(cirq.CZ**4, args, allow_decompose=False) assert args.log_of_measurement_results == {} assert args.tableau == original_tableau foo = sympy.Symbol('foo') with pytest.raises(TypeError, match="Failed to act action on state"): cirq.act_on(cirq.CZ**foo, args) with pytest.raises(TypeError, match="Failed to act action on state"): cirq.act_on(cirq.CZ**1.5, args)