catacomb/__init__.py: Generalize rationals to fields of fractions.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 13 May 2015 10:39:25 +0000 (11:39 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Wed, 13 May 2015 10:39:25 +0000 (11:39 +0100)
Now we can have ratios of binary polynomials too.

catacomb/__init__.py

index 19a973b..b50c99a 100644 (file)
@@ -100,15 +100,16 @@ bytes = ByteString.fromhex
 ### Multiprecision integers and binary polynomials.
 
 def _split_rat(x):
-  if isinstance(x, Rat): return x._n, x._d
+  if isinstance(x, BaseRat): return x._n, x._d
   else: return x, 1
-class Rat (object):
+class BaseRat (object):
+  """Base class implementing fields of fractions over Euclidean domains."""
   def __new__(cls, a, b):
-    a, b = MP(a), MP(b)
+    a, b = cls.RING(a), cls.RING(b)
     q, r = divmod(a, b)
     if r == 0: return q
     g = b.gcd(r)
-    me = super(Rat, cls).__new__(cls)
+    me = super(BaseRat, cls).__new__(cls)
     me._n = a//g
     me._d = b//g
     return me
@@ -117,34 +118,40 @@ class Rat (object):
   @property
   def denom(me): return me._d
   def __str__(me): return '%s/%s' % (me._n, me._d)
-  def __repr__(me): return 'Rat(%s, %s)' % (me._n, me._d)
+  def __repr__(me): return '%s(%s, %s)' % (type(me).__name__, me._n, me._d)
 
   def __add__(me, you):
     n, d = _split_rat(you)
-    return Rat(me._n*d + n*me._d, d*me._d)
+    return type(me)(me._n*d + n*me._d, d*me._d)
   __radd__ = __add__
   def __sub__(me, you):
     n, d = _split_rat(you)
-    return Rat(me._n*d - n*me._d, d*me._d)
+    return type(me)(me._n*d - n*me._d, d*me._d)
   def __rsub__(me, you):
     n, d = _split_rat(you)
-    return Rat(n*me._d - me._n*d, d*me._d)
+    return type(me)(n*me._d - me._n*d, d*me._d)
   def __mul__(me, you):
     n, d = _split_rat(you)
-    return Rat(me._n*n, me._d*d)
+    return type(me)(me._n*n, me._d*d)
   def __div__(me, you):
     n, d = _split_rat(you)
-    return Rat(me._n*d, me._d*n)
+    return type(me)(me._n*d, me._d*n)
   def __rdiv__(me, you):
     n, d = _split_rat(you)
-    return Rat(me._d*n, me._n*d)
+    return type(me)(me._d*n, me._n*d)
   def __cmp__(me, you):
     n, d = _split_rat(you)
-    return cmp(me._n*d, n*me._d)
+    return type(me)(me._n*d, n*me._d)
   def __rcmp__(me, you):
     n, d = _split_rat(you)
     return cmp(n*me._d, me._n*d)
 
+class IntRat (BaseRat):
+  RING = MP
+
+class GFRat (BaseRat):
+  RING = GF
+
 class _tmp:
   def negp(x): return x < 0
   def posp(x): return x > 0
@@ -154,8 +161,8 @@ class _tmp:
   def mont(x): return MPMont(x)
   def barrett(x): return MPBarrett(x)
   def reduce(x): return MPReduce(x)
-  def __div__(me, you): return Rat(me, you)
-  def __rdiv__(me, you): return Rat(you, me)
+  def __div__(me, you): return IntRat(me, you)
+  def __rdiv__(me, you): return IntRat(you, me)
 _augment(MP, _tmp)
 
 class _tmp:
@@ -165,6 +172,8 @@ class _tmp:
   def halftrace(x, y): return x.reduce().halftrace(y)
   def modsqrt(x, y): return x.reduce().sqrt(y)
   def quadsolve(x, y): return x.reduce().quadsolve(y)
+  def __div__(me, you): return GFRat(me, you)
+  def __rdiv__(me, you): return GFRat(you, me)
 _augment(GF, _tmp)
 
 class _tmp: