Постпроцессоры
Постпроцессор — это программа, которая выдает результирующий балл по отправленному решению участника.
В отличие от чекера, эта программа запускается один раз на все тесты, когда выполнение всех тестов завершено. Постпроцессор не управляет вердиктом посылки и не может на него влиять.
В самом простом случае постпроцессор суммирует баллы всех чекеров.
Постпроцессор используют, если нужно:
- получать общий балл за посылку;
- реализовать сложную логику определения баллов за посылку, например по группам тестов или в процентном соотношении от количества пройденных тестов;
- изменить логику суммирования баллов за каждый тест.
Обратите внимание, что баллы за задачу с помощью постпроцессора будут выставляться только в соревнованиях с типом монитора SCORING. Подробнее см. Мониторы.
Загрузка в систему
- Откройте нужную задачу и слева в меню выберите Настройки.
- Внизу списка найдите Дополнительные файлы и обработки.
- В разделе Файлы постпроцессора нажмите Выбрать файл.
- В системном окне выберите нужный файл и подтвердите его загрузку.
- Первым добавьте исполняемый файл постпроцессора.
- Далее добавляйте дополнительные файлы для работы постпроцессора.
- Выберите оружение для запуска постпроцессора.
Внимание
Во время запуска постпроцессора все дополнительные файлы будут находится рядом с исполняемым.
Реализация
Требования к файлу с постпроцессором:
- Содержит переносы строк вида
\n(unix-переносы
). Если переносы будут другого вида (например,\r\n—windows-переносы
), система не сможет запустить файл. - Является исполняемым. Для неисполняемых файлов некомпилируемых языков программирования необходимо указывать окружение (также, как это делается в чекере).
Получить данные для работы постпроцессора можно из stdin. Данные приходят в формате json, поэтому сразу подключите необходимые библиотеки.
На примере Python3 это может быть команда:
#!/usr/local/bin/python3.7
import json
data = json.loads(input())
Результат работы постпроцессора определяет баллы за посылку. Для этого в первой строке output постпроцессора должно содержаться число (long / double).
Пример: print(10).
Структура JSON
Структура данных с результатами тестирования, которые доступны постпроцессору.
{
"tests": [
{
"testName": "tests/01",
"sequenceNumber": 1,
"testsetIdx": 0,
"testsetName": "All tests",
"verdict": "ok",
"score": {
"scoreType": "long",
"longScore": 10
},
"runningTime": 39,
"memoryUsed": 4648960,
"startTimeMillis": 1626862111771
},
{
"testName": "tests/02",
"sequenceNumber": 2,
"testsetIdx": 0,
"testsetName": "All tests",
"verdict": "ok",
"score": {
"scoreType": "double",
"doubleScore": 9.27
},
"runningTime": 52,
"memoryUsed": 162270,
"startTimeMillis": 1626862113546
},
]
}
|
Параметр |
Описание |
|
tests |
array of objects Корневой список с данными каждого из тестов. |
|
testName |
string Путь к файлу теста в файловой системе задачи. |
|
sequenceNumber |
integer |
|
testsetIdx |
integer Уникальный идентификатор набора тестов. |
|
testsetName |
string Название набора тестов. |
|
verdict |
integer Вердикт теста. |
|
score |
object Баллы за тест. |
|
score.scoreType |
boolean Тип поля с баллами. Допустимые значения:
|
|
score.longScore |
integer Количество начисленных баллов (целые числа). Доступно, если |
|
score.doubleScore |
double Количество начисленных баллов (дробные числа). Доступно, если |
|
runningTime |
integer Время выполнения кода участника в мс. |
|
memoryUsed |
integer Использование памяти в байтах. |
|
startTimeMillis |
integer Отметка времени старта тестирования посылки (Unix Timestamp в миллисекундах). |
Корректный запуск
Корректный запуск постпроцессора зависит от правильности настройки соревнования. Например, если постпроцессор выставляет баллы в зависимости от количества пройденных тестов из числа всех тестов — система должна запускать все тесты и не останавливать тестирование при первой ошибке.
Правильность настройки влияет на скорость проверки посылки участника — чем больше тестов, тем дольше выполняется тестирование.
Для настройки постпроцессоров необходимо проверить корректность настроек соревнования. Обратите внимание на следующие параметры:
- Прерывать тестирование при первой ошибке — выключить, если постпроцессор определяет баллы на основе количества тестов.
- Прерывать тестирование при первой ошибке внутри набора тестов — включить, чтобы сэкономить время проверки посылки, когда разные группы тестов проверяют разные свойства решения участника и проверить другую группу тестов нужно, но тестирование в рамках текущей группы тестов уже не имеет смысла.
- При непройденных тестах из условия — установить в состояние Остановить тестирование, чтобы сэкономить время тестирования и быстрее отдать вердикт участнику соревнования.
Примеры постпроцессоров
В процентах от прорешанных тестов: 0-100
В настройках соревнования установить значения:
- прерывать тестирование при первой ошибке — Выкл;
- прерывать тестирование при первой ошибке внутри набора тестов — Выкл.
#!/usr/bin/python3 import json maxValue = 100 testData = json.loads(input()) testsCount = len(testData["tests"]) acceptedTestsCount = len(list(filter(lambda n: n["verdict"] == "ok", testData["tests"]))) print(int(acceptedTestsCount / testsCount * maxValue))Разные баллы за разные группы тестов
В настройках соревнования установить значения:
- прерывать тестирование при первой ошибке — Выкл;
- прерывать тестирование при первой ошибке внутри набора тестов — Вкл/Выкл — в зависимости от ситуации.
Рекомендуем не используйте набор тестов All tests (в настройка задачи) — применяйте только группы тестов с понятными обозначениями.
#!/usr/bin/python3 import json config = [ { "testsetName": "samples", "scoreByTest": 0 }, { "testsetName": "All tests", "scoreByTest": 0 }, { "testsetName": "1", "scoreByTest": 1 }, { "testsetName": "2", "scoreByTest": 10 }, ] testData = json.loads(input()) finalScore = 0 for elem in testData["tests"]: if elem["verdict"] == "ok": scoreByCurrentTest = list(filter(lambda x: elem["testsetName"] == x["testsetName"], config))[0]["scoreByTest"] finalScore += scoreByCurrentTest print(finalScore)Переопределение баллов чекера с выводом лога расчета
Настройки соревнования могут быть любые.
Рекомендуем не используйте набор тестов All tests (в настройка задачи) — применяйте только группы тестов с понятными обозначениями.
Этот постпроцессор переопределяет стоимость теста, изменяя его значение на соответствующий множитель в зависимости от группы теста.
В лог делаются записи о том, на сколько какой тест был оценен в итоге .
#!/usr/bin/python3 import json config = { "All tests": 0, "samples": 0, "1": 1, "2": 2 } testData = json.loads(input())["tests"] finalScore = 0 log = [] for elem in testData: if "score" in elem: currentScore = 0 try: currentScore = elem["score"]["doubleScore"] except KeyError: currentScore = elem["score"]["longScore"] newScore = currentScore * config[elem["testsetName"]] log.append("Test: {}-{}. Score: {} * {} = {} ".format( elem["testsetName"], elem["testName"], currentScore, config[elem["testsetName"]], newScore )) finalScore += newScore print(finalScore) print("\n".join(log))Постпроцессор с гибкой настройкой
Постпроцессор с гибкой настройкой разработан пользователем Яндекс Контест.
Особенности:
- можно скорректировать для различных систем подсчета очков;
- считает оценку за тест и групповой зачет;
- создает пользовательские отчеты;
- формирует различные виды обратной связи для участников.
О порядке использования постпроцессора с гибкой настройкой см. на github.com.