AHC047振り返り
はじめに
トヨタ自動車プログラミングコンテスト(AtCoder Heuristic Contest 047)に参加した。順位としては400番台で大したことなかったが、反省も含めて振り返る。
問題
問題には Lovely Language ModelというLLMをもじったタイトルがつけられている。内容としては、Lovelyな文字列を生成するマルコフ遷移モデルを作成するという問題。各文字列
解いてみる
焼きなましで解けるのは予想がついたが、スコアの近似値の求め方がわからなかった。これは、コンテスト後に他の人のコードを読んで理解したので後述する。コンテスト内で考えた解放について記述する。
まず、状態としてはa
からf
の6個なので、1文字につき2状態が割り当てられる。そこで以下のようにした。
a
を表示する状態a
,b
,c
のどれか、aa
,ab
,ac
のどれかならad
,ae
,af
のどれかなら
実際の動作としては、a
からf
を0から5の数字だとみなして、例えばe
を出力する状態がab
の場合、
「順番に全部出力」と言っているわりには、出力される文字列に偏りがある。これは、スコアが高い文字列の生成確率を上げた方がトータルのスコアが高くなったためで、上記で点数
スコアの推定
時間内ではスコアの推定ができなかったので、焼きなましはできなかった。コンテスト終了後、他の人のコードを読んでいると、定常状態を使ってスコアを求めていたので、それを実装してみる。Heuristic ContestはPythonを使っているので、行列演算ライブラリとしてはnumpyを使う。
import numpy as np
まず、時刻
これを以下のように記述するとする
この時、定常状態(
なので、
ここまでをpythonで書いてみると以下のような感じ。
a = (np.array(original_a) / 100.0).T
ai = a - np.identity(M)
b = np.zeros(M, dtype=float)
あとはこれを多項式だと考えて
の条件下で解くのだが、linalg.solve
は正方形の行列にしか対応していないので、1行足すわけにはいかない。ただ、式(1)は以下が成り立っているので、すべての多項式が完全に独立ではなく、1つ無くても問題はない...というかこれでは解がでない。
そこで、一番上の行を式(2)に置き換えて解く。
ai[0, :] = 1.
b[0] = 1.
phi = np.linalg.solve(ai, b)
これで、各状態の定常状態での発生確率がでてくる。
ここから各文字列が生成される確率を求める。ここで、各文字が生成される文字列だけをフィルタリングする行列a
を出力する時、
とする。こうしておくと、各要素の積(アマダール積と呼ぶらしい)を求めることで、特定の文字列を出力する状態をフィルタリングできる。 あとは、
for text, score in lovely_text:
p:np.array = phi * char_filter[text[0]]
for i in range(1, len(text)):
p = np.matmul(a, p) * char_filter[text[i]]
prob:float = min(1., max(0., p.sum().item()))
prob = min(1., max(0., 1 - (1 - prob) ** (L - len(text))))
result += prob * score
これでスコアの近似値を求めることができるが、実際にこのままだと発生確率が低い文字列が改善してもスコアに反映されないなどの問題があるので、確率 prob
を
おわりに
スコアの近似式を使うと22位ぐらいのスコアをだすことはできた。
結局知識が不足していただけかなぁという気はする。ただ、解説記事を読んでいると「AHC044でもマルコフ遷移を扱ったので」と書いてあった。学びの機会を逃していたという反省と、あれってマルコフで解けるんだという発見が同時にあった。今度044をマルコフ遷移の定常状態で解いてみたいと思う。
Discussion