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 theHEA
instance and modifies it inplace beforekernel()
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 asengine
.
- 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 usesself.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 usesself.engine
.grad (str, optional) – The algorithm to use for the gradient. Defaults to
None
, which meansself.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 asengine
.
- Returns:
hea – An HEA instance
- Return type:
- 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 asengine
.
- Returns:
hea – An HEA instance
- Return type:
- 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()
orenergy()
,- 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 meansself.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 toTrue
.
- property grad¶
- 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.
- 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 asengine
.
- Returns:
hea – An HEA instance
- Return type:
- 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