SqDRIFT 回路を生成する
サンプルベース量子対角化( SQD )では、ビット列をサンプリングするためのアンザッツを選択する必要があります。 SqDRIFT の変種では、代わりに、対象のハミルトニアンから直接構築された時間発展回路のアンサンブルが用いられる。 これは、ハミルトニアンの係数に基づいて、より小さな時間発展演算子をハミルトニアンからサブサンプリングすることで実現され、これは「 qDRIFT トロッター化法」として知られている。
この入門ガイドでは、このようなランダム化回路のアンサンブルを生成する方法について説明します。
1. ハミルトニアン設定
このガイドでは、FCIDUMPファイルから N2 の電子構造ハミルトニアンを読み込んでください。 他にも、これを構築する方法はいくつかあります FermionOperator。 必ずそのドキュメントと、. を確認してください qiskit_fermions.operators.library。
[x] PYTHON
>>> from qiskit_fermions.operators.library import FCIDump
>>> from qiskit_fermions.operators import FermionOperator
>>>
>>> fcidump = FCIDump.from_file("docs/guides/n2.fcidump")
>>> num_modes = 2 * fcidump.norb
>>> hamil = FermionOperator.from_fcidump(fcidump)[] C
#include <qiskit_fermions.h>
QfFCIDump* fcidump = qf_fcidump_from_file("docs/guides/n2.fcidump");
QfFermionOperator* hamil = qf_ferm_op_from_fcidump(fcidump);
uint32_t num_modes = 2 * qf_fcidump_norb(fcidump);2. グループハミルトニアン項
係数が同じ関連する項をグループ化することで、電子構造ハミルトニアンに存在する多くの対称性を利用する。 この操作により、 qDRIFT プロトコルがサンプリングを行う演算子係数の分布が変更されますが、その収束保証には影響しません。 重要な点として、対称性によって関連する項をグループ化すると、パウリ項が好都合に相殺され、それらの作用下で状態を時間発展させた際の回路深度が全体的に短くなる。
このモジュール qiskit_fermions.operators.terms.grouping は、演算子の項をグループ化するための便利な関数を提供します。 これについては、 このガイドでさらに詳しく説明されています。
この実装では、ハミルトニアンの項が正規順序で並んでいることが前提 group_terms_by_electronic_structure() となっています!
[x] PYTHON
>>> from qiskit_fermions.operators.terms.grouping import group_terms_by_electronic_structure
>>> from qiskit_fermions.operators.terms.ordering import canonical_order
>>>
>>> canon = canonical_order(hamil.normal_ordered().simplify(atol=1e-16))
>>> exit_code = group_terms_by_electronic_structure(canon, num_modes, two_body_physicist_order=False)
>>> assert exit_code is None
>>> print(canon.groups) # the groups attribute now contains some list of group indices
[0, ...][] C
QfFermionOperator* normal;
QfExitCode exit = qf_ferm_op_group_terms_by_electronic_structure(normal, num_modes, false);
QfFermionOperator* canon = qf_ferm_op_canonical_order(normal);完全な電子構造ハミルトニアンには、時間発展回路に含めても知覚されるビット列に影響を与えず、したがってサンプリングのオーバーヘッドを増加させるだけとなる特定の項が含まれている。 したがって、次のステップでゲ Evolution ートを構築する前に、この段階でハミルトニアンからそのような項を除去しておくことが推奨される。
この説明に当てはまる項は、占有数基底において対角成分を持つもの、すなわち数演算子の積( )である。これには、時間発展によって回路にグローバルな位相のみを導入する定数エネルギーオフセット、時間発展が単一クビットのZ回転に相当する個々の数演算子、および のような高次積が含まれる。これらはいずれも、サンプリングされたビット列に影響を与えない。
この関 filter_diagonal_terms() 数は、演算子からそのような項をその場で削除します:
[x] PYTHON
>>> from qiskit_fermions.operators.terms.filtering import filter_diagonal_terms
>>>
>>> filter_diagonal_terms(canon)[] C
qf_ferm_op_filter_diagonal_terms(canon);ここで一度フィルタリングを行う方が、繰り返しフィルタリングを行うよりもはるかにコストが低い。 QDriftTrotterization これはトランスパイルされた回路ごとに1回実行されるため、呼び出しのたびにではなく、最初にハミルトニアンをフィルタリングしておけば、そこから生成される各回路ごとに処理を繰り返し行う必要がなくなります。
3. 時間発展回路を準備する
ハミルトニアンの時間発展回路と、そこからサンプルを抽出するためのベース回路を準備する。 この には、Qiskit の規約に準拠しつつ、その処理を行うために必要なすべてのコンポーネントが含ま qiskit_fermions.circuit.library れています。
[x] PYTHON
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>>
>>> time = 1.0 # you can choose a desired scaling factor here
>>> evo_gate = Evolution(num_modes, canon, time)
>>>
>>> circ = FermionicCircuit(num_modes)
>>> circ.append(evo_gate, circ.modes)[] C
// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions.この例では、フェルミオンモードに粒子を初期設定することも、その最終状態を測定することも行いません。
4. QDriftのTrotterization機能を使用して回路をトランスパイルする
このモジュール qiskit_fermions.transpiler はQiskitのトランスパイルパイプラインと直接連携しており、上記で構築 FermionicCircuit されたものを直接.にトランスパイルすることができます QuantumCircuit。
フェルミオンから量子 jordan_wigner() ビットへの写像を用いて、フェルミオンを用いて表されたハミルトニアンを、代わりにパウリ文字列を用いて表されるように変換する。 これは、 EvolutionSynthesis トランスパイル・パス・プラグインを使用することで、トランスパイル処理の一部として直接行うことができます。 を使用して を generate_preset_jw_pass_manager() 構築します FermionicStagedPassManager。これにより、すべての回路命令に対してジョーダン・ウィグナー符号化が一貫して使用されるようになります。
重要な点として、トランスパイレーションパイプラインの ステージ optimization に、 QDriftTrotterization トランスパイレーションパスを追加してください。 これにより、回路がハミルトニアンの全体的な時間発展を利用することがなくなり、その計算量は現在利用可能な量子コンピューティングハードウェアの処理能力を超えることになる。
その代わりに、回路がトランスパイルされるたびに、各回路についてハミルトニアン項のうち groups 一定数をサンプリングします。 これにより、トランスパイレーション・パイプラインを繰り返し実行することで、 SqDRIFT アルゴリズムで必要とされる複数の回路ランダム化を生成することができます。
この手順では、生成する回路をカスタマイズするために使用できるいくつかのパラメータについても紹介します:
- 生成する回路の数:
num_sqdrift_randomizations - 励起群に基づく各回路の長さ:
num_groups
[x] PYTHON
>>> from qiskit_fermions.transpiler import FermionicPassManager
>>> from qiskit_fermions.transpiler.presets import generate_preset_jw_pass_manager
>>> from qiskit_fermions.transpiler.passes import QDriftTrotterization
>>>
>>> num_groups = 10
>>> qdrift = QDriftTrotterization(num_groups, rng=19)
>>>
>>> pm = generate_preset_jw_pass_manager()
>>> pm.optimization = FermionicPassManager([qdrift])
>>>
>>> num_sqdrift_randomizations = 10
>>> sqdrift_circuits = [
... pm.run(circ) for _ in range(num_sqdrift_randomizations)
... ][] C
// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions, which we therefore also cannot transpile
// via this API.前の例では、トランス QDriftTrotterization パイル処理内で使用される乱数生成 seed 器の を固定しています。
5. 些細な励起を除去する
前のステップでフィルタリングされた対角項を超えて、サンプリングされた励起がサンプリングされたビット列に影響を与えない場合もある。 その作用が、占有状態がすでに確定している(すべて占有されているか、すべて空いているか)一連のモードの範囲内でのみ行われる場合、粒子を一方のモードから他方のモードへ移動させることはできないため、状態(ひいては最終的な測定結果)は変化しない。 この QDriftTrotterization パス filter_trivial=True での設定により、サンプリングされた時点でそのような項が排除され、代わりに別の項が再抽出されるため、結果として得られる回路の各スロット num_groups が、非自明な励起を寄与することになる。
このフィルタリングでは、どのモードが最初から占有されているかを把握しておく必要があります。 したがって、回路内の ゲ Evolution ートの前に ゲートを InitializeModes 配置する必要があります。 は、それを実現するための便利な InitializeModes.from_hartree_fock() 方法です。 N2 のハートリー・フォック法に関する参考文献(14個の空間軌道に7個のα電子と7個のβ電子)をここに追加し、サンプリングされた励起状態を、以下の有無で比較してください filter_trivial=True:
[x] PYTHON
>>> from qiskit_fermions.circuit.library import InitializeModes
>>>
>>> init = InitializeModes.from_hartree_fock(fcidump.norb, (7, 7))
>>>
>>> hf_circ = FermionicCircuit(num_modes)
>>> hf_circ.append(init, hf_circ.modes)
>>> hf_circ.append(Evolution(num_modes, canon, time), hf_circ.modes)
>>>
>>> num_groups = 5
>>> qdrift_unfiltered = QDriftTrotterization(num_groups, rng=3480)
>>> qdrift_trivial = QDriftTrotterization(
... num_groups, filter_trivial=True, rng=3480
... )
>>>
>>> for instruction in FermionicPassManager(qdrift_unfiltered).run(hf_circ)._inner.data:
... if instruction.operation.name == "Evolution":
... print(sorted(instruction.operation.operator.get_support()))
[2, 4]
[41, 45, 52]
[15, 45, 55]
[41, 52, 53]
[10, 16, 37, 38]
>>>
>>> for instruction in FermionicPassManager(qdrift_trivial).run(hf_circ)._inner.data:
... if instruction.operation.name == "Evolution":
... print(sorted(instruction.operation.operator.get_support()))
[0, 1, 6, 7]
[0, 1, 28, 29]
[4, 13, 55]
[13, 20, 40, 41]
[0, 1, 28, 29][] C
// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions, which we therefore also cannot transpile
// via this API.フィルタリングを行わずにサンプリングされた励起はいずれも、占有集合(0-6 および 28-34)にまったく触れていないため、占有モードと非占有モードの間で粒子を移動させることはできません。それらはすべて自明であり、サンプリングされたビット列には何の影響も与えません。 の場合 filter_trivial=True、これら5つすべてが排除され、占有モードと非占有モードを結合させる励起に置き換えられる。 例えば、最初に受け入れられた励起は、粒子を占有モード 0, 1, および と 6 、未占有モード の間で移動 [0, 1, 6, 7] させる 7。
励起が受け入れられると、その支持域内のすべてのモードは「不確定」となり、それゆえ、後のサンプルにおいてどちらの役割も果たし得るようになる。そのため、励起が受け入れられるにつれて、占有モード集合と非占有モード集合は拡大し続ける。 これこそが、第2の励起が許容される理由である [0, 1, 28, 29]。 その4つのモードはすべて、 当初から占有されていたモードに含まれているため、当初から未占有だったモードとは結合しない。 これが受け入れられるのは、最初の励起がモード および 0 に接触した時点で、それらのモードが不確定状態 1 となり(したがって、結合の「未占有」側として適格となったため)である。
先行するゲート InitializeModes がない場合、フィルタリングの対象となる職業情報 filter_trivial=True はありません。 それは を発生させ UserWarning 、その ゲート Evolution についてはサンプリングをフィルタリングせずにそのままにします。
(任意)フェルミオンモードのインデックス付けを最適化する
トランスパイルパイプラインに、フェルミオンモードのインデックスを再ラベル付けすることで、フェルミオン励起スパン間の距離を最小化する追加の最適化ステップを追加することができます。 この最適化は、論文『 SqDRIFT 』で提案され、によって実装されています build_excitation_span_minimization_model()。 pass RelabelModes を使用することで、これをトランスパイラーのパイプラインに簡単に組み込むことができます:
[x] PYTHON
>>> from pyomo.environ import SolverFactory
>>> from qiskit_fermions.transpiler.passes import RelabelModes
>>>
>>> solver = SolverFactory("appsi_highs")
>>> solver.options["time_limit"] = 10
>>>
>>> qdrift = QDriftTrotterization(5, rng=19)
>>> relabel = RelabelModes(solver=solver)
>>>
>>> pm.optimization = FermionicPassManager([qdrift, relabel])
>>>
>>> relabeled_circ = pm.run(circ)
>>> # if the automatic mode relabeling was successful, the circuit's
>>> # metadata will contain the mode `permutation` information[] C
// WARNING: This feature is not available via the C API.内部の自動最適化機能( RelabelModes が活用されている build_excitation_span_minimization_model())を使用するには、が管理するオプションの依存関係が必要です HAS_PYOMO。
正しい部分空間対角化を行うためには、最適 RelabelModes 化パスでトランスパイルされた回路からサンプリングされたビット列を、その回路のメタデータに含まれる情報 permutation に基づいて後処理する必要があります!
次のステップ
回路のアンサンブルの生成に成功したので、そこからビット列をサンプリングすることができます。 そのためには、回路をハードウェア上で実行する必要があります。 詳しい手順については、 Qiskitのドキュメントを参照してください。
ビットストリングのサンプルが取得できたら、 SQDアドオンのチュ ートリアルで説明されているように、これらをハミルトニアン係数と組み合わせてSQDの後処理を行うことができます。