Quimbレイヤーベースのバックエンド
qiskit_addon_mpf.backends.quimb_layers
を使用したレイヤーワイズ時間進化バックエンド。 quimb.
このバックエンドは、オプションの依存関係がインストールされている場合にのみ利用可能です:
pip install "qiskit-addon-mpf[quimb]"LayerwiseEvolver | の特別なケースである。 TEBDEvolver レイヤーワイズ進化モデルに基づく |
LayerModel | 時間進化の相互作用のレイヤーを表現するモデル。 |
基礎となる方法
このモジュールは、以下のモジュールによって提供されるTEBDベースのものと同様の時間発展バックエンドを提供する。 quimb_tebd モジュールで提供される 主な違いは、このモジュールが、製品公式を定義するための完全なフレキシビリティをユーザーに与えることである。 quimb ライブラリに組み込まれたオプションに制限されることはありません。
このモジュールが提供するアルゴリズムの核心は、やはりTEBD [1] アルゴリズムである。 しかし、時間発展状態の偶数ボンドと奇数ボンドを交互に更新することを強制するのではなく(以下も参照)、この実装では、複数の時間発展レイヤーの定義に、交互にボンドを更新する責任を委託している。 quimb_tebd.TEBDEvolver.sweep()参照)。この実装では、複数の時間進化レイヤーの定義に、交互にボンドを更新する責任を委託している。
これは例を挙げて説明するのが一番わかりやすい。 ここで、1次元のサイト鎖に作用する一般的なハミルトニアンがあると仮定しよう。
ハミルトニアンのパウリ項の次数は、後の時間発展回路の構造に直接影響するため、以下では慎重に決めている。
>>> from qiskit.quantum_info import SparsePauliOp
>>> hamil = SparsePauliOp.from_sparse_list(
... [("ZZ", (i, i+1), 1.0) for i in range(1, 9, 2)] +
... [("Z", (i,), 0.5) for i in range(10)] +
... [("ZZ", (i, i+1), 1.0) for i in range(0, 9, 2)],
... num_qubits=10,
... )ここで、このハミルトニアンの時間発展回路を、2次のSuzuki-Trotter公式を使って調べてみよう。
>>> from qiskit.synthesis import SuzukiTrotter
>>> from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit
>>> circuit = generate_time_evolution_circuit(hamil, time=1.0, synthesis=SuzukiTrotter(order=2))
>>> circuit.draw("mpl")
<Figure size 956...x869... with 1 Axes>
上の回路では、レイヤーごとの構造を明確に識別できる。 下図のように回路を多層に分割することで、この点をさらに強調することができる(視覚化を容易にするため、 layers 、バリアーを挟んだ単一の回路に組み替えている)。
>>> from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types
>>> layers = slice_by_gate_types(circuit)
>>> combine_slices(layers, include_barriers=True).draw("mpl")
<Figure size 1374...x869... with 1 Axes>
中心層の非対称性は、Qiskitの公式を実装した結果である。 SuzukiTrotter 式を実装した結果である。 2次形式では、ハミルトニアンの最終項の2つの半減期を、2倍の長さの1つにまとめる。 この回路をトランスパイルして、このようなサブエクエント・ゲートをすべて中央の2層に畳み込むことも可能だが(前回と同じように)、この例を簡単にするため、ここではそうしない。
QuimbのTEBDアルゴリズムに、上に示した回路の正確な構造をシミュレートするように指示することはできない。 その理由は、インターフェースの制限にある。ハミルトニアン全体が提供され、それがあらかじめ定義されたトロッター式を使って時間発展させられるからだ。 しかし、そうすることで、ハミルトニアンにおけるパウリ項の次数を(今回のように)重要なものとして扱わなくなる。
(上の例のように)Quimbに実装されている以外の積公式構造を採用した時間発展の動的MPF係数を計算したい場合は、このモジュールが提供する時間発展アルゴリズムを使用することができる。 時間発展がモデル化される単一のモノリシックなハミルトニアンではなく LayerwiseEvolver オブジェクトのリストを受け取る。 LayerModel オブジェクトのリストを受け取ります。 これにより、ユーザーはトロッター分解を最も細かいレベルまで柔軟に定義することができる。
ただし、偶数ボンドと奇数ボンドを交互に更新するというTEBDの特性が保証されるよう、注意を払わなければならない。 幸運なことに、最大2量子ビットのゲートで構成される量子回路では、この性質は構成によって満たされる。
コード例
このセクションでは、上記の例を基に、カスタムトロッターフォーミュラを作成し、それを用いて LayerwiseEvolver を構築する方法を示す。 quimb_tebd.TEBDEvolver で説明したワークフローの quimb_tebd.
このモジュールを使用する際の全体的なワークフローは quimb_tebd モジュールと同じなので、これらの説明も必ず読んでください。
簡単に言えば、回路 layers (上記参照)のそれぞれを LayerModel インスタンスに変換しなければならない。 この目的のためには from_quantum_circuit() メソッドを使用します。
>>> from qiskit_addon_mpf.backends.quimb_layers import LayerModel
>>> model0 = LayerModel.from_quantum_circuit(layers[0])
>>> layer_models = [model0]上のコードでは、互いに排他的な量子ビットに作用する2量子ビットのゲートだけを含むレイヤー(深さ1のレイヤーが保証している)の場合、変換がいかに簡単であるかがわかる。
しかし、単一量子ビットゲートを含むレイヤーには、より注意しなければならない。 の基礎となるTEBDアルゴリズムは、偶数結合と奇数結合を交互に更新しなければならないからだ。 LayerwiseEvolver は偶数ボンドと奇数ボンドを交互に更新しなければならないからである。 また、単一量子ビットゲートはサイト上に適用されるのではなく、半分に分割されて両側の結合に適用されるため、すべての量子ビットに作用する単一量子ビットゲートの層はこの仮定を破ることになる。
この問題を回避するには、1量子ビットのゲートだけで構成される任意のレイヤーを取り出し、2回(偶数結合と奇数結合に1回ずつ)適用すればよい。
>>> model1a = LayerModel.from_quantum_circuit(layers[1], keep_only_odd=True)
>>> model1b = LayerModel.from_quantum_circuit(layers[1], keep_only_odd=False)
>>> layer_models.extend([model1a, model1b])これで、2量子ビットゲートと1量子ビットゲートからなるレイヤーの扱い方がわかったので、残りのレイヤーを変換することができる。
>>> for layer in layers[2:]:
... num_qubits = len(layer.data[0].qubits)
... if num_qubits == 2:
... layer_models.append(LayerModel.from_quantum_circuit(layer))
... else:
... layer_models.append(
... LayerModel.from_quantum_circuit(layer, keep_only_odd=True)
... )
... layer_models.append(
... LayerModel.from_quantum_circuit(layer, keep_only_odd=False)
... )
>>> assert len(layer_models) == 8結局、8つの LayerModel個の2量子ビット層に1個ずつ、2個の1量子ビット層に2個ずつである。
最後に ApproxEvolverFactory プロトコルを setup_dynamic_lse() 関数内で使用するプロトコルを定義します。
>>> from functools import partial
>>> from qiskit_addon_mpf.backends.quimb_layers import LayerwiseEvolver
>>> approx_evolver_factory = partial(
... LayerwiseEvolver,
... layers=layer_models,
... split_opts={"max_bond": 10, "cutoff": 1e-5},
... )このワークフローでは、トロッター式で使われる時間ステップをまだ固定していないことに注意すべきである。 また、トロッター式の繰り返しは1回だけ設定した。 DynamicMPF で実行されるからである。 setup_dynamic_lse().
もちろん、これを使って ExactEvolverFactory. しかし quimb_layers.LayerwiseEvolver を quimb_tebd.TEBDEvolver.
リソース
[1]: https://en.wikipedia.org/wiki/Time-evolving _block_decimation