Skip to content

Commit

Permalink
Merge pull request #1 from LaurinFischer/qiskit-nature-0.7_migration
Browse files Browse the repository at this point in the history
  • Loading branch information
fretchen authored Jan 9, 2024
2 parents fa52c02 + 96ba6fa commit d3fce39
Show file tree
Hide file tree
Showing 19 changed files with 503 additions and 413 deletions.
34 changes: 13 additions & 21 deletions docs/tutorials/01_introduction_and_fermionic_circuits.ipynb

Large diffs are not rendered by default.

38 changes: 15 additions & 23 deletions docs/tutorials/02_spin_circuits.ipynb

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions docs/tutorials/03_fermionic_tweezer_hardware.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"# give initial occupations separated by spin species\n",
"qc = backend.initialize_circuit([[1, 0, 0, 1], [0, 0, 1, 1]])\n",
"\n",
"qc.draw(output='mpl')"
"qc.draw(output='mpl', style='clifford')"
]
},
{
Expand Down Expand Up @@ -163,7 +163,7 @@
"# alternatively append the FH gate directly:\n",
"# qc.fhubbard(j=[0.5, 1., -1.], u=5., mu=[0., -1., 1., 0.], modes=all_modes)\n",
"\n",
"qc.draw(output='mpl')"
"qc.draw(output='mpl', style='clifford')"
]
},
{
Expand Down Expand Up @@ -220,7 +220,7 @@
"# qc.fint(2., all_modes)\n",
"# qc.fphase([1.], [2, 6])\n",
"\n",
"qc.draw(output= \"mpl\")"
"qc.draw(output= \"mpl\", style='clifford')"
]
},
{
Expand All @@ -245,23 +245,23 @@
"text": [
"hopping generator: \n",
" Fermionic Operator\n",
"register length=4, number terms=4\n",
"number spin orbitals=4, number terms=4\n",
" (-0.5+0j) * ( +_0 -_1 )\n",
"+ (0.5+0j) * ( -_0 +_1 )\n",
"+ (-0.5+0j) * ( +_2 -_3 )\n",
"+ (0.5+0j) * ( -_2 +_3 )\n",
"\n",
" interaction generator: \n",
" Fermionic Operator\n",
"register length=8, number terms=4\n",
"number spin orbitals=8, number terms=4\n",
" (2+0j) * ( +_0 -_0 +_4 -_4 )\n",
"+ (2+0j) * ( +_1 -_1 +_5 -_5 )\n",
"+ (2+0j) * ( +_2 -_2 +_6 -_6 )\n",
"+ (2+0j) * ( +_3 -_3 +_7 -_7 )\n",
"\n",
" phase generator: \n",
" Fermionic Operator\n",
"register length=2, number terms=2\n",
"number spin orbitals=2, number terms=2\n",
" (1+0j) * ( +_0 -_0 )\n",
"+ (1+0j) * ( +_1 -_1 )\n"
]
Expand Down Expand Up @@ -293,8 +293,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"counts: {'10100101': 19, '01101001': 21, '01100101': 55, '10101001': 5}\n",
"time taken: 0.05585169792175293\n"
"counts: {'10101001': 7, '01100101': 62, '01101001': 22, '10100101': 9}\n",
"time taken: 0.05115008354187012\n"
]
}
],
Expand Down Expand Up @@ -371,8 +371,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"counts: {'10100101': 18, '01101001': 18, '01100101': 57, '10101001': 7}\n",
"time taken: 0.03786921501159668\n",
"counts: {'10101001': 6, '01100101': 61, '01101001': 16, '10100101': 17}\n",
"time taken: 0.03921198844909668\n",
"basis: \n",
" 0. |0, 0, 1, 1>|0, 0, 1, 1>\n",
" 1. |0, 0, 1, 1>|0, 1, 0, 1>\n",
Expand Down Expand Up @@ -445,7 +445,7 @@
"\n",
"print(\"counts: \", backend.run(qc, num_species=2).result().get_counts())\n",
"\n",
"print(\"basis dimension :\", backend.get_basis(qc).dimension)\n"
"print(\"basis dimension :\", backend.get_basis(qc).dimension)"
]
},
{
Expand Down Expand Up @@ -624,7 +624,7 @@
{
"data": {
"text/html": [
"<h3>Version Information</h3><table><tr><th>Qiskit Software</th><th>Version</th></tr><tr><td><code>qiskit-terra</code></td><td>0.23.1</td></tr><tr><td><code>qiskit-aer</code></td><td>0.11.2</td></tr><tr><td><code>qiskit-nature</code></td><td>0.5.2</td></tr><tr><th>System information</th></tr><tr><td>Python version</td><td>3.9.16</td></tr><tr><td>Python compiler</td><td>MSC v.1916 64 bit (AMD64)</td></tr><tr><td>Python build</td><td>main, Jan 11 2023 16:16:36</td></tr><tr><td>OS</td><td>Windows</td></tr><tr><td>CPUs</td><td>8</td></tr><tr><td>Memory (Gb)</td><td>63.724937438964844</td></tr><tr><td colspan='2'>Wed Feb 22 16:58:34 2023 W. Europe Standard Time</td></tr></table>"
"<h3>Version Information</h3><table><tr><th>Software</th><th>Version</th></tr><tr><td><code>qiskit</code></td><td>0.45.1</td></tr><tr><td><code>qiskit_cold_atom</code></td><td>0.1.0</td></tr><tr><td><code>qiskit_algorithms</code></td><td>0.2.1</td></tr><tr><td><code>qiskit_aer</code></td><td>0.12.0</td></tr><tr><td><code>qiskit_nature</code></td><td>0.7.1</td></tr><tr><th colspan='2'>System information</th></tr><tr><td>Python version</td><td>3.9.16</td></tr><tr><td>Python compiler</td><td>MSC v.1916 64 bit (AMD64)</td></tr><tr><td>Python build</td><td>main, Jan 11 2023 16:16:36</td></tr><tr><td>OS</td><td>Windows</td></tr><tr><td>CPUs</td><td>8</td></tr><tr><td>Memory (Gb)</td><td>63.724937438964844</td></tr><tr><td colspan='2'>Tue Jan 09 11:26:13 2024 W. Europe Standard Time</td></tr></table>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
Expand All @@ -636,7 +636,7 @@
{
"data": {
"text/html": [
"<div style='width: 100%; background-color:#d5d9e0;padding-left: 10px; padding-bottom: 10px; padding-right: 10px; padding-top: 5px'><h3>This code is a part of Qiskit</h3><p>&copy; Copyright IBM 2017, 2023.</p><p>This code is licensed under the Apache License, Version 2.0. You may<br>obtain a copy of this license in the LICENSE.txt file in the root directory<br> of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.<p>Any modifications or derivative works of this code must retain this<br>copyright notice, and modified files need to carry a notice indicating<br>that they have been altered from the originals.</p></div>"
"<div style='width: 100%; background-color:#d5d9e0;padding-left: 10px; padding-bottom: 10px; padding-right: 10px; padding-top: 5px'><h3>This code is a part of Qiskit</h3><p>&copy; Copyright IBM 2017, 2024.</p><p>This code is licensed under the Apache License, Version 2.0. You may<br>obtain a copy of this license in the LICENSE.txt file in the root directory<br> of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.<p>Any modifications or derivative works of this code must retain this<br>copyright notice, and modified files need to carry a notice indicating<br>that they have been altered from the originals.</p></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
Expand Down
24 changes: 15 additions & 9 deletions docs/tutorials/04_collective_spin_hardware.ipynb

Large diffs are not rendered by default.

95 changes: 53 additions & 42 deletions docs/tutorials/06_time_evolution.ipynb

Large diffs are not rendered by default.

92 changes: 62 additions & 30 deletions docs/tutorials/07_squeezing_in_qudits.ipynb

Large diffs are not rendered by default.

76 changes: 52 additions & 24 deletions docs/tutorials/08_fermions_in_double_well.ipynb

Large diffs are not rendered by default.

163 changes: 98 additions & 65 deletions docs/tutorials/09_ryberg_dynamics.ipynb

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions qiskit_cold_atom/applications/fermi_hubbard.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,32 +110,32 @@ def to_fermionic_op(self) -> FermionicOp:
A FermionicOp defining the systems Hamiltonian
"""

operator_labels = []
operator_labels = {}

# add hopping terms
for idx in range(self.size - 1):
right_to_left_up = "I" * idx + "+-" + "I" * (self.size * 2 - idx - 2)
operator_labels.append((right_to_left_up, -self.J))
left_to_right_up = "I" * idx + "-+" + "I" * (self.size * 2 - idx - 2)
operator_labels.append((left_to_right_up, self.J))
right_to_left_down = "I" * (self.size + idx) + "+-" + "I" * (self.size - idx - 2)
operator_labels.append((right_to_left_down, -self.J))
left_to_right_down = "I" * (self.size + idx) + "-+" + "I" * (self.size - idx - 2)
operator_labels.append((left_to_right_down, self.J))
right_to_left_up = f"+_{idx} -_{idx+1}"
operator_labels[right_to_left_up] = -self.J
left_to_right_up = f"-_{idx} +_{idx+1}"
operator_labels[left_to_right_up] = self.J
right_to_left_down = f"+_{self.size + idx} -_{self.size + idx+1}"
operator_labels[right_to_left_down] = -self.J
left_to_right_down = f"-_{self.size + idx} +_{self.size + idx+1}"
operator_labels[left_to_right_down] = self.J

# add interaction terms
for idx in range(self.size):
opstring = "I" * idx + "N" + "I" * (self.size - 1) + "N" + "I" * (self.size - 1 - idx)
operator_labels.append((opstring, self.U))
opstring = f"+_{idx} -_{idx} +_{self.size + idx} -_{self.size + idx}"
operator_labels[opstring] = self.U

# add potential terms
for idx in range(self.size):
op_up = "I" * idx + "N" + "I" * (2 * self.size - idx - 1)
operator_labels.append((op_up, self.mu[idx]))
op_down = "I" * (self.size + idx) + "N" + "I" * (self.size - idx - 1)
operator_labels.append((op_down, self.mu[idx]))
op_up = f"+_{idx} -_{idx}"
operator_labels[op_up] = self.mu[idx]
op_down = f"+_{self.size + idx} -_{self.size + idx}"
operator_labels[op_down] = self.mu[idx]

return FermionicOp(operator_labels)
return FermionicOp(operator_labels, num_spin_orbitals=2 * self.size)

def to_circuit(self, time: float = 1.0) -> QuantumCircuit:
"""
Expand Down
51 changes: 17 additions & 34 deletions qiskit_cold_atom/applications/time_evolution_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
ParityMapper,
)

from qiskit import QuantumCircuit, QuantumRegister
from qiskit.opflow.evolutions import PauliTrotterEvolution
from qiskit import execute
from qiskit import QuantumRegister
from qiskit import QuantumCircuit
from qiskit.algorithms import TimeEvolutionProblem
from qiskit.algorithms.time_evolvers import TrotterQRTE
from qiskit.quantum_info import Statevector

from qiskit_cold_atom.applications.fermionic_evolution_problem import (
FermionicEvolutionProblem,
Expand Down Expand Up @@ -90,23 +92,11 @@ def solve(self, problem: FermionicEvolutionProblem) -> List[float]:
# use qubit pipeline
circuits = self.construct_qubit_circuits(problem)

# construct observable
mapper = self.MAPPER_DICT[self.map_type]
qubit_observable = mapper.map(problem.observable)
observable_mat = qubit_observable.to_spmatrix()

observable_evs = [0.0] * len(problem.evolution_times)

for idx, circuit in enumerate(circuits):
circuit.measure_all()

job = execute(circuit, self.backend, shots=self.shots)
counts = job.result().get_counts().int_outcomes()

for outcome_ind in counts:
prob = counts[outcome_ind] / self.shots

observable_evs[idx] += prob * observable_mat.diagonal()[outcome_ind].real
observable_evs = [
Statevector(qc).expectation_value(qubit_observable) for qc in circuits
]

return observable_evs

Expand All @@ -131,12 +121,12 @@ def construct_qubit_circuits(self, problem: FermionicEvolutionProblem) -> List[Q
circuits = []

# construct circuit of initial state:
label = ["+" if bit else "I" for bit in psi_0.occupations_flat]
bitstr_op = FermionicOp("".join(label))
label = {f"+_{i}": 1.0 for i, bit in enumerate(psi_0.occupations_flat) if bit}
bitstr_op = FermionicOp(label, num_spin_orbitals=len(psi_0.occupations_flat))
qubit_op = mapper.map(bitstr_op)[0]
init_circ = QuantumCircuit(QuantumRegister(qubit_op.num_qubits, "q"))

for i, pauli_label in enumerate(qubit_op.primitive.paulis[0].to_label()[::-1]):
for i, pauli_label in enumerate(qubit_op.paulis.to_labels()[0][::-1]):
if pauli_label == "X":
init_circ.x(i)
elif pauli_label == "Y":
Expand All @@ -145,20 +135,13 @@ def construct_qubit_circuits(self, problem: FermionicEvolutionProblem) -> List[Q
init_circ.z(i)

for time in problem.evolution_times:
# time-step of zero will cause PauliTrotterEvolution to fail
if time == 0.0:
time += 1e-10

# map fermionic hamiltonian to qubits
qubit_hamiltonian = mapper.map(hamiltonian * time)
# get time evolution operator by exponentiating
exp_op = qubit_hamiltonian.exp_i()
# perform trotterization

evolved_op = PauliTrotterEvolution(reps=self.trotter_steps).convert(exp_op)

trotter_circ = evolved_op.to_circuit_op().to_circuit()

circuits.append(init_circ.compose(trotter_circ))
qubit_hamiltonian = mapper.map(hamiltonian)
# construct trotterization circuits
evolution_problem = TimeEvolutionProblem(qubit_hamiltonian, time, init_circ)
trotter_qrte = TrotterQRTE(num_timesteps=self.trotter_steps)
evolved_state = trotter_qrte.evolve(evolution_problem).evolved_state
circuits.append(evolved_state)

return circuits
43 changes: 21 additions & 22 deletions qiskit_cold_atom/fermions/fermion_circuit_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,23 +143,21 @@ def _embed_operator(
f"Expected FermionicOp; got {type(operator).__name__} instead."
)

if operator.register_length != len(qargs):
if operator.num_spin_orbitals != len(qargs):
raise QiskitColdAtomError(
f"length of gate labels {operator.register_length} does not match "
f"length of gate labels {operator.num_spin_orbitals} does not match "
f"qargs {qargs} of the gates"
)

embedded_op_list = []
embedded_terms = []

for partial_label, factor in operator.to_list(display_format="dense"):
full_label = ["I"] * num_wires
for partial_label, factor in operator.terms():
embedded_terms.append((operator._permute_term(partial_label, qargs), factor))

for i, individual_label in enumerate(list(partial_label)):
full_label[qargs[i]] = individual_label
reordered_op = FermionicOp.from_terms(embedded_terms)
reordered_op.num_spin_orbitals = num_wires

embedded_op_list.append(("".join(full_label), factor))

return FermionicOp(embedded_op_list)
return reordered_op

def _check_conservations(self, circuit: QuantumCircuit) -> Tuple[bool, bool]:
"""
Expand Down Expand Up @@ -189,17 +187,17 @@ def _check_conservations(self, circuit: QuantumCircuit) -> Tuple[bool, bool]:
if not isinstance(fermionic_op, FermionicOp):
raise QiskitColdAtomError("operators need to be given as FermionicOp")

for term in fermionic_op.to_list():
opstring = term[0]
if fermionic_op.num_spin_orbitals != circuit.num_qubits:
raise QiskitColdAtomError(
f"Expected length {circuit.num_qubits} for fermionic operator; "
f"received {fermionic_op.num_spin_orbitals}."
)

if len(opstring) != circuit.num_qubits:
raise QiskitColdAtomError(
f"Expected length {circuit.num_qubits} for fermionic operator; "
f"received {len(opstring)}."
)
for opstring, _ in fermionic_op.terms():

num_creators = opstring.count("+")
num_annihilators = opstring.count("-")
op_types = [op for op, _ in opstring]
num_creators = op_types.count("+")
num_annihilators = op_types.count("-")

if num_creators != num_annihilators:
return False, False
Expand All @@ -215,9 +213,10 @@ def _check_conservations(self, circuit: QuantumCircuit) -> Tuple[bool, bool]:

# check if the particle number is conserved for each spin species
for i in range(self.num_species):
ops = opstring[i * sites : (i + 1) * sites]
num_creators = ops.count("+")
num_annihilators = ops.count("-")
spin_range = range(i * sites, (i + 1) * sites)
op_types_in_range = [op for op, idx in opstring if idx in spin_range]
num_creators = op_types_in_range.count("+")
num_annihilators = op_types_in_range.count("-")

if num_creators != num_annihilators:
spin_conservation = False
Expand Down
Loading

0 comments on commit d3fce39

Please sign in to comment.