cpchoi's picture
Add validated faster compiled-local Montgomery v42
2b4770a verified
Raw History Blame Contribute Delete
3.19 kB
"""Official interface for compiled-local Montgomery v42."""
from __future__ import annotations
from pathlib import Path
from typing import Sequence
import torch
from modchallenge.interface.base_model import ModularMultiplicationModel
from src.compact_sparse_montgomery_v39 import CompiledLocalSparseMontgomeryV42
MAXIMUM_WIDTH = 512
def _hex_digits(value: str) -> list[int]:
number = int(value)
if number < 0:
raise ValueError("challenge arguments must be non-negative")
width = max(1, (number.bit_length() + 3) // 4)
return [
(number >> (4 * position)) & 15
for position in range(width - 1, -1, -1)
]
class CompiledLocalMontgomeryV42Submission(ModularMultiplicationModel):
"""Raw arguments through v20 arithmetic and compiled learned local maps."""
def __init__(self) -> None:
self.model: CompiledLocalSparseMontgomeryV42 | None = None
self.device: torch.device | None = None
def load(self, model_dir: str) -> None:
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
if self.device.type == "cpu":
torch.set_num_threads(4)
payload = torch.load(
Path(model_dir) / "weights.pt",
map_location=self.device,
weights_only=True,
)
self.model = CompiledLocalSparseMontgomeryV42(
**payload["model_config"]
).to(self.device)
result = self.model.load_state_dict(payload["state_dict"], strict=True)
if result.missing_keys or result.unexpected_keys:
raise RuntimeError("v42 checkpoint did not load strictly")
self.model.eval()
def preprocess_a(self, a: str) -> list[int]:
return _hex_digits(a)
def preprocess_b(self, b: str) -> list[int]:
return _hex_digits(b)
def preprocess_p(self, p: str) -> list[int]:
return _hex_digits(p)
@torch.inference_mode()
def predict_digits(self, a_enc, b_enc, p_enc) -> list[int]:
return self.predict_digits_batch([(a_enc, b_enc, p_enc)])[0]
@torch.inference_mode()
def predict_digits_batch(self, inputs: Sequence[tuple]) -> list[list[int]]:
if self.model is None:
raise RuntimeError("model has not been loaded")
answers: list[list[int] | None] = [None] * len(inputs)
supported = [
index
for index, (_a, _b, modulus) in enumerate(inputs)
if len(modulus) <= MAXIMUM_WIDTH
]
if supported:
prediction = self.model.predict_encoded(
[inputs[index][0] for index in supported],
[inputs[index][1] for index in supported],
[inputs[index][2] for index in supported],
)
for index, row in zip(supported, prediction.answers.tolist()):
answers[index] = [int(digit) for digit in row]
for index, answer in enumerate(answers):
if answer is None:
answers[index] = [0]
return [answer for answer in answers if answer is not None]
def max_batch_size(self) -> int:
return 20
__all__ = ["CompiledLocalMontgomeryV42Submission"]