Release Notes#
0.7.2#
New Features#
The
AngularMomentum.overlap()
property will now warn the user, when this matrix is non-unitary.
Added support for using Qiskit Nature with Python 3.12.
Bug Fixes#
Fixes the
AngularMomentum
operator further to also support cases where the number of beta-spin particles exceeds the number of alpha-spin particles.
The commutator methods were faultily trying to call
normal_order()
on their operands, which are not guaranteed to have this method. Now, they no longer call this method and instead it is up to the user to normal-order the result as needed.
0.7.1#
New Features#
Added the
get_overlap_ab_from_qcschema()
function which extracts the alpha-beta spin orbital overlap matrix from aQCSchema
instance.
Bug Fixes#
Fixes the following operators when dealing with non-orthonormal orbitals (for example when using unrestricted spin orbitals): -
AnglarMomentum
-s_plus_operator()
-s_minus_operator()
-s_x_operator()
-s_y_operator()
To make the fix take effect, the new additional overlap argument needs to be provided to all of these operators.
Prior to this fix, none of the operators above were able to resolve any spin contamination and would yield misleadingly “clean” expectation values. See this issue for a more complete discussion.
0.7.0#
Prelude#
Qiskit Nature has been migrated to the qiskit-community Github organization to further emphasize that it is a community-driven project. To reflect this change and because we are onboarding additional codeowners and maintainers, with this version (0.7) we have decided to remove all deprecated code, regardless of the time of its deprecation. This ensures that the new members of the development team do not have a large bulk of legacy code to maintain. This can mean one of two things for you as the end-user:
Nothing, if you already migrated your code and no longer rely on any deprecated features.
Otherwise, you need to migrate your code immediately. If you cannot do that, or want to continue using some of the features that were removed, you should pin your version of Qiskit Nature to 0.6
You can check out the migration guides for details on how to update your code. For more context on the changes around Qiskit Nature and the other application projects as well as the algorithms library in Qiskit, be sure to read this blog post.
New Features#
Adds a new lattice class,
HexagonalLattice
for the generation of hexagonal lattices.You construct a hexagonal lattice by specifying the number of rows and columns of hexagons. You can also specify the edge- and on-site-parameters.
Below is a simple example to illustrate this:
from qiskit_nature.second_q.hamiltonians.lattices import HexagonalLattice lattice = HexagonalLattice( 2, 3, edge_parameter=1.0, onsite_parameter=1.5, )
Adds a new lattice class,
KagomeLattice
for the generation of kagome lattices.For example, you can construct a kagome lattice with 4 and 3 unit cells in the x and y direction, respectively, which has weights 1.0 on all edges, weights 1.5 on self-loops and open boundary conditions
from qiskit_nature.second_q.hamiltonians.lattices import ( KagomeLattice, BoundaryCondition, ) kagome = KagomeLattice( 4, 3, edge_parameter = 1.0, onsite_parameter = 1.5, boundary_condition = BoundaryCondition.OPEN )
Adds new operator generator functions to allow more fine-grained spin observables. The new functions are:
the \(S^+\) operator:
s_plus_operator()
the \(S^-\) operator:
s_minus_operator()
the \(S^x\) operator:
s_x_operator()
the \(S^y\) operator:
s_y_operator()
the \(S^z\) operator:
s_z_operator()
All of these functions take the number of spatial orbitals as their only argument and return the constructed
FermionicOp
.This also allows a much simpler implementation of the
AngularMomentum
which is simply the $S^2$ operator:\[S^2 = S^- S^+ + S^z (S^z + 1)\]
Introduced a new feature that implements the bosonic operator
BosonicOp
. Its functionalities are analogous to theFermioniOp
, but for commuting bosonic particles. It should be used to represent a bosonic operator, so if one wants to represent the boson number operator it should do for example:from qiskit_nature.second_q.operators import BosonicOp bosonic_op = BosonicOp({'+_0 -_0': 1}, num_modes=1)
Due to the nature of bosonic particles, this class uses the commutator relations instead of the anti-commutator ones (used by fermionic particles).
In order to use the bosonic operator for quantum applications, this feature also introduces the bosonic linear mapper, which allows to map the BosonicOp to the qubit space. This mapper is based on this paper. To use this mapper one can for example:
from qiskit_nature.second_q.mappers import BosonicLinearMapper mapper = BosonicLinearMapper(truncation=1) qubit_op = mapper.map(bos_op)
The symmetry folding and unfolding routines listed below could become severe bottlenecks for larger system sizes. Now, when PySCF is installed, its routine will be used which is significantly faster.
Adds a new
multi
argument to thePolynomialTensor.apply()
method which allows handling of numpy routines which return more than one array. The same argument also gets exposed byElectronicIntegrals.apply()
.
Adds the following new utility methods for splitting and stacking multi-tensors:
Adds the
SparseLabelOp.from_terms()
method which is the inverse ofSparseLabelOp.terms()
.
Adds the
SparseLabelOp.permute_indices()
method which allows index permutations to be applied to an operator. For example:from qiskit_nature.second_q.operators import FermionicOp op = FermionicOp({"+_0 +_2 -_1 -_3": 1.0}, num_spin_orbitals=4) permuted_op = op.permute_indices([3, 1, 0, 2]) print(permuted_op) # Fermionic Operator # number spin orbitals=4, number terms=1 # 1.0 * ( +_3 +_0 -_1 -_2 )
This is a very powerful method so caution is advised when using it as other components of the stack may rely on assumptions which are no longer valid after such a permutation (for example the builtin two-qubit reduction of the
ParityMapper
).
The
SparseLabelOp.register_length
attribute (and by extension that of its subclasses, too) can no longer takeNone
as its value. However, the attributes which this one might rely on (e.g.FermionicOp.num_spin_orbitals
orBosonicOp.num_modes
) can remainNone
. This ensures that the lower-bound behavior works as intended.
Added linear algebra utilities for performing the double-factorization of a two-body tensor:
The
active_orbitals
argument of theActiveSpaceTransformer
may now also take a pair of lists of integers, each of which have a length identical to the number of active spatial orbitals. In this case, the first list indicates the alpha- and the second list the beta-spin orbital indices, respectively.
Adds a new convenience subclass of the
UCC
ansatz. Namely, the spin-symmetry-adapted ansatz,PUCCSD
, which includes single and double excitations while always pairing the excitations such that both, the number of particles and the total spin, will be preserved.You can use it like any of the other
UCC
-style ansätze, for example:from qiskit_nature.second_q.circuit.library import PUCCSD from qiskit_nature.second_q.mappers import JordanWignerMapper ansatz = PUCCSD( num_spatial_orbitals=4, num_particles=(2, 2), qubit_mapper=JordanWignerMapper(), )
Added the new
include_imaginary
keyword argument to theUCC
,UCCSD
, andPUCCD
classes. WhenTrue
, an extra ansatz parameter is added to each excitation that controls the imaginary contribution to its evolution. Thus, this setting doubles the total number of ansatz parameters, as compared to the default setting ofFalse
.
Upgrade Notes#
Support for running with Python 3.7 has been removed. To run Nature you need a minimum Python version of 3.8.
Bug Fixes#
The
ActiveSpaceTransformer
would sometimes set the wrong number of active particles because of a flawed integer rounding. This has now been fixed.
Fixes a formatting issue when printing an
ElectronicStructureResult
which contains values inextracted_transformer_energies
Fixes the tutorial for the excited state solvers. In doing so, the
EvaluationRule
is properly exposed for importing and documenting accordingly.
Fixes the computation of
ElectronicEnergy.coulomb()
(and by extensionElectronicEnergy.fock()
) when applied to a purely alpha-spin Hamiltonian but providing a mixed spin density.
Fixes the behavior of the
FreezeCoreTransformer
when a charge is present on the molecule.
When using
SparseLabelOp.from_polynomial_tensor()
constructor for one ofBosonicOp
,FermionicOp
,SpinOp
, orVibrationalOp
, the coefficient for the constant term was a 0d Tensor object rather than a number. This has been fixed.
The
ElectronicStructureProblem.reference_energy
is now properly propagated to theElectronicStructureResult.hartree_fock_energy
.
Fixes the logic of the
InterleavedQubitMapper
to actually perform the interleaving on the second-quantization level rather than the qubit level. This ensures that the actually expected benefits from using an interleaved ordering (for example when mapping a paired double-excitation where all Z terms cancel each other) occur, rather than a naive re-shuffling of the already mapped qubit operator.
Fixes the behavior of
SpinOp.to_matrix()
for operators acting on more than a single spin.
Fixes the
copy.copy
andcopy.deepcopy
operations for theTensor
class.
Fixes a regression in the performance of the
map()
method
Compatibility fix to support optional sparse install under Python 3.11.
0.6.0#
Prelude#
Qiskit Nature 0.6 focuses on refactoring of the mappers
module. To that extent, the QubitConverter
class has been deprecated in favor of using the various subclasses of QubitMapper
directly. As a short example, while you were doing something similar to this until now:
solver = GroundStateEigensolver(
QubitConverter(ParityMapper(), two_qubit_reduction=True),
VQE(...),
)
result = solver.solve(problem)
you now simply do the following instead:
solver = GroundStateEigensolver(
ParityMapper(num_particles=problem.num_particles),
VQE(...),
)
result = solver.solve(problem)
Check out the migration guide for the QubitConverter for more details. Besides this major refactoring, a few other changes have been done, so be sure to check out the migration guide from 0.5 to 0.6.
New Features#
Adds a Tapered Qubit Mapper class.
TaperedQubitMapper
is to be used as a wrapper of another standardQubitMapper
that can apply symmetry reduction techniques to operators at the end of the mapping.The following example shows how this class can be constructed from a mapper and a symmetry object.
driver = PySCFDriver() electronic_structure_problem = driver.run() h2_op, _ = electronic_structure_problem.second_q_ops() mapper = JordanWignerMapper() z2_sym = Z2Symmetries( symmetries=[Pauli("ZIIZ"), Pauli("ZIZI"), Pauli("ZZII")], sq_paulis=[Pauli("IIIX"), Pauli("IIXI"), Pauli("IXII")], sq_list=[0, 1, 2], tapering_values=[-1, 1, -1], ) tapered_qubit_mapper = TaperedQubitMapper(mapper, z2symmetries=z2_sym) qubit_op = tapered_qubit_mapper.map(h2_op)
Adds the method
get_tapered_mapper()
to transform aQubitMapper
instance into aTaperedQubitMapper
based on the properties of the current problem.The following example shows how this method can be used to find the symmetries of a problem and create the associate Tapered Qubit Mapper.
driver = PySCFDriver() electronic_structure_problem = driver.run() h2_op, _ = electronic_structure_problem.second_q_ops() mapper = JordanWignerMapper() tapered_qubit_mapper = electronic_structure_problem.get_tapered_mapper(mapper) qubit_op = tapered_qubit_mapper.map(h2_op)
Updates API for the method
symmetry_sector_locator()
to accept the newZ2Symmetries
fromquantum_info
as well as the legacyZ2Symmetries
from theopflow
module.
Added support for running with Python 3.11. At the the time of the release, Psi4 and Sparse didn’t have a python 3.11 version.
Three new methods for creating instances
ElectronicDensity
have been added:constructing an empty (or all-zero) density of a given size:
empty = ElectronicDensity.empty(num_spatial_orbitals=4)
constructing an identity density, meaning that the 1-body matrices are initialized with identity matrices
identity = ElectronicDensity.identity(num_spatial_orbitals=4)
constructing from a provided number of particles. This is a shorter variant of the already existing
from_orbital_occupation
method for the most common use-case.num_spatial_orbitals = 4 num_particles = (2, 2) two_and_two = ElectronicDensity.from_particle_number(num_spatial_orbitals, num_particles) # for example now the 1-body matrices will be: # [[1, 0, 0, 0], # [0, 1, 0, 0], # [0, 0, 0, 0], # [0, 0, 0, 0]]
All of the methods above take the optional keyword-argument
include_rdm2
which determines whether or not the 2-body matrices are computed based on the constructed 1-body matrices. By default, this is set toTrue
.
Added the
InterleavedQubitMapper
which allows wrapping of anotherFermionicMapper
to produce qubit operators where the alpha- and beta-spin components are arranged in the qubit register in an interleaved rather than blocked order.from qiskit_nature.second_q.mappers import JordanWignerMapper, InterleavedQubitMapper from qiskit_nature.second_q.operators import FermionicOp blocked_mapper = JordanWignerMapper() interleaved_mapper = InterleavedQubitMapper(blocked_mapper) ferm_op = FermionicOp({"+_0 -_1": 1}, num_spin_orbitals=4) blocked_op = blocked_mapper.map(ferm_op) # SparsePauliOp(['IIXY', 'IIYY', 'IIXX', 'IIYX'], coeffs=[-0.25j, 0.25, 0.25, 0.25j]) print(interleaved_mapper.map(ferm_op)) # SparsePauliOp(['IXIY', 'IYIY', 'IXIX', 'IYIX'], coeffs=[-0.25j, 0.25, 0.25, 0.25j])
The example above extends naturally to work with any scenario in which a
FermionicMapper
may be used like the construction of aHartreeFock
initial state orUCC
ansatz, for example.
Calling the
transform_hamiltonian()
is now supported, provided that the active space has been prepared properly.# assuming we have the total Hamiltonian of our system available: total_hamiltonian = ElectronicEnergy(...) # now we want to reduce it to an active space of 2 electrons in 2 orbitals transformer = ActiveSpaceTransformer(2, 2) # assuming that our total system size is 10 electrons in 10 orbitals: transformer.prepare_active_space(10, 10) # after preparation, this now works as intended reduced_hamiltonian = transformer.transform_hamiltonian(total_hamiltonian)
Calling the
transform_hamiltonian()
is now supported, provided that the active space has been prepared properly.# assuming we have the total Hamiltonian of our system available: total_hamiltonian = ElectronicEnergy(...) # now we want to apply the freeze-core reduction transformer = FreezeCoreTransformer() # since the FreezeCoreTransformer requires molecular system information, # we need to create that data structure like so: molecule = MoleculeInfo( symbols=["Li", "H"], coords=[(0.0, 0.0, 0.0), (0.0, 0.0, 1.6)], ) # and since the system size depends on the basis set, we need to provide # the total number of spatial orbitals separately: total_num_spatial_orbitals = 11 # e.g. the 6-31g basis # this allows us to prepare the active space correctly like so: transformer.prepare_active_space(molecule, total_num_spatial_orbitals) # after preparation, this now works as intended reduced_hamiltonian = transformer.transform_hamiltonian(total_hamiltonian)
Adds the
symmetric_two_body
module. This module provides utilities to exploit the inherent symmetries of chemistry-ordered two-body electronic integrals. You may use these to reduce memory consumption of your code, for example like so:from pyscf import gto from qiskit_nature.second_q.hamiltonians import ElectronicEnergy from qiskit_nature.second_q.operators import ( ElectronicIntegrals, PolynomialTensor, ) from qiskit_nature.second_q.operators.symmetric_two_body import S8Integrals mol = gto.M(atom="H 0 0 0; H 0 0 0.735", basis="631g*") hamiltonian = ElectronicEnergy( ElectronicIntegrals( PolynomialTensor( { "+-": mol.get_hcore(), "++--": S8Integrals(mol.intor("int2e", aosym=8)), }, validate=False, ) ) ) print(hamiltonian.second_q_op())
Since these integral containers are integrated into the stack, you can continue to use existing tools such as the
BasisTransformer
or even theActiveSpaceTransformer
as if you had stored your integrals in standard arrays.
Adds the
use_symmetry_reduced_integrals
setting. When set toTrue
, this will cause objects like for example theFCIDump
,QCSchema
, orPySCFDriver
to attempt and leverage thesymmetric_two_body
module in order to reduce the memory requirements at runtime.
Adds the new
Tensor
class used internally to consistently deal with n-dimensional tensors throughout the stack. This class also exposes thelabel_template
which allows an end-user to influence the translation procedure implemented infrom_polynomial_tensor()
.
Adds the new
tensor_unwrapping
setting which may be set toFalse
to disable the unwrapping of internally createdTensor
objects stored inside of aPolynomialTensor
. See alsotensor_unwrapping
for more details.
Adds the new argument
num_particles
to theParityMapper
which will implement the two qubit reduction without requiring an instance ofQubitConverter
.from qiskit_nature.second_q.drivers import PySCFDriver from qiskit_nature.second_q.mappers import ParityMapper driver = PySCFDriver() driver_result = driver.run() fermionic_op, _ = driver_result.second_q_ops() mapper = ParityMapper(num_particles=(1, 1)) qubit_op = mapper.map(fermionic_op)
Extends the
VibrationalIntegrals
to fall back to usingnumpy
arrays when the optionalsparse
dependency is not installed.
Leverage library opt_einsum, if installed, for sparse-einsum support. This library supports einsum summation directly on sparse objects as described in its documentation.
The new keyword argument
register_length
has been added to theQubitMapper.map()
method. This allows the user to set the length of aSparseLabelOp
before mapping it (since this length is a lower bound).
Improves the
QEOM
code and implements the calculation of excited state properties and transition amplitudes with QEOM.The new functionalities can be used as follows:
from qiskit.algorithms.optimizers import COBYLA from qiskit.primitives import Estimator from qiskit_nature.units import DistanceUnit from qiskit_nature.second_q.algorithms import VQEUCCFactory, GroundStateEigensolver from qiskit_nature.second_q.algorithms.excited_states_solvers import QEOM from qiskit_nature.second_q.algorithms.excited_states_solvers.qeom import EvaluationRule from qiskit_nature.second_q.circuit.library import UCCSD from qiskit_nature.second_q.drivers import PySCFDriver from qiskit_nature.second_q.mappers import QubitConverter from qiskit_nature.second_q.mappers import JordanWignerMapper optimizer = COBYLA(maxiter=500, disp=False) qubit_converter = QubitConverter( JordanWignerMapper(), z2symmetry_reduction=None, two_qubit_reduction=False ) driver = PySCFDriver( atom="H 0 0 0; H 0 0 1.735", basis="sto3g", charge=0, spin=0, unit=DistanceUnit.ANGSTROM, ) es_problem = driver.run() hamiltonian_op, _ = es_problem.second_q_ops() aux_ops = {"hamiltonian": hamiltonian_op} # Qeom results vqe_solver = VQEUCCFactory(Estimator(), UCCSD(), optimizer) me_gsc = GroundStateEigensolver(qubit_converter, vqe_solver) qeom_solver = QEOM( me_gsc, estimator=Estimator(), excitations="sd", aux_eval_rules=EvaluationRule.ALL ) results_qeom = qeom_solver.solve(es_problem, aux_operators=aux_ops) for n, aux_op_eval in enumerate(results_qeom.aux_operators_evaluated): print(f"Properties of eigen state {n}") for aux_name, aux_result in aux_op_eval.items(): print(f" Expectation value of {aux_name} operator: {aux_result}")
Added public methods
symmetry_reduce_clifford()
andconvert_clifford()
andfind_taper_op()
to allow a step by step tapering of operators.
Changed the behavior of the
qiskit_nature.second_q.algorithms.GroundStateEigensolver
to not raise an error when the user specifies a auxiliary operator which name clashes an internally constructed operator’s name. The new behavior is to apply precedence to the user-defined operators over the builtin ones in case of conflicts. A warning will be logged when this case happens.
Added a tolerance parameter
tol
to control the eigenvalue threshold in the QEOM calculation.
Adds the new
formatting_precision
attribute to all result objects. This attribute sets the number of decimal places to be used when formatting the result object for printing. It defaults to 12.
Added
qiskit_nature.testing
to house testing utilities. Currently it contains some functions for random sampling.
Updated the API to allow
QubitMapper
objects in places whereqiskit_nature.second_q.mappers.QubitConverter
were previously required. This addition advances toward a future deprecation ofQubitConverter
. All inputs of typeQubitConverter
now supportQubitMapper
objects implementing a transformation from second quantized operators to Pauli operators. Note that the mappers currently do not support qubit reduction techniques.
The method
map()
now supports individual operators as well as lists and dictionaries of operators.
Deprecation Notes#
Deprecated all
MinimumEigensolverFactory
andEigensolverFactory
classes. Instead, users should now build the respectively generated solver instances themselves. How-to guides to detail the involved steps have been added:
Deprecated the
to_matrix()
method. The same functionality can be achieved via the qubit-operator after applying theJordanWignerMapper
(one only needs to adapt to the different basis state ordering due to the reversed bitstring endianness).import numpy as np from qiskit_nature.second_q.mappers import JordanWignerMapper from qiskit_nature.second_q.operators import FermionicOp from qiskit_nature.settings import settings settings.use_pauli_sum_op = False op = FermionicOp({"+_0": 1, "-_1": 1}) mat = op.to_matrix().todense() jw = JordanWignerMapper().map(op) print(np.allclose(mat, jw.to_matrix(), atol=1e-8)) # prints False for pauli in jw.paulis: pauli.x = pauli.x[::-1] pauli.z = pauli.z[::-1] print(np.allclose(mat, jw.to_matrix(), atol=1e-8)) # prints True
The
QubitConverter
class is deprecated in favor of using theQubitMapper
implementations directly. As a consequence of this, all public properties and function arguments which referred to theQubitConverter
by name (e.g.qubit_converter
) have been deprecated in favor of properties and function arguments referring toQubitMapper
(e.g.qubit_mapper
), respectively.
The
symmetry_sector_locator()
method has been deprecated without a direct replacement. This utility is no longer needed in the new workflow which usesQubitMapper
instances directly. Qubit tapering can instead now be done using theTaperedQubitMapper
which can be constructed easily using theget_tapered_mapper()
method.
The
match_convert
argument of thehartree_fock_bitstring_mapped()
method has been deprecated without replacement. This utility is no longer needed in the new workflow which usesQubitMapper
instances directly.
The
VQEClient
and its matchingVQERuntimeResult
are now deprecated. Instead, users should migrate their code to use the Qiskit Runtime Primitives. A guide on how to use this can be found here.
Deprecates
np.ndarray
as the return type of thehijkl
,hijkl_ba
, andhijkl_bb
attributes. Instead, these will always beSymmetricTwoBodyIntegrals
. Instances of the latter can be used asnp.ndarray
so in terms of functionality this should not change anything. However,isinstance(integrals, np.ndarray)
will not returnTrue
forintegrals
of typeSymmetricTwoBodyIntegrals
. Additionally, the threeFCIDump
attributes will no longer accept physicist-ordered two-body tensors in the future.
Deprecated the default value (
True
) oftensor_unwrapping
meaning that in the future__getitem__()
will return objects of typeTensor
.
The M, Q, W, V matrix setters and M, Q, W, V matrix standard deviation setters from
QEOMResult
were pending deprecated and remain computable from the H and S matrices.
QubitMapper.allows_two_qubit_reduction
has been deprecated. There is no replacement because it is no longer needed in the new design.
All arguments in the
QubitMapper
API (and its subclasses) which were previously callednmodes
have been renamed toregister_length
.
Bug Fixes#
Fixes
SparseLabelOp.assign_parameters()
failing to assign parameters recursively.
The commutator methods
commutator()
,anti_commutator()
, anddouble_commutator()
no longer faultily simplify the returned operator (i.e. the absolute tolerance during simplification is set to zero instead of defaulting toSparseLabelOp.atol
).
Fixes a bug when printing the
total_dipole_moment_in_debye
Fixes output of
generate_fermionic_excitations()
when called withperserve_spin=False
and unequal number of alpha and beta particles
Fixes the
qcschema_to_problem()
method to takeQCWavefunction.eri_mo_ab
into account whenQCWavefunction.eri_mo_ba
is not available.
Fixes the behavior of
is_zero()
when called on a parameterized operator.
Fixes a bug when multiplying a
SparseLabelOp
with numpy numeric types from the left.
Removes wrong sign change from
qiskit_nature.second_q.operators.SpinOp.index_order()
.
Fixes the
normal_order()
method, which in turn corrects the commutation relations of this operator type.
Fixes the
VQEClient
to work properly with the latest code.
Added missing Gaussian native libraries from package qiskit_nature.second_q.drivers.gaussiand.gauopen to the wheels file distribution.
Fixes a bug in which
BogoliubovTransform
would sometimes throw an error due to an inability to cast complex numbers to floats.
Fix support of
BackendV2
in theVQEClient
. Previously, backends instantiated with theIBMProvider
failed since they return backends of typeBackendV2
, which were not correctly supported in the VQE client. Backends instantiated with theIBMQ
provider continue to work as before.
0.5.0#
Prelude#
Qiskit Nature 0.5 comes with a major redesign of the BaseProblem
layer of its stack. Rather than tightly integrating drivers and transformers, problems are now a lot more standalone and are generated by the various drivers (or built out by a user to their custom needs directly). As a short example comparing the previous to the new problem creation:
problem = ElectronicStructureProblem(driver, [transformer])
The new design works as follows:
problem = driver.to_problem(include_dipole=True)
reduced_problem = transformer.transform(problem)
Check out the migration guide for electronic structure calculations for more details.
Furthermore, as a general refactoring strategy the code was migrated from locations qiskit_nature.X.second_quantization
to qiskit_nature.X.second_q
. However, in doing so some classes/modules were re-categorized, so be sure to check out the detailed migration guide for more details.
New Features#
The
algorithms
module now requires the new algorithms introduced in Qiskit Terra 0.22 which in turn rely on the Qiskit Primitives themselves. For more details check out the migration guide for problem solving.
The refactoring of the electronic structure stack has enabled the development of third-party plugins allowing classical codes to call Qiskit Nature instead of relying on the development of
drivers
in the Qiskit Nature package. One example is the new Qiskit Nature PySCF Plugin which can be used like so:from pyscf import gto, scf, mcscf from qiskit.algorithms.optimizers import SLSQP from qiskit.primitives import Estimator from qiskit_nature.second_q.algorithms import GroundStateEigensolver, VQEUCCFactory from qiskit_nature.second_q.circuit.library import UCCSD from qiskit_nature.second_q.mappers import ParityMapper, QubitConverter from qiskit_nature_pyscf import QiskitSolver mol = gto.M(atom="Li 0 0 0; H 0 0 1.6", basis="sto-3g") h_f = scf.RHF(mol).run() norb, nelec = 2, 2 cas = mcscf.CASCI(h_f, norb, nelec) converter = QubitConverter(ParityMapper(), two_qubit_reduction=True) vqe = VQEUCCFactory(Estimator(), UCCSD(), SLSQP()) algorithm = GroundStateEigensolver(converter, vqe) cas.fcisolver = QiskitSolver(algorithm) cas.run()
Qiskit Nature still provides
drivers
to enable simple testing and provide a more accessible entry to Qiskit Nature for users who do not come from a classical chemistry computing background. Check out the migration guide for electronic structure calculations to learn how to update your code to use the refactored drivers.
The
properties
concept has been largely redesigned and is a lot more refined now. Instead of being a “catchall” for operator factories, the module has been cleanly separated into various components. Check out the corresponding section of the migration guide for electronic structure calculations for more details.
The vibrational structure stack has been refactored in-line with the changes to the electronic structure stack mentioned previously. However, changes to this stack also include corrections to the differentiation of real-space and second-quantized coefficients of the Watson hamiltonian. For more details, check out the migration guide for vibrational structure calculations.
The
lattices
and relatedLatticeModel
classes have undergone some API changes, particularly around the location of the utility methods for uniform lattice generation. For more details check out the migration guide for lattice models.
Added the
qiskit_nature.second_q.properties.HeisenbergModel
which implements the Hamiltonian of the Heisenberg model. This model is used in the study of critical points and phase transitions of magnetic systems. Through the choice of the model constants and the external magnetic field, we can produce many models like: XYZ, XXX, Ising model and others.from qiskit_nature.second_q.hamiltonians import HeisenbergModel from qiskit_nature.second_q.hamiltonians.lattices import LineLattice, BoundaryCondition line_lattice = LineLattice(num_nodes=2, boundary_condition=BoundaryCondition.OPEN) heisenberg_model = HeisenbergModel(lattice=line_lattice) print(heisenberg_model.second_q_ops()) # Output: X_0 X_1 * (-1+0j) + Y_0 Y_1 * (-1+0j) + Z_0 Z_1 * (-1+0j) # These tuples allow us to define a Ising model using the HeisenbergModel J = (0.0, 0.0, -1.0) B = (1.0, 0.0, 0.0) ising_model_hm = HeisenbergModel(lattice = line_lattice, coupling_constants = J, ext_magnetic_field = B) print(ising_model_hm.second_q_ops()) # Output: Z_0 Z_1 * (1+0j) + X_0 * (1+0j) + X_1 * (1+0j)
Adds .SparseLabelOp.equiv for checking approximate equality between two SparseLabelOps.
The performance of the following mappers, when used to map multiple operators of identical size, is significantly improved, by means of caching internal structures used during the mapping procedure:
Adds a new Property for the electronic structure stack to evaluate the 1- and 2-body reduced density matrices. Assuming that you already have an instance of your
qiskit_nature.second_q.problems.ElectronicStructureProblem
, you can add theqiskit_nature.second_q.properties.ElectronicDensity
to it like so:problem: ElectronicStructureProblem = ... from qiskit_nature.second_q.properties import ElectronicDensity # initialize the density in an orthonormal basis simply based on the # orbital occupation numbers alpha_occupation = [1.0, 1.0, 0.0, 0.0] beta_occupation = [1.0, 1.0, 0.0, 0.0] problem.properties.electronic_density = ElectronicDensity.from_orbital_occupation( alpha_occupation, beta_occupation )
Adds the
PropertiesContainer
and its subclasses to simplify the handling ofSparseLabelOpsFactory
instances inside of problems. This container is aMutableSet
and enforces at most a single instance of any Property kind to be stored inside of it This is sufficient for all application purposes of the auxiliary operators (which are generated by these objects).from qiskit_nature.second_q.problems import ElectronicPropertiesContainer from qiskit_nature.second_q.properties import ParticleNumber container = ElectronicPropertiesContainer() container.particle_number = ParticleNumber(10, 10) print(ParticleNumber in container) # True container.particle_number = None print(ParticleNumber in container) # False class MyCustomProperty: # implements the SparseLabelOpsFactory protocol ... custom = MyCustomProperty() container.add(custom) print(custom in container) # True container.discard(MyCustomProperty) print(custom in container) # False
Adds the new keyword argument
mirror
to theSUCCD
ansatz, which allows the inclusion of symmetrically mirrored double excitations while preserving the number of circuit parameters.from qiskit_nature.second_q.circuit.library.ansatzes import SUCCD from qiskit_nature.second_q.mappers import JordanWignerMapper, QubitConverter converter = QubitConverter(JordanWignerMapper()) ansatz = SUCCD(converter, (1, 1), 6, mirror=True)
Adds support for the QCSchema via which we aim to standardize the I/O between classical drivers and Qiskit Nature.
Implements both
HartreeFock
andVSCF
as subclasses ofBlueprintCircuit
. This allows the respective classes to be instantiated without explicitly setting all of their instance attributes. Missing attributes can be set at a later point to complete the respective circuit definitions.from qiskit_nature.second_q.circuit.library import HartreeFock, VSCF from qiskit_nature.second_q.mappers import JordanWignerMapper, QubitConverter # Initialize Hartree-Fock initial_state without specifying # the number of particles and qubit converter. hf_state = HartreeFock(num_spatial_orbitals=4) # ... # complete circuit definition by specifying the rest of the instance attributes hf_state.qubit_converter = QubitConverter(JordanWignerMapper()) hf_state.num_particles = (1,1) # ... # Similarly for VSCF vscf_state = VSCF() # ... # complete circuit definition by specifying the rest of the instance attributes vscf_state.num_modals = [2, 2] # ...
The new
qiskit_nature.second_q.operators.FermionicOp
replaces the oldqiskit_nature.operators.second_quantization.operators.FermionicOp
. This new operator is a subclass of theqiskit_nature.second_q.operators.SparseLabelOp
and, as such, only support sparse labels. It is initialized with a dictionary, mapping sparse label keys to coefficients. It supports the usual algebra for operator addition, scalar multiplication, operator composition, operator tensoring, and complex conjugation. It also provides methods for sorting, equality and equivalency checking, operator simplification, normal ordering, and the computation of induced norms as well as hermiticity properties. Finally, it can also be converted to matrices in the occupation number basis.from qiskit_nature.second_q.operators import FermionicOp op1 = FermionicOp({"+_0 -_1": 1.0}, register_length=2) # scalar multiplication op2 = 2.0 * op1 # operator addition op1 + op2 # operator composition op1 @ op2 # operator tensoring op1 ^ op2 # complex conjugation op1.adjoint() # equality and equivalency checks op1 == op2 op1.equiv(op2) # simplification and normal ordering op3 = FermionicOp({"+_0 -_0 +_0 -_0": 1.0}, register_length=2) op3.simplify() op3.normal_ordered() # sorting op4 = FermionicOp({"+_0": 2, "+_2": 1, "+_1": 1}, register_length=3) op4.sort(weight=False) op4.sort(weight=True) # matrix conversion op3.to_matrix(sparse=True) op3.to_matrix(sparse=False) # norm and hermiticity computation op1.induced_norm() op1.is_hermitian()
Added the
xcf
argument to theqiskit_nature.second_q.drivers.GaussianForcesDriver.from_molecule()
which allows specifying the exchange-correlation functional to be used by Gaussian.
The
excitation_list
property has been removed fromHFInitialPoint
,MP2InitialPoint
, andVSCFInitialPoint
. Thus the excitation list cannot be set directly, rather this must be set via theansatz
.
Following the MP2 T2 and energy correction calculation fix, the APIs for
MP2InitialPoint
andHFInitialPoint
have been changed slightly. After setting thegrouped_property
, thetotal_energy
andenergy_correction
are now accessed via their respective properties, rather than viaget_energy
andget_energy_correction
.
Adds atol parameter to
SparseLabelOp.is_hermitian()
.
The supported
excitation
types in the QEOM code have been updated. It now exposes the full set of excitation generation functionalities provided by the internally used UCC and UVCC ansatze. In particular, this means that rather than providing a custom list of excitation tuples, a function can be set by the user which generates such a custom list. The documentation has been updated accordingly to reflect this in all places.
Changes usage of library
retworkx
to the new substituterustworkx
.
Adds utility functions for converting between chemists’ and physicists’ index ordering for two-body integrals.
qiskit_nature.second_q.operators.tensor_ordering.to_chemist_ordering()
converts from physicists’ or intermediate order to chemists’, whereasqiskit_nature.second_q.operators.tensor_ordering.to_physicist_ordering()
converts to physicists’.qiskit_nature.second_q.operators.tensor_ordering.find_index_order()
returns the index-order type for a given two-body tensor.
Deprecation Notes#
The protein folding stack has been migrated to Qiskit Research. Thus, all of its components in Qiskit Nature have been deprecated.
The
BOPESSampler
has been deprecated without direct replacement. For the future direction in which classical codes will be calling Qiskit Nature (instead of the use ofdrivers
) the features provided by the sampler are no longer the responsibility of Qiskit Nature. A warm-startingInitialPoint
utility has been suggested. You can subscribe to that feature request to receive updates.
Deprecated all code that was migrated to
qiskit_nature/second_q
according to issue: https://github.com/Qiskit/qiskit-nature/issues/749The following table provides a rough overview of the old and new package locations. In certain cases, single classes might have been treated differently. Be sure to check out the referenced issues or the migration guide for more details.
Old
New
qiskit_nature.algorithms
qiskit_nature.second_q.algorithms
qiskit_nature.algorithms.pes_samplers
Removed. For more details, refer to: https://github.com/Qiskit/qiskit-nature/issues/750
qiskit_nature.circuit
qiskit_nature.second_q.circuit
qiskit_nature.converters
qiskit_nature.second_q.mappers
qiskit_nature.drivers
qiskit_nature.second_q.drivers and qiskit_nature.second_q.formats
qiskit_nature.mappers
qiskit_nature.second_q.mappers
qiskit_nature.operators
qiskit_nature.second_q.operators
qiskit_nature.problems
qiskit_nature.second_q.problems
qiskit_nature.problems.sampling
Moved to qiskit-research. For more details, refer to: https://github.com/qiskit-research/qiskit-research
qiskit_nature.properties
qiskit_nature.second_q.hamiltonians and qiskit_nature.second_q.properties For more details, refer to: https://github.com/Qiskit/qiskit-nature/issues/705
qiskit_nature.results
qiskit_nature.second_q.problems
qiskit_nature.transformers
qiskit_nature.second_q.transformers
The utility methods building out the
QEOM
hopping operators have been moved away from theBaseProblem
interface and have been attached to theQEOM
implementation itself.
Bug Fixes#
Fix the initial point classes to account for the number of times the evolved operators are repeated in the ansatz.
Fixes the compatibility of the fermionic excitation generator options which disables spin preserving while also enabling generalized behavior. Now, combining
generalized=True
withpreserve_spin=False
results in all combinations of excitations in the given spin orbital space. De-excitations are not included and filtered accordingly.
Fixes a bug where numpy integer objects were causing integer-based isinstance checks to fail. This also avoids such problems by explicitly converting integer values to Python integers when loading properties from HDF5 files.
Fixed the MP2 T2 amplitudes and energy correction computation to ensure it matches the result from PySCF.
Fixes an issue in the Gaussian Log parsing when the A to H data is provided across multiple instead of on a single line in the file.
Fixes the behavior of
FermionicOp.simplify
when called on a zero-operator.
Fixes the
qiskit_nature.runtime.VQEClient
to correctly detect the type of the wrapped auxiliary operators. Previously, it would always wrap them into a dictionary and then fail when unwrapping them later, since it did not preserve the previously wrapped data type.
The gathering of the auxiliary operator results when using the VQEClient.
Fixes a bug that caused
FermionicOp.is_hermitian()
to return false negatives due to not normal-ordering.
Fixes a bug that caused
FermionicOp.simplify()
to fail when the simplified operator is equal to zero.
Other Notes#
The classes
VQEProgram
andVQEProgramResult
have been removed following the end of the deprecation period.
0.4.0#
New Features#
Adds Hartree-Fock (HF) and vibrational self-consistent field (VSCF) initial point classes.
HFInitialPoint
andVSCFInitialPoint
, are to be used withUCC
, andUVCC
, respectively.This follows the introduction of
MP2InitialPoint
for computing the initial point using the Møller-Plesset 2nd Order (MP2) corrections.MP2InitialPoint
,HFInitialPoint
, andVSCFInitialPoint
all inherit from the abstract base classInitialPoint
.These initial points are intended to be used as starting VQE parameters when using a UCC ansatz (cluster operator coefficients). This should introduce an initial point that is closer to the ground state point, leading to fewer overall evaluations for VQE.
Instances of the appropriate classes are now the default
initial_point
arguments inVQEUCCFactory
andVQEUVCCFactory
. Additionally, one may pass an explicitInitialPoint
instance to the factories. Following are some example snippets.VQE UCC with a HFInitialPoint:
hf_intial_point = HFInitialPoint() vqe_ucc_factory = VQEUCCFactory(quantum_instance, initial_point=hf_initial_point)
VQE UCC with an MP2InitialPoint:
mp2_intial_point = MP2InitialPoint() vqe_ucc_factory = VQEUCCFactory(your_quantum_instance, initial_point=mp2_initial_point)
VQE UVCC with a VSCFInitialPoint:
vscf_intial_point = VSCFInitialPoint() vqe_uvcc_factory = VQEUVCCFactory(your_quantum_instance, initial_point=vscf_initial_point)
They can also be used by following the snippets below and passing the result via
initial_point
to the VQE.UCC with a HF initial point:
hf_intial_point = HFInitialPoint() hf_initial_point.ansatz = your_ucc_ansatz initial_point = hf_initial_point.to_numpy_array()
UVCC with a VSCF initial point:
vscf_initial_point = VSCFInitialPoint() vscf_initial_point.ansatz = your_uvcc_ansatz initial_point = vscf_initial_point.to_numpy_array()
Added logging utility functions accessible through qiskit_nature.logging.
Added Support for Bohr unit in Molecule Class:
mol = Molecule(geometry=[("H", [10.0, 2.0, 0.0]), ("H", [0.0, 20.0, 1.0])], unit=UnitsType.BOHR)
Adds
BogoliubovTransform
. This class constructs a circuit that performs a Bogoliubov transform, which is a single-particle basis change that may or may not conserve particle number. See the Quadratic Hamiltonians and Slater determinants tutorial for a demonstration of how to use this class.
The new setting qiskit_nature.settings.optimize_einsum was added which allows enabling the optimize argument in numpy.einsum calls with more than 2 operands. This is known to yield significant computational efficiency increases at the expense of higher memory consumption. The setting defaults to True.
Adds
qiskit_nature.operators.second_quantization.FermionicOp.terms()
. This returns an iterable of (term, coefficient) pairs describing the terms contained in the operator. Each term is a list of tuples of the form (action, index), where the action is either “+” or “-” and the index is the integer index of the factor in the term.
Added Qiskit Terra’s Gradient Functionality to calculate gradients in
AdaptVQE
. You can choose the gradient method and input it while callingAdaptVQE
. for example:from qiskit.providers.basicaer import BasicAer from qiskit.utils import QuantumInstance from qiskit.opflow.gradients import Gradient from qiskit_nature.algorithms import VQEUCCFactory from qiskit_nature.drivers import UnitsType from qiskit_nature.drivers.second_quantization import PySCFDriver from qiskit_nature.mappers.second_quantization import ParityMapper from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.problems.second_quantization import ElectronicStructureProblem from qiskit_nature.algorithms.ground_state_solvers.adapt_vqe import AdaptVQE driver = PySCFDriver( atom="H .0 .0 .0; H .0 .0 0.735", unit=UnitsType.ANGSTROM, basis="sto3g" ) problem = ElectronicStructureProblem(driver) qubit_converter = QubitConverter(ParityMapper()) solver = VQEUCCFactory(QuantumInstance(BasicAer.get_backend("statevector_simulator"))) grad = Gradient(grad_method="lin_comb", epsilon=1.0) calc = AdaptVQE(qubit_converter, solver, gradient=grad) res = calc.solve(problem)
The HDF5Driver has been refactored to leverage the new HDF5-integration protocol of Qiskit Nature. The driver still supports loading legacy QMolecule HDF5 files and also provides a conversion utility:
driver = HDF5Driver("path_to_qmolecule.hdf5") driver.convert(replace=True)
Adds a new HDF5-integration to support storing and loading of (mostly) Property objects using HDF5 files. A similar feature existed in the legacy QMolecule object but the new implementation is handled more general to enable leveraging this integration throughout more parts of the stack in the future.
To store a driver result of the new drivers in a file you can do:
from qiskit_nature.hdf5 import save_to_hdf5 my_driver_result = driver.run() save_to_hdf5(my_driver_result, "my_driver_result.hdf5")
and to load it again you would do:
from qiskit_nature.hdf5 import load_from_hdf5 my_driver_result = load_from_hdf5("my_driver_result.hdf5")
Support the initialization of FermionicOp with tuple as label.
FermionicOp
can be initialized using a tuple of integers, (action, index), like below:from qiskit_nature.operators.second_quantization import FermionicOp FermionicOp( [([("-", 2), ("+", 1)], 2 + 0j), ([("-", 3)], 34 + 0j)], register_length=4, display_format="sparse", )
Add the option to initialize a
Lattice
from anetworkx.Graph
object, which will be internally converted to aretworkx.PyGraph
for performance.For example, you can now construct a lattice as
import networkx as nx from qiskit_nature.problems.second_quantization.lattice import Lattice # 3-regular random graph on 6 nodes graph = nx.generators.random_graphs.random_regular_graph(3, n=6) lattice = Lattice(graph)
Adds a new problem class,
qiskit_nature.problems.second_quantization.lattice.LatticeModelProblem
, for lattice models. It can create second quantized operators from a lattice model. We can use the Ground State Eigensolver with it to calculate the ground state energy.from qiskit_nature.problems.second_quantization.lattice import ( BoundaryCondition, FermiHubbardModel, LineLattice, LatticeModelProblem ) from qiskit.algorithms import NumPyMinimumEigensolver from qiskit_nature.algorithms import GroundStateEigensolver from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.mappers.second_quantization import JordanWignerMapper solver = NumPyMinimumEigensolver() qubit_converter = QubitConverter(JordanWignerMapper()) calc = GroundStateEigensolver(qubit_converter, solver) line_lattice = LineLattice(num_nodes=4, boundary_condition=BoundaryCondition.OPEN) fhm = FermiHubbardModel.uniform_parameters( lattice=line_lattice, uniform_interaction=-1.0, uniform_onsite_potential=0.0, onsite_interaction=5.0, ) lmp = LatticeModelProblem(lattice_model=fhm) res = calc.solve(lmp)
Adds
qiskit_nature.mappers.second_quantization.LogarithmicMapper
. This class is a mapper for Logarithmic spin-to-qubit mapping. In this local encoding transformation, each individual spin S system is represented via the lowest lying 2S+1 states in a qubit system with the minimal number of qubits needed to represent >= 2S+1 distinct states.
Adds a class to compute the Møller-Plesset 2nd Order (MP2) corrections. The corresponding double-excitation coefficients are intended to be used as an initial point for the VQE parameters (cluster operator coefficients) when using a UCC ansatz. This should introduce an initial point that is closer to the ground state point, leading to fewer overall evaluations for VQE.
MP2InitialPoint
inherits from the abstract base class (interface)InitialPoint
, which takes a driver result and a UCC ansatz either directly via thecompute
method or via their respective property setters.The MP2 computation requires the grouped_property to contain the ElectronicEnergy, which must contain the two-body molecular orbital matrix and the orbital energies. Optionally, it will also use the Hartree-Fock reference energy to compute the absolute energy.
When using
VQEUCCFactory
, anMP2InitialPoint
object can be passed via theinitial_point
keyword argument:mp2_initial_point = MP2InitialPoint() vqe_ucc_factory = VQEUCCFactory(quantum_instance, initial_point=mp2_initial_point)
In this case the driver result and ansatz will be used to compute the initial point automatically. This will then be passed to the VQE.
Outside of the factory, one can do this manually:
mp2_initial_point = MP2InitialPoint() mp2_initial_point.compute(driver_result, ansatz) initial_point = mp2_initial_point.to_numpy_array() algorithm = VQE( ansatz, optimizer=optimizer, quantum_instance=quantum_instance, initial_point=initial_point )
The eventual intention is to retire
preferred_init_points
fromVQE
in Terra, so the implementation avoids this property.
Improves the performance of the
qiskit_nature.properties.second_quantization.electronic.integrals.ElectronicIntegrals.to_second_q_op()
method significantly. Previously, generating the second quantized operators for a system size greater than 20 spin orbitals took on the order of minutes to hours (depending on the actual size). Now, even system sizes of 50 spin orbitals can be handled in a matter of seconds.
Now there is a function to interpret the raw result of solving a protein folding problem. Previously the problem was encoded in order to be solved more efficiently but the result could not be easily understood by a user. This new functionality decodes the result for the user and provides a plotting of the protein as well as a file with the x,y,z coordinates of each one of the beads in the protein.
Added:
ProteinFoldingResult
. This class handles the result found by running a VQE to solve aProteinFoldingProblem
. This class has:Method
get_figure()
which generates a figure of the shape of the protein.Method
save_xyz_file()
which saves a .xyz file with the cartesian coordinates of the shape of the molecule.Property
protein_shape_file_gen
which is an instance ofProteinShapeFileGen
. This class has in its turn a methodget_xyz_data()
which returns an array with the data contained in the .xyz file without having to generate such a file.Property
protein_shape_decoder
which is an instance ofProteinShapeDecoder
. This class has in its turn two propertiesmain_turns
andside_turns
that return the turn sequences of the main chain and the side chains respectively.
result = protein_folding_problem.interpret(raw_result) # Save xyz file in current directory. result.save_xyz_file() # Generate plot. figure = result.get_figure()
Adds
qiskit_nature.operators.second_quantization.QuadraticHamiltonian
. This class is used to represent quadratic fermionic Hamiltonians and includes methods to efficiently diagonalize them.
Adds the simplify method to
qiskit_nature.operators.second_quantization.SecondQuantizedOp
and the normal_ordered method toqiskit_nature.operators.second_quantization.FermionicOp
. These methods replace reduce and to_normal_order, which are deprecated. The differences between the new and old methods are the following:simplify does not perform normal-ordering, while reduce does
normal_ordered simplifies the result, while to_normal_order does not
Adds functionality to prepare Slater determinants and fermionic Gaussian states using the Givens rotation strategy. This functionality is accessed via the following classes:
qiskit_nature.circuit.library.SlaterDeterminant
qiskit_nature.circuit.library.FermionicGaussianState
The solver of
BOPESSampler
now accepts solvers of type Union[GroundStateSolver,ExcitedStatesSolver] instead of only a GroundStateSolver. This generalizes to excited states the sampling of nuclear coordinates for Born Oppenheimer Potential Energy Surfaces. Adds the get_qubit_operators() inqiskit_nature.algorithms.ExcitedStatesEigensolver
. This matches the format ofqiskit_nature.algorithms.GroundStateEigensolver
. BOPESSampler now also accepts auxiliary operators to pass to the solver. Geometry-dependent observable can also be defined as auxiliaries. See the Sampling the potential energy surface tutorial for a demonstration of how to use this calculation of excited state Born Oppenheimer potential energy surfaces.
VQEClient
now extends VariationalAlgorithm, meaning users can now implementBOPESSampler
using bootstrapping, which works similarly now with VQEClientVQEClient
as it did previously with local VQE.
Upgrade Notes#
Added support for running with Python 3.10. At the the time of the release, PySCF didn’t have a python 3.10 version.
Support for running with Python 3.6 has been removed. To run Nature you need a minimum Python version of 3.7.
Changes the default
display_format
of the constructor ofFermionicOp
from “dense” to “sparse”.
Deprecation Notes#
The
delta
argument ofAdaptVQE
is deprecated in favor of supplying agradient
from Qiskit Terra’sqiskit.opflow.gradients
framework. In doing so, the default behavior ofAdaptVQE
changes from using a finite difference scheme for the gradient evaluation to using a parameter shift method. In order to reproduce the original default behavior you must specifydelta=1
explicitly or use the following:from qiskit.providers.basicaer import BasicAer from qiskit.utils import QuantumInstance from qiskit.opflow.gradients import Gradient from qiskit_nature.algorithms import VQEUCCFactory from qiskit_nature.drivers import UnitsType from qiskit_nature.drivers.second_quantization import PySCFDriver from qiskit_nature.mappers.second_quantization import ParityMapper from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.problems.second_quantization import ElectronicStructureProblem from qiskit_nature.algorithms.ground_state_solvers.adapt_vqe import AdaptVQE driver = PySCFDriver( atom="H .0 .0 .0; H .0 .0 0.735", unit=UnitsType.ANGSTROM, basis="sto3g" ) problem = ElectronicStructureProblem(driver) qubit_converter = QubitConverter(ParityMapper()) solver = VQEUCCFactory(QuantumInstance(BasicAer.get_backend("statevector_simulator"))) grad = Gradient(grad_method="fin_diff", epsilon=1.0) calc = AdaptVQE(qubit_converter, solver, gradient=grad) res = calc.solve(problem)
The following second quantization operator methods are deprecated:
qiskit_nature.operators.second_quantization.SecondQuantizedOp.reduce()
. Instead, useqiskit_nature.operators.second_quantization.SecondQuantizedOp.simplify()
.qiskit_nature.operators.second_quantization.FermionicOp.to_normal_order()
. Instead, useqiskit_nature.operators.second_quantization.FermionicOp.normal_ordered()
.
The argument gss of the constructor of
BOPESSampler
was deprecated and replaced by state_solver to match the extension of this class toqiskit_nature.algorithms.ExcitedStatesEigensolver
. Now the constructor has the following positional argument:state_solver
VQEUCCFactory
had setter/getter properties that were repeated with respect toqiskit.algorithms.VQE
.In order to avoid duplicating all of these attributes, potentially leading to inconsistencies between the attributes of the different classes, these are now deprecated and require you to use the attributes from
minimum_eigensolver
instead.For this reason, the constructor of
VQEUCCFactory
has been changed as well. Now the constructor only has the following positional arguments:initial_point
initial_state
ansatz
Any extra keyword arguments are passed to a constructor of
qiskit.algorithms.VQE
which will create a VQE that can be accessed viaminimum_eigensolver
.The same changes have been done for
VQEUVCCFactory
andNumPyMinimumEigensolverFactory
Bug Fixes#
The
BOPESSampler
did not support GroundStateSolvers when built out with MinimumEigensolverFactories. This is fixed, so code like the following now functions correctly:solver = GroundStateEigensolver(converter, VQEUCCFactory(quantum_instance)) sampler = BOPESSampler(solver, bootstrap=True, num_bootstrap=None, extrapolator=None)
Fix incorrect corner cases in BravyiKitaevSuperFastMapper: Input terms with coefficient zero and output operator equal to zero. Also detect and raise an exception if HartreeFock attempts to use the BKSF mapper.
Fix bug in Bravyi-Kitaev Super-Fast (BKSF) Mapper cause by using obsolete method for composing Pauli operators in one kind of fermionic Hamiltonian term.
Fixes a bug in VQEClient using dict based aux_operators instead of deprecated list based ones (enabled via qiskit_nature.settings.dict_aux_operators = True).
Some minor issues in the
ActiveSpaceTransformer
were fixed. Namely:iterated properties are no longer deep-copied resulting in non-transformed ones actually being dropped rather than carried on
the correct return type object is being constructed and returned
Fixes the ability to disable the freeze_core argument of the
FreezeCoreTransformer
Fixes the wrong inference of register_length in
FermionicOp
.
Fixes the units used for the Molecule generated by the PySCFDriver.
Fixes the computation of the spin orbital occupation in a non-singlet state. Previously, a singly occupied MO would result in SO occupations of 0.5 for each spin. Now, the alpha SO will be fully occupied and the beta SO unoccupied.
UCC
andUVCC
when fully configured via the constructor failed to transpile and were not valid circuits. This fixes that to ensure that if UCC / UVCC are fully configured then as circuits they are are immediately valid from the get go.
Fix the groundenergy in
EigenstateResult
to return a correct value.
Alter
UCC
to build theoperators
on demand when requested via the property, rather than, as before, when the circuit is built. Now if the circuit is built, then the operators, if not built, will be created as before, but since they are cached when built, if done earlier, then these are used. This avoids problems when used in conjunction with VQE that presently fail - most cases today use a fully configured UCC being passed into VQE but whose constructor presently has an unintended side-effect of building the circuit via a logging statement. For other scenarios VQE would fail when it checked on number of qubits and the operators were None, even though UCC was fully configured, when the circuit had not yet been built.
Add a type check for the input graphs to
Lattice
which asserts that the edge weights of the graph are either numeric (or one of None or {} which is replaced by a unit weight). This prevents possibly unexpected errors in the application stack when an operator is constructed from the lattice.In particular, the following now raises a ValueError:
from retworkx import PyGraph from qiskit_nature.problems.second_quantization.lattice import Lattice graph = PyGraph(multigraph=False) graph.add_nodes_from(range(3)) graph.add_edges_from([(0, 1, 1), (1, 2, "banana")]) # banana is not a valid weight! lattice = Lattice(graph)
Alter
UVCC
to build theoperators
on demand when requested via the property, rather than, as before, when the circuit is built. This is a similar change as was done toUCC
.
Ensures the VibrationalStructureProblem.truncation_order gets propagated correctly down to the properties before the SecondQuantizedOp instances are constructed.
0.3.0#
New Features#
The degree_of_freedom attribute of the
Molecule
class now has its dedicated getter and setter.
Add:
qiskit_nature.problems.second_quantization.lattice.models.IsingModel
implementing the Hamiltonian of the Ising Model. Add:qiskit_nature.problems.second_quantization.lattice.models.LatticeModel
implementing a base class for Lattice models.
Add:
qiskit_nature.problems.second_quantization.lattice.lattice.Lattice
for the generation of general lattices.Add:
qiskit_nature.problems.second_quantization.lattice.lattice.HyperCubicLattice
for the generation of arbitrary d-dimensional lattices.Add:
qiskit_nature.problems.second_quantization.lattice.lattice.LineLattice
for the generation of one-dimensional lattices.Add:
qiskit_nature.problems.second_quantization.lattice.lattice.SquareLattice
for the generation of two-dimensional lattices.Add:
qiskit_nature.problems.second_quantization.lattice.lattice.TriangularLattice
for the generation of two-dimensional lattices with diagonal edges.Add:
qiskit_nature.problems.second_quantization.lattice.models.FermiHubbardModel
implementing the Hamiltonian of the Fermi-Hubbard Model.
Exposes the callback option of the VQE algorithm in the VQE factory classes. It also adds a general kwargs dictionary which allows passing any additional arguments to the VQE.
Add
to_matrix()
. This method returns the matrix representation of the operator over the full fermionic Fock space in the occupation number basis.
Added Gaussian drivers to allow execution on python 3.9 (MacOS, Windows, Linux).
Support was added for generalized fermionic excitations. These kinds of excitations are effectively ignoring the orbital occupancies and instead yield all possible excitations within a spin species. Furthermore, another option was added which can be used to enabled spin- flipped excitations.
Runs checks for the excitations in a UCC ansatz when the excitations were created by a function. If the excitations are not in the expected format the checks raise a
qiskit_nature.QiskitNatureError
.
Upgrade Notes#
In order to fix the
ElectronicStructureProblem
symmetry_sector_locator()
information on the mapping was required and theQubitConverter
sector_locator
parameter callback signature of theconvert()
method was changed fromsector_locator: Optional[Callable[[Z2Symmetries], Optional[List[int]]]]
tosector_locator: Optional[Callable[[Z2Symmetries, "QubitConverter"], Optional[List[int]]]]
i.e. your supplied callback method must now take a second parameter which is aQubitConverter
instance and when invoked will be the instance upon which theconvert
was called. If you have created your own sector locator then you will need to update it`s signature otherwise the code will fail when calling it now.
The EvolvedOperatorAnsatz, from the Nature circuit.library, which was migrated in an earlier release to core Qiskit i.e. Terra, has now been removed. You should change any code that still uses this over to the core Qiskit one, from qiskit.circuit.library, as a direct replacement.
Deprecation Notes#
Rename the runtime “program” to runtime “client” to avoid name confusions and reflect the fact that it is an interface for code executed in the cloud. The classes
VQEProgram
andVQEProgramResult
have been renamed toVQEClient
,VQERuntimeResult
, respectively.
Bug Fixes#
This also ensures that the getter/setter methods of the VQE factories actually affect the constructed VQE instance.
Fixed the manual active orbital selection when specifying the active number of electrons as a tuple rather than an integer.
Fixed a typo in the ElectronicEnergy._orbital_energies variable name and ensures the correct behavior of the orbital_energies property getter.
The ElectronicStructureResult did not initialize the _computed_dipole_moment variable causing critical errors when trying to print a result from an algorithm which does not compute these observables. Proper initialization fixes this issue. Printing the result would also fail when complex numbers were stored. This has also been remedied.
Fixed an issue where the existing Mapper was incorrectly mapping the creation operator \(+\) and the annihilation operator \(-\). It used to be that \(+\) was mapped to \(\sigma_+\) and \(-\) was mapped to \(\sigma_-\), but it is correct that \(+\) is mapped to \(\sigma_-\) and \(-\) is mapped to :math`sigma_+`.
Fixes the creation on the
HartreeFock
initial state which could fail when Z2Symettry reduction was being used via the providedQubitConverter
.Also fixes the
ElectronicStructureProblem
symmetry_sector_locator()
, which uses the HartreeFock class too, so that it correctly determines the sector containing the ground state whenauto
symmetry reduction is used.
Ensure BaseProblem.molecule_data_transformed is set when using a legacy driver type without any transformers.
Fixes the formatting of the occupied modals and adds the excited state energies when printing a
VibrationalStructureResult
.Fixes the return type of
num_occupied_modals_per_mode()
fromOptional[List[float]]
toOptional[List[List[float]]]
Fixes QEOM such that when using parity mapping with two_qubit_reduction, or Z2 symmetries with any mapping, that the excited states are computed as expected.
Fix the electronic structure problem sector locator such that the ‘auto’ Z2 symmetry conversion, of the qubit converter, results in the ground state for such problems and not some other value due to incorrect sector selection.
Allow input operator to BravyiKitaevSuperFastMapper to be FermionicOp in sparse storage format. Previously, all input was interpreted as dense storage format, which raised an error when parsing sparse format as dense failed.
Updates the runtime tutorial to consistently use the new drivers in combination with the new transformers and the Property-framework in general.
0.2.0#
New Features#
Add
qiskit_nature.mappers.second_quantization.BravyiKitaevSuperFastMapper
implementing the Bravyi-Kitaev super-fast fermion-to-qubit mapping. For examplefrom qiskit_nature.mappers.second_quantization import BravyiKitaevSuperFastMapper mapper = BravyiKitaevSuperFastMapper() mapper.map(fermionic_op)
The
SecondQuantizedOp
now has a methodis_hermitian()
method which will returnTrue
if the operator is equivalent to its adjoint andFalse
otherwise
to_list()
is now an abstract method ofSecondQuantizedOp
that is implemented by all subclasses
Add
to_normal_order()
. It returns the normal ordered fermionic operator that is equivalent to self.
Introduces the
ElectronicStructureMoleculeDriver
andVibrationalStructureMoleculeDriver
that allow for the creation of Molecule-based drivers by specifying a molecule plus basis and method (for Electronic Structure drivers only) and a driver type. An additional type AUTO allows for the lookup of the first driver installed that supports the given method. The documentation of those two molecule driver classes gives more details on it.
The Property framework is the new modular and extensible approach for representing observable quantities. The framework is used as a replacement for the legacy driver results like QMolecule and WatsonHamiltonian. Please refer to the tutorial and documentation for more details. Related Github issues: * https://github.com/Qiskit/qiskit-nature/issues/148 * https://github.com/Qiskit/qiskit-nature/issues/167 * https://github.com/Qiskit/qiskit-nature/pull/220 * https://github.com/Qiskit/qiskit-nature/issues/243 * https://github.com/Qiskit/qiskit-nature/pull/263 * https://github.com/Qiskit/qiskit-nature/issues/264 * https://github.com/Qiskit/qiskit-nature/pull/303
Introduce the
VQEProgram
to allow leveraging Qiskit Runtime to speed up the VQE algorithm. TheVQEProgram
implements theMinimumEigensolver
interface and can thus be used as a drop-in replacement for other minimum eigensolvers likeqiskit.algorithms.VQE
. See the tutorials under docs/tutorials for an explicit example usage.
Upgrade Notes#
The internal data in
FermionicOp
have been changed. As a result, more data type is now accepted by initialize. The ascending order constraint and the no-same index constraint have been removed. In addition, the dense and sparse labels are now automatically detected by the existence of underscores.The property display_format of
FermionicOp
is added. There are two modes dense and sparse. This display format can be switched by the property FermionicOp.display_format.
The internal API of the abstract class
qiskit_nature.operators.second_quantization.SecondQuantizedOp
abstract class has been changed to useStarAlgebraMixin
.
Deprecation Notes#
The
EvolvedOperatorAnsatz
is deprecated. UseEvolvedOperatorAnsatz
as a direct replacement instead.
The property dagger in the second quantized operators is deprecated. Use adjoint() method alternatively.
the legacy driver return types, QMolecule and WatsonHamiltonian
the legacy transformers acting on the now deprecated driver return types
the BaseProblem.molecule_data and BaseProblem.molecule_data_transformed attributes
All currently existing drivers have been moved from qiskit_nature.drivers to qiskit_nature.drivers.second_quantization. This is necessary because future additions to Nature which reside in parallel to the second_quantization submodules will not be using these drivers. Making this separation reflects that in the code structure. The same change was necessary for the existing qiskit_nature.transformers.
Bug Fixes#
Fixed an issue where
FermionicOp
raises unwanted ValueError when initialized with some list of sparse label.
Fixes the issue #198 where total dipole moment was not calculated correctly in the ElectronicStructureResult.
QiskitNatureError``s where not being raised properly by the ``ActiveSpaceTransformer
due to ill-formatted error messages.
Fix
AdaptVQE
after the update ofVQE
which deleted the internal_energy_evaluation
method that Adapt-VQE was relying on.
The FreezeCoreTransformer (and ActiveSpaceTransformer) were incompatible with the automatic Z2Symmetry reduction. This issue was fixed by correcting the ElectronicStructureProblem.symmetry_sector_locator method.
The two-qubit reduction needs to be skipped when a qubit operator only has 2 (or even fewer) qubits.
The
VQEProgram
does support the evaluation of auxiliary operators at the final state, but theqiskit_nature.runtime.VQEProgram.supports_aux_operators()
method previously returned False instead of True.
Allow Qiskit’s
Optimizer
classes as input for theoptimizer
in theVQEProgram
instead of only dictionaries.
Other Notes#
Changed documentation and code to better reflect rebranding of Qiskit’s chemistry module as Qiskit Nature.