def probabilities(self, qubits=None, measurement_gate=None): unmeasured_qubits = tuple(i for i in range(self.nqubits) if i not in qubits) tensor = self.tensor with K.on_cpu(): state = K.reshape(K.square(K.abs(tensor)), self.nqubits * (2, )) return K.sum(state, axis=unmeasured_qubits)
def test_qaoa_callbacks(backend, accelerators): from qibo import callbacks # use ``Y`` Hamiltonian so that there are no errors # in the Trotter decomposition if accelerators: with K.on_cpu(): h = hamiltonians.Y(5) else: h = hamiltonians.Y(5) energy = callbacks.Energy(h) params = 0.1 * np.random.random(4) state = random_state(5) ham = hamiltonians.Y(5, dense=False) qaoa = models.QAOA(ham, callbacks=[energy], accelerators=accelerators) qaoa.set_parameters(params) final_state = qaoa(np.copy(state)) h_matrix = K.to_numpy(h.matrix) m_matrix = K.to_numpy(qaoa.mixer.matrix) calc_energy = lambda s: (s.conj() * h_matrix.dot(s)).sum() target_state = np.copy(state) target_energy = [calc_energy(target_state)] for i, p in enumerate(params): if i % 2: u = expm(-1j * p * m_matrix) else: u = expm(-1j * p * h_matrix) target_state = u @ target_state target_energy.append(calc_energy(target_state)) K.assert_allclose(energy[:], target_energy)
def create_pieces(self): """Creates :class:`qibo.core.states.DistributedState` pieces on CPU.""" n = 2**self.nlocal with K.on_cpu(): self.pieces = [ K.cpu_tensor(K.zeros(n)) for _ in range(self.ndevices) ]
def zero_state(cls, circuit): """Creates ``|00...0>`` as a distributed state.""" state = cls(circuit) state.create_pieces() with K.on_cpu(): piece = K.initial_state(nqubits=state.nlocal) state.pieces[0] = K.cpu_tensor(piece, dtype=state.dtype) return state
def assign_pieces(self, tensor): """Assigns state pieces from a given full state vector. Args: tensor (K.Tensor): The full state vector as a tensor supported by the underlying backend. """ if self.pieces is None: self.create_pieces() with K.on_cpu(): tensor = K.reshape(K.cpu_cast(tensor), self.shapes["device"]) pieces = [tensor[i] for i in range(self.ndevices)] new_tensor = K.zeros(self.shapes["device"]) with K.on_cpu(): new_tensor = K.transpose_state(pieces, new_tensor, self.nqubits, self.qubits.transpose_order) for i in range(self.ndevices): K.cpu_assign(self, i, new_tensor[i])
def plus_state(cls, circuit): """Creates ``|++...+>`` as a distributed state.""" state = cls(circuit) with K.on_cpu(): n = K.cast(2**state.nlocal, dtype=K.dtypes('DTYPEINT')) norm = K.cast(2**float(state.nqubits / 2.0)) state.pieces = [ K.cpu_tensor(K.ones(n) / norm) for _ in range(state.ndevices) ] return state
def _special_gate_execute(self, state, gate: Union["BackendGate"]): """Executes special gates on CPU. Currently special gates are ``Flatten`` or ``CallbackGate``. This method calculates the full state vector because special gates are not implemented for state pieces. """ with K.on_cpu(): # Reverse all global SWAPs that happened so far self._revert_swaps(state, reversed(gate.swap_reset)) full_state = state.tensor with K.on_cpu(): if isinstance(gate, gates.CallbackGate): gate(full_state) else: full_state = gate(full_state) state.assign_pieces(full_state) with K.on_cpu(): # Redo all global SWAPs that happened so far self._revert_swaps(state, gate.swap_reset)
def tensor(self): """Returns the full state vector as a tensor of shape ``(2 ** nqubits,)``. This is done by merging the state pieces to a single tensor. Using this method will double memory usage. """ if self.qubits.list == list(range(self.nglobal)): with K.on_cpu(): tensor = K.concatenate([x[K.newaxis] for x in self.pieces], axis=0) tensor = K.reshape(tensor, self.shapes["full"]) elif self.qubits.list == list(range(self.nlocal, self.nqubits)): with K.on_cpu(): tensor = K.concatenate([x[:, K.newaxis] for x in self.pieces], axis=1) tensor = K.reshape(tensor, self.shapes["full"]) else: # fall back to the transpose op with K.on_cpu(): tensor = K.zeros(self.shapes["full"]) tensor = K.transpose_state(self.pieces, tensor, self.nqubits, self.qubits.reverse_transpose_order) return tensor
def set_device_seed(seed, accelerators): if accelerators: with K.on_cpu(): K.set_seed(seed) else: K.set_seed(seed)
def _device(self): return K.on_cpu()
def calculate_callbacks_distributed(state): with K.on_cpu(): if not isinstance(state, K.tensor_types): state = state.tensor with K.on_cpu(): calculate_callbacks(state)