def _base_iterator(self, circuit, qubit_order, initial_state, perform_measurements=True): qubits = cirq.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qid_shape = cirq.qid_shape(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} if isinstance(initial_state, int): state_val = initial_state else: state_val = cirq.big_endian_digits_to_int(initial_state, base=qid_shape) state = _State.from_basis_state(state_val, qid_shape, path_limit=self.path_limit, tolerance=self.tolerance) if len(circuit) == 0: yield FeynmanPathSimulatorStep(state, {}, qubit_map) def on_stuck(bad_op): return TypeError( "Can't simulate unknown operations that don't specify a" "unitary or a decomposition. {!r}".format(bad_op)) def keep(potential_op): return (cirq.has_unitary(potential_op) or cirq.has_mixture(potential_op) or cirq.is_measurement(potential_op) or cirq.op_gate_isinstance(potential_op, cirq.ResetChannel)) def simulate_op(op, temp_state): indices = [qubit_map[q] for q in op.qubits] if cirq.op_gate_isinstance(op, cirq.ResetChannel): self._simulate_reset(op, cirq.ResetChannel) elif cirq.is_measurement(op): if perform_measurements: self._simulate_measurement( op, temp_state, indices, measurements) elif cirq.has_mixture(op): self._simulate_mixture(op, temp_state, indices) else: if cirq.num_qubits(op) <= 3: self._simulate_unitary(op, temp_state, indices) else: decomp_ops = cirq.decompose_once(op, default=None) if decomp_ops is None: self._simulate_unitary(op, temp_state, indices) else: for sub_op in cirq.flatten_op_tree(decomp_ops): simulate_op(sub_op, temp_state) for moment in circuit: measurements = defaultdict(list) known_ops = cirq.decompose(moment, keep=keep, on_stuck_raise=on_stuck) for op in known_ops: simulate_op(op, state) yield FeynmanPathSimulatorStep(state, measurements, qubit_map)
def test_big_endian_digits_to_int(): with pytest.raises(ValueError, match=r'len\(base\)'): _ = cirq.big_endian_digits_to_int([1, 2, 3], base=[2, 3, 5, 7]) with pytest.raises(ValueError, match='Out of range'): _ = cirq.big_endian_digits_to_int([105, 106, 107], base=4) assert cirq.big_endian_digits_to_int([0, 1], base=102) == 1 assert cirq.big_endian_digits_to_int([1, 0], base=102) == 102 assert cirq.big_endian_digits_to_int([1, 0], base=[5, 7]) == 7 assert cirq.big_endian_digits_to_int([0, 1], base=[5, 7]) == 1 assert cirq.big_endian_digits_to_int([1, 2, 3, 4], base=[2, 3, 5, 7]) == 200 assert cirq.big_endian_digits_to_int([1, 2, 3, 4], base=10) == 1234 # Use-once digit and base iterators. assert cirq.big_endian_digits_to_int((e for e in [1, 2, 3, 4]), base=(e for e in [2, 3, 5, 7])) == 200
def _apply_unitary(self, op, unitary, op_shape, state, indices): indices = list(indices) target_state = state[indices] target_val = cirq.big_endian_digits_to_int(target_state, base=op_shape) result_wavefunction = unitary[:, target_val] result_val = np.argmax(np.abs(result_wavefunction)) if not (np.isclose(np.abs(result_wavefunction[result_val]), 1) and np.sum(1 - np.isclose(result_wavefunction, 0)) == 1): # The output state vector does not represent a single basis state raise ValueError( "Can't simulate non-classical operations. " "The operation's unitary is not a permutation matrix: " "{!r}\n{!r}".format(op, unitary)) result_state = cirq.big_endian_int_to_digits(result_val, base=op_shape) state[indices] = result_state
def apply_unitary(self, indices, unitary): sub_shape = [self.qid_shape[i] for i in indices] self.buffer_state.clear() for digits, amplitude in self.state.items(): new_digits = list(digits) if np.isclose(amplitude, 0, rtol=1, atol=self.tolerance): continue target_val = cirq.big_endian_digits_to_int( (digits[i] for i in indices), base=sub_shape) result_wavefunction = unitary[:, target_val] for result_amp, new_targ_digits in zip( result_wavefunction, itertools.product(*(range(d) for d in sub_shape))): if np.isclose(result_amp, 0, rtol=1, atol=self.tolerance): continue for i, dig in zip(indices, new_targ_digits): new_digits[i] = dig self.buffer_state[tuple(new_digits)] += amplitude * result_amp self.state, self.buffer_state = self.buffer_state, self.state if len(self.state) > self.path_limit: raise PathLimitError
def _base_iterator(self, circuit, qubit_order, initial_state, perform_measurements=True): qubits = cirq.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qid_shape = cirq.qid_shape(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} if isinstance(initial_state, int): state_val = initial_state else: state_val = cirq.big_endian_digits_to_int(initial_state, base=qid_shape) state = np.array(list( cirq.big_endian_int_to_digits(state_val, base=qid_shape)), dtype=np.uint8) if len(circuit) == 0: yield ClassicalSimulatorStep(state, {}, qubit_map) def on_stuck(bad_op): return TypeError( "Can't simulate unknown operations that don't specify a " "unitary or a decomposition. {!r}".format(bad_op)) def keep(op): return ((cirq.num_qubits(op) <= 32 and (cirq.has_unitary(op) or cirq.has_mixture(op))) or cirq.is_measurement(op) or isinstance(op.gate, cirq.ResetChannel)) def simulate_op(op, temp_state): indices = [qubit_map[q] for q in op.qubits] if isinstance(op.gate, cirq.ResetChannel): self._simulate_reset(op, temp_state, indices) elif cirq.is_measurement(op): if perform_measurements: self._simulate_measurement(op, temp_state, indices, measurements) else: decomp_ops = cirq.decompose_once(op, default=None) if decomp_ops is None: self._simulate_from_matrix(op, temp_state, indices) else: try: temp2_state = temp_state.copy() for sub_op in cirq.flatten_op_tree(decomp_ops): simulate_op(sub_op, temp2_state) temp_state[...] = temp2_state except ValueError: # Non-classical unitary in the decomposition self._simulate_from_matrix(op, temp_state, indices) for moment in circuit: measurements = defaultdict(list) known_ops = cirq.decompose(moment, keep=keep, on_stuck_raise=on_stuck) for op in known_ops: simulate_op(op, state) yield ClassicalSimulatorStep(state.copy(), measurements, qubit_map)