Repository: quantumlib/Cirq

Issue:
Support repetitions=0 in cirq.sample and related utilities
Currently, setting `repetitions` to 0 raises

```
ValueError: operands could not be broadcast together with shapes (0,) (5,)
```


Discussion:

Resolving patch:
diff --git a/cirq/sim/simulator.py b/cirq/sim/simulator.py
--- a/cirq/sim/simulator.py
+++ b/cirq/sim/simulator.py
@@ -553,7 +553,7 @@ def sample_measurement_ops(
 
         results = {}
         for k, (s, e) in bounds.items():
-            before_invert_mask = np.array([x[s:e] for x in indexed_sample])
+            before_invert_mask = indexed_sample[:, s:e]
             results[k] = before_invert_mask ^ (np.logical_and(
                 before_invert_mask < 2, meas_ops[k].full_invert_mask()))
         return results
diff --git a/cirq/study/trial_result.py b/cirq/study/trial_result.py
--- a/cirq/study/trial_result.py
+++ b/cirq/study/trial_result.py
@@ -108,7 +108,10 @@ def data(self) -> pd.DataFrame:
                 converted_dict[key] = [
                     value.big_endian_bits_to_int(m_vals) for m_vals in val
                 ]
-            self._data = pd.DataFrame(converted_dict)
+            # Note that when a numpy array is produced from this data frame,
+            # Pandas will try to use np.int64 as dtype, but will upgrade to
+            # object if any value is too large to fit.
+            self._data = pd.DataFrame(converted_dict, dtype=np.int64)
         return self._data
 
     @staticmethod


Test patch:
diff --git a/cirq/experiments/fidelity_estimation_test.py b/cirq/experiments/fidelity_estimation_test.py
--- a/cirq/experiments/fidelity_estimation_test.py
+++ b/cirq/experiments/fidelity_estimation_test.py
@@ -19,12 +19,9 @@ def sample_noisy_bitstrings(circuit: cirq.Circuit,
     incoherent_samples = np.random.randint(dim, size=n_incoherent)
     circuit_with_measurements = cirq.Circuit(
         circuit, cirq.measure(*qubit_order, key='m'))
-    # TODO(viathor): Remove conditional after #2114.
-    if n_coherent > 0:
-        r = cirq.sample(circuit_with_measurements, repetitions=n_coherent)
-        coherent_samples = r.data['m'].to_numpy()
-        return np.concatenate((coherent_samples, incoherent_samples))
-    return incoherent_samples
+    r = cirq.sample(circuit_with_measurements, repetitions=n_coherent)
+    coherent_samples = r.data['m'].to_numpy()
+    return np.concatenate((coherent_samples, incoherent_samples))
 
 
 def make_random_quantum_circuit(qubits: Sequence[cirq.Qid],
diff --git a/cirq/sim/mux_test.py b/cirq/sim/mux_test.py
--- a/cirq/sim/mux_test.py
+++ b/cirq/sim/mux_test.py
@@ -211,3 +211,13 @@ def test_final_wavefunction_seed():
     np.testing.assert_allclose(cirq.final_wavefunction(
         [cirq.X(a)**0.5, cirq.measure(a)], seed=124), [0.707107 + 0.707107j, 0],
                                atol=1e-4)
+
+
+@pytest.mark.parametrize('repetitions', (0, 1, 100))
+def test_repetitions(repetitions):
+    a = cirq.LineQubit(0)
+    c = cirq.Circuit(cirq.H(a), cirq.measure(a, key='m'))
+    r = cirq.sample(c, repetitions=repetitions)
+    samples = r.data['m'].to_numpy()
+    assert samples.shape == (repetitions,)
+    assert np.issubdtype(samples.dtype, np.integer)
diff --git a/cirq/sim/simulator_test.py b/cirq/sim/simulator_test.py
--- a/cirq/sim/simulator_test.py
+++ b/cirq/sim/simulator_test.py
@@ -147,7 +147,8 @@ def __setstate__(self, state):
         pass
 
     def sample(self, qubits, repetitions):
-        return [[qubit in self._ones_qubits for qubit in qubits]] * repetitions
+        return np.array([[qubit in self._ones_qubits for qubit in qubits]] *
+                        repetitions)
 
 
 def test_step_sample_measurement_ops():