Re:pythonで順序数を扱いたい

注)初回投稿のときから値のデータ管理を変えたのでコードも一新されています。
### 1.pythonで順序数を扱うclassがほしい
ので作りました。（バグあるかもしれません）

```Python
class Ordinal: #基本的にあるのはOrdinal([(0,0)])だけ。あとはカントール標準形でのみ生成する。
  def __init__(self,l):
    if l != []:
      self.l = l
    else:
      self.l = [(0,0)]
  
  def __repr__(self):
    if self.is_finit():
      return str(int(self))
    l = self.l
    s = []
    for i in l:
      if i[0] == 1:
        if i[1] == 0:
          s.append("1")
        elif i[1] == 1:
          s.append("omega")
        else:
          p = repr(i[1])
          if "+" in p or "*" in p or "**" in p:
            s.append(f"omega**({p})")
          else:
            s.append(f"omega**{p}")
      else:
        if i[1] == 0:
          s.append(f"{i[0]}")
        elif i[1] == 1:
          s.append(f"omega*{i[0]}")
        else:
          p = str(i[1])
          if "+" in p or "*" in p or "**" in p:
            s.append(f"omega**({p})*{i[0]}")
          else:
            s.append(f"omega**{p}*{i[0]}")
    return " + ".join(s)

  def __str__(self):
    if self.is_finit():
      return str(int(self))
    l = self.l
    s = []
    for i in l:
      if i[0] == 1:
        if i[1] == 0:
          s.append("1")
        elif i[1] == 1:
          s.append("ω")
        else:
          p = str(i[1])
          if "+" in p or "*" in p or "^" in p:
            s.append(f"ω^({p})")
          else:
            s.append(f"ω^{p}")
      else:
        if i[1] == 0:
          s.append(f"{i[0]}")
        elif i[1] == 1:
          s.append(f"ω*{i[0]}")
        else:
          p = str(i[1])
          if "+" in p or "*" in p or "^" in p:
            s.append(f"ω^({p})*{i[0]}")
          else:
            s.append(f"ω^{p}*{i[0]}")
    return " + ".join(s)

  def is_zero(self):
    if len(self.l) == 1 and type(self.l[0][1]) == int and self.l == [(0,0)]: #0であるか？
      return True
    return False

  def is_finit(self):
    if self.is_zero():
      return True
    if len(self.l) == 1 and type(self.l[0][1]) == Ordinal and self.l[0][1].is_zero(): #1以上の自然数か？
      return True
    return False

  def _richcmp(self,other):
    if self.is_zero():
      if other.is_zero():
        #print("premitive")
        return None
      else:
        return True
    else:
      if other.is_zero():
        return False
    for i in range(min(len(self.l),len(other.l))):
      B = self.l[i][1]._richcmp(other.l[i][1])
      #print(B)
      if B == True:
        return True
      elif B == False:
        return False
      if self.l[i][0] < other.l[i][0]:
        return True
      elif self.l[i][0] > other.l[i][0]:
        return False
    if len(self.l) == len(other.l):
      return None
    elif len(self.l) < len(other.l):
      return True
    else:
      return False

  def __eq__(self,other):
    #int型が混ざったときの処理
    if type(self) == int and type(other) == Ordinal:
      if self == 0:
        return Ordinal([(0,0)]) == other
      else:
        return Ordinal([(self,Ordinal([(0,0)]))]) == other
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return self == Ordinal([(0,0)])
      else:
        return self == Ordinal([(other,Ordinal([(0,0)]))])
    #通常の処理
    B = self._richcmp(other)
    return B == None

  def __le__(self,other): # 'le' means 'self is less than or equal other'
    #int型が混ざったときの処理
    if type(self) == int and type(other) == Ordinal:
      if self == 0:
        return Ordinal([(0,0)]) <= other
      else:
        return Ordinal([(self,Ordinal([(0,0)]))]) <= other
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return self <= Ordinal([(0,0)])
      else:
        return self <= Ordinal([(other,Ordinal([(0,0)]))])
    #通常の処理
    B = self._richcmp(other)
    return (B == True) or (B == None)


  def __lt__(self,other):
    #int型が混ざったときの処理
    if type(self) == int and type(other) == Ordinal:
      if self == 0:
        return Ordinal([(0,0)]) < other
      else:
        return Ordinal([(self,Ordinal([(0,0)]))]) < other
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return self < Ordinal([(0,0)])
      else:
        return self < Ordinal([(other,Ordinal([(0,0)]))])
    #通常の処理
    B = self._richcmp(other)
    return B == True


  def __ge__(self,other):
    #int型が混ざったときの処理
    if type(self) == int and type(other) == Ordinal:
      if self == 0:
        return Ordinal([(0,0)]) >= other
      else:
        return Ordinal([(self,Ordinal([(0,0)]))]) >= other
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return self >= Ordinal([(0,0)])
      else:
        return self >= Ordinal([(other,Ordinal([(0,0)]))])
    #通常の処理
    B = self._richcmp(other)
    return (B == False) or (B == None)

  def __gt__(self,other):
    #int型が混ざったときの処理
    if type(self) == int and type(other) == Ordinal:
      if self == 0:
        return Ordinal([(0,0)]) > other
      else:
        return Ordinal([(self,Ordinal([(0,0)]))]) > other
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return self > Ordinal([(0,0)])
      else:
        return self > Ordinal([(other,Ordinal([(0,0)]))])
    #通常の処理
    B = self._richcmp(other)
    return B == False

  def __ne__(self,other):
    #int型が混ざったときの処理
    if type(self) == int and type(other) == Ordinal:
      if self == 0:
        return Ordinal([(0,0)]) != other
      else:
        return Ordinal([(self,Ordinal([(0,0)]))]) != other
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return self != Ordinal([(0,0)])
      else:
        return self != Ordinal([(other,Ordinal([(0,0)]))])
    #通常の処理
    B = self._richcmp(other)
    return (B == True) or (B == False)

  def __int__(self):
    if self.is_zero():
      return 0
    elif self.is_finit():
      return self.l[0][0]
    return -1

  def __bool__(self):
    return self.is_zero()

  def normed(self):
    if self == Ordinal([(0,0)]):
      return Ordinal([(0,0)])
    l = list(self.l)
    for x in range(len(l)):
      l[x] = (l[x][0],l[x][1].normed())
    #print(l)
    i = 0
    while i < len(l):
      if i == 0:
        i += 1
        #print(i,l)
      elif l[i-1][1] < l[i][1]:
        l = self.l[:i-1] + l[i:]
        i -= 1
        #print(i,l)
      elif l[i-1][1] > l[i][1]:
        i += 1
        #print(i,l)
      else:
        l = l[:i-1] + [(l[i-1][0] + l[i][0],l[i][1])] + l[i+1:]
        i -= 1
        #print(i,l)
    return Ordinal(l)

  def __add__(self,other):
    #int型が混ざったときの処理
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return self
      else:
        return self + Ordinal([(other,Ordinal([(0,0)]))])
    #そもそも二項とも0でないことを仮定する
    if self.is_zero():
      return other
    elif other.is_zero():
      return self
    #まず二分探索でotherの最高次の指数に対応するselfの指数の位置を調べる
    l_index = [i[1] for i in self.l] #指数の配列
    a = other.l[0][1]
    right = len(l_index)
    left = 0
    #print(left,right,None,l_index[left:right+1])
    while left < right:
      mid = (right+left)//2
      # left ~ mid の範囲にあるか？
      B = l_index[mid]._richcmp(a) # l_index[mid] < a の意
      if B == False:
        left = mid+1
      elif B == True:
        right = mid
      else:
        index = mid+1
        break
      #print(left,right,mid,l_index[left:right+1])
    if left == right:
      index = left
    #計算部分
    L = self.l[:index]
    if L == []:
      L = list(other.l)
    elif L[-1][1] == a:
      L[-1] = (L[-1][0]+other.l[0][0],a)
      L = L + other.l[1:]
    else:
      L = L + other.l
    return Ordinal(L)
    

  def __radd__(self,other):
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return self
      else:
        return Ordinal([(other,Ordinal([(0,0)]))]) + self

  def __sub__(self,other): #a-b,,,self-other
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return self
      else:
        return self - Ordinal([(other,Ordinal([(0,0)]))])
    #そもそも結果が負にならないことが前提
    if self < other:
      return None
    #そもそもself=otherでないことを確認する
    if self == other:
      return Ordinal([(0,0)])
    #そもそも二項とも0でないことを仮定する。other!=0なら、self >= other > 0より両方調べたことになる。
    if other.is_zero():
      return self
    #まずω^(a_r)*n_r > ω^(b_r)*m_rとなる初めてのrを探す。
    r = 0
    while r < len(other.l):
      if self.l[r][1] > other.l[r][1]:
        L = self.l[r:]
        return Ordinal(L)
      if self.l[r][1] == other.l[r][1] and self.l[r][0] > other.l[r][0]:
        L = [(self.l[r][0]-other.l[r][0],self.l[r][1])] + self.l[r+1:]
        return Ordinal(L)
      r += 1
    return Ordinal(self.l[r:])
      

  def __rsub__(self,other):
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        if self.is_zero():
          return Ordinal([(0,0)])
        return None
      else:
        return Ordinal([(other,Ordinal([(0,0)]))]) - self
  
  def __mul__(self,other):
    #int型が混ざったときの処理
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return Ordinal([(0,0)])
      else:
        return self * Ordinal([(other,Ordinal([(0,0)]))])
    #そもそも0じゃないか？
    if self.is_zero() or other.is_zero():
      return Ordinal([(0,0)])
    #otherに定数項があるか？
    if other.l[-1][1].is_zero():
      m = other.l[-1][0]
    else:
      m = 0
    #mで場合分け
    if m > 0:
      a = self.l[0][1]
      L = [(i[0],a+i[1])for i in other.l[:-1]] + [(self.l[0][0]*m,self.l[0][1])] + self.l[1:]
    else:
      a = self.l[0][1]
      L = [(i[0],a+i[1])for i in other.l]
    return Ordinal(L)

  def __rmul__(self,other):
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return Ordinal([(0,0)])
      else:
        return Ordinal([(other,Ordinal([(0,0)]))]) * self

  def _divmod(self,other):
    q = Ordinal([(0,0)])
    r = Ordinal(self.l)
    d = other.l[0][1]
    while r >= other:
      if r.l[0][1] != d:
        q = q + Ordinal([(r.l[0][0],r.l[0][1]-d)])
        r = r - other*Ordinal([(r.l[0][0],r.l[0][1]-d)])
      else:
        a = r.l[0][0]
        b = other.l[0][0]
        n = a//b
        if a > n*b: #引き算する余裕があるとき
          if n != 0:
            q = q + Ordinal([(n,Ordinal([(0,0)]))])
            r = r - other*Ordinal([(n,Ordinal([(0,0)]))])
        else: # a == n*b 
          if n != 0:
            q_ = q + Ordinal([(n,Ordinal([(0,0)]))])
            r_ = r - other*Ordinal([(n,Ordinal([(0,0)]))])
            if r_ is None:
              n -= 1
              if n != 0:
                q = q + Ordinal([(n,Ordinal([(0,0)]))])
                r = r - other*Ordinal([(n,Ordinal([(0,0)]))])
            else:
              q = q_
              r = r_
    if self != other*q+r:
      print("Fxxk you!!")
      exit()
    return q,r

  def __truediv__(self, other):
    if type(self) == Ordinal and type(other) == int:
      return self / Ordinal([(other,Ordinal([(0,0)]))])
    if other == 0:
      raise ZeroDivisionError("division by zero")
    res = self._divmod(other)
    if res[1] == 0:
      return res[0]
    return None

  def __rtruediv__(self, other):
    if type(self) == Ordinal and type(other) == int:
      return Ordinal([(other,Ordinal([(0,0)]))]) / self
    
  def __floordiv__(self, other):
    if type(self) == Ordinal and type(other) == int:
        return self // Ordinal([(other, Ordinal([(0, 0)]))])
    if other == 0:
        raise ZeroDivisionError("division by zero")
    res = self._divmod(other)
    return res[0]

  def __rfloordiv__(self, other):
      if type(self) == Ordinal and type(other) == int:
          return Ordinal([(other, Ordinal([(0, 0)]))]) // self

  def __mod__(self, other):
    if type(self) == Ordinal and type(other) == int:
      return self % Ordinal([(other, Ordinal([(0, 0)]))])
    if other == 0:
      raise ZeroDivisionError("division by zero")
    res = self._divmod(other)
    return res[1]

  def __rmod__(self, other):
    if type(self) == Ordinal and type(other) == int:
      return Ordinal([(other, Ordinal([(0, 0)]))]) % self

  def __pow__(self,other):
    #int型が混ざったときの処理
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        return Ordinal([(1,Ordinal([(0,0)]))])
      else:
        return self ** Ordinal([(other,Ordinal([(0,0)]))])
    #そもそも0じゃないか？
    if other.is_zero():
      return Ordinal([(1,Ordinal([(0,0)]))])
    elif self.is_zero():
      return Ordinal([(0,0)])
    #otherに定数項があるか？
    if other.l[-1][1].is_zero():
      m = other.l[-1][0]
    else:
      m = 0
    #selfが有限のときor無限のとき
    if self.is_finit():
      if other.is_finit():
        return Ordinal([(int(self)**int(other),Ordinal([(0,0)]))])
      if self == 1:
        return 1
      #有限の無限乗
      if m > 0:
        I = Ordinal([(1,Ordinal(other.l[:-1]))])
      else:
        I = Ordinal([(1,other)])
      a = Ordinal(list(self.l))
      b = m
      res = Ordinal([(1,Ordinal([(0,0)]))])
      while b:
        if b % 2 == 1:
          res *= a
        a = a*a
        b //= 2
      return I*res
    else:
      if m > 0:
        I = Ordinal([(1,self.l[0][1]*Ordinal(other.l[:-1]))])
      else:
        I = Ordinal([(1,self.l[0][1]*other)])
      a = Ordinal(list(self.l))
      b = m
      res = Ordinal([(1,Ordinal([(0,0)]))])
      while b:
        if b % 2 == 1:
          res *= a
        a = a*a
        b //= 2
      return I*res

  def __rpow__(self,other):
    if type(self) == Ordinal and type(other) == int:
      if other == 0:
        if self.is_zero():
          return Ordinal([(1,Ordinal([(0,0)]))])
        return Ordinal([(0,0)])
      else:
        return Ordinal([(other,Ordinal([(0,0)]))]) ** self


  def sqrt(self): #平方数であるか？
    if self.is_finit():
      n = int(self)
      if n == 0:
        return Ordinal([(0,0)])
      digit = (len(bin(n)[2:])+1)//2 # 2**len(bin(n)[2:]-1)  <=  n  <= 2**(len(bin(n)[2:]))
      left = 2**(digit-1)            # 1 -> 1, 2 -> 1, 3 -> 2, 4 -> 2
      right = 2**digit
      while left <= right:
          mid = (left + right) // 2
          square = mid * mid
          if square == n:
              return mid
          if square < n:
              left = mid + 1
          else:
              right = mid - 1
      return None
    a = self.l[0][1].l[0][0] #最高次の指数の係数
    if a%2 != 0:
      return None
    s = Ordinal([(self.l[0][0],Ordinal([(self.l[0][1].l[0][0]//2,self.l[0][1].l[0][1])]+self.l[0][1].l[1:]))])
    r = Ordinal(self.l) - s**2
    if r == 0:
      return s
    while True:
      p = r.l[0][1] - s.l[0][1]
      if p is None:
        break
      s = s + Ordinal([(r.l[0][0],p)])
      r = Ordinal(self.l) - s**2
      if r == 0:
        return s
    return None

  def pred(self):
    if self.l[-1][1].is_zero():
      m = self.l[-1][0]
      if m == 1:
        return Ordinal(self.l[:-1])
      else:
        return Ordinal(self.l[:-1]+[(m-1,Ordinal([(0,0)]))])
    else:
      return None
  
  def deg(self):
    if self.is_zero():
      return None
    return self.l[0][1]

  #計算のための情報
  #(ω^n)? = n-1             (n < ω)
  #(ω^n)? = ω^(ω^n)       (n >= ω)
  #(α+ω^n)? = α?+ω^n       (α >= ω^n)

  def factorial(self):
    #selfを展開する。つまり、ω^ω*2+ω^4*5+4 -> ω^ω+ω^ω+ω^4+ω^4+ω^4+ω^4+1+1+1+1
    #実際に展開するわけではないが、そう考えるとやりやすい...か？
    if self == 0:
      return 1
    if type(self) == int:
      self = Ordinal([(self,Ordinal([(0,0)]))])
    flag = True
    now = 0
    res = Ordinal([(1,Ordinal([(0,0)]))])
    if self.l[-1][1].is_zero():
      m = self.l[-1][0]
    else:
      m = 0
    for x in self.l:
      #print(x)
      c,p = x
      for i in range(c):
        #print(p,i,res)
        if flag:
          if p == 1:
            res = Ordinal([(1,Ordinal([(1,Ordinal([(0,0)]))]))])**(p-1) #つまり、ω^ω^(p-1)
          elif 1 < p:
            res = Ordinal([(1,Ordinal([(1,Ordinal([(0,0)]))]))])**p #つまり、ω^ω^p=ω^ω^(p-1)。統一してもいいんだけどね。
          flag = False
          now += Ordinal([(1,Ordinal([(1,Ordinal([(0,0)]))]))])**p
          continue
        if p != 0:
          res += now.deg()*Ordinal([(1,Ordinal([(1,Ordinal([(0,0)]))]))])**p
          now += Ordinal([(1,Ordinal([(1,Ordinal([(0,0)]))]))])**p
    if not self.is_finit():
      res = Ordinal([(1,Ordinal([(1,Ordinal([(0,0)]))]))])**res
    for i in range(1,m+1):
      res *= Ordinal(self.l[:-1])+i
    #print(now)
    return res 

OMEGA = Ordinal([(1,Ordinal([(1,Ordinal([(0,0)]))]))])
ω = OMEGA
```

コメントアウトは気にしないでください。バグ発見したらコメントで教えてください。

追記)べき乗の計算が間違っていたので修正しました。

### 2.機能
足し算　　　　... α+β
引き算　　　　... α-β
掛け算　　　　... α*β
割り算　　　　... α/β
切り捨て除算　... α//β
剰余　　　　　... α%β
平方根　　　　... α.sqrt()
階乗　　　　　... α.factorial()

引き算,割り算,平方根では解が存在しない(割り切れないなど)ときはNoneが返されます。
階乗はオリジナルの定義なので異論は認めます。コメント書いてください。

### 3.参考文献
https://www.behounek.online/logic/papers/ordcalc/index.html
https://proofwiki.org/wiki/Division_Theorem_for_Ordinals
https://manabitimes.jp/math/1318

### 4.追記
意味もなくPyPIに上げました。
https://pypi.org/project/ordinal-number/
import ordinal_number でできます。