def sample(self, variables, samples, *args, **kwargs) -> numpy.array: # todo: generalize in baseclass. Do Hamiltonian mapping on initialization self.update_variables(variables) result = [] for H in self._abstract_hamiltonians: E = 0.0 for ps in H.paulistrings: # change basis, measurement is destructive so copy the state # to avoid recomputation bc = QCircuit() zero_string = False for idx, p in ps.items(): if idx not in self.U.qubit_map: # circuit does not act on the qubit # case1: paulimatrix is 'Z' -> unit factor: ignore that part # case2: zero factor -> continue with next ps if p.upper() != "Z": zero_string = True else: bc += change_basis(target=idx, axis=p) if zero_string: continue qbc = self.U.create_circuit(abstract_circuit=bc, variables=None) Esamples = [] for sample in range(samples): state_tmp = qulacs.QuantumState(self.U.n_qubits) self.U.circuit.update_quantum_state(state_tmp) if len( bc.gates ) > 0: # otherwise there is no basis change (empty qulacs circuit does not work out) qbc.update_quantum_state(state_tmp) ps_measure = 1.0 for idx in ps.keys(): if idx not in self.U.qubit_map: continue # means its 1 or Z and <0|Z|0> = 1 anyway else: M = qulacs.gate.Measurement( self.U.qubit_map[idx], self.U.qubit_map[idx]) M.update_quantum_state(state_tmp) measured = state_tmp.get_classical_value( self.U.qubit_map[idx]) ps_measure *= (-2.0 * measured + 1.0 ) # 0 becomes 1 and 1 becomes -1 Esamples.append(ps_measure) E += ps.coeff * sum(Esamples) / len(Esamples) result.append(E) return numpy.asarray(result)
def sample(self, variables, samples, *args, **kwargs) -> numpy.array: """ Sample this Expectation Value. Parameters ---------- variables: variables, to supply to the underlying circuit. samples: int: the number of samples to take. args kwargs Returns ------- numpy.ndarray: the result of sampling as a number. """ self.update_variables(variables) state = self.U.initialize_state(self.n_qubits) self.U.circuit.update_quantum_state(state) result = [] for H in self._reduced_hamiltonians: # those are the hamiltonians which where non-used qubits are already traced out E = 0.0 if H.is_all_z() and not self.U.has_noise: E = super().sample(samples=samples, variables=variables, *args, **kwargs) else: for ps in H.paulistrings: # change basis, measurement is destructive so the state will be copied # to avoid recomputation (except when noise was required) bc = QCircuit() for idx, p in ps.items(): bc += change_basis(target=idx, axis=p) qbc = self.U.create_circuit(abstract_circuit=bc, variables=None) Esamples = [] for sample in range(samples): if self.U.has_noise and sample > 0: state = self.U.initialize_state(self.n_qubits) self.U.circuit.update_quantum_state(state) state_tmp = state else: state_tmp = state.copy() if len( bc.gates ) > 0: # otherwise there is no basis change (empty qulacs circuit does not work out) qbc.update_quantum_state(state_tmp) ps_measure = 1.0 for idx in ps.keys(): assert idx in self.U.abstract_qubits # assert that the hamiltonian was really reduced M = qulacs.gate.Measurement( self.U.qubit(idx), self.U.qubit(idx)) M.update_quantum_state(state_tmp) measured = state_tmp.get_classical_value( self.U.qubit(idx)) ps_measure *= (-2.0 * measured + 1.0 ) # 0 becomes 1 and 1 becomes -1 Esamples.append(ps_measure) E += ps.coeff * sum(Esamples) / len(Esamples) result.append(E) return numpy.asarray(result)