Repository: quantumlib/Cirq

Issue:
Density matrix simulator sometimes returns measurement results when ignore_measurement_results is True
Split off from #2567 .
Input:
```
import cirq

q = cirq.LineQubit(0)
circuit1 = cirq.Circuit(cirq.measure(q))
circuit2 = circuit1 + cirq.I(q)

print('Circuit 1:')
print(circuit1)
print()
print('Circuit2:')
print(circuit2)
print()

simulator = cirq.DensityMatrixSimulator(noise=cirq.X, ignore_measurement_results=True)
result1 = simulator.run(circuit1, repetitions=10)
result2 = simulator.run(circuit2, repetitions=10)

print('Result 1:')
print(result1)
print()
print('Result 2:')
print(result2)
print()
```
Output:
```
Circuit 1:
0: ───M───

Circuit2:
0: ───M───I───

Result 1:
0=1111111111

Result 2:

```


Discussion:
This bug appears to be due to the `ignore_measurement_results`, and not the `noise`.
Input:
```
import cirq

q = cirq.LineQubit(0)
circuit1 = cirq.Circuit(cirq.measure(q))
circuit2 = circuit1 + cirq.I(q)

print('Circuit 1:')
print(circuit1)
print()
print('Circuit2:')
print(circuit2)
print()

simulator = cirq.DensityMatrixSimulator(ignore_measurement_results=True)
result1 = simulator.run(circuit1, repetitions=10)
result2 = simulator.run(circuit2, repetitions=10)

print('Result 1:')
print(result1)
print()
print('Result 2:')
print(result2)
print()
```
Output:
```
Circuit 1:
0: ───M───

Circuit2:
0: ───M───I───

Result 1:
0=0000000000

Result 2:

```
I don't think it makes sense to call `simulator.run` when `ignore_measurement_results` has been set to True. We should just raise an exception in that case. Or, should we return the empty result?
If you start with an exception, you can relax it later if people clamor about it. It's hard to go the other way
At Cirq cynq we decided to make it raise an exception.
If I understand correctly this issue is simply adding this to `_run` and modifying the docstring:

```
if self._ignore_measurement_results: 
   raise ValueError("run() is not supported when ignore_measurement_results = True")
```

@mpharrigan @kevinsung I don't think I was present for this discussion - can you confirm? 
@Ashalynd are you planning to work on this? 
Yes, that's correct.
@balopat I'm happy to contribute here
Thank you @akushnarov! It's all yours! 

Resolving patch:
diff --git a/cirq/sim/density_matrix_simulator.py b/cirq/sim/density_matrix_simulator.py
--- a/cirq/sim/density_matrix_simulator.py
+++ b/cirq/sim/density_matrix_simulator.py
@@ -143,10 +143,10 @@ def __init__(
                In the other case:
                >>> simulator = cirq.DensityMatrixSimulator(
                ...     ignore_measurement_results = True)
-               >>> result = simulator.run(circuit)
 
-               The measurement result will be the maximally mixed state
-               with equal probability for 0 and 1.
+               will raise a `ValueError` exception if you call `simulator.run`
+               when `ignore_measurement_results` has been set to True
+               (for more see https://github.com/quantumlib/Cirq/issues/2777).
         """
         if dtype not in {np.complex64, np.complex128}:
             raise ValueError(f'dtype must be complex64 or complex128, was {dtype}')
@@ -160,6 +160,9 @@ def _run(
         self, circuit: circuits.Circuit, param_resolver: study.ParamResolver, repetitions: int
     ) -> Dict[str, np.ndarray]:
         """See definition in `cirq.SimulatesSamples`."""
+        if self._ignore_measurement_results:
+            raise ValueError("run() is not supported when ignore_measurement_results = True")
+
         param_resolver = param_resolver or study.ParamResolver({})
         resolved_circuit = protocols.resolve_parameters(circuit, param_resolver)
         check_all_resolved(resolved_circuit)


Test patch:
diff --git a/cirq/sim/density_matrix_simulator_test.py b/cirq/sim/density_matrix_simulator_test.py
--- a/cirq/sim/density_matrix_simulator_test.py
+++ b/cirq/sim/density_matrix_simulator_test.py
@@ -66,6 +66,16 @@ def test_invalid_dtype():
         cirq.DensityMatrixSimulator(dtype=np.int32)
 
 
+@pytest.mark.parametrize('dtype', [np.complex64, np.complex128])
+def test_run_with_ignore_measurement_results(dtype):
+    q0, q1 = cirq.LineQubit.range(2)
+    simulator = cirq.DensityMatrixSimulator(dtype=dtype, ignore_measurement_results=True)
+
+    circuit = cirq.Circuit(cirq.X(q0), cirq.X(q1), cirq.measure(q0))
+    with pytest.raises(ValueError, match="ignore_measurement_results = True"):
+        simulator.run(circuit)
+
+
 @pytest.mark.parametrize('dtype', [np.complex64, np.complex128])
 def test_run_no_measurements(dtype):
     q0, q1 = cirq.LineQubit.range(2)
@@ -109,7 +119,7 @@ def test_run_bit_flips(dtype):
 @pytest.mark.parametrize('dtype', [np.complex64, np.complex128])
 def test_run_bit_flips_with_dephasing(dtype):
     q0, q1 = cirq.LineQubit.range(2)
-    simulator = cirq.DensityMatrixSimulator(dtype=dtype, ignore_measurement_results=True)
+    simulator = cirq.DensityMatrixSimulator(dtype=dtype)
     for b0 in [0, 1]:
         for b1 in [0, 1]:
             circuit = cirq.Circuit(