rcas 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CITATION.cff +17 -0
- data/DESIGN.md +783 -0
- data/LICENSE +21 -0
- data/MANUAL.md +6265 -0
- data/README.md +267 -0
- data/bin/rcas +9 -0
- data/bin/rcas-app +9 -0
- data/bin/rcas-chat +9 -0
- data/lib/rcas/algebraic.rb +481 -0
- data/lib/rcas/analysis.rb +966 -0
- data/lib/rcas/app/launcher.rb +203 -0
- data/lib/rcas/app/public/app.css +402 -0
- data/lib/rcas/app/public/app.js +449 -0
- data/lib/rcas/app/public/index.html +46 -0
- data/lib/rcas/app/server.rb +220 -0
- data/lib/rcas/app/window.rb +94 -0
- data/lib/rcas/app/worksheet.rb +290 -0
- data/lib/rcas/app.rb +168 -0
- data/lib/rcas/background.rb +758 -0
- data/lib/rcas/chat/assistant.rb +199 -0
- data/lib/rcas/chat/picker.rb +164 -0
- data/lib/rcas/chat/repl.rb +583 -0
- data/lib/rcas/chat/session.rb +137 -0
- data/lib/rcas/chat/settings.rb +71 -0
- data/lib/rcas/chat/style.rb +30 -0
- data/lib/rcas/chat/tool.rb +53 -0
- data/lib/rcas/chat/ui.rb +316 -0
- data/lib/rcas/chat/usage.rb +62 -0
- data/lib/rcas/chat/workspace.rb +132 -0
- data/lib/rcas/chat.rb +54 -0
- data/lib/rcas/coefficients.rb +170 -0
- data/lib/rcas/combinatorics.rb +274 -0
- data/lib/rcas/complex_parts.rb +160 -0
- data/lib/rcas/constants.rb +129 -0
- data/lib/rcas/core_ext.rb +35 -0
- data/lib/rcas/decide.rb +501 -0
- data/lib/rcas/decompositions.rb +241 -0
- data/lib/rcas/differentiate.rb +144 -0
- data/lib/rcas/discussion.rb +558 -0
- data/lib/rcas/distributions.rb +980 -0
- data/lib/rcas/dixon.rb +95 -0
- data/lib/rcas/docs.rb +321 -0
- data/lib/rcas/domains.rb +728 -0
- data/lib/rcas/expand.rb +174 -0
- data/lib/rcas/expression.rb +613 -0
- data/lib/rcas/factor.rb +605 -0
- data/lib/rcas/finite_field.rb +577 -0
- data/lib/rcas/fourier.rb +118 -0
- data/lib/rcas/fps.rb +678 -0
- data/lib/rcas/fraction.rb +126 -0
- data/lib/rcas/functions.rb +1136 -0
- data/lib/rcas/gcd.rb +112 -0
- data/lib/rcas/geometry.rb +266 -0
- data/lib/rcas/groebner.rb +162 -0
- data/lib/rcas/hold.rb +277 -0
- data/lib/rcas/hypothesis.rb +364 -0
- data/lib/rcas/inequalities.rb +689 -0
- data/lib/rcas/integral_functions.rb +260 -0
- data/lib/rcas/integrate.rb +1589 -0
- data/lib/rcas/integrate_substitutions.rb +434 -0
- data/lib/rcas/interpolate.rb +40 -0
- data/lib/rcas/irb.rb +146 -0
- data/lib/rcas/laplace.rb +159 -0
- data/lib/rcas/latex.rb +556 -0
- data/lib/rcas/lattice.rb +172 -0
- data/lib/rcas/linear_algebra.rb +117 -0
- data/lib/rcas/linear_program.rb +416 -0
- data/lib/rcas/lint.rb +79 -0
- data/lib/rcas/matrix.rb +531 -0
- data/lib/rcas/matrix_multiply.rb +202 -0
- data/lib/rcas/multimodular.rb +286 -0
- data/lib/rcas/named_polynomials.rb +274 -0
- data/lib/rcas/number_theory.rb +443 -0
- data/lib/rcas/numerics.rb +825 -0
- data/lib/rcas/ode.rb +488 -0
- data/lib/rcas/openmath/objects.rb +364 -0
- data/lib/rcas/openmath/phrasebook.rb +551 -0
- data/lib/rcas/openmath/popcorn.rb +518 -0
- data/lib/rcas/openmath/xml.rb +309 -0
- data/lib/rcas/openmath.rb +49 -0
- data/lib/rcas/petkovsek.rb +165 -0
- data/lib/rcas/piecewise.rb +488 -0
- data/lib/rcas/plot.rb +763 -0
- data/lib/rcas/plot3d.rb +419 -0
- data/lib/rcas/poly_matrix.rb +318 -0
- data/lib/rcas/poly_recurrence.rb +117 -0
- data/lib/rcas/polynomial.rb +466 -0
- data/lib/rcas/precision.rb +925 -0
- data/lib/rcas/printer.rb +150 -0
- data/lib/rcas/product.rb +155 -0
- data/lib/rcas/q_difference.rb +296 -0
- data/lib/rcas/q_functions.rb +158 -0
- data/lib/rcas/q_summation.rb +308 -0
- data/lib/rcas/q_zeilberger.rb +199 -0
- data/lib/rcas/random.rb +506 -0
- data/lib/rcas/rational_function.rb +186 -0
- data/lib/rcas/recurrence.rb +323 -0
- data/lib/rcas/render.rb +431 -0
- data/lib/rcas/results.rb +192 -0
- data/lib/rcas/scalar.rb +219 -0
- data/lib/rcas/series.rb +726 -0
- data/lib/rcas/simplify.rb +649 -0
- data/lib/rcas/solve.rb +2002 -0
- data/lib/rcas/special.rb +163 -0
- data/lib/rcas/statistics.rb +175 -0
- data/lib/rcas/steps.rb +835 -0
- data/lib/rcas/summation.rb +532 -0
- data/lib/rcas/trig.rb +264 -0
- data/lib/rcas/van_hoeij.rb +241 -0
- data/lib/rcas/vector.rb +175 -0
- data/lib/rcas/vector_calculus.rb +411 -0
- data/lib/rcas/version.rb +5 -0
- data/lib/rcas/zeilberger.rb +358 -0
- data/lib/rcas.rb +91 -0
- data/package.json +8 -0
- metadata +206 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RCAS
|
|
4
|
+
# The named families of polynomials, in a namespace of their own: they are
|
|
5
|
+
# many, and bare names are precious (`legendre` is already the Legendre
|
|
6
|
+
# symbol of number theory, `bernoulli` the Bernoulli number).
|
|
7
|
+
#
|
|
8
|
+
# Poly.chebyshev_t(5, x) # => 5*x - 20*x**3 + 16*x**5
|
|
9
|
+
# Poly.legendre(4, x) # => 3/8 - 15*x**2/4 + 35*x**4/8
|
|
10
|
+
# Poly.cyclotomic(12, x) # => 1 - x**2 + x**4
|
|
11
|
+
#
|
|
12
|
+
# Each family is computed from its three-term recurrence (Jacobi: from its
|
|
13
|
+
# explicit sum) on lists of exact coefficients and handed back expanded, so
|
|
14
|
+
# the second argument may be any expression - `Poly.legendre(2, cos(t))` is
|
|
15
|
+
# the Legendre polynomial in cos(t), `Poly.hermite(3, 2)` a number. The
|
|
16
|
+
# parameters `alpha:` and `beta:` of the classical families may stay
|
|
17
|
+
# symbolic; they default to the indeterminates of the same name.
|
|
18
|
+
#
|
|
19
|
+
# Sources (keys: MANUAL.md, Sources): [AS64, ch. 22, ch. 23]; [Sze75];
|
|
20
|
+
# [GKP94, ch. 5, ch. 6]; [vzGG13, ch. 14].
|
|
21
|
+
module Poly
|
|
22
|
+
extend self
|
|
23
|
+
|
|
24
|
+
# Poly.chebyshev_t(5, x): the Chebyshev polynomial T_n of the first kind, T_n(cos(u)) = cos(n*u)
|
|
25
|
+
def chebyshev_t(n, x = :x)
|
|
26
|
+
build(three_term(degree(n, "chebyshev_t"), [num(1)], [num(0), num(1)]) { [num(2), num(0), num(-1)] }, x)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Poly.chebyshev_u(4, x): the Chebyshev polynomial U_n of the second kind, U_n(cos(u)) = sin((n + 1)*u)/sin(u)
|
|
30
|
+
def chebyshev_u(n, x = :x)
|
|
31
|
+
build(three_term(degree(n, "chebyshev_u"), [num(1)], [num(0), num(2)]) { [num(2), num(0), num(-1)] }, x)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Poly.legendre(4, x): the Legendre polynomial P_n, orthogonal on [-1, 1] with weight 1
|
|
35
|
+
def legendre(n, x = :x)
|
|
36
|
+
coeffs = three_term(degree(n, "legendre"), [num(1)], [num(0), num(1)]) do |k|
|
|
37
|
+
[num(Rational(2 * k - 1, k)), num(0), num(Rational(1 - k, k))]
|
|
38
|
+
end
|
|
39
|
+
build(coeffs, x)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Poly.hermite(3, x): the physicists' Hermite polynomial H_n, weight exp(-x**2)
|
|
43
|
+
def hermite(n, x = :x)
|
|
44
|
+
coeffs = three_term(degree(n, "hermite"), [num(1)], [num(0), num(2)]) { |k| [num(2), num(0), num(2 - 2 * k)] }
|
|
45
|
+
build(coeffs, x)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Poly.hermite_prob(3, x): the probabilists' Hermite polynomial He_n, weight exp(-x**2/2)
|
|
49
|
+
def hermite_prob(n, x = :x)
|
|
50
|
+
coeffs = three_term(degree(n, "hermite_prob"), [num(1)], [num(0), num(1)]) { |k| [num(1), num(0), num(1 - k)] }
|
|
51
|
+
build(coeffs, x)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Poly.laguerre(3, x) or Poly.laguerre(3, x, alpha: 1): the (generalized) Laguerre polynomial L_n, weight x**alpha*exp(-x)
|
|
55
|
+
def laguerre(n, x = :x, alpha: 0)
|
|
56
|
+
a = Expression.lift(alpha)
|
|
57
|
+
coeffs = three_term(degree(n, "laguerre"), [num(1)], [Scalar.add(num(1), a), num(-1)]) do |k|
|
|
58
|
+
[num(Rational(-1, k)), # -x/k
|
|
59
|
+
scale(Scalar.add(a, num(2 * k - 1)), Rational(1, k)), # (2k - 1 + alpha)/k
|
|
60
|
+
scale(Scalar.add(a, num(k - 1)), Rational(-1, k))] # -(k - 1 + alpha)/k
|
|
61
|
+
end
|
|
62
|
+
build(coeffs, x)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Poly.gegenbauer(3, x, alpha: 2): the Gegenbauer (ultraspherical) polynomial C_n, weight (1 - x**2)**(alpha - 1/2)
|
|
66
|
+
def gegenbauer(n, x = :x, alpha: :alpha)
|
|
67
|
+
a = Expression.lift(alpha)
|
|
68
|
+
coeffs = three_term(degree(n, "gegenbauer"), [num(1)], [num(0), Scalar.mul(num(2), a)]) do |k|
|
|
69
|
+
[scale(Scalar.add(a, num(k - 1)), Rational(2, k)), num(0), # 2(k - 1 + alpha)*x/k
|
|
70
|
+
scale(Scalar.add(Scalar.mul(num(2), a), num(k - 2)), Rational(-1, k))] # -(k - 2 + 2*alpha)/k
|
|
71
|
+
end
|
|
72
|
+
build(coeffs, x)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Poly.jacobi(2, x, alpha: 1, beta: 2): the Jacobi polynomial P_n, weight (1 - x)**alpha*(1 + x)**beta
|
|
76
|
+
def jacobi(n, x = :x, alpha: :alpha, beta: :beta)
|
|
77
|
+
n = degree(n, "jacobi")
|
|
78
|
+
a = Expression.lift(alpha)
|
|
79
|
+
b = Expression.lift(beta)
|
|
80
|
+
left = [num(Rational(-1, 2)), num(Rational(1, 2))] # (x - 1)/2
|
|
81
|
+
right = [num(Rational(1, 2)), num(Rational(1, 2))] # (x + 1)/2
|
|
82
|
+
coeffs = (0..n).reduce([num(0)]) do |sum, s|
|
|
83
|
+
c = Scalar.mul(binomial_polynomial(Scalar.add(a, num(n)), n - s), binomial_polynomial(Scalar.add(b, num(n)), s))
|
|
84
|
+
padd(sum, pscale(pmul(ppow(left, s), ppow(right, n - s)), c))
|
|
85
|
+
end
|
|
86
|
+
build(coeffs, x)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Poly.bernoulli(4, x): the Bernoulli polynomial B_n, with B_n(0) the Bernoulli number
|
|
90
|
+
def bernoulli(n, x = :x) = build(bernoulli_coeffs(degree(n, "bernoulli")), x)
|
|
91
|
+
|
|
92
|
+
# Poly.euler(3, x): the Euler polynomial E_n, from B_(n+1) by E_n(x) = 2/(n + 1)*(B_(n+1)(x) - 2**(n+1)*B_(n+1)(x/2))
|
|
93
|
+
def euler(n, x = :x)
|
|
94
|
+
n = degree(n, "euler")
|
|
95
|
+
coeffs = bernoulli_coeffs(n + 1).each_with_index.map do |c, k|
|
|
96
|
+
scale(c, Rational(2, n + 1) * (1 - 2**(n + 1 - k)))
|
|
97
|
+
end
|
|
98
|
+
build(coeffs, x)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Poly.cyclotomic(12, x): the cyclotomic polynomial Phi_n, the minimal polynomial of a primitive n-th root of unity
|
|
102
|
+
def cyclotomic(n, x = :x)
|
|
103
|
+
n = degree(n, "cyclotomic")
|
|
104
|
+
raise ArgumentError, "cyclotomic: n must be positive" if n.zero?
|
|
105
|
+
build(cyclotomic_coeffs(n).map { |c| num(c) }, x)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Poly.swinnerton_dyer(2, x): the minimal polynomial of sqrt(2) + sqrt(3) + ... over the first n primes, of degree 2**n
|
|
109
|
+
def swinnerton_dyer(n, x = :x)
|
|
110
|
+
n = degree(n, "swinnerton_dyer")
|
|
111
|
+
coeffs = primes(n).reduce([0, 1]) { |f, p| conjugate_product(f, p) }
|
|
112
|
+
build(coeffs.map { |c| num(c) }, x)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Poly.abel(3, x) or Poly.abel(3, x, a: 2): the Abel polynomial A_n(x; a) = x*(x - a*n)**(n - 1)
|
|
116
|
+
def abel(n, x = :x, a: 1)
|
|
117
|
+
n = degree(n, "abel")
|
|
118
|
+
return build([num(1)], x) if n.zero?
|
|
119
|
+
root = Scalar.mul(Expression.lift(a), num(-n))
|
|
120
|
+
coeffs = ppow([root, num(1)], n - 1)
|
|
121
|
+
build(pshift(coeffs), x)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Poly.fibonacci(6, x): the Fibonacci polynomial F_n, F_n(1) the Fibonacci number
|
|
125
|
+
def fibonacci(n, x = :x)
|
|
126
|
+
build(three_term(degree(n, "fibonacci"), [num(0)], [num(1)]) { [num(1), num(0), num(1)] }, x)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Poly.lucas(5, x): the Lucas polynomial L_n, L_n(1) the Lucas number
|
|
130
|
+
def lucas(n, x = :x)
|
|
131
|
+
build(three_term(degree(n, "lucas"), [num(2)], [num(0), num(1)]) { [num(1), num(0), num(1)] }, x)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Poly.bell(4, x): the Bell (Touchard) polynomial, the Stirling numbers of the second kind as coefficients; bell(n, 1) is the Bell number
|
|
135
|
+
def bell(n, x = :x)
|
|
136
|
+
build(stirling2_row(degree(n, "bell")).map { |c| num(c) }, x)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# ---- the machinery ------------------------------------------------------
|
|
140
|
+
#
|
|
141
|
+
# Polynomials are lists of coefficients, lowest degree first; every entry
|
|
142
|
+
# is an Expression, so a symbolic parameter is no different from a number.
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
|
|
146
|
+
def num(value) = Num.new(value)
|
|
147
|
+
|
|
148
|
+
# p_k = (a*x + b)*p_(k-1) + c*p_(k-2), from the two given lists.
|
|
149
|
+
def three_term(n, first, second)
|
|
150
|
+
return first if n.zero?
|
|
151
|
+
prev, cur = first, second
|
|
152
|
+
(2..n).each do |k|
|
|
153
|
+
a, b, c = yield(k)
|
|
154
|
+
prev, cur = cur, padd(padd(pscale(pshift(cur), a), pscale(cur, b)), pscale(prev, c))
|
|
155
|
+
end
|
|
156
|
+
cur
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def padd(f, g) = Array.new([f.size, g.size].max) { |i| Scalar.add(f[i] || num(0), g[i] || num(0)) }
|
|
160
|
+
def pscale(f, c) = f.map { |a| Scalar.mul(a, c) }
|
|
161
|
+
def pshift(f, k = 1) = Array.new(k, num(0)) + f
|
|
162
|
+
def scale(a, r) = Scalar.mul(a, num(r))
|
|
163
|
+
|
|
164
|
+
def pmul(f, g)
|
|
165
|
+
out = Array.new(f.size + g.size - 1) { num(0) }
|
|
166
|
+
f.each_with_index do |a, i|
|
|
167
|
+
next if a.is_a?(Num) && a.value.zero?
|
|
168
|
+
g.each_with_index { |b, j| out[i + j] = Scalar.add(out[i + j], Scalar.mul(a, b)) }
|
|
169
|
+
end
|
|
170
|
+
out
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def ppow(f, k) = k.zero? ? [num(1)] : (2..k).reduce(f) { |acc, _| pmul(acc, f) }
|
|
174
|
+
|
|
175
|
+
# The coefficient list as an expanded expression in x.
|
|
176
|
+
def build(coeffs, x)
|
|
177
|
+
v = Expression.lift(x)
|
|
178
|
+
terms = coeffs.each_with_index.reject { |c, _| c.is_a?(Num) && c.value.zero? }
|
|
179
|
+
return num(0) if terms.empty?
|
|
180
|
+
sum = terms.map { |c, i| i.zero? ? c : c * v**i }.reduce(:+)
|
|
181
|
+
sum.variables.empty? ? sum.simplify : sum.expand
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def degree(n, name)
|
|
185
|
+
n = n.value if n.is_a?(Num)
|
|
186
|
+
raise ArgumentError, "#{name}: the degree must be a non-negative integer, got #{n}" unless n.is_a?(Integer) && !n.negative?
|
|
187
|
+
n
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# binomial(u, k) with an integer k as the polynomial u(u-1)...(u-k+1)/k!,
|
|
191
|
+
# so that a symbolic alpha survives into the coefficients.
|
|
192
|
+
def binomial_polynomial(u, k) = Combinatorics.expand_binomial(u, num(k))
|
|
193
|
+
|
|
194
|
+
# B_n(x) = sum(binomial(n, k)*B_(n-k)*x**k), with the Bernoulli numbers of summation.rb.
|
|
195
|
+
def bernoulli_coeffs(n)
|
|
196
|
+
(0..n).map { |k| num(Summation.bernoulli(n - k) * binomial_integer(n, k)) }
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def binomial_integer(n, k) = (0...k).reduce(1) { |acc, i| acc * (n - i) } / (1..k).reduce(1, :*)
|
|
200
|
+
|
|
201
|
+
# Stirling numbers of the second kind, S(n, k) for k = 0..n, by the
|
|
202
|
+
# recurrence S(n, k) = k*S(n-1, k) + S(n-1, k-1).
|
|
203
|
+
def stirling2_row(n)
|
|
204
|
+
(1..n).reduce([1]) do |row, _|
|
|
205
|
+
Array.new(row.size + 1) { |k| (k * (row[k] || 0)) + (k.positive? ? row[k - 1] : 0) }
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# ---- cyclotomic and Swinnerton-Dyer, over the integers -------------------
|
|
210
|
+
|
|
211
|
+
@cyclotomic = {}
|
|
212
|
+
|
|
213
|
+
# x**n - 1 = product(Phi_d(x), d | n), so Phi_n is one exact division away.
|
|
214
|
+
def cyclotomic_coeffs(n)
|
|
215
|
+
@cyclotomic[n] ||= begin
|
|
216
|
+
numerator = Array.new(n + 1, 0)
|
|
217
|
+
numerator[0] = -1
|
|
218
|
+
numerator[n] = 1
|
|
219
|
+
divisors = (1...n).select { |d| (n % d).zero? }
|
|
220
|
+
divisors.reduce(numerator) { |acc, d| divide_exactly(acc, cyclotomic_coeffs(d)) }
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Division of integer coefficient lists, the divisor monic (it always is here).
|
|
225
|
+
def divide_exactly(f, g)
|
|
226
|
+
f = f.dup
|
|
227
|
+
quotient = Array.new(f.size - g.size + 1, 0)
|
|
228
|
+
(quotient.size - 1).downto(0) do |i|
|
|
229
|
+
c = f[i + g.size - 1]
|
|
230
|
+
quotient[i] = c
|
|
231
|
+
next if c.zero?
|
|
232
|
+
g.each_with_index { |b, j| f[i + j] -= c * b }
|
|
233
|
+
end
|
|
234
|
+
quotient
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def primes(n)
|
|
238
|
+
found = []
|
|
239
|
+
candidate = 2
|
|
240
|
+
while found.size < n
|
|
241
|
+
found << candidate
|
|
242
|
+
candidate = NumberTheory.nextprime(candidate)
|
|
243
|
+
end
|
|
244
|
+
found
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# f(x - sqrt(p))*f(x + sqrt(p)): writing f(x + s) = u(x) + s*v(x) with
|
|
248
|
+
# s**2 = p, the product is u**2 - p*v**2 and the radical is gone.
|
|
249
|
+
def conjugate_product(f, p)
|
|
250
|
+
u = Array.new(f.size, 0)
|
|
251
|
+
v = Array.new(f.size, 0)
|
|
252
|
+
f.each_with_index do |a, m|
|
|
253
|
+
next if a.zero?
|
|
254
|
+
(0..m).each do |j|
|
|
255
|
+
c = a * binomial_integer(m, j)
|
|
256
|
+
if j.even? then u[m - j] += c * p**(j / 2)
|
|
257
|
+
else v[m - j] += c * p**((j - 1) / 2)
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
square = multiply_integers(u, u)
|
|
262
|
+
correction = multiply_integers(v, v).map { |c| c * p }
|
|
263
|
+
Array.new(square.size) { |i| square[i] - (correction[i] || 0) }
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def multiply_integers(f, g)
|
|
267
|
+
out = Array.new(f.size + g.size - 1, 0)
|
|
268
|
+
f.each_with_index { |a, i| g.each_with_index { |b, j| out[i + j] += a * b } unless a.zero? }
|
|
269
|
+
out
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
Constants.const_set(:Poly, Poly)
|
|
274
|
+
end
|