from __future__ import annotations
import ctypes
from ctypes import c_uint32, c_uint64, c_double, c_int32, c_char_p
from dataclasses import dataclass
from pathlib import Path
from os import fspath
@dataclass(frozen=True)
class Result:
rank: int
strategy: str
ok: bool
class _ElliGf2Result(ctypes.Structure):
_fields_ = [
("rank", c_uint64),
("strategy", c_uint32),
("ok", c_int32),
]
def _candidate_lib_paths() -> list[Path]:
here = Path(__file__).resolve()
repo_root = here.parents[2]
names = [
"libelli_gf2.dylib", "libelli_gf2.so", "elli_gf2.dll", ]
paths = []
for name in names:
paths.append(repo_root / "target" / "release" / name)
paths.append(repo_root / "target" / "debug" / name)
return paths
def _load_lib() -> ctypes.CDLL:
for path in _candidate_lib_paths():
if path.exists():
return ctypes.CDLL(str(path))
searched = "\n".join(str(p) for p in _candidate_lib_paths())
raise FileNotFoundError(
"Could not find compiled elli-gf2 shared library.\n"
"Build it first with: cargo build --release\n"
f"Searched:\n{searched}"
)
_lib = _load_lib()
_lib.elli_gf2_strategy_name.argtypes = [c_uint32]
_lib.elli_gf2_strategy_name.restype = c_char_p
_lib.elli_gf2_reduce_er_auto.argtypes = [c_uint64, c_uint64, c_double, c_uint64]
_lib.elli_gf2_reduce_er_auto.restype = _ElliGf2Result
_lib.elli_gf2_reduce_ldpc_auto.argtypes = [c_uint64, c_uint64, c_uint64, c_uint64]
_lib.elli_gf2_reduce_ldpc_auto.restype = _ElliGf2Result
_lib.elli_gf2_reduce_banded_auto.argtypes = [c_uint64, c_uint64, c_uint64, c_uint64, c_uint64]
_lib.elli_gf2_reduce_banded_auto.restype = _ElliGf2Result
_lib.elli_gf2_reduce_file_auto.argtypes = [c_char_p]
_lib.elli_gf2_reduce_file_auto.restype = _ElliGf2Result
def _decode_result(raw: _ElliGf2Result) -> Result:
strategy = _lib.elli_gf2_strategy_name(raw.strategy)
strategy_str = strategy.decode("utf-8") if strategy else "Unknown"
return Result(
rank=int(raw.rank),
strategy=strategy_str,
ok=bool(raw.ok),
)
def reduce_er_auto(rows: int, cols: int, density: float, seed: int = 1337) -> Result:
raw = _lib.elli_gf2_reduce_er_auto(rows, cols, density, seed)
return _decode_result(raw)
def reduce_ldpc_auto(rows: int, cols: int, col_weight: int, seed: int = 1337) -> Result:
raw = _lib.elli_gf2_reduce_ldpc_auto(rows, cols, col_weight, seed)
return _decode_result(raw)
def reduce_banded_auto(
rows: int,
cols: int,
bandwidth: int,
weight: int,
seed: int = 1337,
) -> Result:
raw = _lib.elli_gf2_reduce_banded_auto(rows, cols, bandwidth, weight, seed)
return _decode_result(raw)
def reduce_file_auto(path: str | Path) -> Result:
raw = _lib.elli_gf2_reduce_file_auto(fspath(path).encode("utf-8"))
return _decode_result(raw)