このパッケージとffsimの関係
このガイドで説明する概念は、Python APIでのみ利用できます。
ffsimとこのパッケージは、重複するのではなく、1本の線に沿って役割を分担しています。
| ffsimが担当 | qiskit-fermionsが担当 |
|---|---|
結合クラスター振幅またはパラメータ・ベクトルから構築される、高レベルのアンザッツ演算子(UCJOpSpinBalanced、UCCSDOpRestrictedRealおよびその類似のもの) | それらの演算子が変換されるフェルミオンCircuit(FermionicCircuit)と、任意のフェルミオン-QubitエンコーディングによるそのトランスパイルでのQubit Circuitへの変換 |
| コンパクトな粒子数固定空間での高速シミュレーション | Circuitの構築に用いるマッパー・フレームワークと演算子のデータ構造 |
実際上の帰結は、双方向に及びます。アンザッツの数学はffsimにあるため、UCJとUCCは、ffsimの演算子を入力として直接受け取ります。逆に、ffsim独自のQiskit Gateはおもにパリティではなく、Jordan-Wigner変換に固有のものであるため、そのアンザッツ演算子を別のエンコーディングで下位レベルに変換できることが、ここに持ち込む利点です。
シミュレーションは両者が出会う場所であり、このガイドではその方法を説明します。ffsimはこのパッケージのシミュレーション・バックエンドであり、ラッパーではなく、独自のプロトコルを介して利用されます。SKQDガイドでは、ffsim.apply_unitary()、ffsim.linear_operator()、ffsim.sample_state_vector()を、変換ステップなしで、FermionicCircuitオブジェクトとFermionOperatorオブジェクトに対して直接呼び出しています。
ffsimのシミュレーション・インターフェースに接続する
ffsimは、粒子数とスピンZの保存を利用して、一般的な次元のQubit状態ベクトルよりもコンパクトに状態ベクトルを表現する、フェルミオン・クォンタムCircuit向けの高性能シミュレーターです。任意のオブジェクトがそのシミュレーション機構に参加するために実装できるプロトコルを定義しています(このパッケージ独自のプロトコルについては、同じ設計に従うqiskit_fermions.protocolsを参照してください)。
-
ffsim.SupportsApplyUnitary:メソッド_apply_unitary_(vec, norb, nelec, copy)により、オブジェクトを粒子数固定の状態ベクトルへのユニタリとして適用します -
ffsim.SupportsLinearOperator:メソッド_linear_operator_(norb, nelec)により、同じセクター上でのオブジェクトのscipy.sparse.linalg.LinearOperatorビューを返します -
ffsim.SupportsTrace:メソッド_trace_(norb, nelec)により、そのセクター上でのオブジェクトのトレースを返します。
このパッケージはそのインターフェースを実装しています。qiskit_fermions.circuit.libraryのすべてのフェルミオン・Gateは_apply_unitary_を提供し、FermionOperatorは_linear_operator_と_trace_を提供します。これにより、このパッケージの演算子とCircuitがffsimと互換性を持ち、変換ステップなしでそのツールがネイティブに動作します。ffsim.apply_unitary()はFermionicCircuitをエンドツーエンドでシミュレーションでき、ffsim.linear_operator()はFermionOperatorを対角化でき、ffsim.sample_state_vector()のようなサンプリング・ユーティリティ(SKQDガイドで、シミュレーションされた状態ベクトルを測定カウントに変換するために使用)は、変更なしで動作します。
_linear_operator_が返すのは通常のSciPyのLinearOperatorなので、scipy.sparse.linalg.eigsh()などもそれに対して動作します。
>>> import ffsim
>>> import numpy as np
>>>
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.operators import FermionOperator, ann, cre
>>>
>>> norb, nelec = 2, (1, 1)
>>> hamiltonian = FermionOperator.from_terms([
... ([cre(0), ann(1)], 0.5),
... ([cre(1), ann(0)], 0.5),
... ])
>>>
>>> circuit = FermionicCircuit(2 * norb)
>>> circuit.append(Evolution(2 * norb, hamiltonian, time=1.0), circuit.modes)
>>>
>>> reference = ffsim.hartree_fock_state(norb, nelec)
>>> state = ffsim.apply_unitary(reference, circuit, norb=norb, nelec=nelec) # native ffsim call
ffsimのプロトコルを介して連携することで、活発に開発されているシミュレーションおよびサンプリング・ユーティリティのエコシステムが、このパッケージのCircuitと演算子にそのまま適用できます。また、すでにffsimを使っているユーザーは、別のシミュレーションAPIを学ぶことなく、このパッケージのGateと演算子を組み合わせられます。
ffsimはオプションの依存関係です
ffsimはオプションの追加パッケージとして宣言されており(pip install "qiskit-fermions[ffsim]"、または[all]による間接的なインストール)、実行時にはHAS_FFSIMによって保護されています(上で示したとおりです)。インストールするとシミュレーションが使えるようになります。ffsim.SupportsLinearOperatorとffsim.SupportsTraceは、このパッケージのFermionOperatorをffsim.FermionOperatorに変換することで実装されているため、ffsimがないとMissingOptionalLibraryErrorが発生します。シミュレーションを行わないすべての処理(演算子の構築、そのマッピング、結果として得られるCircuitのトランスパイル)では、ffsimは一切必要ありません。
フェルミオン・シミュレーションは粒子数固定のセクターで行われる
_apply_unitary_と_linear_operator_はどちらもnelec引数を取り、汎用のQubitシミュレーターが使用する次元の完全な空間ではなく、ffsim(および間接的にPySCF)のFCI空間の設定に倣って、その(norb, nelec)セクターの粒子数固定の行列式基底上で状態ベクトルを表現します。これははるかに小さな空間です(そのサイズは2のべき乗ではなく二項係数の積です)が、厳しい制約を伴います。この空間で表現できるのは、粒子数を保存する演算子とGateだけです(スピンを持つ場合は、各スピン種の粒子数をそれぞれ保存するもの)。作用によって振幅が別の粒子数に移ってしまう演算子には、その振幅を置く場所がありません。
ffsimは、そのような演算子を完全に拒否することでこれを解決します。そのような演算子を線形演算子に変換しようとすると、どの保存則が成り立たないかを示すValueErrorが発生します。粒子数を保存しない項を持つハミルトニアンに対してを適用すると、本来ユニタリであるはずのものが非ユニタリで物理的に意味のない写像になってしまうため、これは適切なデフォルトです。
-
Evolutionは、時間発展させる演算子からその拒否を表面化させます。 -
OrbitalRotationは、スピンありの場合に、(埋め込まれた)回転行列がアルファ/ベータの分割に関してブロック対角であるかを検査し、スピン・セクターが混在している場合はValueErrorを送出します。
>>> from qiskit_fermions.circuit.library import Evolution
>>>
>>> non_conserving = FermionOperator.from_terms([([cre(0), cre(1)], 1.0)]) # creates 2 particles
>>> gate = Evolution(2 * norb, non_conserving, time=1.0)
>>>
>>> try:
... gate._apply_unitary_(reference, norb, nelec, copy=True)
... except ValueError as exc:
... print("rejected:", exc)
rejected: The given FermionOperator could not be converted to a LinearOperator because it does not conserve particle number and the z component of spin. Conserves particle number: False Conserves spin z: False
したがって、粒子数を保存しないシミュレーションは、固定セクター表現の構造上、フェルミオン空間では行えません。これは、フェルミオン・シミュレーションを扱いやすくするコンパクトな FCI 空間の代償です。アルゴリズムが粒子数を破るオペレーター(たとえば、量子ビットネイティブなエラーチャネルや、項ごとには粒子数を保存しないマッピング済みハミルトニアン用のオペレーター)を必要とする場合は、まず量子ビットにトランスパイルし、得られた QuantumCircuit を量子ビットレベルのシミュレーターでシミュレートしてください。トランスパイルの方法はどれでも構いません。フェルミオン回路ガイドとトランスパイルガイドに詳細がありますが、generate_preset_jw_pass_manager() が妥当なデフォルトの選択肢です。
スピンありの系におけるブロック・スピン規約
nelec の型は int | tuple[int, int] で、別のフラグではなくその型によって、サポートされるモード配置のいずれかが選択されます。
-
int はスピンなしの解釈を選択します。
norb個のモードはそのままスピンなし軌道として扱われ、nelecは粒子の総数です。 -
ペア
(n_alpha, n_beta)は、固定されたブロック・スピン規約のもとでの2 * norb個のモードのスピンありの解釈を選択します。モード0 .. norbはアルファ(上向きスピン)軌道、モードnorb .. 2 * norbはベータ(下向きスピン)軌道です。各スピン種は独立に保存されます。アルファのみの項は電子をアルファモード間で移動できますが、ベータモードへは決して移動できず、その逆も同様です。
このディスパッチは、このパッケージ内のすべての ffsim プロトコルのエントリーポイント(ゲートのコンストラクター、_apply_unitary_placed_ の実装、ネイティブ Rust カーネルのセクター・コンパイル)で行われ、LUCJ ガイドと SKQD ガイド全体で使われる規約でもあります(たとえば、InitializeModes.from_hartree_fock() は、アルファの占有をモード 0 .. n_alpha に、ベータの占有をモード norb .. norb + n_beta に割り当てます)。これは、スピンの意味を本来持たない汎用のモード・インデックスを使う qiskit_fermions.operators モジュールや FermionicCircuit 全般と対比すると分かりやすいでしょう(フェルミオン回路ガイドを参照)。ブロック・スピンの意味は、スピンありの nelec がシミュレーション呼び出しに渡されたときにのみ課されるもので、オペレーターや回路の表現自体に組み込まれているわけではありません。
>>> from qiskit_fermions.circuit.library import InitializeModes
>>>
>>> norb, nelec = 3, (2, 1)
>>> init = InitializeModes.from_hartree_fock(norb, nelec)
>>> print([bool(occ) for occ in init.occupation]) # alpha modes 0,1; beta mode 3 (= norb + 0)
[True, True, False, True, False, False]
次のステップ
-
SKQD ガイドを読んで、
ffsim.apply_unitary()とffsim.sample_state_vector()を組み合わせて、このパッケージのゲートで構築した回路をサンプリングする方法や、ffsim.linear_operator()を通じてハミルトニアンの期待値を評価する方法(これ自体もここで説明した_linear_operator_プロトコル・メソッドに支えられています)を確認してください。 -
LUCJ ガイドを読んで、もう一方の半分、つまり ffsim のアンザッツ・オペレーターをこのパッケージのトランスパイル・パイプラインに通してデバイスのカップリングマップに載せる方法を確認してください。
-
シミュレーション呼び出しの外で使われる、汎用でスピンに依存しないモード・インデックスについては、フェルミオン回路ガイドを読んでください。
-
フェルミオン空間から離れて量子ビット上でシミュレートする方法については、トランスパイルガイドを読んでください
これは粒子数を保存しないオペレーターに必要です。
-
qiskit_fermions.protocolsを参照すると、このパッケージが定義するプロトコルの全カタログを確認できます。ffsim とは無関係の変換プロトコル(SupportsFermionOperator、SupportsMajoranaOperator)も含まれます。 -
ffsim が担うワークフローについては、ffsim 独自のガイド、特に UCJ アンザッツの構築と変分的な最適化を読んでください。これらのガイドが扱うパラメーター・ベクトルは、
UCJとUCCが、それらが構築するオペレーターを通じて受け取るものです。