|
2 | 2 |
|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | | -from itertools import pairwise |
6 | 5 | from typing import Annotated, Literal, Self |
7 | 6 |
|
8 | 7 | from pydantic import Field, StrictInt, field_validator, model_validator |
9 | 8 |
|
10 | | -from jacobian.canonical import parse_canonical_integer |
11 | 9 | from jacobian.contracts.exact import CanonicalInteger, CanonicalRational |
12 | 10 | from jacobian.contracts.matrices import ( |
13 | 11 | MAX_MATRIX_DIMENSION, |
@@ -263,53 +261,6 @@ def require_dense_monic_coefficients(self) -> Self: |
263 | 261 | return self |
264 | 262 |
|
265 | 263 |
|
266 | | -class SmithNormalFormResult(ContractModel): |
267 | | - normal_form: IntegerMatrix |
268 | | - rank: int = Field(ge=0, le=MAX_MATRIX_DIMENSION) |
269 | | - invariant_factors: tuple[CanonicalInteger, ...] = Field( |
270 | | - max_length=MAX_MATRIX_DIMENSION |
271 | | - ) |
272 | | - transformation_available: Literal[False] = False |
273 | | - convention: Literal["POSITIVE_DIVISIBILITY_DIAGONAL"] = ( |
274 | | - "POSITIVE_DIVISIBILITY_DIAGONAL" |
275 | | - ) |
276 | | - |
277 | | - @model_validator(mode="after") |
278 | | - def require_invariant_factor_chain(self) -> Self: |
279 | | - if len(self.invariant_factors) != self.rank: |
280 | | - raise ValueError("nonzero invariant factor count must equal rank") |
281 | | - rows = len(self.normal_form.entries) |
282 | | - columns = len(self.normal_form.entries[0]) |
283 | | - if self.rank > min(rows, columns): |
284 | | - raise ValueError("Smith rank cannot exceed the matrix dimensions") |
285 | | - factors = tuple( |
286 | | - parse_canonical_integer(value) for value in self.invariant_factors |
287 | | - ) |
288 | | - if any(value <= 0 for value in factors): |
289 | | - raise ValueError("Smith invariant factors must be positive") |
290 | | - if any(right % left != 0 for left, right in pairwise(factors)): |
291 | | - raise ValueError("each Smith invariant factor must divide the next") |
292 | | - for row, entries in enumerate(self.normal_form.entries): |
293 | | - for column, value in enumerate(entries): |
294 | | - expected = factors[row] if row == column and row < self.rank else 0 |
295 | | - if parse_canonical_integer(value) != expected: |
296 | | - raise ValueError( |
297 | | - "Smith normal form must contain its positive invariant " |
298 | | - "factors on the leading diagonal and zero elsewhere" |
299 | | - ) |
300 | | - return self |
301 | | - |
302 | | - @field_validator("invariant_factors") |
303 | | - @classmethod |
304 | | - def require_bounded_invariant_factors( |
305 | | - cls, |
306 | | - values: tuple[CanonicalInteger, ...], |
307 | | - ) -> tuple[CanonicalInteger, ...]: |
308 | | - for value in values: |
309 | | - _check_integer_digits(value, maximum=MAX_MATRIX_SCALAR_DIGITS) |
310 | | - return values |
311 | | - |
312 | | - |
313 | 264 | class MatrixInverseResult(ContractModel): |
314 | 265 | inverse: RationalMatrix |
315 | 266 | convention: Literal["TWO_SIDED_INVERSE_OVER_QQ"] = "TWO_SIDED_INVERSE_OVER_QQ" |
|
0 commit comments