def _dagger(self) -> "Unitary": unitary = self.parameters if isinstance(unitary, K.Tensor): ud = K.conj(K.transpose(unitary)) else: ud = unitary.conj().T return self.__class__(ud, *self.target_qubits, **self.init_kwargs)
def _custom_density_matrix_call(self, state): state = K._density_matrix_half_call(self, state) matrix = K.conj(K.matrices.Y) shape = state.shape state = K.reshape(state, (K.np.prod(shape), )) original_targets = tuple(self.target_qubits) self._target_qubits = self.cache.target_qubits_dm self._nqubits *= 2 self.gate_op = K.op.apply_gate self._custom_op_matrix = K.conj(K.matrices.Y) state = K.state_vector_matrix_call(self, state) self._custom_op_matrix = K.matrices.Y self.gate_op = K.op.apply_y self._nqubits //= 2 self._target_qubits = original_targets return K.reshape(state, shape)
def _custom_density_matrix_call(self, state): state = K._density_matrix_half_call(self, state) matrix = K.conj(K.matrices.Y) shape = state.shape state = K.reshape(state, (K.np.prod(shape), )) original_targets = tuple(self.target_qubits) self._target_qubits = self.cache.target_qubits_dm self._nqubits *= 2 self.name = "Unitary" # change name temporarily so that ``apply_gate`` op is used self._custom_op_matrix = K.conj(K.matrices.Y) state = K.state_vector_matrix_call(self, state) self._custom_op_matrix = K.matrices.Y self.name = "y" self._nqubits //= 2 self._target_qubits = original_targets return K.reshape(state, shape)
def _dagger(self) -> "GenerelizedfSim": unitary, phi = self.parameters if isinstance(unitary, K.native_types): ud = K.conj(K.transpose(unitary)) else: ud = unitary.conj().T q0, q1 = self.target_qubits return self.__class__(q0, q1, ud, -phi)
def density_matrix_call(self, state): state = self.gate_op(state, self.qubits_tensor_dm, 2 * self.nqubits, *self.target_qubits, get_threads()) matrix = K.conj(matrices.Y) state = K.op.apply_gate(state, matrix, self.qubits_tensor, 2 * self.nqubits, *self.target_qubits_dm, get_threads()) return state
def expectation(self, hamiltonian, normalize=False): statec = K.conj(self.tensor) hstate = hamiltonian @ self.tensor ev = K.real(K.sum(statec * hstate)) if normalize: norm = K.sum(K.square(K.abs(self.tensor))) ev = ev / norm return ev
def _custom_density_matrix_call(self, state): state = self.gate_op(state, self.cache.qubits_tensor + self.nqubits, 2 * self.nqubits, *self.target_qubits, K.get_threads()) matrix = K.conj(K.matrices.Y) state = K.op.apply_gate(state, matrix, self.cache.qubits_tensor, 2 * self.nqubits, *self.cache.target_qubits_dm, K.get_threads()) return state
def density_matrix_call(self, state): state = K.reshape(state, self.tensor_shape) if self.is_controlled_by: ncontrol = len(self.control_qubits) nactive = self.nqubits - ncontrol n = 2**ncontrol state = K.transpose(state, self.control_cache.order(True)) state = K.reshape(state, 2 * (n, ) + 2 * nactive * (2, )) state01 = K.gather(state, indices=range(n - 1), axis=0) state01 = K.squeeze(K.gather(state01, indices=[n - 1], axis=1), axis=1) state01 = self.einsum(self.calculation_cache.right0, state01, K.conj(self.matrix)) state10 = K.gather(state, indices=range(n - 1), axis=1) state10 = K.squeeze(K.gather(state10, indices=[n - 1], axis=0), axis=0) state10 = self.einsum(self.calculation_cache.left0, state10, self.matrix) state11 = K.squeeze(K.gather(state, indices=[n - 1], axis=0), axis=0) state11 = K.squeeze(K.gather(state11, indices=[n - 1], axis=0), axis=0) state11 = self.einsum(self.calculation_cache.right, state11, K.conj(self.matrix)) state11 = self.einsum(self.calculation_cache.left, state11, self.matrix) state00 = K.gather(state, indices=range(n - 1), axis=0) state00 = K.gather(state00, indices=range(n - 1), axis=1) state01 = K.concatenate([state00, state01[:, K.newaxis]], axis=1) state10 = K.concatenate([state10, state11[K.newaxis]], axis=0) state = K.concatenate([state01, state10[K.newaxis]], axis=0) state = K.reshape(state, 2 * self.nqubits * (2, )) state = K.transpose(state, self.control_cache.reverse(True)) else: state = self.einsum(self.calculation_cache.right, state, K.conj(self.matrix)) state = self.einsum(self.calculation_cache.left, state, self.matrix) return K.reshape(state, self.flat_shape)
def density_matrix_call(self, state): state = self.gate_op( state, self.matrix, self.qubits_tensor_dm, # pylint: disable=E1121 2 * self.nqubits, *self.target_qubits, get_threads()) adjmatrix = K.conj(self.matrix) state = self.gate_op(state, adjmatrix, self.qubits_tensor, 2 * self.nqubits, *self.target_qubits_dm, get_threads()) return state
def __call__(self, cache: Dict, state: K.Tensor, gate: K.Tensor) -> K.Tensor: shapes = cache["shapes"] state = K.reshape(state, shapes[0]) state = K.transpose(state, cache["ids"]) if cache["conjugate"]: state = K.reshape(K.conj(state), shapes[1]) else: state = K.reshape(state, shapes[1]) n = len(tuple(gate.shape)) if n > 2: dim = 2**(n // 2) state = K.matmul(K.reshape(gate, (dim, dim)), state) else: state = K.matmul(gate, state) state = K.reshape(state, shapes[2]) state = K.transpose(state, cache["inverse_ids"]) state = K.reshape(state, shapes[3]) return state
def state_vector_partial_trace(self, state): self._set_nqubits(state) state = K.reshape(state, self.nqubits * (2, )) axes = 2 * [list(self.target_qubits)] rho = K.tensordot(state, K.conj(state), axes=axes) return K.reshape(rho, self.cache.reduced_shape)
def _dagger(self) -> "Unitary": ud = K.conj(K.transpose(self.parameters)) return self.__class__(ud, *self.target_qubits, **self.init_kwargs)
def construct_unitary(self): t = K.cast(self.parameters) phase = K.exp(1j * t / 2.0)[K.newaxis] diag = K.concatenate([K.conj(phase), phase], axis=0) return K.diag(diag)
def _construct_unitary(self): return K.conj( K.matrices.T) # no need to transpose because it's diagonal
def __init__(self, state): super().__init__() self.statec = K.conj(K.cast(state, dtype='DTYPECPX'))
def to_density_matrix(self): matrix = K.outer(self.tensor, K.conj(self.tensor)) return MatrixState.from_tensor(matrix, nqubits=self.nqubits)