from __future__ import annotations from pathlib import Path import struct from composer_ans.types import ( HOPFIELD_WEIGHT_DIMENSION, LegacyBPWeights, LegacyPaths, SALIERI_NODE_COUNT, SalieriConfig, ) def load_legacy_paths(root: str | Path) -> LegacyPaths: return LegacyPaths(root=Path(root)) def load_sequence_table(path: str | Path) -> tuple[str, ...]: sequence_path = Path(path) return tuple( line.strip().rstrip("\x1a") for line in sequence_path.read_text(encoding="ascii").splitlines() if line.strip().rstrip("\x1a") ) def load_salieri_config(path: str | Path) -> SalieriConfig: values: dict[str, str] = {} for raw_line in Path(path).read_text(encoding="ascii").splitlines(): line = raw_line.strip() if not line.startswith("!"): continue code = line[1:2].upper() if code == "Z": break payload = line[2:].strip() values[code] = payload return SalieriConfig( learning_rate=float(values["L"]), alpha=float(values["A"]), n_input=int(values["I"]), n_hidden=int(values["H"]), n_output=int(values["O"]), training_iterations=int(values["T"].split()[0]), error_tolerance=float(values["E"]), data_file=values["D"], report_file=values["R"], weight_file=values["W"], ) def load_salieri_weights(path: str | Path) -> LegacyBPWeights: vector_length = None weights: list[tuple[float, ...]] = [] thetas: tuple[float, ...] | None = None for raw_line in Path(path).read_text(encoding="ascii").splitlines(): line = raw_line.strip() if not line.startswith("!"): continue code = line[1:2].upper() payload = line[2:].strip() if code == "V": vector_length = int(payload) elif code == "W": row = tuple(float(item) for item in payload.split()) weights.append(row) elif code == "T": thetas = tuple(float(item) for item in payload.split()) elif code == "Z": break if vector_length is None: raise ValueError("missing !V in weight file") if len(weights) != vector_length: raise ValueError(f"expected {vector_length} weight rows, got {len(weights)}") if any(len(row) != vector_length for row in weights): raise ValueError("weight matrix is not square") if thetas is None: raise ValueError("missing !T in weight file") if len(thetas) != vector_length: raise ValueError(f"expected {vector_length} theta values, got {len(thetas)}") return LegacyBPWeights( vector_length=vector_length, weights=tuple(weights), thetas=thetas, ) def load_hopfield_weight_matrix(path: str | Path) -> tuple[tuple[float, ...], ...]: data = Path(path).read_bytes() expected_size = HOPFIELD_WEIGHT_DIMENSION * HOPFIELD_WEIGHT_DIMENSION * 4 if len(data) != expected_size: raise ValueError(f"expected {expected_size} bytes, got {len(data)}") values = struct.unpack( f"<{HOPFIELD_WEIGHT_DIMENSION * HOPFIELD_WEIGHT_DIMENSION}f", data, ) rows = [] for offset in range(0, len(values), HOPFIELD_WEIGHT_DIMENSION): rows.append(tuple(values[offset : offset + HOPFIELD_WEIGHT_DIMENSION])) return tuple(rows) def extract_active_hopfield_submatrix( matrix: tuple[tuple[float, ...], ...], ) -> tuple[tuple[float, ...], ...]: active_size = SALIERI_NODE_COUNT - 21 return tuple(tuple(row[:active_size]) for row in matrix[:active_size])