div.sage 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. class Divisor:
  2. def __init__(self, func, support):
  3. self.func = func
  4. self.support = support
  5. def __repr__(self):
  6. rep = ""
  7. first = True
  8. for v, P in self.support:
  9. if first:
  10. if v < 0:
  11. rep = "- "
  12. first = False
  13. else:
  14. if v < 0:
  15. rep += " - "
  16. else:
  17. rep += " + "
  18. v = abs(v)
  19. if v == 1:
  20. rep += f"[{P}]"
  21. else:
  22. rep += f"{v}[{P}]"
  23. return rep
  24. def rename(self, symbol, new_point):
  25. for i, (v, P) in enumerate(self.support):
  26. if repr(P) == symbol:
  27. self.support[i][1] = new_point
  28. def copy_support(self):
  29. support = []
  30. for v, P in self.support:
  31. support.append([v, P.copy()])
  32. return support
  33. def __add__(self, other):
  34. support = self.copy_support()
  35. for n, P in other.support:
  36. found = False
  37. for i, (_, Q) in enumerate(support):
  38. if P.P == Q.P:
  39. found = True
  40. support[i][0] += n
  41. if not found:
  42. support.append([n, P])
  43. func = self.func * other.func
  44. return Divisor(func, support)._cleanup()
  45. def _cleanup(self):
  46. # Cleanup
  47. support = []
  48. for n, P in self.support:
  49. if n == 0:
  50. continue
  51. support.append([n, P])
  52. self.support = support
  53. return self
  54. def __neg__(self):
  55. support = []
  56. for n, P in self.support:
  57. support.append([-n, P])
  58. func = 1/self.func
  59. return Divisor(func, support)
  60. def __sub__(self, other):
  61. other = -other
  62. return self + other
  63. def is_equiv(self, support):
  64. support = support.copy()
  65. for n, P in self.support:
  66. P = repr(P)
  67. if P not in support:
  68. return False
  69. if n != support[P]:
  70. return False
  71. del support[P]
  72. return not support
  73. def eval(self, other):
  74. f = self.func
  75. result = 1
  76. for n, P in other.support:
  77. if P.P == E(0, 1, 0):
  78. continue
  79. Px, Py = P.P.xy()
  80. result *= f(x=Px, y=Py)^n
  81. return result
  82. def effective_degree(self):
  83. deg = 0
  84. for n, P in self.support:
  85. if P.P == E(0, 1, 0):
  86. continue
  87. deg += n
  88. return deg
  89. def slope_intercept(P1, P2):
  90. P1x, P1y = P1.xy()
  91. P2x, P2y = P2.xy()
  92. P3x, P3y = (-(P1 + P2)).xy()
  93. λ = (P2y - P1y) / (P2x - P1x)
  94. μ = P2y - λ*P2x
  95. return λ, μ
  96. def line(P1, P2):
  97. if -(P1 + P2) == E(0, 1, 0):
  98. assert P1[0] == P2[0]
  99. return x - P1[0]
  100. if P1 == P2:
  101. # Use P3 instead
  102. P2 = -(P1 + P2)
  103. λ, μ = slope_intercept(P1, P2)
  104. return y - λ*x - μ
  105. class LabelPoint:
  106. def __init__(self, P, labels):
  107. self.P = P
  108. self.labels = labels
  109. def _add_labels(self, other_labels):
  110. labels = self.labels.copy()
  111. for key, value in other_labels.items():
  112. if key in labels:
  113. labels[key] += value
  114. else:
  115. labels[key] = value
  116. return labels
  117. def copy(self):
  118. return LabelPoint(self.P, self.labels.copy())
  119. def __add__(self, Q):
  120. P = self.P + Q.P
  121. labels = self._add_labels(Q.labels)
  122. return LabelPoint(P, labels)
  123. def __mul__(self, n):
  124. labels = self.labels.copy()
  125. for key in labels:
  126. labels[key] *= n
  127. return LabelPoint(n*self.P, labels)
  128. def __neg__(self):
  129. P = -self.P
  130. labels = self.labels.copy()
  131. for key in labels:
  132. labels[key] *= -1
  133. return LabelPoint(P, labels)
  134. def __repr__(self):
  135. rep = ""
  136. first = True
  137. for P, m in self.labels.items():
  138. if first:
  139. if m < 0:
  140. rep = "-"
  141. first = False
  142. else:
  143. if m < 0:
  144. rep += " - "
  145. else:
  146. rep += " + "
  147. m = abs(m)
  148. if m == 1:
  149. rep += f"{P}"
  150. else:
  151. rep += f"{m}{P}"
  152. return rep
  153. def div_line(P1, P2):
  154. inf = LabelPoint(E(0, 1, 0), {"∞": 1})
  155. P3 = -(P1 + P2)
  156. if P1 == P2:
  157. support = [
  158. [ 2, P1],
  159. [ 1, P3],
  160. [-3, inf]
  161. ]
  162. elif P3.P == E(0, 1, 0):
  163. support = [
  164. [ 1, P1],
  165. [ 1, P2],
  166. [-2, inf]
  167. ]
  168. else:
  169. support = [
  170. [ 1, P1],
  171. [ 1, P2],
  172. [ 1, P3],
  173. [-3, inf]
  174. ]
  175. func = line(P1.P, P2.P)
  176. return Divisor(func, support)