Vibrational Structure Problems with v0.5#
Further resources#
Be sure to check out the vibrational structure tutorial for more details on how to use the new code.
TL;DR#
This section gives you one cell with a v0.4 code followed by one cell with v0.5 code doing the same things. Hopefully this already gives you all the information which you were looking for.
Previously#
from qiskit_nature.drivers.second_quantization import GaussianForcesDriver
from qiskit_nature.problems.second_quantization import VibrationalStructureProblem
from qiskit_nature.settings import settings
settings.dict_aux_operators = True
driver = GaussianForcesDriver(logfile="aux_files/CO2_freq_B3LYP_631g.log")
problem = VibrationalStructureProblem(driver, num_modals=[2, 2, 3, 4], truncation_order=2)
# Note: at this point, `driver.run()` has NOT been called yet. We can trigger this indirectly like so:
second_q_ops = problem.second_q_ops()
hamiltonian = second_q_ops["VibrationalEnergy"]
print("\n".join(str(hamiltonian).splitlines()[:10] + ["..."]))
NIIIIIIIIII * (1268.0676746875001+0j)
+ INIIIIIIIII * (3813.8767834375008+0j)
+ IINIIIIIIII * (705.8633818750001+0j)
+ II+-IIIIIII * (-46.025705898886045+0j)
+ II-+IIIIIII * (-46.025705898886045+0j)
+ IIINIIIIIII * (2120.1145593750007+0j)
+ IIIINIIIIII * (238.31540750000005+0j)
+ IIII+I-IIII * (19.820422279761104+0j)
+ IIIIINIIIII * (728.9613775000003+0j)
+ IIII-I+IIII * (19.820422279761104+0j)
...
New#
from qiskit_nature.second_q.drivers import GaussianForcesDriver
from qiskit_nature.second_q.problems import HarmonicBasis
driver = GaussianForcesDriver(logfile="aux_files/CO2_freq_B3LYP_631g.log")
basis = HarmonicBasis(num_modals=[2, 2, 3, 4])
# this is now done explicitly and already requires the basis
problem = driver.run(basis=basis)
problem.hamiltonian.truncation_order = 2
hamiltonian = problem.hamiltonian.second_q_op()
print("\n".join(str(hamiltonian).splitlines()[:10] + ["..."]))
Vibrational Operator
number modes=4, number modals=[2, 2, 3, 4], number terms=177
(1268.0676746875001+0j) * ( +_0_0 -_0_0 )
+ (3813.8767834375008+0j) * ( +_0_1 -_0_1 )
+ (705.8633818750002+0j) * ( +_1_0 -_1_0 )
+ (-46.025705898886045+0j) * ( +_1_0 -_1_1 )
+ (-46.025705898886045+0j) * ( +_1_1 -_1_0 )
+ (2120.1145593750007+0j) * ( +_1_1 -_1_1 )
+ (238.31540750000005+0j) * ( +_2_0 -_2_0 )
+ (19.82042227976109+0j) * ( +_2_0 -_2_2 )
...
qiskit_nature.drivers
#
This section deals exclusively with the migration of the vibrational structure-related drivers.
The table below summarizes where each of the vibrational structure
components of qiskit_nature.drivers.second_quantization
has ended
up.
Legacy component |
New location |
---|---|
BaseDriver |
|
VibrationalStructureDriver |
|
VibrationalStructureDriverType |
removed |
VibrationalStructureMoleculeDriver |
removed |
GaussianForcesDriver |
|
GaussianLogDriver |
|
GaussianLogResult |
|
Furthermore, the two components from qiskit_nature.drivers
were
moved like so:
Legacy component |
New location |
---|---|
Molecule |
|
UnitsType |
|
A few notes are worth adding:
The
VibrationalStructureMoleculeDriver
was removed because we are steering towards a future with tighter, plugin-like integration with classical codes, making the concept of drivers where Qiskit starts a classical simulation outdated. You can still use the.from_molecule(...)
methods of the remaining drivers in combination with theMoleculeInfo
class.The
MoleculeInfo
has become a pure data container and no longer supports degrees of freedom.
Vibrational Structure Drivers#
Vibrational structure drivers work slightly differently than their electronic structure counterparts, because you must supply a basis upon running the driver, which maps the real-space Watson hamiltonian into second-quantized space. This was treated inconsistently in Qiskit Nature v0.4 as explained below.
Previously#
In Qiskit Nature v0.4 the stack implementation was actually inconsistent
because the VibrationalIntegrals
(which were part of the
second_quantization
stack) were actually storing the coefficients of
the real-space Watson hamiltonian. Only later would these get mapped to
a specified basis:
from qiskit_nature.drivers.second_quantization import GaussianLogResult
from qiskit_nature.properties.second_quantization.vibrational.bases import HarmonicBasis
from qiskit_nature.settings import settings
settings.dict_aux_operators = True
log_result = GaussianLogResult("aux_files/CO2_freq_B3LYP_631g.log")
hamiltonian = log_result.get_vibrational_energy()
print(hamiltonian)
hamiltonian.basis = HarmonicBasis([2, 2, 3, 4])
op = hamiltonian.second_q_ops()["VibrationalEnergy"]
print("\n".join(str(op).splitlines()[:10] + ["..."]))
VibrationalEnergy:
None
1-Body Terms:
<sparse integral list with 13 entries>
(2, 2) = 352.3005875
(-2, -2) = -352.3005875
(1, 1) = 631.6153975
(-1, -1) = -631.6153975
(4, 4) = 115.653915
... skipping 8 entries
2-Body Terms:
<sparse integral list with 11 entries>
(1, 1, 2) = -88.2017421687633
(4, 4, 2) = 42.675273102831454
(3, 3, 2) = 42.675273102831454
(1, 1, 2, 2) = 4.9425425
(4, 4, 2, 2) = -4.194299375
... skipping 6 entries
3-Body Terms:
<sparse integral list with 0 entries>
NIIIIIIIIII * (1268.0676746875001+0j)
+ INIIIIIIIII * (3813.8767834375008+0j)
+ IINIIIIIIII * (705.8633818750001+0j)
+ II+-IIIIIII * (-46.025705898886045+0j)
+ II-+IIIIIII * (-46.025705898886045+0j)
+ IIINIIIIIII * (2120.1145593750007+0j)
+ IIIINIIIIII * (238.31540750000005+0j)
+ IIII+I-IIII * (19.820422279761104+0j)
+ IIIIINIIIII * (728.9613775000003+0j)
+ IIII-I+IIII * (19.820422279761104+0j)
...
New#
As of Qiskit Nature v0.5 the design is now consistently separating the
treatment of the real-space Watson hamiltonian from the second-quantized
coefficients. This is achieved by introducing a dedicated dataclass
storing a WatsonHamiltonian
:
from qiskit_nature.second_q.drivers import GaussianLogResult
from qiskit_nature.second_q.formats import watson_to_problem
from qiskit_nature.second_q.problems import HarmonicBasis
log_result = GaussianLogResult("aux_files/CO2_freq_B3LYP_631g.log")
watson = log_result.get_watson_hamiltonian()
print(watson)
basis = HarmonicBasis(num_modals=[2, 2, 3, 4])
problem = watson_to_problem(watson, basis)
hamiltonian = problem.hamiltonian.second_q_op()
print("\n".join(str(hamiltonian).splitlines()[:10] + ["..."]))
WatsonHamiltonian(quadratic_force_constants=<COO: shape=(4, 4), dtype=float64, nnz=4, fill_value=0.0>, cubic_force_constants=<COO: shape=(4, 4, 4), dtype=float64, nnz=4, fill_value=0.0>, quartic_force_constants=<COO: shape=(4, 4, 4, 4), dtype=float64, nnz=12, fill_value=0.0>, kinetic_coefficients=<COO: shape=(4, 4), dtype=float64, nnz=4, fill_value=-0.0>)
Vibrational Operator
number modes=4, number modals=[2, 2, 3, 4], number terms=177
(1268.0676746875001+0j) * ( +_0_0 -_0_0 )
+ (3813.8767834375008+0j) * ( +_0_1 -_0_1 )
+ (705.8633818750002+0j) * ( +_1_0 -_1_0 )
+ (-46.025705898886045+0j) * ( +_1_0 -_1_1 )
+ (-46.025705898886045+0j) * ( +_1_1 -_1_0 )
+ (2120.1145593750007+0j) * ( +_1_1 -_1_1 )
+ (238.31540750000005+0j) * ( +_2_0 -_2_0 )
+ (19.82042227976109+0j) * ( +_2_0 -_2_2 )
...
The VibrationalStructureProblem
(qiskit_nature.problems
)#
This section details all the changes around the
VibrationalStructureProblem
.
The table below summarizes the vibrational components of the new
qiskit_nature.second_q.problems
module, and shows from where these
parts originated in the old code:
New component |
Legacy location |
---|---|
|
|
|
|
|
similar to
|
|
|
|
|
|
|
|
did not exist yet |
|
|
Previously#
from qiskit_nature.drivers.second_quantization import GaussianForcesDriver
from qiskit_nature.problems.second_quantization import VibrationalStructureProblem
driver = GaussianForcesDriver(logfile="aux_files/CO2_freq_B3LYP_631g.log")
problem = VibrationalStructureProblem(driver, num_modals=[2, 2, 3, 4], truncation_order=2)
# we trigger driver.run() implicitly like so:
second_q_ops = problem.second_q_ops()
hamiltonian_op = second_q_ops.pop("VibrationalEnergy")
aux_ops = second_q_ops
New#
from qiskit_nature.second_q.drivers import GaussianForcesDriver
from qiskit_nature.second_q.problems import HarmonicBasis
driver = GaussianForcesDriver(logfile="aux_files/CO2_freq_B3LYP_631g.log")
basis = HarmonicBasis(num_modals=[2, 2, 3, 4])
problem = driver.run(basis=basis)
problem.hamiltonian.truncation_order = 2
hamiltonian_op, aux_ops = problem.second_q_ops()
For more information on the new and improved
VibrationalStructureProblem
, please refer to the vibrational
structure tutorial.
qiskit_nature.properties
#
The properties module has been refactored and split into multiple locations. In this section, we will only be focusing on its vibrational components.
The following table lists where each component of
qiskit_nature.properties
has been moved to.
Legacy component |
New location |
---|---|
|
|
|
succeeded by
|
|
removed |
|
|
|
|
|
|
|
|
|
succeeded by
|
We suggest that you look at the vibrational structure tutorial for more in-depth explanations, but we will leave a few comments here:
the
VibrationalBasis
is now only tracked on theVibrationalStructureProblem
and not for each operator individuallythe
VibrationalEnergy
(which has always been a_special_Property
) is in the newsecond_q.hamiltonians
module to highlight this special role