Skip to main content
IBM Quantum Platform

最適化ソルバー:Q-CTRL Fire OpalによるQiskit関数

APIリファレンスを参照してください

Note

Qiskit 関数は、 IBM Quantum® Premium Plan、Flex Plan、およびオンプレム ( IBM Quantum Platform API 経由) Plan ユーザーだけが利用できる実験的な機能です。 これらはプレビューリリースの状態であり、変更される可能性がある。

  • このページのコードは、以下の要件に基づいて開発されました。 これらのバージョン以降のご利用をお勧めします。

    qiskit-ibm-runtime~=0.47.0
    sympy~=1.14.0
    

概要

Fire Opal最適化ソルバーでは、量子ハードウェア上でユーティリティスケールの最適化問題を解くことができます。 高レベルの問題定義を入力するだけで、あとはソルバーが処理してくれる。 ワークフロー全体はノイズを意識しており、 Fire Opalのパフォーマンス・マネジメントを活用している。 Solverは、最大の IBM® QPU上でフルデバイススケールであっても、古典的な難問に対して一貫して正確な解を提供します。

ソルバーは柔軟性が高く、目的関数や任意のグラフとして定義された組み合わせ最適化問題を解くために使用できます。 問題をデバイスのトポロジーに紐付ける必要はありません。 制約条件をペナルティ項として定式化できるのであれば、制約のない問題も制約のある問題も解くことができる。 このガイドに掲載されている例では、さまざまなソルバー入力タイプを使用して、制約なしおよび制約付きの大規模最適化問題を解く方法を示しています。 最初の例は、156ノードの3正則グラフ上で定義された最大切断問題に関するものであり、2番目の例は、コスト関数によって定義された50ノードの最小頂点被覆問題に取り組むものである。

最適化ソルバーへのアクセスについては、 Q-CTRLにお問い合わせください。


関数の説明

ソルバーは、ハードウェアレベルでのエラー抑制から、効率的な問題マッピング、クローズドループの古典的最適化まで、アルゴリズム全体を完全に最適化し、自動化します。 その裏では、ソルバーのパイプラインがあらゆる段階でエラーを減らし、有意義なスケーリングに必要なパフォーマンスの向上を可能にしている。 基礎となるワークフローは量子近似最適化アルゴリズム(Quantum Approximate Optimization Algorithm:QAOA)にインスパイアされたもので、これはハイブリッド量子古典アルゴリズムである。 Optimization Solverのワークフローの詳細については、 発表された原稿を参照されたい。

最適化ソルバーのワークフローの可視化

最適化ソルバーで一般的な問題を解く:

  1. 問題を目的関数、グラフ、 SparsePauliOp スピンチェーンとして定義する。
  2. Qiskitファンクションカタログからファンクションに接続します。
  3. ソルバーで問題を実行し、結果を取得する。

対応している問題形式

  • 目的関数の多項式表現。 Python、既存の SymPy Polyオブジェクトで作成し、次のようにして文字列に整形するのが理想的です。 sympy.srepr.
  • 特定の問題タイプのグラフ表現。 グラフは Python の networkx ライブラリを使って作成する。 その後、networkx関数 [nx.readwrite.json_graph.adjacency_data](http://nx.readwrite.json_graph.adjacency_data.) を使って文字列に変換する。
  • 特定の問題をスピンの連鎖で表現。 スピンチェインは SparsePauliOp オブジェクトとして表現する必要があります。詳細はドキュメントを参照してください。
この関数は、すべての IBM バックエンドに対応していますか?

この関数が現在サポートしていないバックエンドを使用したい場合は、 Q-CTRLまでご連絡いただき、サポートの追加をご依頼ください。


ベンチマーク

公開されたベンチマーク結果では、ソルバーが120量子ビット以上の問題を解くことに成功しており、量子アニーリングやトラップドイオンデバイスに関する既発表の結果をも上回っている。 以下のベンチマーク・メトリクスは、いくつかの例に基づいて、問題タイプの精度とスケーリングを大まかに示すものです。 実際の測定基準は、目的関数の項数(密度)やその局所性、変数の数、多項式の次数など、さまざまな問題の特徴によって異なる場合があります。

表示されている "量子ビット数 "は難しい制限ではなく、極めて安定した解の精度が期待できる大まかな閾値を表しています。 より大きな問題サイズでも解決に成功しており、この限界を超えたテストが奨励されている。

すべての問題タイプにおいて、任意の量子ビット接続がサポートされている。

問題のタイプ
量子ビット数
正確性
合計回数
ランタイム使用量 (s)
反復数
疎結合2次問題1563-レギュラー・マックスカット100%176429316
高次バイナリ最適化156イジング・スピングラス模型100%146127216
密結合二次問題50完全連結最大カット100%175826812
ペナルティ項を持つ制約問題50エッジ密度8%の重み付き最小頂点カバー100%107421510

使用を開始する

まず、 IBM Quantum のAPIキーを使用して認証を行ってください。 次に、次のようにQiskit関数を選択します。 (このスニペットは、アカウントがすでにローカル環境に保存されていることを前提としています。)

from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# Verify that you have access to the function
catalog.list()

Output:

[QiskitFunction(qunova/hivqe-chemistry),
 QiskitFunction(global-data-quantum/quantum-portfolio-optimizer),
 QiskitFunction(algorithmiq/tem),
 QiskitFunction(qedma/qesem),
 QiskitFunction(multiverse/singularity),
 QiskitFunction(ibm/circuit-function),
 QiskitFunction(q-ctrl/optimization-solver),
 QiskitFunction(colibritd/quick-pde),
 QiskitFunction(q-ctrl/performance-management),
 QiskitFunction(kipu-quantum/iskay-quantum-optimizer)]
# Access Function
solver = catalog.load("q-ctrl/optimization-solver")

例:制約なし最適化

最大カット (max-cut)問題を解く。 以下の例では、156ノードの3正則無重みグラフにおける最大切断問題を用いてソルバーの機能を紹介していますが、重み付きグラフの問題も解くことができます。

この例を実行するには、 qiskit-ibm-catalog に加え、 networkxnumpy のパッケージも使用します。 IPythonカーネルを使ってこのサンプルをノートブックで実行している場合は、以下のセルをアンコメントすることでこれらのパッケージをインストールできます。

# %pip install networkx numpy

1. 問題を定義する

problem_type='maxcut'グラフ問題を定義し、を指定することで、最大切断問題を実行できます。

import networkx as nx
import numpy as np

# Generate a random graph with 156 nodes
maxcut_graph = nx.random_regular_graph(d=3, n=156, seed=8)
# Optionally, visualize the graph
nx.draw_networkx(
    maxcut_graph, nx.kamada_kawai_layout(maxcut_graph), node_size=100
)

Output:

Output of the previous code cell

ソルバーは問題定義の入力として文字列を受け付ける。

# Convert graph to string
problem_as_str = nx.readwrite.json_graph.adjacency_data(maxcut_graph)

2. 問題を実行する

グラフベースの入力方法を使用する場合は、問題タイプを指定する。

# Solve the problem
maxcut_job = solver.run(
    problem=problem_as_str,
    problem_type="maxcut",
    backend_name=backend_name,  # E.g. "ibm_fez"
)

Qiskit Function ワークロードのステータスを確認したり、 結果を返したりするには、次のように操作してください:

# Print the ID so you can use it later, if necessary
print(maxcut_job.job_id)

# Get job status
print(maxcut_job.status())

Output:

34b53970-d95a-4e24-8763-fc6f3d112843
QUEUED

3. 結果を取得する

結果辞書から最適なカット値を取得する。

Note

変数のビット列へのマッピングが変更された可能性があります。 出力辞書にはサブ variables_to_bitstring_index_map 辞書が含まれており、順序の検証に役立ちます。

# Poll for results
maxcut_result = maxcut_job.result()

# Take the absolute value of the solution since the cost function is minimized
qctrl_maxcut = abs(maxcut_result["solution_bitstring_cost"])

# Print the optimal cut value found by the Optimization Solver
print(f"Optimal cut value: {qctrl_maxcut}")

Output:

Optimal cut value: 210.0

のようなオープンソースのソルバーで古典的に問題を解くことで、結果の正確さを検証することができる。 PuLP グラフが密結合でない場合は 高密度の問題では、解を検証するために高度な古典的ソルバーが必要になることがある。


例:制約付き最適化

前述の最大切断問題の例は、一般的な制約なしの二次二値最適化問題である。 Q-CTRLの最適化ソルバーは、制約付き最適化を含む様々な種類の問題に利用できます。 制約条件をペナルティ項としてモデル化した多項式で表される問題定義を入力することで、任意の種類の問題を解くことができます。

次の例は、制約付き最適化問題である最小頂点カバー (MVC)のコスト関数を構築する方法を示しています。

qiskit-ibm-catalogqiskit パッケージに加え、このサンプルを実行するには以下のパッケージも使用する: numpy networkx、および sympy。 IPythonカーネルを使ってこのサンプルをノートブックで実行している場合は、以下のセルをアンコメントすることでこれらのパッケージをインストールできます。

# %pip install numpy networkx sympy

1. 問題を定義する

ランダムに重み付けされたノードを持つグラフを生成することで、ランダムMVC問題を定義する。

import networkx as nx
from sympy import symbols, Poly, srepr

# To change the weights, change the seed to any integer.
rng_seed = 18
_rng = np.random.default_rng(rng_seed)
node_count = 50
edge_probability = 0.08
mvc_graph = nx.erdos_renyi_graph(
    node_count, edge_probability, seed=rng_seed, directed=False
)

# add node weights
for i in mvc_graph.nodes:
    mvc_graph.add_node(i, weight=_rng.random())

# Optionally, visualize the graph
nx.draw_networkx(mvc_graph, nx.kamada_kawai_layout(mvc_graph), node_size=200)

Output:

Output of the previous code cell

重み付けMVCの標準的な最適化モデルは以下のように定式化できる。 まず、エッジが部分集合の頂点に接続されていない場合には、ペナルティを加えなければならない。 したがって、頂点 ii がカバーの中にある(つまり部分集合の中にある)場合は ni=1n_i = 1 とし、そうでない場合は ni=0n_i = 0 とする。 第二に、目標は部分集合内の頂点の総数を最小化することであり、これは以下の関数で表すことができる:

Minimizey=iVωini\textbf{Minimize}\qquad y = \sum_{i\in V} \omega_i n_i

# Construct the cost function.
variables = symbols([f"n[{i}]" for i in range(node_count)])
cost_function = Poly(0, variables)

for i in mvc_graph.nodes():
    weight = mvc_graph.nodes[i].get("weight", 0)
    cost_function += variables[i] * weight

さて、グラフのすべての辺は、カバーからの端点を少なくとも1つ含んでいなければならないが、これは不等式で表すことができる:

ni+nj1 for all (i,j)En_i + n_j \ge 1 \texttt{ for all } (i,j)\in E

エッジがカバーの頂点に接続されていない場合は、ペナルティを与えなければならない。 これは、 P(1ninj+ninj)P(1-n_i-n_j+n_i n_j)PP は正のペナルティ定数)の形のペナルティを加えることでコスト関数で表すことができる。 従って、重み付きMVCの制約付き不等式に代わる制約なしの不等式は次のようになる:

Minimizey=iVωini+P((i,j)E(1ninj+ninj))\textbf{Minimize}\qquad y = \sum_{i\in V}\omega_i n_i + P(\sum_{(i,j)\in E}(1 - n_i - n_j + n_i n_j))

# Add penalty term.
penalty_constant = 2
for i, j in mvc_graph.edges():
    cost_function += penalty_constant * (
        1 - variables[i] - variables[j] + variables[i] * variables[j]
    )

2. 問題を実行する

# Solve the problem
mvc_job = solver.run(
    problem=srepr(cost_function),
    backend_name=backend_name,  # E.g. "ibm_fez"
)

Qiskit Function ワークロードのステータスを確認したり、 結果を返したりするには、次のように操作してください:

print(mvc_job.status())

Output:

QUEUED

3. 結果を得る

ソリューションを取得し、結果を分析する。 この問題には重み付けノードがあるため、解は単純にカバーされるノードの最小数ではない。 代わりに、解コストは頂点カバーに含まれる頂点の重みの合計を表す。 これは、選択された頂点を使用してグラフ内のすべての辺をカバーするための「コスト」または「重み」の合計を表す。

mvc_result = mvc_job.result()
qctrl_cost = mvc_result["solution_bitstring_cost"]

# Print results
print(f"Solution cost: {qctrl_cost}")

Output:

Solution cost: 10.248198273708624

サポートの利用

ご質問や問題がありましたら、 Q-CTRLまでご連絡ください。


変更ログ

  • 2026-02-11: 以下のサポートを追加しました ibm_miami

次のステップ

このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。