| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- # memoize calls to the class constructors for fields
- # this helps typechecking by never creating two separate
- # instances of a number class.
- def memoize(f):
- cache = {}
- def memoizedFunction(*args, **kwargs):
- argTuple = args + tuple(kwargs)
- if argTuple not in cache:
- cache[argTuple] = f(*args, **kwargs)
- return cache[argTuple]
- memoizedFunction.cache = cache
- return memoizedFunction
- # type check a binary operation, and silently typecast 0 or 1
- def typecheck(f):
- def newF(self, other):
- if (hasattr(other.__class__, 'operatorPrecedence') and
- other.__class__.operatorPrecedence > self.__class__.operatorPrecedence):
- return NotImplemented
- if type(self) is not type(other):
- try:
- other = self.__class__(other)
- except TypeError:
- message = 'Not able to typecast %s of type %s to type %s in function %s'
- raise TypeError(message % (other, type(other).__name__, type(self).__name__, f.__name__))
- except Exception as e:
- message = 'Type error on arguments %r, %r for functon %s. Reason:%s'
- raise TypeError(message % (self, other, f.__name__, type(other).__name__, type(self).__name__, e))
- return f(self, other)
- return newF
- # require a subclass to implement +-* neg and to perform typechecks on all of
- # the binary operations finally, the __init__ must operate when given a single
- # argument, provided that argument is the int zero or one
- class DomainElement(object):
- operatorPrecedence = 1
- # the 'r'-operators are only used when typecasting ints
- def __radd__(self, other): return self + other
- def __rsub__(self, other): return -self + other
- def __rmul__(self, other): return self * other
- # square-and-multiply algorithm for fast exponentiation
- def __pow__(self, n):
- if type(n) is not int:
- raise TypeError
- Q = self
- R = self if n & 1 else self.__class__(1)
- i = 2
- while i <= n:
- Q = (Q * Q)
- if n & i == i:
- R = (Q * R)
- i = i << 1
- return R
- # requires the additional % operator (i.e. a Euclidean Domain)
- def powmod(self, n, modulus):
- if type(n) is not int:
- raise TypeError
- Q = self
- R = self if n & 1 else self.__class__(1)
- i = 2
- while i <= n:
- Q = (Q * Q) % modulus
- if n & i == i:
- R = (Q * R) % modulus
- i = i << 1
- return R
- # additionally require inverse() on subclasses
- class FieldElement(DomainElement):
- def __truediv__(self, other): return self * other.inverse()
- def __rtruediv__(self, other): return self.inverse() * other
- def __div__(self, other): return self.__truediv__(other)
- def __rdiv__(self, other): return self.__rtruediv__(other)
|