Quickstart#

Qudas は、Welcome to Qudas’s documentation! で示したとおり パイプライン・形式変換(QuData)・ゲート/アニーリング実行(任意) を組み合わせて使います。ここではインストールと代表的なコード例だけをまとめます。

インストール#

コアのみ、または用途に応じた extra を指定します。

pip install qudas                 # コア(numpy + matplotlib)
pip install "qudas[annealing]"    # 変換 + アニーリング実行一式
pip install "qudas[gate]"         # Qiskit ベースのゲート実行
pip install "qudas[all]"          # gate + annealing

変換だけ使いたい場合も、現状は変換用 SDK が annealing extra に含まれます(実行用依存との分離は今後検討)。

ブラックボックス最適化(FMQA)のパイプライン作成例#

以下のコードは、FMQAのパイプライン作成例です。

 1# qudas & pipline
 2from qudas.pipeline import Pipeline
 3from torch_fmqa import TorchFMQA
 4from anneal_fmqa import AnnealFMQA
 5from pipe_iteration import PipeIteration
 6from utils import make_blackbox_func, init_training_data
 7
 8# module
 9import torch
10
11# ENV
12from dotenv import load_dotenv
13import os
14
15# .envファイルの内容をロード
16load_dotenv()
17
18# envファイルからtokenを取得
19token = os.getenv("AMPLIFY_TOKEN")
20
21# 適当な関数を作成 (d次元, y = xQx)
22d = 100
23blackbox = make_blackbox_func(d)
24
25# 初期教師データの数
26N0 = 60
27x, y = init_training_data(d, N0, blackbox)
28print(f"{x.shape=}, {y.shape=}")
29
30# FMQA サイクルの実行回数
31N = 10
32
33# 初期パラメータ
34k = 10
35v = torch.randn((d, k), requires_grad=True)
36w = torch.randn((d,), requires_grad=True)
37w0 = torch.randn((), requires_grad=True)
38global_parameters = {'v': v, 'w': w, 'w0': w0, 'blackbox': blackbox, 'd': d}
39
40# pipeline
41steps = [('TorchFMQA', TorchFMQA()), ('AnnealFMQA', AnnealFMQA(token))]
42
43pipe = Pipeline(steps, iterator=PipeIteration(loop_num=N))
44pipe.set_global_params(global_parameters)
45
46# 最適化
47result = pipe.optimize(x, y)
48print(f"{result=}")
49# result={'TorchFMQA': None, 'AnnealFMQA': array([0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1,
50#        1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
51#        0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0,
52#        1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1,
53#        1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0])}

ここで、TorchFMQA, AnnealFMQA, PipeIteration は別途定義する必要があります。3つの処理を Pipeline module を用いて実行することができます。

詳しくは examples/fmqa/main.py を参照。

データ変換例(入力・変換専用)#

QuData.input() は QdAnnealingIR を返します。Executor は不要です。

pyqubo から Amplify への変換#

from pyqubo import Binary
from qudas import QuData

# Pyqubo で問題を定義
q0, q1 = Binary("q0"), Binary("q1")
prob = (q0 + q1) ** 2

# QuData に Pyqubo の問題を渡す(実体は QdAnnealingIR)
qudata = QuData.input().from_pyqubo(prob)
print(qudata.qubo)  # または qudata.prob

# Amplify 形式に変換
amplify_prob = qudata.to_amplify()
print(amplify_prob)

配列から BQM への変換#

import numpy as np
from qudas import QuData

# Numpy 配列を定義
prob = np.array([
    [1, 1, 0],
    [0, 2, 0],
    [0, 0, -1],
])

# QuData に配列を渡す
qudata = QuData.input().from_array(prob)
print(qudata.qubo)

# BQM 形式に変換
bqm_prob = qudata.to_dimod_bqm()
print(bqm_prob)

CSV から PuLP への変換#

from qudas import QuData

# CSVファイルのパス
csv_file_path = './data/qudata.csv'

# QuData に CSV を渡す
qudata = QuData.input().from_csv(csv_file_path)
print(qudata.qubo)

# PuLP 形式に変換
pulp_prob = qudata.to_pulp()
print(pulp_prob)

データ変換例(出力・変換専用)#

QuData.output() は QdAnnealingOutput を返します。 出力側に .qubo / to_amplify() はありません(入力変換は QuData.input() を使います)。

PuLP 結果の取り込み#

import pulp
from qudas import QuData

prob = pulp.LpProblem("Test_Problem", pulp.LpMinimize)
x = pulp.LpVariable('x', lowBound=0, upBound=1, cat='Binary')
y = pulp.LpVariable('y', lowBound=0, upBound=1, cat='Binary')
prob += 2 * x - y
prob.solve()

out = QuData.output().from_pulp(prob)
print(out.results["block0"]["solution"])
print(out.results["block0"]["energy"])
print(out.results["block0"]["device"])

SciPy 結果から dimod SampleSet へ#

import numpy as np
from sympy import symbols, lambdify
from scipy.optimize import minimize, Bounds
from qudas import QuData

q0, q1, q2 = symbols('q0 q1 q2')
objective_function = 2 * q0 - q1 - q2
f = lambdify([q0, q1, q2], objective_function, 'numpy')
q = [0.5, 0.5, 0.5]
bounds = Bounds([0, 0, 0], [1, 1, 1])
res = minimize(lambda q: f(q[0], q[1], q[2]), q, method='SLSQP', bounds=bounds)

out = QuData.output().from_scipy(res)
print(out.results["block0"]["solution"])
dimod_samples = out.to_dimod()
print(dimod_samples)

詳しくは tests/qudata/test_qudata_facade.py および QdAnnealingIR / QdAnnealingOutput を参照。

アニーリング実行例#

変換とは別経路です。QdAnnealingExecutor を使います。

from qudas.annealing import QdAnnealingInput, QdAnnealingBlock, QdAnnealingExecutor

qubo = {('q0', 'q1'): 1.0, ('q1', 'q1'): -1.0}
block = QdAnnealingBlock(qubo, label='block0')
qd_input = QdAnnealingInput([block])
output = QdAnnealingExecutor(provider='default').run(qd_input)
print(output.results["block0"]["solution"], output.results["block0"]["energy"])