itl_expr チュートリアル
このチュートリアルでは、ITF1788 スイートの ITL 形式で書かれた IEEE 1788 の区間テストケースを ball_float に対して実行する方法を説明します。ITL テキストをケースに構文解析し、各ケースを実行して、結果を要約します。ファイル全体を対象とするコマンドラインランナーは itl_expr_cli です。
クイックスタート
moon.pkg にパッケージを追加します。
import {
"Luna-Flow/floating/frontend/itl_expr",
}
テストケースのブロックを構文解析して実行します。
///|
test "quick start" {
let source =
#|testcase demo {
#| add [1.0,2.0] [3.0,4.0] = [4.0,6.0];
#| intersection [1.0,3.0] [2.0,4.0] = [2.0,3.0];
#|}
let cases = @itl_expr.parse_itl(source).unwrap()
let summary = @itl_expr.summarize_results(
cases.map(case => @itl_expr.execute_case(case)),
)
inspect(summary.passed_cases(), content="2")
inspect(summary.success(), content="true")
}
各文 operation operand… = expected; は、ID が testcase:index である 1 つの ItlCase になります。
日常的なタスク
構文解析されたケースを調べる
///|
test "parsed cases" {
let source =
#|testcase bounds {
#| inf [-0x1.8p1,2.5] = -3.0;
#| mul [1.0,2.0]
#| [entire] = [entire];
#|}
let cases = @itl_expr.parse_itl(source).unwrap()
inspect(cases.map(c => c.id()).join(" "), content="bounds:1 bounds:2")
inspect(cases[1].operation(), content="mul")
inspect(cases[1].operands().join(" "), content="[1.0,2.0] [entire]")
inspect(cases[1].expected(), content="[entire]")
}
文は複数行にまたがってもよく、; で終わります。端点は 10 進または 16 進(0x1.8p1)のテキストで書くことができ、リテラル [empty]、[entire]、[nai] も解釈されます。
装飾を検査する
期待値に装飾の接尾辞(_com、_dac、_def、_trv、_ill)を付けると、装飾もテスト対象になります。接尾辞がなければ集合だけが比較されます。失敗メッセージでは区間を中心・半径形式で表示します。
///|
test "decorations" {
let source =
#|testcase deco {
#| add [1.0,2.0]_com [3.0,4.0]_com = [4.0,6.0]_com;
#| add [1.0,2.0]_com [3.0,4.0]_com = [4.0,6.0]_def;
#| add [1.0,2.0]_com [3.0,4.0]_com = [4.0,6.0];
#|}
let cases = @itl_expr.parse_itl(source).unwrap()
let passed = cases.map(c => @itl_expr.execute_case(c).passed().to_string())
inspect(passed.join(" "), content="true false true")
inspect(
@itl_expr.execute_case(cases[1]).message(),
content="expected 5p0 +/- 1p0_def, got 5p0 +/- 1p0_com",
)
}
数値、真偽値、重なり状態
区間の結果のほか、ITL のケースは数値(inf、sup、mid、rad、wid、mag、mig)、真偽値(isEmpty、subset、isMember、…)、または重なり状態の名前を期待値とすることができます。
///|
test "other result kinds" {
let source =
#|testcase kinds {
#| wid [1.0,3.5] = 2.5;
#| subset [1.0,2.0] [0.0,3.0] = true;
#| isMember 4.0 [1.0,3.0] = false;
#| overlap [1.0,2.0] [2.0,3.0] = meets;
#|}
let cases = @itl_expr.parse_itl(source).unwrap()
let summary = @itl_expr.summarize_results(
cases.map(c => @itl_expr.execute_case(c)),
)
inspect(summary.passed_cases(), content="4")
}
サポートされないケースと不正なケース
実行器が実装していないケースは Unsupported、オペランドを読み取れないケースは Diagnostic になります。どちらも失敗には数えられませんが、診断があると success() は false になります。
///|
test "dispositions" {
let source =
#|testcase odd {
#| mulRevToPair [1.0,2.0] [3.0,4.0] = [1.0,2.0];
#| sqrt [one,two] = [1.0,2.0];
#|}
let results = @itl_expr.parse_itl(source)
.unwrap()
.map(c => @itl_expr.execute_case(c))
let summary = @itl_expr.summarize_results(results)
inspect(summary.unsupported_cases(), content="1")
inspect(summary.diagnostic_cases(), content="1")
inspect(summary.success(), content="false")
}
さらに進んで
- コーパスの実行。
just conformance run intervalは固定された ITF1788 コーパスを取得し、native ランナーをビルドして、testdata/interval/interpreter_stages.jsonに列挙された strict なフェーズを実行します。検証 を参照してください。 - 演算による絞り込み。 CLI の
--operation NAMEオプションはその演算のケースだけを残します。コードでは、実行前にcasesをoperation()で絞り込みます。 - 精度。
execute_case(case, precision=p)は端点をpビットで解析します。区間演算自体は binary64 に丸められるため、ITF1788 のデータには既定値の53を使ってください。
よくある落とし穴
- 10 進の端点は最近接に丸められます。
0.1のような端点は外向きに丸められるのではなく最も近い binary64 の数として読まれるため、[0.1,0.1]はその binary64 の数の単集合になります。 - シグナルは検査されません。 期待値の後に置かれた
signal …のような ITL の注釈があると期待値を読み取れなくなり、そのようなケースは合格ではなくサポート外または診断になります。 - 構文解析エラーは入力を拒否します。 いずれかの文に
=や演算がない場合、またはテキストが文の途中で終わっている場合、parse_itlは診断だけを返します。
次のステップ
- すべての項目と実行される演算の一覧については itl_expr API。
- 合格規則については itl_expr 設計。
- テスト対象の区間演算については ball_float チュートリアル。