def _calculate_unitaries(self): matrices = K.stack([ self._tfkron( self.one_qubit_gate(q1, theta=self.params[q1]).unitary, self.one_qubit_gate(q2, theta=self.params[q2]).unitary) for q1, q2 in self.pairs ], axis=0) entangling_matrix = self.two_qubit_gate(0, 1).unitary matrices = K.matmul(entangling_matrix, matrices) additional_matrix = None q = self.additional_target if q is not None: additional_matrix = self.one_qubit_gate( q, theta=self.params[q]).unitary if self.params2: matrices2 = K.stack([ self._tfkron( self.one_qubit_gate(q1, theta=self.params2[q1]).unitary, self.one_qubit_gate(q2, theta=self.params2[q2]).unitary) for q1, q2 in self.pairs ], axis=0) matrices = K.matmul(matrices2, matrices) q = self.additional_target if q is not None: additional_matrix = K.matmul( self.one_qubit_gate(q, theta=self.params2[q]).unitary, additional_matrix) return matrices, additional_matrix
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 __call__(self, state): propagator = self.current_hamiltonian.exp(self.dt) self.t += self.dt return K.matmul(propagator, state[:, K.newaxis])[:, 0]
def _convert_to_decimal(self): _range = K.range(self.nqubits - 1, -1, -1, dtype=K.dtypes('DTYPEINT')) _range = K.pow(2, _range)[:, K.newaxis] return K.matmul(self.binary, _range)[:, 0]
def density_matrix_call(self, state): return K.trace(K.matmul(self.hamiltonian.matrix, state))