def convert(self, op: ops.Operation) -> ops.OP_TREE: return protocols.decompose( op, intercepting_decomposer=self._convert_one, keep=self._keep, on_stuck_raise=(None if self.ignore_failures else self._on_stuck_raise), )
def convert(self, op: 'cirq.Operation') -> List['cirq.Operation']: a = protocols.decompose(op, keep=is_sqrt_iswap_compatible, intercepting_decomposer=self._convert_one, on_stuck_raise=(None if self.ignore_failures else self._on_stuck_raise)) return a
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: Union[int, np.ndarray], perform_measurements: bool = True, ) -> Iterator[simulator.StepResult]: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} state = wave_function.to_valid_state_vector(initial_state, num_qubits, self._dtype) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate unknown operations that don't specify a " "_unitary_ method, a _decompose_ method, or " "(_has_unitary_ + _apply_unitary_) methods" ": {!r}".format(bad_op)) def keep(potential_op: ops.Operation) -> bool: return (protocols.has_unitary(potential_op) or ops.MeasurementGate.is_measurement(potential_op)) state = np.reshape(state, (2, ) * num_qubits) buffer = np.empty((2, ) * num_qubits, dtype=self._dtype) for moment in circuit: measurements = collections.defaultdict( list) # type: Dict[str, List[bool]] unitary_ops_and_measurements = protocols.decompose( moment.operations, keep=keep, on_stuck_raise=on_stuck) for op in unitary_ops_and_measurements: indices = [qubit_map[qubit] for qubit in op.qubits] if ops.MeasurementGate.is_measurement(op): gate = cast(ops.MeasurementGate, cast(ops.GateOperation, op).gate) if perform_measurements: invert_mask = gate.invert_mask or num_qubits * ( False, ) # Measure updates inline. bits, _ = wave_function.measure_state_vector( state, indices, state) corrected = [ bit ^ mask for bit, mask in zip(bits, invert_mask) ] measurements[cast(str, gate.key)].extend(corrected) else: result = protocols.apply_unitary( op, args=protocols.ApplyUnitaryArgs( state, buffer, indices)) if result is buffer: buffer = state state = result yield SimulatorStep(state, measurements, qubit_map, self._dtype)
def decompose_operation(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE': if self.is_native_or_final(operation): return operation return protocols.decompose( operation, intercepting_decomposer=self.operation_decomposer, keep=self.is_native_or_final, on_stuck_raise=None)
def optimization_at(self, circuit, index, op): decomposition = protocols.decompose(op, keep=self.no_decomp, on_stuck_raise=None) if decomposition is op: return None return PointOptimizationSummary( clear_span=1, clear_qubits=op.qubits, new_operations=decomposition)
def optimization_at( self, circuit: 'cirq.Circuit', index: int, op: 'cirq.Operation') -> Optional['cirq.PointOptimizationSummary']: decomposition = protocols.decompose(op, keep=self.no_decomp, on_stuck_raise=None) if decomposition == [op]: return None return PointOptimizationSummary(clear_span=1, clear_qubits=op.qubits, new_operations=decomposition)
def assert_decompose_ends_at_default_gateset(val: Any): """Asserts that cirq.decompose(val) ends at default cirq gateset or a known gate.""" if _known_gate_with_no_decomposition(val): return # coverage: ignore args = () if isinstance(val, ops.Operation) else (tuple( devices.LineQid.for_gate(val)), ) dec_once = protocols.decompose_once(val, [val(*args[0]) if args else val], *args) for op in [*ops.flatten_to_ops(protocols.decompose(d) for d in dec_once)]: assert _known_gate_with_no_decomposition(op.gate) or ( op in protocols.decompose_protocol.DECOMPOSE_TARGET_GATESET ), f'{val} decomposed to {op}, which is not part of default cirq target gateset.'
def convert(self, op: ops.Operation) -> List[ops.Operation]: def on_stuck_raise(bad): return TypeError("Don't know how to work with {!r}. " "It isn't a native xmon operation, " "a 1 or 2 qubit gate with a known unitary, " "or composite.".format(bad)) return protocols.decompose( op, keep=xmon_gates.is_native_xmon_op, intercepting_decomposer=self._convert_one, on_stuck_raise=None if self.ignore_failures else on_stuck_raise)
def _write_operations( self, op_tree: 'cirq.OP_TREE', output: Callable[[str], None], output_line_gap: Callable[[int], None], ) -> None: def keep(op: 'cirq.Operation') -> bool: return protocols.qasm(op, args=self.args, default=None) is not None def fallback(op): if len(op.qubits) not in [1, 2]: return NotImplemented mat = protocols.unitary(op, None) if mat is None: return NotImplemented if len(op.qubits) == 1: return QasmUGate.from_matrix(mat).on(*op.qubits) return QasmTwoQubitGate.from_matrix(mat).on(*op.qubits) def on_stuck(bad_op): return ValueError( 'Cannot output operation as QASM: {!r}'.format(bad_op)) for main_op in ops.flatten_op_tree(op_tree): decomposed = protocols.decompose(main_op, keep=keep, fallback_decomposer=fallback, on_stuck_raise=on_stuck) qasms = [protocols.qasm(op, args=self.args) for op in decomposed] should_annotate = decomposed != [main_op ] or qasms[0].count('\n') > 1 if should_annotate: output_line_gap(1) if isinstance(main_op, ops.GateOperation): x = str(main_op.gate).replace('\n', '\n //') output('// Gate: {!s}\n'.format(x)) else: x = str(main_op).replace('\n', '\n //') output('// Operation: {!s}\n'.format(x)) for qasm in qasms: output(qasm) if should_annotate: output_line_gap(1)
def __init__(self, circuit: circuits.Circuit, initial_state: Union[int, np.ndarray]): self.grouping = _QubitGrouping(circuit) self.circuit = circuits.Circuit( protocols.decompose( circuit, intercepting_decomposer=self.grouping.intercept_decompose_func, keep=self.grouping.decompose_keep_func)) self.layers = _circuit_as_layers(self.circuit, self.grouping) self.feed_dict = {} # type: Dict[tf.Tensor, Any] # Capture initial state. self._initial_state_func = self._pick_initial_state_func(initial_state) # Store list of CZ indices for each layer. max_czs = 0 if self.layers: max_czs = max(len(e.cz_indices) for e in self.layers) max_czs = max(1, max_czs) self.secret_cz_indices = tf.placeholder( name='cz_indices', dtype=tf.int32, shape=(len(self.layers), max_czs, 2)) padded_cz_indices = np.array( [ e.cz_indices + [(-1, -1)] * (max_czs - len(e.cz_indices)) for e in self.layers ], dtype=np.int32 ).reshape((len(self.layers), max_czs, 2)) self.feed_dict[self.secret_cz_indices] = padded_cz_indices # Store matrices for each qubit group at each layer. self.secret_group_matrices = [ tf.placeholder( name='group_matrices_{}'.format(i), dtype=tf.complex64, shape=(len(self.layers), 1 << len(g), 1 << len(g))) for i, g in enumerate(self.grouping.groups) ] for i in range(len(self.grouping.groups)): j = len(self.grouping.groups) - i - 1 self.feed_dict[self.secret_group_matrices[j]] = np.array([ e.group_matrices[j] for e in self.layers ])
def optimization_at( self, circuit: circuits.Circuit, index: int, op: ops.Operation) -> Optional[circuits.PointOptimizationSummary]: converted = protocols.decompose( op, intercepting_decomposer=self._decompose_two_qubit_unitaries, keep=self._keep, on_stuck_raise=(None if self.ignore_failures else self._on_stuck_raise)) if converted == [op]: return None return circuits.PointOptimizationSummary(clear_span=1, new_operations=converted, clear_qubits=op.qubits)
def _write_quil(self, output_func: Callable[[str], None]) -> None: output_func('# Created using Cirq.\n\n') if len(self.measurements) > 0: measurements_declared: Set[str] = set() for m in self.measurements: key = protocols.measurement_key(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') def keep(op: 'cirq.Operation') -> bool: return protocols.quil(op, formatter=self.formatter) is not None def fallback(op): if len(op.qubits) not in [1, 2]: return NotImplemented mat = protocols.unitary(op, None) if mat is None: return NotImplemented # Following code is a safety measure # Could not find a gate that doesn't decompose into a gate # with a _quil_ implementation # coverage: ignore if len(op.qubits) == 1: return QuilOneQubitGate(mat).on(*op.qubits) return QuilTwoQubitGate(mat).on(*op.qubits) def on_stuck(bad_op): return ValueError(f'Cannot output operation as QUIL: {bad_op!r}') for main_op in self.operations: decomposed = protocols.decompose(main_op, keep=keep, fallback_decomposer=fallback, on_stuck_raise=on_stuck) for decomposed_op in decomposed: output_func( protocols.quil(decomposed_op, formatter=self.formatter))
def decompose_operation(self, operation: 'ops.Operation') -> 'ops.OP_TREE': if isinstance(operation.gate, self.auto_decompose_gates): return protocols.decompose(operation) return operation
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: Union[int, np.ndarray], perform_measurements: bool = True) -> Iterator: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} matrix = density_matrix_utils.to_valid_density_matrix( initial_state, num_qubits, self._dtype) if len(circuit) == 0: yield DensityMatrixStepResult(matrix, {}, qubit_map, self._dtype) matrix = np.reshape(matrix, (2,) * num_qubits * 2) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate operations that don't implement " "SupportsUnitary, SupportsApplyUnitary, SupportsMixture, " "SupportsChannel or is a measurement: {!r}".format(bad_op)) def keep(potential_op: ops.Operation) -> bool: return (protocols.has_channel(potential_op) or (ops.op_gate_of_type(potential_op, ops.MeasurementGate) is not None) or isinstance(potential_op, (ops.SamplesDisplay, ops.WaveFunctionDisplay, ops.DensityMatrixDisplay)) ) matrix = np.reshape(matrix, (2,) * num_qubits * 2) noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits())) for moment in noisy_moments: measurements = collections.defaultdict( list) # type: Dict[str, List[bool]] channel_ops_and_measurements = protocols.decompose( moment, keep=keep, on_stuck_raise=on_stuck) for op in channel_ops_and_measurements: indices = [qubit_map[qubit] for qubit in op.qubits] if isinstance(op, (ops.SamplesDisplay, ops.WaveFunctionDisplay, ops.DensityMatrixDisplay)): continue # TODO: support more general measurements. meas = ops.op_gate_of_type(op, ops.MeasurementGate) if meas: if perform_measurements: invert_mask = meas.invert_mask or num_qubits * (False,) # Measure updates inline. bits, _ = density_matrix_utils.measure_density_matrix( matrix, indices, matrix) corrected = [bit ^ mask for bit, mask in zip(bits, invert_mask)] key = protocols.measurement_key(meas) measurements[key].extend(corrected) else: # TODO: Use apply_channel similar to apply_unitary. gate = cast(ops.GateOperation, op).gate channel = protocols.channel(gate) sum_buffer = np.zeros((2,) * 2 * num_qubits, dtype=self._dtype) buffer = np.empty((2,) * 2 * num_qubits, dtype=self._dtype) out = np.empty((2,) * 2 * num_qubits, dtype=self._dtype) for krauss in channel: krauss_tensor = np.reshape(krauss.astype(self._dtype), (2,) * gate.num_qubits() * 2) result = linalg.targeted_conjugate_about(krauss_tensor, matrix, indices, buffer=buffer, out=out) sum_buffer += result np.copyto(dst=matrix, src=sum_buffer) yield DensityMatrixStepResult( density_matrix=matrix, measurements=measurements, qubit_map=qubit_map, dtype=self._dtype)
def _decompose_(self) -> 'cirq.OP_TREE': return protocols.decompose(self.sub_operation)
def _base_iterator(self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: Union[int, np.ndarray], perform_measurements: bool = True) -> Iterator: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} matrix = density_matrix_utils.to_valid_density_matrix( initial_state, num_qubits, self._dtype) if len(circuit) == 0: yield DensityMatrixStepResult(matrix, {}, qubit_map, self._dtype) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate operations that don't implement " "SupportsUnitary, SupportsApplyUnitary, SupportsMixture, " "SupportsChannel or is a measurement: {!r}".format(bad_op)) def keep(potential_op: ops.Operation) -> bool: return (protocols.has_channel(potential_op) or (ops.op_gate_of_type(potential_op, ops.MeasurementGate) is not None) or isinstance(potential_op, (ops.SamplesDisplay, ops.WaveFunctionDisplay, ops.DensityMatrixDisplay))) matrix = np.reshape(matrix, (2**num_qubits, 2**num_qubits)) noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits())) state = qulacs.DensityMatrix(num_qubits) state.load(matrix) for moment in noisy_moments: measurements = collections.defaultdict( list) # type: Dict[str, List[bool]] channel_ops_and_measurements = protocols.decompose( moment, keep=keep, on_stuck_raise=on_stuck) for op in channel_ops_and_measurements: #indices = [qubit_map[qubit] for qubit in op.qubits] indices = [ num_qubits - 1 - qubit_map[qubit] for qubit in op.qubits ] indices.reverse() if isinstance(op, (ops.SamplesDisplay, ops.WaveFunctionDisplay, ops.DensityMatrixDisplay)): continue # TODO: support more general measurements. meas = ops.op_gate_of_type(op, ops.MeasurementGate) if meas: # Not implemented raise NotImplementedError( "Measurement is not supported in qulacs simulator") else: # TODO: Use apply_channel similar to apply_unitary. gate = cast(ops.GateOperation, op).gate channel = protocols.channel(gate) qulacs_gates = [] for krauss in channel: krauss = krauss.astype(np.complex128) qulacs_gate = qulacs.gate.DenseMatrix(indices, krauss) qulacs_gates.append(qulacs_gate) qulacs_cptp_map = qulacs.gate.CPTP(qulacs_gates) qulacs_cptp_map.update_quantum_state(state) matrix = state.get_matrix() matrix = np.reshape(matrix, (2, ) * num_qubits * 2) yield DensityMatrixStepResult(density_matrix=matrix, measurements=measurements, qubit_map=qubit_map, dtype=self._dtype)
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: 'cirq.STATE_VECTOR_LIKE', perform_measurements: bool = True, ) -> Iterator: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qid_shape = protocols.qid_shape(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} state = qis.to_valid_state_vector(initial_state, num_qubits, qid_shape=qid_shape, dtype=self._dtype) if len(circuit) == 0: yield SparseSimulatorStep(state, {}, qubit_map, self._dtype) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate unknown operations that don't specify a " "_unitary_ method, a _decompose_ method, " "(_has_unitary_ + _apply_unitary_) methods," "(_has_mixture_ + _mixture_) methods, or are measurements." ": {!r}".format(bad_op)) def keep(potential_op: ops.Operation) -> bool: # The order of this is optimized to call has_xxx methods first. return (protocols.has_unitary(potential_op) or protocols.has_mixture(potential_op) or protocols.is_measurement(potential_op) or isinstance(potential_op.gate, ops.ResetChannel)) data = _StateAndBuffer(state=np.reshape(state, qid_shape), buffer=np.empty(qid_shape, dtype=self._dtype)) for moment in circuit: measurements = collections.defaultdict( list) # type: Dict[str, List[int]] unitary_ops_and_measurements = protocols.decompose( moment, keep=keep, on_stuck_raise=on_stuck) for op in unitary_ops_and_measurements: indices = [qubit_map[qubit] for qubit in op.qubits] if isinstance(op.gate, ops.ResetChannel): self._simulate_reset(op, data, indices) elif protocols.has_unitary(op): self._simulate_unitary(op, data, indices) elif protocols.is_measurement(op): # Do measurements second, since there may be mixtures that # operate as measurements. # TODO: support measurement outside the computational basis. # Github issue: # https://github.com/quantumlib/Cirq/issues/1357 if perform_measurements: self._simulate_measurement(op, data, indices, measurements, num_qubits) elif protocols.has_mixture(op): self._simulate_mixture(op, data, indices) yield SparseSimulatorStep( state_vector=data.state, measurements=measurements, qubit_map=qubit_map, dtype=self._dtype)
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: Union[int, np.ndarray], perform_measurements: bool = True, ) -> Iterator: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} state = wave_function.to_valid_state_vector(initial_state, num_qubits, self._dtype) if len(circuit) == 0: yield SparseSimulatorStep(state, {}, qubit_map, self._dtype) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate unknown operations that don't specify a " "_unitary_ method, a _decompose_ method, or " "(_has_unitary_ + _apply_unitary_) methods" ": {!r}".format(bad_op)) def keep(potential_op: ops.Operation) -> bool: return (protocols.has_unitary(potential_op) or protocols.is_measurement(potential_op)) state = np.reshape(state, (2, ) * num_qubits) buffer = np.empty((2, ) * num_qubits, dtype=self._dtype) for moment in circuit: measurements = collections.defaultdict( list) # type: Dict[str, List[bool]] non_display_ops = (op for op in moment if not isinstance(op, ( ops.SamplesDisplay, ops.WaveFunctionDisplay, ops.DensityMatrixDisplay))) unitary_ops_and_measurements = protocols.decompose( non_display_ops, keep=keep, on_stuck_raise=on_stuck) for op in unitary_ops_and_measurements: indices = [qubit_map[qubit] for qubit in op.qubits] # TODO: Support measurements outside of computational basis. # TODO: Support mixtures. meas = ops.op_gate_of_type(op, ops.MeasurementGate) if meas: if perform_measurements: invert_mask = meas.invert_mask or num_qubits * ( False, ) # Measure updates inline. bits, _ = wave_function.measure_state_vector( state, indices, state) corrected = [ bit ^ mask for bit, mask in zip(bits, invert_mask) ] key = protocols.measurement_key(meas) measurements[key].extend(corrected) else: result = protocols.apply_unitary( op, args=protocols.ApplyUnitaryArgs( state, buffer, indices)) if result is buffer: buffer = state state = result yield SparseSimulatorStep(state_vector=state, measurements=measurements, qubit_map=qubit_map, dtype=self._dtype)
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: Union[np.ndarray, 'cirq.STATE_VECTOR_LIKE'], all_measurements_are_terminal=False, is_raw_state=False, ) -> Iterator: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) qid_shape = protocols.qid_shape(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} initial_matrix = (qis.to_valid_density_matrix(initial_state, len(qid_shape), qid_shape=qid_shape, dtype=self._dtype) if not is_raw_state else initial_state) if np.may_share_memory(initial_matrix, initial_state): initial_matrix = initial_matrix.copy() measured = collections.defaultdict( bool) # type: Dict[Tuple[cirq.Qid, ...], bool] if len(circuit) == 0: yield DensityMatrixStepResult(initial_matrix, {}, qubit_map, self._dtype) return state = _StateAndBuffers( len(qid_shape), initial_matrix.reshape(qid_shape * 2) if not is_raw_state else initial_matrix, ) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate operations that don't implement " "SupportsUnitary, SupportsConsistentApplyUnitary, " "SupportsMixture, SupportsChannel or is a measurement: {!r}". format(bad_op)) def keep(potential_op: ops.Operation) -> bool: return protocols.has_channel( potential_op, allow_decompose=False) or isinstance( potential_op.gate, ops.MeasurementGate) noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits())) for moment in noisy_moments: measurements = collections.defaultdict( list) # type: Dict[str, List[int]] channel_ops_and_measurements = protocols.decompose( moment, keep=keep, on_stuck_raise=on_stuck) for op in channel_ops_and_measurements: indices = [qubit_map[qubit] for qubit in op.qubits] # TODO: support more general measurements. # Github issue: https://github.com/quantumlib/Cirq/issues/1357 if all_measurements_are_terminal and measured[op.qubits]: continue if isinstance(op.gate, ops.MeasurementGate): measured[op.qubits] = True meas = op.gate if all_measurements_are_terminal: continue if self._ignore_measurement_results: for i, q in enumerate(op.qubits): self._apply_op_channel( ops.phase_damp(1).on(q), state, [indices[i]]) else: invert_mask = meas.full_invert_mask() # Measure updates inline. bits, _ = density_matrix_utils.measure_density_matrix( state.tensor, indices, qid_shape=qid_shape, out=state.tensor, seed=self._prng, ) corrected = [ bit ^ (bit < 2 and mask) for bit, mask in zip(bits, invert_mask) ] key = protocols.measurement_key(meas) measurements[key].extend(corrected) else: self._apply_op_channel(op, state, indices) yield DensityMatrixStepResult( density_matrix=state.tensor, measurements=measurements, qubit_map=qubit_map, dtype=self._dtype, )
def map_func(op: 'cirq.Operation', _) -> 'cirq.OP_TREE': if context and context.deep and isinstance(op.untagged, circuits.CircuitOperation): return op return protocols.decompose(op, keep=no_decomp, on_stuck_raise=None)
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: Union[int, np.ndarray], perform_measurements: bool = True, ) -> Iterator: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} state = wave_function.to_valid_state_vector(initial_state, num_qubits, self._dtype) if len(circuit) == 0: yield SparseSimulatorStep(state, {}, qubit_map, self._dtype) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate unknown operations that don't specify a " "_unitary_ method, a _decompose_ method, " "(_has_unitary_ + _apply_unitary_) methods," "(_has_mixture_ + _mixture_) methods, or are measurements." ": {!r}".format(bad_op)) def keep(potential_op: ops.Operation) -> bool: # The order of this is optimized to call has_xxx methods first. return (protocols.has_unitary(potential_op) or protocols.has_mixture(potential_op) or protocols.is_measurement(potential_op)) data = _StateAndBuffer(state=np.reshape(state, (2, ) * num_qubits), buffer=np.empty((2, ) * num_qubits, dtype=self._dtype)) for moment in circuit: measurements = collections.defaultdict( list) # type: Dict[str, List[bool]] non_display_ops = (op for op in moment if not isinstance(op, ( ops.SamplesDisplay, ops.WaveFunctionDisplay, ops.DensityMatrixDisplay))) unitary_ops_and_measurements = protocols.decompose( non_display_ops, keep=keep, on_stuck_raise=on_stuck) for op in unitary_ops_and_measurements: indices = [qubit_map[qubit] for qubit in op.qubits] if protocols.has_unitary(op): self._simulate_unitary(op, data, indices) elif protocols.is_measurement(op): # Do measurements second, since there may be mixtures that # operate as measurements. # TODO: support measurement outside the computational basis. if perform_measurements: self._simulate_measurement(op, data, indices, measurements, num_qubits) elif protocols.has_mixture(op): self._simulate_mixture(op, data, indices) yield SparseSimulatorStep(state_vector=data.state, measurements=measurements, qubit_map=qubit_map, dtype=self._dtype)
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: Union[int, np.ndarray], perform_measurements: bool = True, ) -> Iterator: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} state = wave_function.to_valid_state_vector(initial_state, num_qubits, self._dtype) if len(circuit) == 0: yield SparseSimulatorStep(state, {}, qubit_map, self._dtype) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate unknown operations that don't specify a " "_unitary_ method, a _decompose_ method, " "(_has_unitary_ + _apply_unitary_) methods," "(_has_mixture_ + _mixture_) methods, or are measurements." ": {!r}".format(bad_op)) def keep(potential_op: ops.Operation) -> bool: # The order of this is optimized to call has_xxx methods first. return (protocols.has_unitary(potential_op) or protocols.has_mixture(potential_op) or protocols.is_measurement(potential_op)) data = _StateAndBuffer(state=np.reshape(state, (2, ) * num_qubits), buffer=np.empty((2, ) * num_qubits, dtype=self._dtype)) shape = np.array(data.state).shape # Qulacs qulacs_flag = 0 qulacs_state = qulacs.QuantumStateGpu(int(num_qubits)) qulacs_circuit = qulacs.QuantumCircuit(int(num_qubits)) for moment in circuit: measurements = collections.defaultdict( list) # type: Dict[str, List[bool]] non_display_ops = (op for op in moment if not isinstance(op, ( ops.SamplesDisplay, ops.WaveFunctionDisplay, ops.DensityMatrixDisplay))) unitary_ops_and_measurements = protocols.decompose( non_display_ops, keep=keep, on_stuck_raise=on_stuck) for op in unitary_ops_and_measurements: indices = [ num_qubits - 1 - qubit_map[qubit] for qubit in op.qubits ] if protocols.has_unitary(op): # single qubit unitary gates if isinstance(op.gate, ops.pauli_gates._PauliX): qulacs_circuit.add_X_gate(indices[0]) elif isinstance(op.gate, ops.pauli_gates._PauliY): qulacs_circuit.add_Y_gate(indices[0]) elif isinstance(op.gate, ops.pauli_gates._PauliZ): qulacs_circuit.add_Z_gate(indices[0]) elif isinstance(op.gate, ops.common_gates.HPowGate): qulacs_circuit.add_H_gate(indices[0]) elif isinstance(op.gate, ops.common_gates.XPowGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, ops.common_gates.YPowGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, ops.common_gates.ZPowGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, circuits.qasm_output.QasmUGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, ops.matrix_gates.SingleQubitMatrixGate): qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) # Two Qubit Unitary Gates elif isinstance(op.gate, ops.common_gates.CNotPowGate): qulacs_circuit.add_CNOT_gate(indices[0], indices[1]) elif isinstance(op.gate, ops.common_gates.CZPowGate): qulacs_circuit.add_CZ_gate(indices[0], indices[1]) elif isinstance(op.gate, ops.common_gates.SwapPowGate): qulacs_circuit.add_SWAP_gate(indices[0], indices[1]) elif isinstance(op.gate, ops.common_gates.ISwapPowGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, ops.parity_gates.XXPowGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, ops.parity_gates.YYPowGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, ops.parity_gates.ZZPowGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, ops.matrix_gates.TwoQubitMatrixGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) # Three Qubit Unitary Gates elif isinstance(op.gate, ops.three_qubit_gates.CCXPowGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, ops.three_qubit_gates.CCZPowGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) elif isinstance(op.gate, ops.three_qubit_gates.CSwapGate): indices.reverse() qulacs_circuit.add_dense_matrix_gate( indices, op._unitary_()) qulacs_flag = 1 elif protocols.is_measurement(op): # Do measurements second, since there may be mixtures that # operate as measurements. # TODO: support measurement outside the computational basis. if perform_measurements: if qulacs_flag == 1: self._simulate_on_qulacs(data, shape, qulacs_state, qulacs_circuit) qulacs_flag = 0 self._simulate_measurement(op, data, indices, measurements, num_qubits) elif protocols.has_mixture(op): if qulacs_flag == 1: self._simulate_on_qulacs(data, shape, qulacs_state, qulacs_circuit) qulacs_flag = 0 qulacs_circuit = qulacs.QuantumCircuit(int(num_qubits)) self._simulate_mixture(op, data, indices) if qulacs_flag == 1: self._simulate_on_qulacs(data, shape, qulacs_state, qulacs_circuit) qulacs_flag = 0 del qulacs_state del qulacs_circuit yield SparseSimulatorStep(state_vector=data.state, measurements=measurements, qubit_map=qubit_map, dtype=self._dtype)
def _base_iterator(self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: Union[int, np.ndarray], perform_measurements: bool = True) -> Iterator: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) qid_shape = protocols.qid_shape(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} initial_matrix = density_matrix_utils.to_valid_density_matrix( initial_state, len(qid_shape), qid_shape=qid_shape, dtype=self._dtype) if len(circuit) == 0: yield DensityMatrixStepResult(initial_matrix, {}, qubit_map, self._dtype) return state = _StateAndBuffers(len(qid_shape), initial_matrix.reshape(qid_shape * 2)) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate operations that don't implement " "SupportsUnitary, SupportsConsistentApplyUnitary, " "SupportsMixture, SupportsChannel or is a measurement: {!r}". format(bad_op)) def keep(potential_op: ops.Operation) -> bool: return (protocols.has_channel(potential_op) or (ops.op_gate_of_type(potential_op, ops.MeasurementGate) is not None) or isinstance(potential_op, (ops.SamplesDisplay, ops.WaveFunctionDisplay, ops.DensityMatrixDisplay))) noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits())) for moment in noisy_moments: measurements = collections.defaultdict( list) # type: Dict[str, List[int]] channel_ops_and_measurements = protocols.decompose( moment, keep=keep, on_stuck_raise=on_stuck) for op in channel_ops_and_measurements: indices = [qubit_map[qubit] for qubit in op.qubits] if isinstance(op, (ops.SamplesDisplay, ops.WaveFunctionDisplay, ops.DensityMatrixDisplay)): continue # TODO: support more general measurements. meas = ops.op_gate_of_type(op, ops.MeasurementGate) if meas: if perform_measurements: invert_mask = meas.full_invert_mask() # Measure updates inline. bits, _ = density_matrix_utils.measure_density_matrix( state.tensor, indices, qid_shape=qid_shape, out=state.tensor) corrected = [ bit ^ (bit < 2 and mask) for bit, mask in zip(bits, invert_mask) ] key = protocols.measurement_key(meas) measurements[key].extend(corrected) else: # TODO: Use apply_channel similar to apply_unitary. self._apply_op_channel(op, state, indices) yield DensityMatrixStepResult(density_matrix=state.tensor, measurements=measurements, qubit_map=qubit_map, dtype=self._dtype)
def map_func(op: 'cirq.Operation', _) -> 'cirq.OP_TREE': return protocols.decompose(op, keep=no_decomp, on_stuck_raise=None)