Skip to content

Commit

Permalink
No format analysis for ongoing ABC contests (#286)
Browse files Browse the repository at this point in the history
* Enable the functionality to skip input format analysis for ongoing ABC contests

* Fix format

* Fix unit tests
  • Loading branch information
kyuridenamida authored Jun 7, 2024
1 parent 9c91981 commit 880a131
Show file tree
Hide file tree
Showing 15 changed files with 520 additions and 433 deletions.
2 changes: 2 additions & 0 deletions atcodertools/atcoder_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ def main():
if len(sys.argv) < 2 or sys.argv[1] not in ("gen", "test", "submit", "codegen", "compile", "set", "version"):
print("Usage:")
print("{} gen -- to generate workspace".format(sys.argv[0]))
print(
"{} codegen -- to generate code for one problem".format(sys.argv[0]))
print(
"{} compile -- to compile codes in your workspace".format(sys.argv[0]))
print("{} test -- to test codes in your workspace".format(sys.argv[0]))
Expand Down
3 changes: 2 additions & 1 deletion atcodertools/common/language.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ def from_name(cls, name: str):
name="python",
display_name="Python",
extension="py",
submission_lang_pattern=re.compile(".*Python \\(3.*|.*Python \\(CPython 3.*"),
submission_lang_pattern=re.compile(
".*Python \\(3.*|.*Python \\(CPython 3.*"),
default_code_generator=python.main,
default_template_path=get_default_template_path('py'),
compile_command="python3 -mpy_compile {filename}.py",
Expand Down
42 changes: 41 additions & 1 deletion atcodertools/constprediction/constants_prediction.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ def __init__(self, cands):
self.cands = cands


class FailingToKnowFormatAnalysisAllowedByRuleError(Exception):
def __init__(self, reason):
self.reason = reason


MOD_ANCHORS = ["余り", "あまり", "mod", "割っ", "modulo"]
DECIMAL_ANCHORS = ["誤差", " error "]
LIMIT_ANCHORS = ["時間制限", "Time Limit"]
Expand Down Expand Up @@ -206,6 +211,26 @@ def normalize(sentence):
raise MultipleModCandidatesError(limit_cands)


def predict_is_format_analysis_allowed_by_rule(html: str) -> bool:
soup = BeautifulSoup(html, "html.parser")
url_meta_tag = soup.find("meta", property="og:url")
if url_meta_tag is None:
raise FailingToKnowFormatAnalysisAllowedByRuleError(
"No meta tag detected, which is important as a clue to know if the input analysis is allowed.")

# ABC is the target of "No LLM rules" by AtCoder (See https://info.atcoder.jp/entry/llm-abc-rules-ja or https://info.atcoder.jp/entry/llm-abc-rules-en)
is_target_contest_of_no_llm_rule = "/contests/abc" in url_meta_tag["content"]

# If there is no virtual standings link, assume it's ongoing.
is_ongoing_contest = len([tag for tag in soup.find_all(
"a") if "/standings/virtual" in tag.get("href", "")]) == 0

if is_target_contest_of_no_llm_rule and is_ongoing_contest:
return False

return True


def predict_constants(html: str) -> ProblemConstantSet:
try:
yes_str, no_str = predict_yes_no(html)
Expand Down Expand Up @@ -233,4 +258,19 @@ def predict_constants(html: str) -> ProblemConstantSet:
"two or more candidates {} are detected as limit".format(e.cands))
timeout = None

return ProblemConstantSet(mod=mod, yes_str=yes_str, no_str=no_str, judge_method=judge, timeout=timeout)
try:
is_format_analysis_allowed_by_rule = predict_is_format_analysis_allowed_by_rule(
html)
except FailingToKnowFormatAnalysisAllowedByRuleError as e:
logger.warning(
"Failed to know whether format analysis is allowed by the contest rules -- ", e.reason)
is_format_analysis_allowed_by_rule = None

return ProblemConstantSet(
mod=mod,
yes_str=yes_str,
no_str=no_str,
judge_method=judge,
timeout=timeout,
is_format_analysis_allowed_by_rule=is_format_analysis_allowed_by_rule,
)
4 changes: 3 additions & 1 deletion atcodertools/constprediction/models/problem_constant_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ def __init__(self,
yes_str: str = None,
no_str: str = None,
judge_method: Judge = None,
timeout: float = None
timeout: float = None,
is_format_analysis_allowed_by_rule: bool = None,
):
self.mod = mod
self.yes_str = yes_str
self.no_str = no_str
self.judge_method = judge_method
self.timeout = timeout
self.is_format_analysis_allowed_by_rule = is_format_analysis_allowed_by_rule
9 changes: 8 additions & 1 deletion atcodertools/fmtprediction/predict_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ def __init__(self, cands):
self.cands = cands


def predict_format(content: ProblemContent) -> FormatPredictionResult:
class PredictionNotAllowedError(Exception):
pass


def predict_format(content: ProblemContent, is_format_analysis_allowed_by_rule: bool) -> FormatPredictionResult:
if not is_format_analysis_allowed_by_rule:
raise PredictionNotAllowedError

input_format = content.get_input_format()
samples = content.get_samples()

Expand Down
14 changes: 9 additions & 5 deletions atcodertools/tools/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from atcodertools.config.config import Config
from atcodertools.constprediction.constants_prediction import predict_constants
from atcodertools.fmtprediction.models.format_prediction_result import FormatPredictionResult
from atcodertools.fmtprediction.predict_format import MultiplePredictionResultsError, NoPredictionResultError, predict_format
from atcodertools.fmtprediction.predict_format import MultiplePredictionResultsError, NoPredictionResultError, PredictionNotAllowedError, predict_format
from atcodertools.tools import get_default_config_path
from atcodertools.tools.envgen import USER_CONFIG_PATH, get_config, output_splitter
from atcodertools.tools.utils import with_color
Expand Down Expand Up @@ -89,19 +89,23 @@ def emit_info(text):
emit_error("Failed to download samples.")
raise e

constants = predict_constants(content.original_html)

try:
prediction_result = predict_format(content)
prediction_result = predict_format(
content, constants.is_format_analysis_allowed_by_rule or False)
emit_info(
with_color("Format prediction succeeded", Fore.LIGHTGREEN_EX))
except (NoPredictionResultError, MultiplePredictionResultsError) as e:
except (NoPredictionResultError, MultiplePredictionResultsError, PredictionNotAllowedError) as e:
prediction_result = FormatPredictionResult.empty_result()
if isinstance(e, NoPredictionResultError):
msg = "No prediction -- Failed to understand the input format"
else:
elif isinstance(e, MultiplePredictionResultsError):
msg = "Too many prediction -- Failed to understand the input format"
elif isinstance(e, PredictionNotAllowedError):
msg = "Format prediction is skipped because it's not allowed by AtCoder rules (At least not allowed in ongoing ABC contests) -- See https://info.atcoder.jp/entry/llm-abc-rules-en"
emit_warning(with_color(msg, Fore.LIGHTRED_EX))

constants = predict_constants(content.original_html)
code_generator = config.code_style_config.code_generator
with open(template_code_path, "r") as f:
template = f.read()
Expand Down
14 changes: 9 additions & 5 deletions atcodertools/tools/envgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
create_code
from atcodertools.fmtprediction.models.format_prediction_result import FormatPredictionResult
from atcodertools.fmtprediction.predict_format import NoPredictionResultError, \
MultiplePredictionResultsError, predict_format
MultiplePredictionResultsError, PredictionNotAllowedError, predict_format
from atcodertools.tools import get_default_config_path
from atcodertools.tools.models.metadata import Metadata
from atcodertools.tools.utils import with_color
Expand Down Expand Up @@ -117,19 +117,23 @@ def emit_info(text):
code_file_path,
new_path))

constants = predict_constants(content.original_html)

try:
prediction_result = predict_format(content)
prediction_result = predict_format(
content, constants.is_format_analysis_allowed_by_rule or False)
emit_info(
with_color("Format prediction succeeded", Fore.LIGHTGREEN_EX))
except (NoPredictionResultError, MultiplePredictionResultsError) as e:
except (NoPredictionResultError, MultiplePredictionResultsError, PredictionNotAllowedError) as e:
prediction_result = FormatPredictionResult.empty_result()
if isinstance(e, NoPredictionResultError):
msg = "No prediction -- Failed to understand the input format"
else:
elif isinstance(e, MultiplePredictionResultsError):
msg = "Too many prediction -- Failed to understand the input format"
elif isinstance(e, PredictionNotAllowedError):
msg = "Format prediction is skipped because it's not allowed by AtCoder rules (At least not allowed in ongoing ABC contests) -- See https://info.atcoder.jp/entry/llm-abc-rules-en"
emit_warning(with_color(msg, Fore.LIGHTRED_EX))

constants = predict_constants(content.original_html)
code_generator = config.code_style_config.code_generator
with open(template_code_path, "r") as f:
template = f.read()
Expand Down
Loading

0 comments on commit 880a131

Please sign in to comment.