add EvalOpValueRange
authorJacob Lifshay <programmerjake@gmail.com>
Tue, 8 Nov 2022 08:00:54 +0000 (00:00 -0800)
committerJacob Lifshay <programmerjake@gmail.com>
Tue, 8 Nov 2022 08:00:54 +0000 (00:00 -0800)
src/bigint_presentation_code/toom_cook.py

index 7e9748ca2e135e1c065450a81eddce5138c828ad..03f3e9327c827c4d0403889653e9fa3f37ff76f1 100644 (file)
@@ -1,14 +1,15 @@
 """
 Toom-Cook multiplication algorithm generator for SVP64
 """
-from abc import abstractmethod
+from abc import ABCMeta, abstractmethod
 from enum import Enum
 from fractions import Fraction
 from typing import Any, Generic, Iterable, Mapping, TypeVar, Union
 
 from nmutil.plain_data import plain_data
 
-from bigint_presentation_code.compiler_ir import Fn, OpKind, SSAVal
+from bigint_presentation_code.compiler_ir import (GPR_SIZE_IN_BITS, Fn, OpKind,
+                                                  SSAVal)
 from bigint_presentation_code.matrix import Matrix
 from bigint_presentation_code.type_util import Literal, final
 
@@ -22,7 +23,7 @@ class PointAtInfinity(Enum):
 
 
 POINT_AT_INFINITY = PointAtInfinity.POINT_AT_INFINITY
-WORD_BITS = 64
+WORD_BITS = GPR_SIZE_IN_BITS
 
 _EvalOpPolyCoefficients = Union["Mapping[int | None, Fraction | int]",
                                 "EvalOpPoly", Fraction, int, None]
@@ -158,12 +159,42 @@ class EvalOpPoly:
         return f"EvalOpPoly({self.coefficients})"
 
 
+@plain_data(frozen=True, unsafe_hash=True)
+class EvalOpValueRange:
+    __slots__ = ("eval_op", "inputs_words", "min_value", "max_value",
+                 "is_signed")
+
+    def __init__(self, eval_op, inputs_words):
+        # type: (EvalOp[Any, Any], Iterable[int]) -> None
+        super().__init__()
+        self.eval_op = eval_op
+        self.inputs_words = tuple(inputs_words)
+        for words in self.inputs_words:
+            if words <= 0:
+                raise ValueError(f"invalid word count: {words}")
+        min_value = max_value = eval_op.poly.const_coeff
+        for var, coeff in enumerate(eval_op.poly.var_coeffs):
+            if coeff == 0:
+                continue
+            var_min = 0
+            var_max = (1 << self.inputs_words[var] * WORD_BITS) - 1
+            term_min = var_min * coeff
+            term_max = var_max * coeff
+            if term_min > term_max:
+                term_min, term_max = term_max, term_min
+            min_value += term_min
+            max_value += term_max
+        self.min_value = min_value
+        self.max_value = max_value
+        self.is_signed = min_value < 0
+
+
 _EvalOpLHS = TypeVar("_EvalOpLHS", int, "EvalOp[Any, Any]")
 _EvalOpRHS = TypeVar("_EvalOpRHS", int, "EvalOp[Any, Any]")
 
 
 @plain_data(frozen=True, unsafe_hash=True)
-class EvalOp(Generic[_EvalOpLHS, _EvalOpRHS]):
+class EvalOp(Generic[_EvalOpLHS, _EvalOpRHS], metaclass=ABCMeta):
     __slots__ = "lhs", "rhs", "poly"
 
     @property