def test_qasm_output_args_format(): a = cirq.NamedQubit('a') b = cirq.NamedQubit('b') m_a = cirq.measure(a, key='meas_a') m_b = cirq.measure(b, key='meas_b') args = cirq.QasmArgs( precision=4, version='2.0', qubit_id_map={a: 'aaa[0]', b: 'bbb[0]'}, meas_key_id_map={'meas_a': 'm_a', 'meas_b': 'm_b'}, ) assert args.format('_{0}_', a) == '_aaa[0]_' assert args.format('_{0}_', b) == '_bbb[0]_' assert args.format('_{0:meas}_', cirq.measurement_key_name(m_a)) == '_m_a_' assert args.format('_{0:meas}_', cirq.measurement_key_name(m_b)) == '_m_b_' assert args.format('_{0}_', 89.1234567) == '_89.1235_' assert args.format('_{0}_', 1.23) == '_1.23_' assert args.format('_{0:half_turns}_', 89.1234567) == '_pi*89.1235_' assert args.format('_{0:half_turns}_', 1.23) == '_pi*1.23_' assert args.format('_{0}_', 'other') == '_other_'
def test_measurement_key_not_implemented(): class ReturnsNotImplemented: def _measurement_key_name_(self): return NotImplemented with pytest.raises(TypeError, match='NotImplemented'): cirq.measurement_key_name(ReturnsNotImplemented()) assert cirq.measurement_key_name(ReturnsNotImplemented(), None) is None assert cirq.measurement_key_name(ReturnsNotImplemented(), NotImplemented) is NotImplemented assert cirq.measurement_key_name(ReturnsNotImplemented(), 'a') == 'a'
def test_matrix_mixture_remap_keys(): dp = cirq.depolarize(0.1) mm = cirq.MixedUnitaryChannel.from_mixture(dp) with pytest.raises(TypeError): _ = cirq.measurement_key_name(mm) assert cirq.with_measurement_key_mapping(mm, {'a': 'b'}) is NotImplemented mm_x = cirq.MixedUnitaryChannel.from_mixture(dp, key='x') assert cirq.with_measurement_key_mapping(mm_x, {'a': 'b'}) is mm_x assert cirq.measurement_key_name(cirq.with_key_path(mm_x, ('path',))) == 'path:x' mm_a = cirq.MixedUnitaryChannel.from_mixture(dp, key='a') mm_b = cirq.MixedUnitaryChannel.from_mixture(dp, key='b') assert mm_a != mm_b assert cirq.with_measurement_key_mapping(mm_a, {'a': 'b'}) == mm_b
def _write_quil(self, output_func: Callable[[str], None]) -> None: """Calls `output_func` for successive lines of QUIL output. Args: output_func: A function that accepts a string of QUIL. This will likely write the QUIL to a file. Returns: None. """ if self._decompose_operation is None: return super()._write_quil(output_func) output_func("# Created using Cirq.\n\n") if len(self.measurements) > 0: measurements_declared: Set[str] = set() for m in self.measurements: key = cirq.measurement_key_name(m) if key in measurements_declared: continue measurements_declared.add(key) output_func(f"DECLARE {self.measurement_id_map[key]} BIT[{len(m.qubits)}]\n") output_func("\n") for main_op in self.operations: decomposed = self._decompose_operation(main_op) for decomposed_op in decomposed: output_func(self._op_to_quil(decomposed_op))
def _serialize_measurement_gate( self, gate: cirq.MeasurementGate, targets: Sequence[int] ) -> dict: key = cirq.measurement_key_name(gate) if chr(31) in key or chr(30) in key: raise ValueError( 'Measurement gates for IonQ API cannot have a key with a ascii unit' f'or record separator in it. Key was {key}' ) return {'gate': 'meas', 'key': key, 'targets': ','.join(str(t) for t in targets)}
def test_matrix_mixture_from_unitaries(): q0 = cirq.LineQubit(0) mix = [(0.5, np.array([[1, 0], [0, 1]])), (0.5, np.array([[0, 1], [1, 0]]))] half_flip = cirq.MixedUnitaryChannel(mix, key='flip') assert cirq.measurement_key_name(half_flip) == 'flip' circuit = cirq.Circuit(half_flip.on(q0), cirq.measure(q0, key='m')) sim = cirq.Simulator(seed=0) results = sim.simulate(circuit) assert 'flip' in results.measurements assert results.measurements['flip'] == results.measurements['m']
def test_measurement_key(): class ReturnsStr: def _measurement_key_name_(self): return 'door locker' class DeprecatedMagicMethod(cirq.SingleQubitGate): def _measurement_key_(self): return 'door locker' assert cirq.is_measurement(ReturnsStr()) with cirq.testing.assert_deprecated(deadline="v0.13"): assert cirq.measurement_key(ReturnsStr()) == 'door locker' with cirq.testing.assert_deprecated(deadline="v0.13"): assert cirq.measurement_key_name( DeprecatedMagicMethod()) == 'door locker' with cirq.testing.assert_deprecated(deadline="v0.13"): assert (cirq.measurement_key_name(DeprecatedMagicMethod().on( cirq.LineQubit(0))) == 'door locker') assert cirq.measurement_key_name(ReturnsStr()) == 'door locker' assert cirq.measurement_key_name(ReturnsStr(), None) == 'door locker' assert cirq.measurement_key_name(ReturnsStr(), NotImplemented) == 'door locker' assert cirq.measurement_key_name(ReturnsStr(), 'a') == 'door locker'
def test_kraus_channel_from_channel(): q0 = cirq.LineQubit(0) dp = cirq.depolarize(0.1) kc = cirq.KrausChannel.from_channel(dp, key='dp') assert cirq.measurement_key_name(kc) == 'dp' circuit = cirq.Circuit(kc.on(q0)) sim = cirq.Simulator(seed=0) results = sim.simulate(circuit) assert 'dp' in results.measurements # The depolarizing channel has four Kraus operators. assert results.measurements['dp'] in range(4)
def _measure_to_proto(gate: cirq.MeasurementGate, qubits: Sequence[cirq.Qid]): if len(qubits) == 0: raise ValueError('Measurement gate on no qubits.') invert_mask = None if gate.invert_mask: invert_mask = gate.invert_mask + (False, ) * (gate.num_qubits() - len(gate.invert_mask)) if invert_mask and len(invert_mask) != len(qubits): raise ValueError('Measurement gate had invert mask of length ' 'different than number of qubits it acts on.') return operations_pb2.Measurement( targets=[_qubit_to_proto(q) for q in qubits], key=cirq.measurement_key_name(gate), invert_mask=invert_mask, )
def _sample_measure_results( self, program: cirq.Circuit, repetitions: int = 1, ) -> Dict[str, np.ndarray]: """Samples from measurement gates in the circuit. Note that this will execute the circuit 'repetitions' times. Args: program: The circuit to sample from. repetitions: The number of samples to take. Returns: A dictionary from measurement gate key to measurement results. Measurement results are stored in a 2-dimensional numpy array, the first dimension corresponding to the repetition and the second to the actual boolean measurement results (ordered by the qubits being measured.) Raises: ValueError: If there are multiple MeasurementGates with the same key, or if repetitions is negative. """ # Add noise to the circuit if a noise model was provided. all_qubits = program.all_qubits() program = qsimc.QSimCircuit( self.noise.noisy_moments(program, sorted(all_qubits)) if self.noise is not cirq.NO_NOISE else program, ) # Compute indices of measured qubits ordered_qubits = cirq.QubitOrder.DEFAULT.order_for(all_qubits) num_qubits = len(ordered_qubits) qubit_map = { qubit: index for index, qubit in enumerate(ordered_qubits) } # Compute: # - number of qubits for each measurement key. # - measurement ops for each measurement key. # - measurement info for each measurement. # - total number of measured bits. measurement_ops = [ op for _, op, _ in program.findall_operations_with_gate_type( cirq.MeasurementGate) ] num_qubits_by_key: Dict[str, int] = {} meas_ops: Dict[str, List[cirq.GateOperation]] = {} meas_infos: List[MeasInfo] = [] num_bits = 0 for op in measurement_ops: gate = op.gate key = cirq.measurement_key_name(gate) meas_ops.setdefault(key, []) i = len(meas_ops[key]) meas_ops[key].append(op) n = len(op.qubits) if key in num_qubits_by_key: if n != num_qubits_by_key[key]: raise ValueError( f"repeated key {key!r} with different numbers of qubits: " f"{num_qubits_by_key[key]} != {n}") else: num_qubits_by_key[key] = n meas_infos.append( MeasInfo( key=key, idx=i, invert_mask=gate.full_invert_mask(), start=num_bits, end=num_bits + n, )) num_bits += n # Set qsim options options = {**self.qsim_options} results = { key: np.ndarray(shape=(repetitions, len(meas_ops[key]), n), dtype=int) for key, n in num_qubits_by_key.items() } noisy = _needs_trajectories(program) if not noisy and program.are_all_measurements_terminal( ) and repetitions > 1: # Measurements must be replaced with identity gates to sample properly. # Simply removing them may omit qubits from the circuit. for i in range(len(program.moments)): program.moments[i] = cirq.Moment( op if not isinstance(op.gate, cirq.MeasurementGate) else [cirq.IdentityGate(1).on(q) for q in op.qubits] for op in program.moments[i]) translator_fn_name = "translate_cirq_to_qsim" options["c"], _ = self._translate_circuit( program, translator_fn_name, cirq.QubitOrder.DEFAULT, ) options["s"] = self.get_seed() raw_results = self._sim_module.qsim_sample_final( options, repetitions) full_results = np.array([[ bool(result & (1 << q)) for q in reversed(range(num_qubits)) ] for result in raw_results]) for key, oplist in meas_ops.items(): for i, op in enumerate(oplist): meas_indices = [qubit_map[qubit] for qubit in op.qubits] invert_mask = op.gate.full_invert_mask() # Apply invert mask to re-ordered results results[ key][:, i, :] = full_results[:, meas_indices] ^ invert_mask else: if noisy: translator_fn_name = "translate_cirq_to_qtrajectory" sampler_fn = self._sim_module.qtrajectory_sample else: translator_fn_name = "translate_cirq_to_qsim" sampler_fn = self._sim_module.qsim_sample options["c"], _ = self._translate_circuit( program, translator_fn_name, cirq.QubitOrder.DEFAULT, ) measurements = np.empty(shape=(repetitions, num_bits), dtype=int) for i in range(repetitions): options["s"] = self.get_seed() measurements[i] = sampler_fn(options) for m in meas_infos: results[m.key][:, m.idx, :] = (measurements[:, m.start:m.end] ^ m.invert_mask) return results
def test_measurement_key(): a = cirq.NamedQubit('a') assert cirq.measurement_key_name(cirq.measure(a, key='lock')) == 'lock'