yukicoder で testlib を使うためのメモ
この記事は
この記事は yukicoder での作問において testlib を用いて簡単に正確な入力の検証、およびスペシャルジャッジ作成をしよう、という記事です。 また、ローカルでの作業に Rime を使うことを想定しています。
実際のコードについては以下を参照してください
testlib とは?
testlib は、Codeforcces の admin の MikeMirzayanov 氏が作ったライブラリ(C++ のヘッダーファイル)です。
主に以下を行う際に便利な関数が含まれています。
- 入力生成器 (generator) の作成
- 入力検証器 (validator) の作成
- 出力検証器 (checker / judge) の作成
入力検証器、出力検証器は作らなくても問題を出題することはできますが、問題を用意する際には必ず用意するべきだと考えています。
なぜ入力検証器が必要なのか
入力検証器とは、生成した(または手で作った)入力ファイルが入力フォーマットを満たしているかを判定するプログラムのことを指します。
競技プログラミングに参加する人の多くは C++ を使っており、問題の準備において writer / tester による想定解が C++ のみしか用意されない、ということも少なくありません。 ところで C++ の istream(std::cin 等)は半角スペース、改行等を自動で読み飛ばしてくれます。
よって、例え制約等は assert 等でチェックしていたとしても、以下のようなケースを検出することができません。 そして、そのようなケースで正常に動作しないような言語は存在するため、コンテスト中に指摘された場合は入力を修正してリジャッジを行う必要が出てきます。 (以下は全て実際のコンテストで遭遇したことがあります)
- 行頭または行末に不要な半角スペースが含まれている
- 問題文中では空白区切りで入力されると書かれているが、実際には改行区切りで入力される
なぜ出力検証器が必要なのか
出力検証器とは、提出されたプログラムの出力が正答であるかを判定するプログラムのことを指します。
基本的には事前に用意した想定出力との diff を取ることで判定することができますが、最近は多くのジャッジで不要な半角スペースや改行を許容するジャッジになっていることが多く、これはそのような判定プログラムを書くことで実現しています。 また、想定出力が複数あるような場合は単純な diff では判定できないため、その場合も判定プログラムを書く必要があります。
これも C++ 等で普通に書けば良いような気がしますが、以下のようなケースで正常に判定できないことがあります。
- プログラムの出力が足りない場合
- std::cin は EOF に到達した状態でさらに値を読んでもなんらかの値を返すため
- 実数が出力されるべきところで
nan
と出力された場合- 実際に、誤差ジャッジにおいて
nan
と出力して AC となってしまったような問題が存在しました
- 実際に、誤差ジャッジにおいて
testlibの使い方記事、みたいなのがあると嬉しいな、と実は思っていたり。
— chokudai(高橋 直大)🍆 (@chokudai) 2020年1月13日
自分はtestlibの機能あんまり把握しきれてないのよね。outputcheckerとかvalidatorでしか使ってなくて、テストケース生成とかの時にtestlib使うのとかあんまり知らないのよね。
現在 testlib に関する詳細なドキュメントは存在しません(上に貼った Codeforces のページが一番詳しく、それ以上の情報は実際の実装を読むしかありません)。
自分もそこまで詳しくはないので、誰か複数人で非公式 doc でも用意できればいいんですが……
Rime とは?
Rime は、JAG(日本の ICPC の OB/OG 会)が作成した、プログラミングコンテストの問題作成支援ツールです。 ドキュメントやブログ記事が詳しいので詳しくは以下を見てください。
なぜ Rime なのか
Rime 以外にも作問支援ツールは多く存在するため、特に Rime を使う必要はありません。他の作問支援ツールについてはいくつかは以下の issue で触れられています。
その中で、今回は以下の理由から Rime を用いました(別に他のツールでも良いと思います)。
- 大学合宿コンテスト等の有志コンテストの準備においてよく用いられている
- 他の作問支援ツールに比べて機能が多い
yukicoder で testlib を用いる
最近、yukicoder の環境で testlib.h が使えるようになりました(ありがとうございます!!)。
【お知らせ】
— yukicoder公式アカウント (@yukicoder) 2020年11月23日
各種言語バージョンアップしました。
・Standard ML(MLton の少し古め) を追加しました
・C++を使用する場合に testlib.h が置かれるようになりました。
・gcc 4.8.5 は非推奨にする方向に考えています
(glibc が古く、新しい言語を入れるのが大変になる関係のため)#yukicoder pic.twitter.com/NvcJcGX5PG
ただ、実際には testlib (or Rime) で想定されている用い方と yukicoder の仕様が異なるケースも多く、そのまますぐスペシャルジャッジ等に使えるというわけではありません。
yukicoder で testlib を使ったスペシャルジャッジを書こうかと思ってたけど出力の与えられ方が違うので無理そうか?
— りあん (@rian_tkb) 2020年11月25日
よって、この記事では以下を実現することを目的とします。
- yukicoder 上で testlib を用いたジェネレータ、スペシャルジャッジ、リアクティブジャッジ、スコアリングジャッジを作る
- バリデーターについては現状 yukicoder でバリデーターを登録する機能がないため、通常の AC コードの入力を受け取る部分を testlib に置き換えることで対応する必要があります。
- yukicoder と Rime で同じコードでジェネレータ、スペシャルジャッジ、リアクティブジャッジ、スコアリングジャッジが動くようにする
- ジェネレータについては、同じケースが生成されるようにする
詳しくは以下の README を参照してください!(あとでもう少し情報を追加するかもしれません)