Qamomile v0.14.0では、Pauli、Ising-Z、周期シフト向けのLCU block encodingと、量子特異値変換(QSVT)を行うqmc.qsvtを追加しました。また、定数加算などの量子算術回路を追加し、Shorの位数探索を論理量子ビット数を抑えた反復型へ刷新しました。さらに、Ekerå–Håstad法の量子部分を構築するqmc.ekera_hastad_factoringを追加しました。
pip install qamomile==0.14.0破壊的変更¶
一部の関数のimport先を変更しました。
shor_order_findingをqamomile.circuit.stdlibからqamomile.circuit.algorithmへ移動しました。modular_incrementとmodular_decrementは逆に、qamomile.circuit.algorithmとそのarithmeticサブパッケージからqamomile.circuit.stdlibへ移動しました。top-levelのqmc.shor_order_finding、qmc.modular_increment、qmc.modular_decrementは引き続き利用できます(#608、#613)。qmc.shor_order_findingが返す量子カーネルから、量子レジスタ幅を表すn引数を廃止しました。 量子レジスタ幅はmodulus.bit_length()から自動的に計算されます。位相ビット数はprecision、modular multiplicationで一度に参照する量子ビット数はwindow_sizeで指定します。実行にはmid-circuit measurement、reset、feed-forwardに対応したbackendが必要です(#613)。qmc.modmul_constを測定とresetを用いるFTQC向けの実装へ変更しました。regの幅はqmc.modmul_constを呼び出す時点で確定している必要があり、modular multiplicationで入力を一度に何量子ビットずつ処理するかは、新しいwindow_size引数で指定します(#613)。
新機能¶
LCU block encodingとQSVT¶
qamomile.linalgに、次元が2のべき乗である一般の複素正方行列向けのPauliLCUと、1次元または多次元の周期シフト演算子向けのPeriodicShiftLCUを追加しました。対応するblock encoding APIとして、qmc.pauli_lcu_block_encodingとqmc.periodic_shift_lcu_block_encodingを追加しました。このほか、Ising-Z、identity、既存の複数のblock encodingを組み合わせるAPIも追加しました。各APIはnormalization、signal register幅、system register幅、および再利用可能なunitary量子カーネルを持つインスタンスを返します。
qmc.qsvtは、呼び出し側が与えたprojector phase列を任意のLCUBlockEncodingに適用します。位相値はトランスパイル時のbindingsで固定できます。また、phase_countをbindingsで固定し、parameters=["phases"]を指定すると、位相列をruntime parameterとして残せます。qmc.qsvtは、目的の多項式に対する位相の生成や、他のQSP conventionからの変換には対応していません。必要な位相列はユーザーが事前に用意する必要があります(#598、#608、#611、#618)。
import numpy as np
import qamomile.circuit as qmc
from qamomile.linalg import PauliLCU
from qamomile.qiskit import QiskitTranspiler
@qmc.qkernel
def transform(
encoding: qmc.LCUBlockEncoding,
phases: qmc.Vector[qmc.Float],
) -> tuple[qmc.Vector[qmc.Bit], qmc.Vector[qmc.Bit]]:
signal = qmc.qubit_array(encoding.num_signal_qubits, "signal")
system = qmc.qubit_array(encoding.num_system_qubits, "system")
signal, system = qmc.qsvt(signal, system, phases, encoding)
return qmc.measure(signal), qmc.measure(system)
matrix = np.array([[1.0, 0.0], [0.0, -1.0]], dtype=complex)
block_encoding = qmc.pauli_lcu_block_encoding(PauliLCU.from_matrix(matrix))
transpiler = QiskitTranspiler()
executable = transpiler.transpile(
transform,
bindings={
"encoding": block_encoding,
"phases": [0.0, 0.0],
},
)算術回路と量子ビット幅を抑えた素因数分解回路¶
qmc.stdlibに定数加算、制御付き定数加算、定数modular addition、量子レジスタをaddressとして表を参照し、対応する値を別の量子レジスタにXORする関数を追加しました。また、既存のqmc.shor_order_findingを更新し、modular multiplicationをwindowed方式に変更しました。
qmc.ekera_hastad_factoringは、同程度のビット長を持つ2つの素数の積に対して、Ekerå–Håstad法の量子計算部分を構築します。返り値は素因数ではなく、素因数を復元する古典計算へ渡す測定結果のビット列です。回路は測定後にresetした量子ビットを再利用することで、同時に使用する論理量子ビット数を抑えています。測定結果から素因数を求める古典的な後処理は含まれません(#613)。
import qamomile.circuit as qmc
from qamomile.qiskit import QiskitTranspiler
order_finding = qmc.shor_order_finding(
base=2,
modulus=15,
precision=2,
)
short_dlp = qmc.ekera_hastad_factoring(
generator=2,
modulus=21,
window_size=1,
)
transpiler = QiskitTranspiler()
order_executable = transpiler.transpile(order_finding)
short_dlp_executable = transpiler.transpile(short_dlp)チュートリアル05 — リソース推定も参照してください。
qmc.struct、固定長のBit配列、レジスタ幅の計算¶
qmc.structデコレータを使うと、ヘルパー関数で大規模なアルゴリズムを実装する際のコードを整理できます。ただし、量子カーネルの引数や返り値には使えません。qmc.bit_arrayは、ゼロで初期化した固定長の1次元Vector[Bit]を作り、測定結果をインデックスごとに格納して1つの値として返せます(#613、#623)。
古典値演算としてqmc.log2とqmc.ceilが追加されました。入力値が確定している場合は即座に計算され、未確定の場合はresource estimateでsymbolicなまま保持されます。回路を生成する前に、トランスパイル時のbindingsで指定する必要があります(#615)。
import qamomile.circuit as qmc
from qamomile.qiskit import QiskitTranspiler
@qmc.struct
class Workspace:
qubits: qmc.Vector[qmc.Qubit]
@qmc.qkernel
def collect_bits(size: qmc.UInt) -> qmc.Vector[qmc.Bit]:
width = qmc.ceil(qmc.log2(size))
workspace = Workspace(qmc.qubit_array(width, "workspace"))
measured = qmc.measure(workspace.qubits)
output = qmc.bit_array(width, name="output")
for index in qmc.range(width):
output[index] = measured[index]
return output
transpiler = QiskitTranspiler()
executable = transpiler.transpile(
collect_bits,
bindings={"size": 9},
)内部的な変更¶
量子カーネルのeffect情報¶
QKernel.effectsはMEASUREMENT、RESET、FEED_FORWARDからなるKernelEffectのフラグ集合を返し、KernelEffect.NONEはunitaryな本体を表します。effectは入れ子のcallable definitionを通じて伝播し、serialization後も再構築されます(#613)。
import qamomile.circuit as qmc
from qamomile.qiskit import QiskitTranspiler
@qmc.qkernel
def reset_and_read() -> tuple[qmc.Bit, qmc.Bit]:
qubit = qmc.x(qmc.qubit("qubit"))
qubit, before = qmc.measure_reset(qubit)
after = qmc.measure(qubit)
return before, after
effects = reset_and_read.effects
transpiler = QiskitTranspiler()
executable = transpiler.transpile(reset_and_read)region dataflowの明示化¶
if、for、whileのstructured regionは、capture、carried value、引数、yieldを明示的に記録するようになりました。このinterfaceはProtobuf serialization後も保持され、lowering前に検証されます(#616)。
import qamomile.circuit as qmc
from qamomile.qiskit import QiskitTranspiler
@qmc.qkernel
def fill_register(size: qmc.UInt) -> qmc.Vector[qmc.Bit]:
qubits = qmc.qubit_array(size, "qubits")
for index in qmc.range(size):
qubits[index] = qmc.x(qubits[index])
return qmc.measure(qubits)
transpiler = QiskitTranspiler()
executable = transpiler.transpile(
fill_register,
bindings={"size": 3},
)バグ修正¶
control、inverse、SELECTのserializationを修正しました。
qmc.controlやqmc.inverseを含む量子カーネルをserializationして読み戻した後も、正しくトランスパイルできるようになりました。また、量子ビット配列を1つの制御量子ビットとして扱う不正なinverse callを検出し、古典引数を量子レジスタより先に受け取るSELECT caseも正しく読み戻せるようになりました(#605、#606、#608)。変換先固有の処理から共通実装へ切り替えた際に、途中まで生成されたgateが残る問題を修正しました。 変換先固有の実装で処理できない場合は、追加済みのgateを取り除いてから共通実装で回路を生成します(#607)。
ドキュメント¶
チュートリアル05 — リソース推定を更新し、量子算術回路、反復型Shor位数探索、Ekerå–Håstad法の量子段階の具体的なコストを導出しました(#613)。
アルゴリズム一覧ページからMöttönen振幅エンコーディングへのリンクを修正し、Qamomile APIの説明を更新しました(#620)。
多次元量子フーリエ変換によるナノシート物質特性推定のタイトルを明確にし、論文の引用を修正しました(#621)。
Pauli Correlation Encodingでは、MaxCutワークフローのセクション名、相互参照、一覧ページの説明を分かりやすくしました(#622)。