OQDの抽象構文木、式を変える規則とたどる順序を分ける

淡青色の枝分かれした木に、ノードを結ぶ青灰色の帯を重ね、変換する要素とたどる経路を表した抽象画。

式の一部を書き換える処理が正しくても、その処理をかける順序が合わなければ、必要な値がまだそろっていないことがあります。プログラムを別の表し方へ変換するコンパイラーでは、「何をするか」と「どこから処理するか」の両方を設計します。

非営利団体Open Quantum Design(OQD)が公開するコンパイラー基盤は、この二つを規則(Rule)と走査(Walk)に分けています。量子計算のソフトウェアを支える仕組みですが、その関係は小さな足し算と掛け算でも理解できます。ここでは抽象構文木(AST)をたどる例から、変換の順序を選ぶ理由と、動作確認で分かる範囲を見ていきます。[1、5]

簡単にまとめると?

  • 抽象構文木は、式を演算とその引数の親子関係で表します。OQDは、各要素で行う処理と、要素をたどる順序を分けています。
  • 子の変換結果を使って親を変換するなら、子を先に処理するPostが必要です。親から見るPreとは用途が異なります。
  • 複数の処理をつなぐ順序や繰返しの停止条件も、変換規則とは別に確認します。構文木を処理できたことだけでは、量子ハードウェアの性能は分かりません。

式のまとまりを、抽象構文木で表す

1 + 2 × 3という式を考えてみましょう。掛け算のまとまりは2 × 3で、その結果を1に足します。これを木の形で表すと、一番上の「+」から「1」と「×」へ枝が分かれ、「×」の下に「2」と「3」がつながります。

このように、演算と引数の関係を表すのが抽象構文木です。木の一つひとつの要素をノードと呼びます。たとえば「×」は「2」と「3」の親であり、「+」の子でもあります。式の見た目の文字列を左から読むだけでなく、どの演算が何を受け取るのかを明示できます。

OQDの電卓チュートリアルも、整数、加算、乗算、累乗をそれぞれの型で表します。ここで使う小例は、その構造を足し算と掛け算だけに絞ったものです。量子状態や量子ビットの配置を表す図ではありません。[2]

1+2×3を表す同じ抽象構文木。Preは+、1、×、2、3の順、Postは1、2、3、×、+の順にノードを見る。Postでは2と3を先に処理して6を得てから、1との加算で7を得られる。
図1 同じ式でも、ノードを見る順序は異なる。番号は訪問順で、式の計算結果ではない。下段はPostで子の計算結果を親へ渡す関係を示す。OQDのWalkと電卓の説明に基づく模式図。[1、2]

Ruleは処理内容、Walkはたどる順序

Ruleは、ある種類のノードを見つけたときに行う処理です。「掛け算のノードなら左右の値を掛ける」「特定の形の式なら別の形に書き換える」といった内容を持ちます。一方のWalkは、木のどのノードへ、どの順序でRuleを適用するかを受け持ちます。

図1のPre(前順)は、親を先に見てから子へ進みます。左の枝からたどると、訪問順は「+ → 1 → × → 2 → 3」です。Post(後順)では、子を先に見てから親へ戻るため、「1 → 2 → 3 → × → +」になります。これは訪問順の違いであり、Preを選んだから足し算を掛け算より先に計算する、という意味ではありません。実際に何をするかはRuleによって決まります。

OQDのreverse指定は、兄弟にあたる要素を右から左へたどるためのものです。Postに指定した場合、この小例の順序は「3 → 2 → × → 1 → +」になります。子を先にする性質は保たれ、PostがPreへ切り替わるわけではありません。[1、3]

子の結果が必要な変換には、Postを使う

この違いが効くのが、式を整数の値へ変換するときです。「×」のノードから整数6を得るには、まず左右の子から2と3を得る必要があります。その後で「+」へ1と6を渡せば、整数7を得られます。

OQDでは、同じ構文木の互換性のあるノードへ書き換えるRewriteRuleと、異なる型や表現へ変換するConversionRuleを分けています。後者のPost実装は、元のノードに加えて、先に変換した子の結果をoperandsとして規則へ渡します。電卓の加算なら、左右の結果を足す処理です。この受渡しがあるため、子の結果を使う変換にはPostが必要になります。[2、3]

対して、2 × (3 + 4)を(2 × 3) + (2 × 4)へ展開する処理は、式の値をその場で整数にせず、式の形を変えます。チュートリアルでは、この分配法則による変形をRewriteRuleで定義しています。整数だけのこの例では、変形前後とも値は14です。

ただし、規則を記述できることと、その規則があらゆる入力で意味を保つことは別です。ここで確かめたのは整数の小例です。浮動小数点数では演算の順序によって丸めの結果が変わり得るため、同じ変形をそのまま一般化できません。どの値や演算を扱う言語なのかも、規則の正しさの条件になります。[6]

処理をつなぐ順序と、止まる条件も分けて考える

構文木全体に対して行う一つの処理をパス(Pass)と呼びます。OQDでは、複数のパスを指定した順に実行するChainと、同じパスを繰り返すFixedPointが用意されています。たとえば、式の形をそろえる処理を先に行い、その後で値へ変換する、といった組合せを表せます。[4]

FixedPointは、結果が変わらなくなるまで処理を繰り返すための仕組みです。ただし、確認した実装には繰返しを打ち切る上限もあります。上限に達した場合も結果を返すため、戻り値を得ただけで「変換が落ち着いた」とは判断できません。規則が行き来を繰り返さないか、比較方法が適切か、どこで打ち切られたかを別に調べる必要があります。

使い分けを考えるときは、まず処理が必要とする情報を整理すると分かりやすくなります。

行いたいこと 見る組合せ 確認する条件
親の形を見てから、その中へ進む Preと適切なRule 書換え後の子へどう処理が進むか
子の変換結果をまとめて親を変換する PostとConversionRule 左右などの子の結果を、規則へ正しく渡せるか
複数の処理を段階的に行う Chain 前のパスの出力が、次のパスの入力条件を満たすか
形が変わらなくなるまで整える FixedPoint 収束を判定できるか、上限で打ち切られていないか

OQDにはInやLevelという走査もありますが、公式説明では、これらを構文木を変更しない解析・検査向けに位置づけています。名前や見やすさだけで順序を選ぶのではなく、その規則が必要とする情報と、走査が結果を受け渡す方法を合わせて見ることが大切です。[1、3]

公開実装から確かめられること

今回の説明では、OQDのコンパイラー基盤の2026年10月8日付コミットを参照しました。同じ版の電卓Notebookと、Rule・Walk・Rewriterに関わる実装部品をローカルで実行し、Notebookの例が163になること、小例の訪問順と計算結果が説明に一致することを確認しています。パッケージ全体の動作保証や、処理速度の比較を行ったものではありません。[2〜4]

この確認で分かるのは、選んだ規則と順序が小さな式をどう処理するかです。量子プログラムを実機へ接続するには、変換先の命令や装置の制約を満たすことを、さらに確かめる必要があります。構文木の検査に通ること、意図した計算を保つこと、実機で精度よく実行できることは、それぞれ確認する対象が異なります。

OQDの分離設計は、変換がうまくいかないときに「規則の内容」「子と親を処理する順序」「パスの組合せ」のどこを見直すかを考える手掛かりになります。公開されたコードを読む価値は、結果の数値だけでなく、その結果ができるまでの条件を追えるところにもあります。

参考資料

  1. Open Quantum Design — Compiler Infrastructure。Rule、Walk、Pass、Rewriterの説明。
  2. Open Quantum Design — Calculator Notebook。関連するWebチュートリアルも参照。実行確認にはNotebookを使用。
  3. Open Quantum Design — walk.py、rule.py。子の処理結果と元のノードの受渡しを確認。
  4. Open Quantum Design — rewriter.py。ChainとFixedPointの実装。コード資料[2〜4]はコミット1e861eda(2026年10月8日)。
  5. Open Quantum Design — About。団体の位置づけ。
  6. Python Documentation — Floating-Point Arithmetic: Issues and Limitations。丸め誤差と演算の扱い。資料確認日:2026年10月16日。