Headware-Efficient Ansatz and Noisy Circuit Simulation

class tencirchem.HEA(h_qubit_op: ~openfermion.ops.operators.qubit_operator.QubitOperator, circuit: ~typing.Callable | ~qiskit.circuit.quantumcircuit.QuantumCircuit, init_guess: ~typing.List[float] | ~numpy.ndarray, engine: str = None, engine_conf: [<class 'tensorcircuit.noisemodel.NoiseConf'>, <class 'tencirchem.static.engine_hea.QpuConf'>] = None)[source]

Bases: object

Run hardware-efficient ansatz calculation. For a comprehensive tutorial see Noisy Circuit Simulation.

__init__(h_qubit_op: ~openfermion.ops.operators.qubit_operator.QubitOperator, circuit: ~typing.Callable | ~qiskit.circuit.quantumcircuit.QuantumCircuit, init_guess: ~typing.List[float] | ~numpy.ndarray, engine: str = None, engine_conf: [<class 'tensorcircuit.noisemodel.NoiseConf'>, <class 'tencirchem.static.engine_hea.QpuConf'>] = None)[source]

Construct the HEA class from Hamiltonian in QubitOperator form and the ansatz.

Parameters:
  • h_qubit_op (QubitOperator) – Hamiltonian as openfermion QubitOperator.

  • circuit (Callable or QuantumCircuit) – The ansatz as a function or Qiskit QuantumCircuit

  • init_guess (list of float or np.ndarray) – The parameter initial guess.

  • engine (str, optional) – The engine to run the calculation. See Engines for details. Defaults to "tensornetwork".

  • engine_conf (NoiseConf, optional) – The noise configuration for the circuit. Defaults to None, in which case if a noisy engine is used, an isotropic depolarizing error channel for all 2-qubit gates with \(p=0.02\) is added to the circuit.

classmethod as_pyscf_solver(config_function: Callable | None = None, opt_engine: str | None = None, **kwargs)[source]

Converts the HEA class to a PySCF FCI solver using \(R_y\) ansatz.

Parameters:
  • config_function (callable) – A function to configure the HEA instance. Accepts the HEA instance and modifies it inplace before kernel() is called.

  • opt_engine (str) – The engine to use when performing the circuit parameter optimization.

  • kwargs – Other arguments to be passed to the __init__() function such as engine.

Return type:

FCISolver

Examples

>>> from pyscf.mcscf import CASSCF
>>> from tencirchem import HEA
>>> from tencirchem.molecule import h8
>>> # normal PySCF workflow
>>> hf = h8.HF()
>>> round(hf.kernel(), 6)
-4.149619
>>> casscf = CASSCF(hf, 2, 2)
>>> # set the FCI solver for CASSCF to be HEA
>>> casscf.fcisolver = HEA.as_pyscf_solver(n_layers=1)
>>> round(casscf.kernel()[0], 6)
-4.166473
densitymatrix(params: Any | None = None) Any[source]

Evaluate the circuit density matrix in the presence of circuit noise. Only valid for "tensornetwork-noise" and "tensornetwork-noise&shot" engines.

Parameters:

params (Tensor, optional) – The circuit parameters. Defaults to None, which uses the optimized parameter and kernel() must be called before.

Returns:

densitymatrix

Return type:

Tensor

See also

statevector

Evaluate the circuit state vector.

energy

Evaluate the total energy.

energy_and_grad

Evaluate the total energy and parameter gradients.

Examples

>>> import numpy as np
>>> from tencirchem import UCC, HEA
>>> from tencirchem.molecule import h2
>>> ucc = UCC(h2)
>>> hea = HEA.ry(ucc.int1e, ucc.int2e, ucc.n_elec, ucc.e_core,
...         n_layers=1, engine="tensornetwork-noise")
>>> np.round(hea.densitymatrix([0, np.pi, 0, 0]), 8)  # HF state with noise
array([[0.00533333+0.j, 0.        +0.j, 0.        +0.j, 0.        +0.j],
       [0.        +0.j, 0.984     +0.j, 0.        +0.j, 0.        +0.j],
       [0.        +0.j, 0.        +0.j, 0.00533333+0.j, 0.        +0.j],
       [0.        +0.j, 0.        +0.j, 0.        +0.j, 0.00533333+0.j]])
energy(params: Any | None = None, engine: str | None = None) float[source]

Evaluate the total energy.

Parameters:
  • params (Tensor, optional) – The circuit parameters. Defaults to None, which uses the optimized parameter and kernel() must be called before.

  • engine (str, optional) – The engine to use. Defaults to None, which uses self.engine.

Returns:

energy – Total energy

Return type:

float

See also

statevector

Evaluate the circuit state vector.

densitymatrix

Evaluate the circuit density matrix in the presence of circuit noise.

energy_and_grad

Evaluate the total energy and parameter gradients.

Examples

>>> import numpy as np
>>> from tencirchem import UCC, HEA
>>> from tencirchem.molecule import h2
>>> ucc = UCC(h2)
>>> hea = HEA.ry(ucc.int1e, ucc.int2e, ucc.n_elec, ucc.e_core,
...         n_layers=1, engine="tensornetwork-noise")
>>> # HF state, no noise
>>> round(hea.energy([0, np.pi, 0, 0], "tensornetwork"), 8)
-1.11670614
>>> # HF state, gate noise
>>> round(hea.energy([0, np.pi, 0, 0], "tensornetwork-noise"), 4)
-1.1001
>>> # HF state, measurement noise. Set the number of shots by `hea.shots`
>>> round(hea.energy([0, np.pi, 0, 0], "tensornetwork-shot"), 1)
-1.1
>>> # HF state, gate+measurement noise
>>> hea.energy([0, np.pi, 0, 0], "tensornetwork-noise&shot")  
-1...
energy_and_grad(params: Any | None = None, engine: str | None = None, grad: str | None = None) Tuple[float, Any][source]

Evaluate the total energy and parameter gradients using parameter-shift rule.

Parameters:
  • params (Tensor, optional) – The circuit parameters. Defaults to None, which uses the optimized parameter and kernel() must be called before.

  • engine (str, optional) – The engine to use. Defaults to None, which uses self.engine.

  • grad (str, optional) – The algorithm to use for the gradient. Defaults to None, which means self.grad will be used. Possible options are "param-shift" for parameter-shift rule and "autodiff" for auto-differentiation. Note that "autodiff" is not compatible with "tensornetwork-shot" and "tensornetwork-noise&shot" engine.

Returns:

  • energy (float) – Total energy

  • grad (Tensor) – The parameter gradients

See also

statevector

Evaluate the circuit state vector.

densitymatrix

Evaluate the circuit density matrix in the presence of circuit noise.

energy

Evaluate the total energy.

classmethod from_integral(int1e: ndarray, int2e: ndarray, n_elec: int, e_core: float, mapping: str, circuit: Callable | QuantumCircuit, init_guess: ndarray, **kwargs)[source]

Construct the HEA class from electron integrals and custom quantum circuit. Overlap integral is assumed to be identity.

Parameters:
  • int1e (np.ndarray) – One-body integral in spatial orbital.

  • int2e (np.ndarray) – Two-body integral, in spatial orbital, chemists’ notation, and without considering symmetry.

  • n_elec (int) – The number of electrons

  • e_core (float) – The nuclear energy or core energy if active space approximation is involved.

  • mapping (str) – The fermion to qubit mapping. Supported mappings are "parity", and "bravyi-kitaev".

  • circuit (Callable or QuantumCircuit) – The ansatz as a function or Qiskit QuantumCircuit

  • init_guess (list of float or np.ndarray) – The parameter initial guess.

  • kwargs – Other arguments to be passed to the __init__() function such as engine.

Returns:

hea – An HEA instance

Return type:

HEA

classmethod from_molecule(m: Mole, active_space=None, n_layers=3, mapping='parity', **kwargs)[source]

Construct the HEA class from the given molecule. The \(R_y\) ansatz is employed. By default, the number of layers is set to 3.

Parameters:
  • m (Mole) – The molecule object.

  • active_space (Tuple[int, int], optional) – Active space approximation. The first integer is the number of electrons and the second integer is the number or spatial-orbitals. Defaults to None.

  • n_layers (int) – The number of layers in the \(R_y\) ansatz. Defaults to 3.

  • mapping (str) – The fermion to qubit mapping. Supported mappings are "parity", and "bravyi-kitaev".

  • kwargs – Other arguments to be passed to the __init__() function such as engine.

Returns:

hea – An HEA instance

Return type:

HEA

get_dmcircuit(params: Any | None = None, noise_conf: NoiseConf | None = None) DMCircuit2[source]

Get the DMCircuit with noise. Only valid for "tensornetwork-noise" and "tensornetwork-noise&shot" engines.

Parameters:
  • params (Tensor, optional) – The circuit parameters. Defaults to None, which uses the optimized parameter and kernel() must be called before.

  • noise_conf (NoiseConf, optional) – The noise configuration for the circuit. Defaults to None, in which case self.engine_conf is used.

Returns:

dmcircuit

Return type:

DMCircuit

get_dmcircuit_no_noise(params: Any | None = None) DMCircuit2[source]

Get the DMCircuit without noise.

Parameters:

params (Tensor, optional) – The circuit parameters. Defaults to None, which uses the optimized parameter and kernel() must be called before.

Returns:

dmcircuit

Return type:

DMCircuit

get_opt_function(grad: str | None = None, with_time: bool = False) Callable | Tuple[Callable, float][source]

Returns the cost function in SciPy format for optimization. Basically a wrapper to energy_and_grad() or energy(),

Parameters:
  • with_time (bool, optional) – Whether return staging time. Defaults to False.

  • grad (str, optional) – The algorithm to use for the gradient. Defaults to None, which means self.grad will be used. Possible options are "param-shift" for parameter-shift rule and "autodiff" for auto-differentiation. Note that "autodiff" is not compatible with "tensornetwork-noise&shot" engine.

Returns:

  • opt_function (Callable) – The optimization cost function in SciPy format.

  • time (float) – Staging time. Returned when with_time is set to True.

property grad
kernel()[source]
make_rdm1(params: Any | None = None) ndarray[source]

Evaluate the spin-traced one-body reduced density matrix (1RDM).

\[\textrm{1RDM}[p,q] = \langle p_{\alpha}^\dagger q_{\alpha} \rangle + \langle p_{\beta}^\dagger q_{\beta} \rangle\]
Parameters:

params (Tensor, optional) – The circuit parameters. Defaults to None, which uses the optimized parameter and kernel() must be called before.

Returns:

rdm1 – The spin-traced one-body RDM.

Return type:

np.ndarray

See also

make_rdm2

Evaluate the spin-traced two-body reduced density matrix (2RDM).

make_rdm2(params: Any | None = None) ndarray[source]

Evaluate the spin-traced two-body reduced density matrix (2RDM).

\[\begin{split}\begin{aligned} \textrm{2RDM}[p,q,r,s] & = \langle p_{\alpha}^\dagger r_{\alpha}^\dagger s_{\alpha} q_{\alpha} \rangle + \langle p_{\beta}^\dagger r_{\alpha}^\dagger s_{\alpha} q_{\beta} \rangle \\ & \quad + \langle p_{\alpha}^\dagger r_{\beta}^\dagger s_{\beta} q_{\alpha} \rangle + \langle p_{\beta}^\dagger r_{\beta}^\dagger s_{\beta} q_{\beta} \rangle \end{aligned}\end{split}\]
Parameters:

params (Tensor, optional) – The circuit parameters. Defaults to None, which uses the optimized parameter and kernel() must be called before.

Returns:

rdm2 – The spin-traced two-body RDM.

Return type:

np.ndarray

See also

make_rdm1

Evaluate the spin-traced one-body reduced density matrix (1RDM).

property n_params

The number of parameter in the ansatz/circuit.

property params

The circuit parameters.

print_circuit()[source]
print_summary()[source]
classmethod ry(int1e: ndarray, int2e: ndarray, n_elec: int, e_core: float, n_layers: int, init_circuit: Circuit | None = None, mapping: str = 'parity', **kwargs)[source]

Construct the HEA class from electron integrals and the \(R_y\) ansatz. The circuit consists of interleaved layers of $R_y$ and CNOT gates

\[|\Psi(\theta)\rangle=\prod_{l=k}^1\left [ L_{R_y}^{(l)}(\theta) L_{CNOT}^{(l)} \right ] L_{R_y}^{(0)}(\theta) |{\phi}\rangle\]

where $k$ is the total number of layers, and the layers are defined as

\[L_{CNOT}^{(l)}=\prod_{j=N/2-1}^1 CNOT_{2j, 2j+1} \prod_{j=N/2}^{1} CNOT_{2j-1, 2j}\]
\[L_{R_y}^{(l)}(\theta)=\prod_{j=N}^{1} RY_{j}(\theta_{lj})\]

Overlap integral is assumed to be identity. Parity transformation is used to transform from fermion operators to qubit operators by default.

Parameters:
  • int1e (np.ndarray) – One-body integral in spatial orbital.

  • int2e (np.ndarray) – Two-body integral, in spatial orbital, chemists’ notation, and without considering symmetry.

  • n_elec (int) – The number of electrons

  • e_core (float) – The nuclear energy or core energy if active space approximation is involved.

  • n_layers (int) – The number of layers in the ansatz.

  • init_circuit (Circuit) – The initial circuit before the \(R_y\) ansatz. Defaults to None.

  • mapping (str) – The fermion to qubit mapping. Supported mappings are "parity", and "bravyi-kitaev".

  • kwargs – Other arguments to be passed to the __init__() function such as engine.

Returns:

hea – An HEA instance

Return type:

HEA

statevector(params: Any | None = None) Any[source]

Evaluate the circuit state vector without considering noise. Valid for "tensornetwork" and "tensornetwork-shot" engine.

Parameters:

params (Tensor, optional) – The circuit parameters. Defaults to None, which uses the optimized parameter and kernel() must be called before.

Returns:

statevector – Corresponding state vector

Return type:

Tensor

See also

densitymatrix

Evaluate the circuit density matrix in the presence of circuit noise.

energy

Evaluate the total energy.

energy_and_grad

Evaluate the total energy and parameter gradients.

Examples

>>> import numpy as np
>>> from tencirchem import UCC, HEA
>>> from tencirchem.molecule import h2
>>> ucc = UCC(h2)
>>> hea = HEA.ry(ucc.int1e, ucc.int2e, ucc.n_elec, ucc.e_core, n_layers=1)
>>> np.round(hea.statevector([0, np.pi, 0, 0]), 8)  # HF state
array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j])
tencirchem.static.hea.get_ry_circuit(params: Any, n_qubits: int, n_layers: int) Circuit[source]

Get the parameterized \(R_y\) circuit.

Parameters:
  • params (Tensor) – The circuit parameters.

  • n_qubits (int) – The number of qubits.

  • n_layers (int) – The number of layers in the ansatz.

Returns:

c

Return type:

Circuit

tencirchem.static.hea.parity(fermion_operator: FermionOperator, n_modes: int, n_elec: int) QubitOperator[source]

Performs parity transformation.

Parameters:
  • fermion_operator (FermionOperator) – The fermion operator.

  • n_modes (int) – The number of modes (spin-orbitals).

  • n_elec (int) – The number of electrons.

Returns:

qubit_operator

Return type:

QubitOperator

tencirchem.static.hea.binary(fermion_operator: FermionOperator, n_modes: int, n_elec: int) QubitOperator[source]

Performs binary transformation.

Parameters:
  • fermion_operator (FermionOperator) – The fermion operator.

  • n_modes (int) – The number of modes.

  • n_elec (int) – The number of electrons.

Returns:

qubit_operator

Return type:

QubitOperator