def test_basis_change(simulator): for angle in list(uniform(0, 2 * pi, 5)): EX = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle), H=PX(0)), backend=simulator) EY = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle), H=PY(0)), backend=simulator) EZ = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle), H=PZ(0)), backend=simulator) EXX = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle) + change_basis(target=0, axis=0), H=PZ(0)), backend=simulator) EYY = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle) + change_basis(target=0, axis=1), H=PZ(0)), backend=simulator) EZZ = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle) + change_basis(target=0, axis=2), H=PZ(0)), backend=simulator) assert (isclose(EX, EXX, atol=1.e-4)) assert (isclose(EY, EYY, atol=1.e-4)) assert (isclose(EZ, EZZ, atol=1.e-4)) for i, gate in enumerate([gates.Rx, gates.Ry, gates.Rz]): angle = uniform(0, 2 * pi) U1 = gate(target=0, angle=angle) U2 = change_basis(target=0, axis=i) + gates.Rz(target=0, angle=angle) + change_basis(target=0, axis=i, daggered=True) wfn1 = simulate(U1, backend=simulator) wfn2 = simulate(U2, backend=simulator) assert (isclose(numpy.abs(wfn1.inner(wfn2)) ** 2, 1.0, atol=1.e-4)) if simulator == "qiskit": return # initial state not yet supported wfn1 = simulate(U1, initial_state=1, backend=simulator) wfn2 = simulate(U2, initial_state=1, backend=simulator) assert (isclose(numpy.abs(wfn1.inner(wfn2)) ** 2, 1.0, atol=1.e-4))
def sample_paulistring(self, samples: int, paulistring, variables, *args, **kwargs) -> numbers.Real: """ Sample an individual pauli word (pauli string) and return the average result thereof. Parameters ---------- samples: int: how many samples to evaluate. paulistring: the paulistring to be sampled. args kwargs Returns ------- float: the average result of sampling the chosen paulistring """ not_in_u = [ q for q in paulistring.qubits if q not in self.abstract_qubits ] reduced_ps = paulistring.trace_out_qubits(qubits=not_in_u) if reduced_ps.coeff == 0.0: return 0.0 if len(reduced_ps._data.keys()) == 0: return reduced_ps.coeff # make basis change and translate to backend basis_change = QCircuit() qubits = [] for idx, p in reduced_ps.items(): qubits.append(idx) basis_change += change_basis(target=idx, axis=p) # add basis change to the circuit # deepcopy is necessary to avoid changing the circuits # can be circumvented by optimizing the measurements # on construction: tq.ExpectationValue(H=H, U=U, optimize_measurements=True) circuit = self.create_circuit(circuit=copy.deepcopy(self.circuit), abstract_circuit=basis_change) # run simulators counts = self.sample(samples=samples, circuit=circuit, read_out_qubits=qubits, variables=variables, *args, **kwargs) # compute energy E = 0.0 n_samples = 0 for key, count in counts.items(): parity = key.array.count(1) sign = (-1)**parity E += sign * count n_samples += count assert n_samples == samples E = E / samples * paulistring.coeff return E
def sample_paulistring(self, samples: int, paulistring, *args, **kwargs) -> numbers.Real: # make basis change and translate to backend basis_change = QCircuit() not_in_u = [ ] # all indices of the paulistring which are not part of the circuit i.e. will always have the same outcome qubits = [] for idx, p in paulistring.items(): if idx not in self.abstract_qubit_map: not_in_u.append(idx) else: qubits.append(idx) basis_change += change_basis(target=idx, axis=p) # check the constant parts as <0|pauli|0>, can only be 0 or 1 # so we can do a fast return of one of them is not Z for i in not_in_u: pauli = paulistring[i] if pauli.upper() != "Z": return 0.0 # make measurement instruction measure = QCircuit() if len(qubits) == 0: # no measurement instructions for a constant term as paulistring return paulistring.coeff else: measure += Measurement(target=qubits) #measure += Measurement(name=str(paulistring), target=qubits) circuit = self.circuit + self.create_circuit(basis_change + measure) # run simulators counts = self.do_sample(samples=samples, circuit=circuit, *args, **kwargs) # compute energy E = 0.0 n_samples = 0 for key, count in counts.items(): parity = key.array.count(1) sign = (-1)**parity E += sign * count n_samples += count E = E / samples * paulistring.coeff return E
def sample_paulistring(self, samples: int, paulistring, variables, *args, **kwargs): """ Has to be rewritten because of the pro-scription in qibo against calling already executed circuits. Parameters ---------- samples: int: how many samples to take. paulistring: QubitHamiltonian: the paulistring to sample. variables: dict: the variables to instantiate upon sampling. args kwargs Returns ------- """ not_in_u = [ q for q in paulistring.qubits if q not in self.abstract_qubits ] reduced_ps = paulistring.trace_out_qubits(qubits=not_in_u) if reduced_ps.coeff == 0.0: return 0.0 if len(reduced_ps._data.keys()) == 0: return reduced_ps.coeff # make basis change and translate to backend basis_change = QCircuit() qubits = [] for idx, p in reduced_ps.items(): qubits.append(idx) basis_change += change_basis(target=idx, axis=p) highest_qubit = max(paulistring.qubits) new = self.rebuild_for_sample(abstract_circuit=basis_change, variables=variables, highest_qubit=highest_qubit) # run simulators counts = new.sample(samples=samples, circuit=new.circuit, read_out_qubits=qubits, variables=variables, *args, **kwargs) # compute energy E = 0.0 n_samples = 0 #print('printing the counts') #print(counts) for key, count in counts.items(): parity = key.array.count(1) sign = (-1)**parity E += sign * count n_samples += count assert n_samples == samples E = E / samples * paulistring.coeff return E