# 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 a`QCSchema`

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 the`FermioniOp`

, 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 the`PolynomialTensor.apply()`

method which allows handling of numpy routines which return more than one array. The same argument also gets exposed by`ElectronicIntegrals.apply()`

.

Adds the following new utility methods for splitting and stacking multi-tensors:

Adds the

`SparseLabelOp.from_terms()`

method which is the inverse of`SparseLabelOp.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 take`None`

as its value. However, the attributes which this one might rely on (e.g.`FermionicOp.num_spin_orbitals`

or`BosonicOp.num_modes`

) can remain`None`

. 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 the`ActiveSpaceTransformer`

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 the`UCC`

,`UCCSD`

, and`PUCCD`

classes. When`True`

, 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 of`False`

.

### 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 in`extracted_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 extension`ElectronicEnergy.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 of`BosonicOp`

,`FermionicOp`

,`SpinOp`

, or`VibrationalOp`

, 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 the`ElectronicStructureResult.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`

and`copy.deepcopy`

operations for the`Tensor`

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 standard`QubitMapper`

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 a`QubitMapper`

instance into a`TaperedQubitMapper`

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 new`Z2Symmetries`

from`quantum_info`

as well as the legacy`Z2Symmetries`

from the`opflow`

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 to`True`

.

Added the

`InterleavedQubitMapper`

which allows wrapping of another`FermionicMapper`

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 a`HartreeFock`

initial state or`UCC`

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 the`ActiveSpaceTransformer`

as if you had stored your integrals in standard arrays.

Adds the

`use_symmetry_reduced_integrals`

setting. When set to`True`

, this will cause objects like for example the`FCIDump`

,`QCSchema`

, or`PySCFDriver`

to attempt and leverage the`symmetric_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 the`label_template`

which allows an end-user to influence the translation procedure implemented in`from_polynomial_tensor()`

.

Adds the new

`tensor_unwrapping`

setting which may be set to`False`

to disable the unwrapping of internally created`Tensor`

objects stored inside of a`PolynomialTensor`

. See also`tensor_unwrapping`

for more details.

Adds the new argument

`num_particles`

to the`ParityMapper`

which will implement the two qubit reduction without requiring an instance of`QubitConverter`

.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 using`numpy`

arrays when the optional`sparse`

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 the`QubitMapper.map()`

method. This allows the user to set the length of a`SparseLabelOp`

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()`

and`convert_clifford()`

and`find_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 where`qiskit_nature.second_q.mappers.QubitConverter`

were previously required. This addition advances toward a future deprecation of`QubitConverter`

. All inputs of type`QubitConverter`

now support`QubitMapper`

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`

and`EigensolverFactory`

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 the`JordanWignerMapper`

(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 the`QubitMapper`

implementations directly. As a consequence of this, all public properties and function arguments which referred to the`QubitConverter`

by name (e.g.`qubit_converter`

) have been deprecated in favor of properties and function arguments referring to`QubitMapper`

(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 uses`QubitMapper`

instances directly. Qubit tapering can instead now be done using the`TaperedQubitMapper`

which can be constructed easily using the`get_tapered_mapper()`

method.

The

`match_convert`

argument of the`hartree_fock_bitstring_mapped()`

method has been deprecated without replacement. This utility is no longer needed in the new workflow which uses`QubitMapper`

instances directly.

The

`VQEClient`

and its matching`VQERuntimeResult`

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 the`hijkl`

,`hijkl_ba`

, and`hijkl_bb`

attributes. Instead, these will always be`SymmetricTwoBodyIntegrals`

. Instances of the latter can be used as`np.ndarray`

so in terms of functionality this should not change anything. However,`isinstance(integrals, np.ndarray)`

will*not*return`True`

for`integrals`

of type`SymmetricTwoBodyIntegrals`

. Additionally, the three`FCIDump`

attributes will no longer accept physicist-ordered two-body tensors in the future.

Deprecated the default value (

`True`

) of`tensor_unwrapping`

meaning that in the future`__getitem__()`

will return objects of type`Tensor`

.

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 called`nmodes`

have been renamed to`register_length`

.

### Bug Fixes#

Fixes

`SparseLabelOp.assign_parameters()`

failing to assign parameters recursively.

The commutator methods

`commutator()`

,`anti_commutator()`

, and`double_commutator()`

no longer faultily simplify the returned operator (i.e. the absolute tolerance during simplification is set to zero instead of defaulting to`SparseLabelOp.atol`

).

Fixes a bug when printing the

`total_dipole_moment_in_debye`

Fixes output of

`generate_fermionic_excitations()`

when called with`perserve_spin=False`

and unequal number of alpha and beta particles

Fixes the

`qcschema_to_problem()`

method to take`QCWavefunction.eri_mo_ab`

into account when`QCWavefunction.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 the`VQEClient`

. Previously, backends instantiated with the`IBMProvider`

failed since they return backends of type`BackendV2`

, which were not correctly supported in the VQE client. Backends instantiated with the`IBMQ`

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 related`LatticeModel`

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 the`qiskit_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 of`SparseLabelOpsFactory`

instances inside of problems. This container is a`MutableSet`

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 the`SUCCD`

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`

and`VSCF`

as subclasses of`BlueprintCircuit`

. 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 old`qiskit_nature.operators.second_quantization.operators.FermionicOp`

. This new operator is a subclass of the`qiskit_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 the`qiskit_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 from`HFInitialPoint`

,`MP2InitialPoint`

, and`VSCFInitialPoint`

. Thus the excitation list cannot be set directly, rather this must be set via the`ansatz`

.

Following the MP2 T2 and energy correction calculation fix, the APIs for

`MP2InitialPoint`

and`HFInitialPoint`

have been changed slightly. After setting the`grouped_property`

, the`total_energy`

and`energy_correction`

are now accessed via their respective properties, rather than via`get_energy`

and`get_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 substitute`rustworkx`

.

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’, whereas`qiskit_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 of`drivers`

) the features provided by the sampler are no longer the responsibility of Qiskit Nature. A warm-starting`InitialPoint`

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 the`BaseProblem`

interface and have been attached to the`QEOM`

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`

with`preserve_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`

and`VQEProgramResult`

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`

and`VSCFInitialPoint`

, are to be used with`UCC`

, and`UVCC`

, respectively.This follows the introduction of

`MP2InitialPoint`

for computing the initial point using the Møller-Plesset 2nd Order (MP2) corrections.`MP2InitialPoint`

,`HFInitialPoint`

, and`VSCFInitialPoint`

all inherit from the abstract base class`InitialPoint`

.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 in`VQEUCCFactory`

and`VQEUVCCFactory`

. Additionally, one may pass an explicit`InitialPoint`

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 calling`AdaptVQE`

. 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 a`networkx.Graph`

object, which will be internally converted to a`retworkx.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 the`compute`

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`

, an`MP2InitialPoint`

object can be passed via the`initial_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`

from`VQE`

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 a`ProteinFoldingProblem`

. 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 of`ProteinShapeFileGen`

. This class has in its turn a method`get_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 of`ProteinShapeDecoder`

. This class has in its turn two properties`main_turns`

and`side_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 to`qiskit_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() in`qiskit_nature.algorithms.ExcitedStatesEigensolver`

. This matches the format of`qiskit_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 implement`BOPESSampler`

using bootstrapping, which works similarly now with VQEClient`VQEClient`

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 of`FermionicOp`

from “dense” to “sparse”.

### Deprecation Notes#

The

`delta`

argument of`AdaptVQE`

is deprecated in favor of supplying a`gradient`

from Qiskit Terra’s`qiskit.opflow.gradients`

framework. In doing so, the default behavior of`AdaptVQE`

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 specify`delta=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, use`qiskit_nature.operators.second_quantization.SecondQuantizedOp.simplify()`

.`qiskit_nature.operators.second_quantization.FermionicOp.to_normal_order()`

. Instead, use`qiskit_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 to`qiskit_nature.algorithms.ExcitedStatesEigensolver`

. Now the constructor has the following positional argument:state_solver

`VQEUCCFactory`

had setter/getter properties that were repeated with respect to`qiskit.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 via`minimum_eigensolver`

.The same changes have been done for

`VQEUVCCFactory`

and`NumPyMinimumEigensolverFactory`

### 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`

and`UVCC`

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 the`operators`

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 the`operators`

on demand when requested via the property, rather than, as before, when the circuit is built. This is a similar change as was done to`UCC`

.

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 the`QubitConverter`

`sector_locator`

parameter callback signature of the`convert()`

method was changed from`sector_locator: Optional[Callable[[Z2Symmetries], Optional[List[int]]]]`

to`sector_locator: Optional[Callable[[Z2Symmetries, "QubitConverter"], Optional[List[int]]]]`

i.e. your supplied callback method must now take a second parameter which is a`QubitConverter`

instance and when invoked will be the instance upon which the`convert`

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`

and`VQEProgramResult`

have been renamed to`VQEClient`

,`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 provided`QubitConverter`

.Also fixes the

`ElectronicStructureProblem`

`symmetry_sector_locator()`

, which uses the HartreeFock class too, so that it correctly determines the sector containing the ground state when`auto`

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()`

from`Optional[List[float]]`

to`Optional[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 method`is_hermitian()`

method which will return`True`

if the operator is equivalent to its adjoint and`False`

otherwise

`to_list()`

is now an abstract method of`SecondQuantizedOp`

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`

and`VibrationalStructureMoleculeDriver`

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. The`VQEProgram`

implements the`MinimumEigensolver`

interface and can thus be used as a drop-in replacement for other minimum eigensolvers like`qiskit.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 use`StarAlgebraMixin`

.

### Deprecation Notes#

The

`EvolvedOperatorAnsatz`

is deprecated. Use`EvolvedOperatorAnsatz`

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 of`VQE`

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 the`qiskit_nature.runtime.VQEProgram.supports_aux_operators()`

method previously returned False instead of True.

Allow Qiskit’s

`Optimizer`

classes as input for the`optimizer`

in the`VQEProgram`

instead of only dictionaries.

### Other Notes#

Changed documentation and code to better reflect rebranding of Qiskit’s chemistry module as Qiskit Nature.