주 콘텐츠로 건너뛰기

양자 화학을 위한 해밀토니안

VQE에서 해밀토니안이 담당하는 역할을 간략히 살펴보겠습니다.

VQE에서의 해밀토니안 개요

Victoria Lipinska 박사가 해밀토니안과 양자 컴퓨팅에서 이를 매핑하는 방법을 안내합니다.

참고 문헌

위 영상에서 언급된 논문들입니다.

양자 화학을 위한 해밀토니안 준비

화학 문제에 양자 컴퓨팅을 적용할 때 좋은 첫 단계는 관심 있는 시스템에 대한 해밀토니안을 정의하는 것입니다. 여기서는 동일한 페르미온 시스템에 특화된 일부 매핑이 필요한 양자 화학 해밀토니안에 한정하여 논의하겠습니다.

양자 화학 분야에서 일하시는 분이라면, 아마 이미 분자를 모델링하기 위해 즐겨 사용하는 소프트웨어를 가지고 있으실 것이며, 이 소프트웨어로 관심 있는 시스템을 기술하는 해밀토니안을 생성할 수 있습니다. 여기서는 PySCF, numpy, Qiskit만으로 구축된 코드를 사용합니다. 하지만 해밀토니안 준비 과정은 사전 패키징된 솔루션에도 동일하게 적용됩니다. 이 접근 방식과 다른 소프트웨어와의 유일한 차이점은 사소한 구문 차이뿐이며, 이 중 일부는 기존 워크플로의 통합을 용이하게 하기 위해 "타사 소프트웨어" 하위 섹션에서 다룹니다.

IBM Quantum® QPU에서 사용하기 위한 양자 화학 해밀토니안을 생성하는 과정은 다음 단계로 이루어집니다.

  1. 분자를 정의합니다 (기하학적 구조, 스핀, 활성 공간 등)
  2. 페르미온 해밀토니안을 생성합니다 (생성 및 소멸 연산자)
  3. 페르미온 해밀토니안을 보손 연산자로 매핑합니다 (이 맥락에서는 Pauli 연산자를 사용)
  4. 타사 소프트웨어를 사용하는 경우: 생성 소프트웨어와 Qiskit 사이의 구문 불일치를 처리합니다

페르미온 해밀토니안은 페르미온 연산자로 작성되며, 특히 전자가 구별 불가능한 페르미온이라는 점을 고려합니다. 즉, 전자는 구별 가능한 보손 Qubit과는 완전히 다른 통계를 따릅니다. 이 때문에 매핑 과정이 필요합니다.

이러한 과정에 이미 익숙한 분들은 이 섹션을 건너뛰셔도 됩니다. 목표:

최종 목표는 다음과 같은 형태의 해밀토니안을 얻는 것입니다.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy openfermion pyscf qiskit
H = [(1, "XX"), (1, "YY"), (1, "ZZ")]
print(H)
[(1, 'XX'), (1, 'YY'), (1, 'ZZ')]

또는

from qiskit.quantum_info import SparsePauliOp

H = SparsePauliOp(["XX", "YY", "ZZ"], coeffs=[1.0 + 0.0j, 1.0 + 0.0j, 1.0 + 0.0j])
print(H)
SparsePauliOp(['XX', 'YY', 'ZZ'],
coeffs=[1.+0.j, 1.+0.j, 1.+0.j])

먼저 몇 가지 패키지를 임포트하는 것으로 시작하겠습니다.

import numpy as np
from pyscf import ao2mo, gto, mcscf, scf
  1. 분자 정의

여기서는 관심 있는 분자의 속성을 지정합니다. 이 예제에서는 (결과 해밀토니안이 표시할 수 있을 정도로 충분히 짧기 때문에) 이원자 수소를 선택했습니다. Python 기반 화학 시뮬레이션 프레임워크(PySCF)는 양자 컴퓨팅에 적합한 분자 해밀토니안을 생성하는 등 여러 용도로 사용할 수 있는 다양한 전자 구조 모듈을 제공합니다. PySCF Quickstart 가이드는 모든 변수와 기능에 대한 전체 설명을 위한 훌륭한 자료입니다. 많은 분들이 이미 익숙할 것이므로 여기서는 매우 간략한 개요만 제공하겠습니다. 더 잘 이해하려면 PySCF를 방문하세요. 간략하게:

__distance__는 이원자 분자에 사용할 수 있으며, 또는 단순히 각 원자에 대한 직교 좌표를 지정할 수 있습니다. 거리 단위는 옹스트롬입니다.

__gto__는 가우시안 형 오비탈을 생성합니다.

__basis__는 분자 오비탈을 모델링하는 데 사용되는 함수를 의미합니다. 여기서 'sto-6g'는 6개의 원시 가우시안 오비탈을 사용하여 Slater형 오비탈을 피팅하는 것에서 이름을 따온 일반적인 최소 기저입니다.

__spin__은 짝지어지지 않은 전자의 수를 나타내는 정수 값(2S2S와 같음)입니다. 일부 소프트웨어는 다중도(2S+12S+1)를 대신 사용한다는 점에 유의하세요.

__charge__는 분자의 전하입니다.

__symmetry__는 분자의 점 대칭군으로, 문자열로 지정하거나 "symmetry = True"로 설정하여 자동으로 감지할 수 있습니다. 여기서 "Dooh"는 두 개의 동일한 원자종으로 이루어진 이원자 분자에 적합한 대칭군입니다.

distance = 0.735
a = distance / 2
mol = gto.Mole()
mol.build(
verbose=0,
atom=[
["H", (0, 0, -a)],
["H", (0, 0, a)],
],
basis="sto-6g",
spin=0,
charge=0,
symmetry="Dooh",
)
<pyscf.gto.mole.Mole at 0x7fc718f07610>

총 에너지(핵간 반발 에너지와 전자 에너지를 모두 포함), 총 전자 오비탈 에너지, 또는 전자 오비탈의 일부 부분 집합의 에너지(보완적 부분 집합은 고정됨)를 기술할 수 있다는 점을 명심하세요. H2\text{H}_2의 특정 경우에 대해, 아래의 다양한 에너지를 살펴보고, 총 에너지에서 핵간 반발 에너지를 뺀 값이 실제로 전자 에너지를 산출한다는 점에 주목하세요.

mf = scf.RHF(mol)
mf.scf()

print(
mf.energy_nuc(),
mf.energy_elec()[0],
mf.energy_tot(),
mf.energy_tot() - mol.energy_nuc(),
)
0.7199689944489797 -1.8455976628764188 -1.125628668427439 -1.8455976628764188
active_space = range(mol.nelectron // 2 - 1, mol.nelectron // 2 + 1)
  1. 페르미온 해밀토니안 생성

__scf__는 광범위한 자기 일관장 방법을 의미합니다.

__rhf__는 mf에서 mf = scf.RHF(mol)로, 제한된 Hartree-Fock 계산을 사용하는 솔버입니다. 이것의 커널(아래의 E)은 핵간 반발과 분자 오비탈을 포함한 총 에너지입니다.

__mcscf__는 다중 구성 자기 일관장 패키지입니다.

__ao2mo__는 원자 오비탈에서 분자 오비탈로의 변환입니다.

또한 다음 변수들을 사용합니다.

ncas: 완전 활성 공간의 오비탈 수

nelecas: 완전 활성 공간의 전자 수

E1 = mf.kernel()
mx = mcscf.CASCI(mf, ncas=2, nelecas=(1, 1))
mo = mx.sort_mo(active_space, base=0)
E2 = mx.kernel(mo)[:2]

해밀토니안을 원하는데, 이는 종종 전자 코어의 에너지(ecore, 최소화에 관여하지 않음), 단일 전자 연산자(h1e), 그리고 두 전자 에너지(h2e)로 분리됩니다. 이들은 아래의 마지막 두 줄에서 명시적으로 추출됩니다.

h1e, ecore = mx.get_h1eff()
h2e = ao2mo.restore(1, mx.get_h2eff(), mx.ncas)

이러한 해밀토니안은 현재 페르미온 (생성 및 소멸) 연산자로, (구별 불가능한) 페르미온 시스템에 적용 가능하며, 이에 따라 교환 시 반대칭에 종속됩니다. 이는 구별 가능하거나 보손 시스템에 적용되는 것과는 다른 정역학을 결과로 합니다. IBM Quantum QPU에서 계산을 실행하려면 에너지를 기술하는 보손 연산자가 필요합니다. 이러한 매핑의 결과는 관례적으로 Pauli 연산자로 작성되는데, 이는 Pauli 연산자가 에르미트적이면서 동시에 유니타리이기 때문입니다. 사용할 수 있는 매핑은 여러 가지가 있습니다. 가장 단순한 것 중 하나가 Jordan-Wigner 변환입니다.

  1. 해밀토니안 매핑

화학 해밀토니안을 양자 컴퓨터에서 실행할 수 있는 형태로 매핑할 수 있는 도구는 많이 있다는 점에 유의해야 합니다. 여기서는 PySCF, numpy, Qiskit만 사용하여 Jordan-Wigner 매핑을 직접 구현합니다. 다른 솔루션의 구문 고려 사항에 대해서는 아래에서 논평합니다. Cholesky 함수는 해밀토니안의 두 전자 항에 대한 저랭크 분해를 얻는 데 도움이 됩니다.

def cholesky(V, eps):
# see https://arxiv.org/pdf/1711.02242.pdf section B2
# see https://arxiv.org/abs/1808.02625
# see https://arxiv.org/abs/2104.08957
no = V.shape[0]
chmax, ng = 20 * no, 0
W = V.reshape(no**2, no**2)
L = np.zeros((no**2, chmax))
Dmax = np.diagonal(W).copy()
nu_max = np.argmax(Dmax)
vmax = Dmax[nu_max]
while vmax > eps:
L[:, ng] = W[:, nu_max]
if ng > 0:
L[:, ng] -= np.dot(L[:, 0:ng], (L.T)[0:ng, nu_max])
L[:, ng] /= np.sqrt(vmax)
Dmax[: no**2] -= L[: no**2, ng] ** 2
ng += 1
nu_max = np.argmax(Dmax)
vmax = Dmax[nu_max]
L = L[:, :ng].reshape((no, no, ng))
print(
"accuracy of Cholesky decomposition ",
np.abs(np.einsum("prg,qsg->prqs", L, L) - V).max(),
)
return L, ng

identitycreators_destructors 함수는 페르미온 해밀토니안의 생성 및 소멸 연산자를 Pauli 연산자로 대체합니다. creators_destructors는 Jordan-Wigner 매핑을 사용합니다.

def identity(n):
return SparsePauliOp.from_list([("I" * n, 1)])

def creators_destructors(n, mapping="jordan_wigner"):
c_list = []
if mapping == "jordan_wigner":
for p in range(n):
if p == 0:
ell, r = "I" * (n - 1), ""
elif p == n - 1:
ell, r = "", "Z" * (n - 1)
else:
ell, r = "I" * (n - p - 1), "Z" * p
cp = SparsePauliOp.from_list([(ell + "X" + r, 0.5), (ell + "Y" + r, -0.5j)])
c_list.append(cp)
else:
raise ValueError("Unsupported mapping.")
d_list = [cp.adjoint() for cp in c_list]
return c_list, d_list

마지막으로, build_hamiltoniancholesky, identity, creators_destructors 함수를 사용하여 양자 컴퓨터에서 실행하기에 적합한 최종 해밀토니안을 생성합니다.

def build_hamiltonian(ecore: float, h1e: np.ndarray, h2e: np.ndarray) -> SparsePauliOp:
ncas, _ = h1e.shape

C, D = creators_destructors(2 * ncas, mapping="jordan_wigner")
Exc = []
for p in range(ncas):
Excp = [C[p] @ D[p] + C[ncas + p] @ D[ncas + p]]
for r in range(p + 1, ncas):
Excp.append(
C[p] @ D[r]
+ C[ncas + p] @ D[ncas + r]
+ C[r] @ D[p]
+ C[ncas + r] @ D[ncas + p]
)
Exc.append(Excp)

# low-rank decomposition of the Hamiltonian
Lop, ng = cholesky(h2e, 1e-6)
t1e = h1e - 0.5 * np.einsum("pxxr->pr", h2e)

H = ecore * identity(2 * ncas)
# one-body term
for p in range(ncas):
for r in range(p, ncas):
H += t1e[p, r] * Exc[p][r - p]
# two-body term
for g in range(ng):
Lg = 0 * identity(2 * ncas)
for p in range(ncas):
for r in range(p, ncas):
Lg += Lop[p, r, g] * Exc[p][r - p]
H += 0.5 * Lg @ Lg

return H.chop().simplify()

마지막으로, build_hamiltonian을 사용하여 Jordan-Wigner 변환을 통해 Pauli 연산자로 Qubit 해밀토니안을 구성합니다. 또한 우리가 사용한 Cholesky 분해의 정확도도 알 수 있습니다.

H = build_hamiltonian(ecore, h1e, h2e)
print(H)
accuracy of Cholesky decomposition  2.220446049250313e-16
SparsePauliOp(['IIII', 'IIIZ', 'IZII', 'IIZI', 'ZIII', 'IZIZ', 'IIZZ', 'ZIIZ', 'IZZI', 'ZZII', 'ZIZI', 'YYYY', 'XXYY', 'YYXX', 'XXXX'],
coeffs=[-0.09820182+0.j, -0.1740751 +0.j, -0.1740751 +0.j, 0.2242933 +0.j,
0.2242933 +0.j, 0.16891402+0.j, 0.1210099 +0.j, 0.16631441+0.j,
0.16631441+0.j, 0.1210099 +0.j, 0.17504456+0.j, 0.04530451+0.j,
0.04530451+0.j, 0.04530451+0.j, 0.04530451+0.j])

예제 분자 노트북은 다양한 복잡도를 가진 여러 분자에 대한 설정과 해밀토니안을 보여줍니다. 약간의 수정만으로 대부분의 작은 분자를 검토할 수 있을 것입니다.

분자에 대한 페르미온 연산자를 구성할 때 고려해야 할 두 가지 중요한 점을 간략히 언급하겠습니다. 분자 유형이 변경됨에 따라 대칭이 변합니다. 마찬가지로, 원통 대칭 "A1"과 같은 다양한 대칭을 가진 오비탈의 수도 변경됩니다. 이러한 변화는 아래에서 볼 수 있는 LiH로의 단순한 확장에서도 분명히 드러납니다.

distance = 1.56
mol = gto.Mole()
mol.build(
verbose=0,
atom=[["Li", (0, 0, 0)], ["H", (0, 0, distance)]],
basis="sto-6g",
spin=0,
charge=0,
symmetry="Coov",
)
mf = scf.RHF(mol)
E1 = mf.kernel()

# %% ----------------------------------------------------------------------------------------------

mx = mcscf.CASCI(mf, ncas=5, nelecas=(1, 1))
cas_space_symmetry = {"A1": 3, "E1x": 1, "E1y": 1}
mo = mcscf.sort_mo_by_irrep(mx, mf.mo_coeff, cas_space_symmetry)
E2 = mx.kernel(mo)[:2]
h1e, ecore = mx.get_h1eff()
h2e = ao2mo.restore(1, mx.get_h2eff(), mx.ncas)

또한 최종적으로 결과로 나오는 해밀토니안에 대한 직관을 빠르게 잃을 수 있다는 점도 짚어볼 만합니다. LiH에 대한 해밀토니안은 (Jordan-Wigner 매퍼를 사용하여) 이미 276개 항으로 구성되어 있습니다.

len(build_hamiltonian(ecore, h1e, h2e))
accuracy of Cholesky decomposition  1.1102230246251565e-16
276

대칭에 대해 의문이 들 때는 symmetry = Trueverbose = 4를 설정하여 분자에 대한 일부 대칭 정보를 생성할 수도 있습니다.

distance = 1.56
mol = gto.Mole()
mol.build(
verbose=4,
atom=[["Li", (0, 0, 0)], ["H", (0, 0, distance)]],
basis="sto-6g",
spin=0,
charge=0,
symmetry=True,
)
System: uname_result(system='Linux', node='IBM-R912JTRT', release='5.10.102.1-microsoft-standard-WSL2', version='#1 SMP Wed Mar 2 00:30:59 UTC 2022', machine='x86_64')  Threads 16
Python 3.11.12 (main, May 16 2025, 02:33:32) [GCC 11.4.0]
numpy 2.3.1 scipy 1.16.0 h5py 3.14.0
Date: Mon Jun 30 12:56:55 2025
PySCF version 2.9.0
PySCF path /home/porter284/.pyenv/versions/3.11.12/lib/python3.11/site-packages/pyscf

[CONFIG] conf_file None
[INPUT] verbose = 4
[INPUT] num. atoms = 2
[INPUT] num. electrons = 4
[INPUT] charge = 0
[INPUT] spin (= nelec alpha-beta = 2S) = 0
[INPUT] symmetry True subgroup None
[INPUT] Mole.unit = angstrom
[INPUT] Symbol X Y Z unit X Y Z unit Magmom
[INPUT] 1 Li 0.000000000000 0.000000000000 0.000000000000 AA 0.000000000000 0.000000000000 0.000000000000 Bohr 0.0
[INPUT] 2 H 0.000000000000 0.000000000000 1.560000000000 AA 0.000000000000 0.000000000000 2.947972754321 Bohr 0.0

nuclear repulsion = 1.01764848253846
point group symmetry = Coov
symmetry origin: [0. 0. 0.73699319]
symmetry axis x: [1. 0. 0.]
symmetry axis y: [0. 1. 0.]
symmetry axis z: [0. 0. 1.]
num. orbitals of irrep A1 = 4
num. orbitals of irrep E1x = 1
num. orbitals of irrep E1y = 1
number of shells = 4
number of NR pGTOs = 36
number of NR cGTOs = 6
basis = sto-6g
ecp = {}
CPU time: 9.85
<pyscf.gto.mole.Mole at 0x7fc719f94850>

다른 유용한 정보 중에서, 이는 point group symmetry = Coov와 각 기약 표현의 오비탈 수를 모두 반환합니다.

point group symmetry = Coov
num. orbitals of irrep A1 = 4
num. orbitals of irrep E1x = 1
num. orbitals of irrep E1y = 1
number of shells = 4

이것이 활성 공간에 포함하고자 하는 오비탈의 수를 반드시 알려주는 것은 아니지만, 어떤 오비탈이 존재하고 그들의 대칭이 무엇인지 확인하는 데 도움이 됩니다.

대칭과 오비탈을 지정하는 것이 종종 도움이 되지만, 포함시키고자 하는 오비탈의 수를 지정할 수도 있습니다. 아래 에틸렌의 경우를 살펴보겠습니다. verbose = 4를 사용하여 다양한 오비탈의 대칭을 출력할 수 있습니다.

# Replace these variables with correct distances:
a = 1
b = 1
c = 1

# Build
mol = gto.Mole()
mol.build(
verbose=4,
atom=[
["C", (0, 0, a)],
["C", (0, 0, -a)],
["H", (0, c, b)],
["H", (0, -c, b)],
["H", (0, c, -b)],
["H", (0, -c, -b)],
],
basis="sto-6g",
spin=0,
charge=0,
symmetry=True,
)
System: uname_result(system='Linux', node='IBM-R912JTRT', release='5.10.102.1-microsoft-standard-WSL2', version='#1 SMP Wed Mar 2 00:30:59 UTC 2022', machine='x86_64')  Threads 16
Python 3.11.12 (main, May 16 2025, 02:33:32) [GCC 11.4.0]
numpy 2.3.1 scipy 1.16.0 h5py 3.14.0
Date: Mon Jun 30 12:57:07 2025
PySCF version 2.9.0
PySCF path /home/porter284/.pyenv/versions/3.11.12/lib/python3.11/site-packages/pyscf

[CONFIG] conf_file None
[INPUT] verbose = 4
[INPUT] num. atoms = 6
[INPUT] num. electrons = 16
[INPUT] charge = 0
[INPUT] spin (= nelec alpha-beta = 2S) = 0
[INPUT] symmetry True subgroup None
[INPUT] Mole.unit = angstrom
[INPUT] Symbol X Y Z unit X Y Z unit Magmom
[INPUT] 1 C 0.000000000000 0.000000000000 1.000000000000 AA 0.000000000000 0.000000000000 1.889726124565 Bohr 0.0
[INPUT] 2 C 0.000000000000 0.000000000000 -1.000000000000 AA 0.000000000000 0.000000000000 -1.889726124565 Bohr 0.0
[INPUT] 3 H 0.000000000000 1.000000000000 1.000000000000 AA 0.000000000000 1.889726124565 1.889726124565 Bohr 0.0
[INPUT] 4 H 0.000000000000 -1.000000000000 1.000000000000 AA 0.000000000000 -1.889726124565 1.889726124565 Bohr 0.0
[INPUT] 5 H 0.000000000000 1.000000000000 -1.000000000000 AA 0.000000000000 1.889726124565 -1.889726124565 Bohr 0.0
[INPUT] 6 H 0.000000000000 -1.000000000000 -1.000000000000 AA 0.000000000000 -1.889726124565 -1.889726124565 Bohr 0.0

nuclear repulsion = 29.3377079104231
point group symmetry = D2h
symmetry origin: [0. 0. 0.]
symmetry axis x: [0. 1. 0.]
symmetry axis y: [1. 0. 0.]
symmetry axis z: [-0. -0. -1.]
num. orbitals of irrep Ag = 4
num. orbitals of irrep B2g = 2
num. orbitals of irrep B3g = 1
num. orbitals of irrep B1u = 4
num. orbitals of irrep B2u = 1
num. orbitals of irrep B3u = 2
number of shells = 10
number of NR pGTOs = 84
number of NR cGTOs = 14
basis = sto-6g
ecp = {}
CPU time: 9.92
<pyscf.gto.mole.Mole at 0x7fc719fa9290>

다음을 얻습니다.

num. orbitals of irrep Ag = 4

num. orbitals of irrep B2g = 2

num. orbitals of irrep B3g = 1

num. orbitals of irrep B1u = 4

num. orbitals of irrep B2u = 1

num. orbitals of irrep B3u = 2

그러나 모든 오비탈을 대칭으로 지정하는 대신, 단순히 다음과 같이 작성할 수 있습니다.

active_space = range(mol.nelectron // 2 - 2, mol.nelectron // 2 + 2)

이 접근 방식에서는 채움 수준 근처의 오비탈(원자가 및 비점유) 여러 개를 사용합니다. 여기서는 활성 공간에 포함하기 위해 5개의 오비탈(6번째부터 10번째)이 선택되었습니다.

print(
mol.nelectron // 2 - 2,
mol.nelectron // 2 + 2,
)
6 10
  1. 타사 소프트웨어

양자 화학을 위해 개발된 여러 소프트웨어 패키지가 있으며, 일부는 다중 매퍼와 활성 공간 제한 도구를 제공합니다. 위에서 설명한 단계는 일반적이며 타사 소프트웨어에도 적용됩니다. 그러나 이러한 다른 소프트웨어는 Qiskit이 받아들이지 않는 형식으로 해밀토니안을 반환할 수 있습니다. 예를 들어, 일부 소프트웨어는 다음과 같은 형태의 해밀토니안을 반환합니다.

H = -0.042 [] + -0.045 [X0 X1 Y2 Y3] + ... + 0.178 [Z0] + ... + 0.176 [Z2 Z3] + -0.243 [Z3] 특히 Gate에 번호가 매겨져 있고 항등 연산자가 표시되지 않는다는 점에 유의하세요. 이는 Qiskit에서 사용되는 해밀토니안과는 대조되며, Qiskit에서는 [Z2 Z3] 항을 ZZII로 표기합니다(Qubit 0과 1은 항등 연산자가 작용하고, Qubit 2와 3은 Z 연산자가 작용하며, Qubit 0이 가장 오른쪽에 위치하는 순서).

기존에 가지고 있는 워크스트림을 수용하기 위해, 아래 코드 블록은 한 구문에서 다른 구문으로 변환합니다. convert_openfermion_to_qiskit 함수는 OpenFermion이나 Tangelo에서 생성된 (그리고 사용 가능한 매퍼를 사용하여 이미 Pauli 연산자로 매핑된) 해밀토니안과 분자에 필요한 Qubit 수를 인수로 받습니다.

from openfermion import QubitOperator
from qiskit.quantum_info import SparsePauliOp

def convert_openfermion_to_qiskit(
openfermion_operator: QubitOperator, num_qubits: int
) -> SparsePauliOp:
terms = openfermion_operator.terms

labels = []
coefficients = []

for term, constant in terms.items():
# Default set to identity
operator = list("I" * num_qubits)

# Iterate through PauliSum and replace I with Pauli
for index, pauli in term:
operator[index] = pauli
label = "".join(operator)
labels.append(label)
coefficients.append(constant)

return SparsePauliOp(labels, coefficients)

또한, 이 Python 노트북에는 위의 변환을 포함하여 다른 소프트웨어 워크플로의 해밀토니안을 Qiskit으로 마이그레이션하기 위한 완전한 샘플 코드가 포함되어 있습니다.

이제 IBM® 양자 컴퓨터에서 양자 화학 계산을 수행하는 데 필요한 해밀토니안을 얻기 위한 도구들을 갖추셨을 것입니다.