このパッケージとffsimとの関係
このガイドで説明している機能は、 Python APIでのみ利用可能です。
ffsim とこのパッケージは、単一のラインに沿って、作業が重複することなく分担されています:
ffsimが所有している | qiskit-fermions owns |
|---|---|
結合クラスター振幅またはパラメータベクトルから構成される高次のアンザッツ演算子 (UCJOpSpinBalanced、 UCCSDOpRestrictedReal およびそれらと同種の演算子) | それらの演算子が形成するフェルミオン回路 (FermionicCircuit)と、任意のフェルミオンからクビットへの符号化に基づくクビット回路への変換 |
| コンパクトな固定粒子数空間における高速シミュレーション | 回路を構成するマッパー・フレームワークと演算子データ構造 |
その実際的な影響は、双方に及ぶ。 アンザッツ計算はffsim内に実装されているため、 UCJ および は、ffsim演算子を直接入力として UCC 受け取ります。 逆に、ffsim独自のQiskitゲートはジョーダン・ウィグナー変換に特化しているため、 別のエンコーディングを用いてそのアンザッツ演算子の1つを低次化できることが、これをここに導入するメリットとなります。
シミュレーションこそが、この2つが結びつく場であり、このガイドではその仕組みについて解説します。 ffsim は、このパッケージのシミュレーションバックエンドであり、ラッパーを介さず、独自のプロトコルを介して呼び出されます。 SKQD ガイドでは、 FermionicCircuitオブジェクトや FermionOperatorオブジェクトに対して、変換ステップを経ることなく、直接 ffsim.sample_state_vector() ffsim.apply_unitary(), ffsim.linear_operator(), および を呼び出しています。
ffsimのシミュレーションインターフェースへの接続
ffsimは、フェルミオン量子回路向けの高性能シミュレータであり、粒子数およびスピンZの保存則を活用することで、一般的な 次元クビット状態ベクトルよりもコンパクトな形で状態ベクトルを表現します。 このパッケージは、あらゆるオブジェクトがそのシミュレーション機構に参加するために実装できるプロトコルを定義しています(同じ設計に従ったこのパッケージ独自のプロトコルについては 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 し _apply_unitary_、 は と _linear_operator_ を提供 FermionOperator します _trace_。 そのため、このパッケージの演算子や回路はffsimと互換性があり、変換手順を経ることなく、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 callffsimのプロトコルによる連携が、このパッケージの最大の利点です。ffsimのシミュレーションおよびサンプリングユーティリティからなる、活発に開発が進められているエコシステムが、このパッケージの回路や演算子にそのまま適用されます。また、すでにffsimを利用しているユーザーは、別のシミュレーションAPIを習得することなく、このパッケージのゲートや演算子を組み合わせて使用することができます。
ffsim はオプションの依存関係です
ffsim はオプションの追加機能(pip install "qiskit-fermions[ffsim]"、あるいは推移的に によって [all])として宣言されており、実行時には ( HAS_FFSIM 前述の通り)によって保護されています。 これをインストールするとシミュレーションが有効になります。 および ffsim.SupportsLinearOperator は、このパッケージの を に変換 FermionOperator することで実装されている ffsim.SupportsTrace ため ffsim.FermionOperator、ffsim がない場合は が発生します MissingOptionalLibraryError。 シミュレーションに関与しない処理(演算子の構築、それらのマッピング、および結果として得られる回路のトランスパイル)については、これらを一切必要としません。
ffsim はPySCF に間接的に依存していますが、PySCFはWindowsに対応していないため、Windowsではこの追加の依存関係はインストール失敗にはならず、(マーカー sys_platform を介した)何もしない処理として処理されます。 シミュレーションを行いたいWindowsユーザーは、当面の間、 「 Linux 用Windowsサブシステム」 を通じてシミュレーションを行うことができます。
フェルミオンシミュレーションは、粒子数が固定されたセクターで行われる
と は _apply_unitary_ ともに nelec 引数 _linear_operator_ を受け取り、そのセクター (norb, nelec) の固定粒子数行列式基底上の状態ベクトルを表します。これは、一般的な量子ビットシミュレータが使用する完全な 次元空間ではなく、ffsim(および、転じて PySCF’s )のFCI空間の設定を反映したものです。 これははるかに小さな空間ですが(その大きさは2の累乗ではなく、二項係数の積で表されます)、厳しい制約が伴います。 この枠組みでは、粒子数を保存する演算子およびゲート(スピンを持つ場合、各スピン種の粒子数を個別に保存するもの)のみを表現することができる。 その動作によって振幅が別の粒子番号に移動してしまうような演算子には、その振幅を配置する場所がありません。
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。 - ペアは、固定されたブロックスピン規約の下で、モード
2 * norbのスピンフルな解釈を選択(n_alpha, n_beta)する。 モード はアルファ(スピンアップ)軌道0 .. norbであり、モード はベータ(スピンダウン)軌道norb .. 2 * norbである。 各スピン種は独立して保存される。アルファ項のみでは、電子をアルファモード間で移動させることはできるが、ベータモードへ移行させることは決してできず、その逆も同様である。
このディスパッチは、このパッケージ内のすべての ffsim-protocol エントリポイント(ゲートのコンストラクタ、 _apply_unitary_placed_ 実装、およびネイティブ Rust カーネルのセクタコンパイル)で発生し、これは LUCJ および SKQD ガイド全体で採用されている規約です(例えば、アルファ占有をモード に 0 .. n_alpha 、ベータ占有をモード に割り当てる InitializeModes.from_hartree_fock() など 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アンザッツ演算子をこのパッケージのトランスパイルパイプラインに通し、デバイスの結合マップへと導く手順――を確認しましょう。
-
シミュレーション呼び出し以外で使用される、汎用的でスピンに依存しないモードインデックス付けについては、 フェルミオン回路ガイドを参照してください。
-
フェルミオン空間から抜け出す方法については、 トランスパイレーションガイドをご覧ください
そして、非粒子保存演算子に必要な、量子ビットを用いたシミュレーションを行う。
-
このパッケージで定義されているプロトコルの完全な一覧(ffsimとは関係のない変換プロトコル(
SupportsFermionOperator,SupportsMajoranaOperator)を含む)をqiskit_fermions.protocols閲覧してください。 -
ffsimが提供するワークフローについては、ffsim独自のガイドを参照してください。特に、 UCJアンザッツの構築や、 その変分法による最適化については、ガイドを参考にしてください。 それらのガイドが駆動するパラメータベクトルは、 および
UCJが、それらが構築する演算子を通じてUCC受け取るものです。