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,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RCAS
|
|
4
|
+
# Rational-function normalisation: one numerator over one denominator with
|
|
5
|
+
# the polynomial gcd cancelled.
|
|
6
|
+
#
|
|
7
|
+
# (1/(a**2*(-1 - 1/a)) + 1/a).cancel # => 1/(1 + a)
|
|
8
|
+
# ((:x**2 - 1)/(:x - 1)).cancel # => 1 + x
|
|
9
|
+
module Fraction
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# => [numerator, denominator] as Polynomials over QQ in all variables, or
|
|
13
|
+
# nil when the expression is not a rational function with rational
|
|
14
|
+
# coefficients.
|
|
15
|
+
def as_fraction(expr, vars = nil)
|
|
16
|
+
vars = (vars || []) | expr.variables
|
|
17
|
+
return nil if vars.empty?
|
|
18
|
+
ring = QQ[*vars]
|
|
19
|
+
constant, table = Expand.table(expr)
|
|
20
|
+
return nil unless rational?(constant)
|
|
21
|
+
# Terms with the same denominator are added over it first, and the
|
|
22
|
+
# groups are then brought together over the lcm of their
|
|
23
|
+
# denominators: multiplying every term's denominator into the running
|
|
24
|
+
# one turned (x + y + 1)**12 expanded over x + y + 1 into a
|
|
25
|
+
# denominator of degree 91 and took nine seconds (third review,
|
|
26
|
+
# section 5).
|
|
27
|
+
groups = {}
|
|
28
|
+
groups[[]] = [ring.call(constant), ring.one]
|
|
29
|
+
table.each do |factors, coeff|
|
|
30
|
+
return nil unless rational?(coeff)
|
|
31
|
+
n = ring.call(coeff)
|
|
32
|
+
d = ring.one
|
|
33
|
+
key = []
|
|
34
|
+
factors.each do |base, exp|
|
|
35
|
+
return nil unless exp.is_a?(Integer)
|
|
36
|
+
bn, bd = begin
|
|
37
|
+
[ring.call(base), ring.one]
|
|
38
|
+
rescue DomainError
|
|
39
|
+
return nil unless base.is_a?(Add) || base.is_a?(Sub) # nested fraction inside a sum
|
|
40
|
+
inner = as_fraction(base) or return nil
|
|
41
|
+
inner.map { |q| q.to_ring(ring) }
|
|
42
|
+
end
|
|
43
|
+
if exp.positive?
|
|
44
|
+
n *= bn**exp
|
|
45
|
+
d *= bd**exp
|
|
46
|
+
key << [base, :up, exp] unless bd.constant?
|
|
47
|
+
else
|
|
48
|
+
n *= bd**(-exp)
|
|
49
|
+
d *= bn**(-exp)
|
|
50
|
+
key << [base, exp]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
key = key.sort_by(&:to_s)
|
|
54
|
+
if (group = groups[key])
|
|
55
|
+
group[0] = group[0] + n
|
|
56
|
+
else
|
|
57
|
+
groups[key] = [n, d]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
num = ring.zero
|
|
61
|
+
den = ring.one
|
|
62
|
+
groups.each_value do |n, d|
|
|
63
|
+
next if n.zero?
|
|
64
|
+
common = den.lcm(d)
|
|
65
|
+
num = num * common.exact_div(den) + n * common.exact_div(d)
|
|
66
|
+
den = common
|
|
67
|
+
end
|
|
68
|
+
g = num.gcd(den)
|
|
69
|
+
[num.exact_div(g), den.exact_div(g)]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def cancel(expr)
|
|
73
|
+
pair = as_fraction(expr) or return expr.simplify
|
|
74
|
+
num, den = pair
|
|
75
|
+
lc = den.leading_coefficient
|
|
76
|
+
num *= Scalar.div(Num.new(1), lc)
|
|
77
|
+
den = den.monic
|
|
78
|
+
(den.constant? ? num.to_expr : num.to_expr / den.to_expr).simplify
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def rational?(v) = v.is_a?(Integer) || v.is_a?(Rational)
|
|
82
|
+
|
|
83
|
+
# Clear square roots from denominators: 1/(1 + sqrt(2)) => -1 + sqrt(2).
|
|
84
|
+
# Handles denominators that are sums of a rational and one surd term.
|
|
85
|
+
def rationalize(expr)
|
|
86
|
+
if (exact = Algebraic.exact(expr))
|
|
87
|
+
return exact.to_expr.simplify
|
|
88
|
+
end
|
|
89
|
+
_, table = Expand.table(expr)
|
|
90
|
+
surd_denominators = table.each_key.flat_map do |factors|
|
|
91
|
+
factors.select { |base, exp| exp.is_a?(Integer) && exp.negative? && surd_sum?(base) }.map(&:first)
|
|
92
|
+
end.uniq
|
|
93
|
+
return expr.simplify if surd_denominators.empty?
|
|
94
|
+
result = expr
|
|
95
|
+
surd_denominators.each do |den|
|
|
96
|
+
conj = conjugate(den)
|
|
97
|
+
norm = (den * conj).expand
|
|
98
|
+
return expr.simplify unless norm.is_a?(Num) && !norm.zero?
|
|
99
|
+
constant, table = Expand.table(result)
|
|
100
|
+
result = Num.new(constant)
|
|
101
|
+
table.each do |factors, coeff|
|
|
102
|
+
e = factors[den]
|
|
103
|
+
if e.is_a?(Integer) && e.negative?
|
|
104
|
+
k = -e
|
|
105
|
+
rest = factors.reject { |b, _| b == den }
|
|
106
|
+
result += (Simplify.rebuild_product(coeff.quo(norm.value**k), rest) * conj**k).expand
|
|
107
|
+
else
|
|
108
|
+
result += Simplify.rebuild_product(coeff, factors)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
result.simplify
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def surd_sum?(base)
|
|
116
|
+
return false unless base.is_a?(Add) || base.is_a?(Sub)
|
|
117
|
+
constant, terms = Simplify.termize(base)
|
|
118
|
+
terms.size == 1 && terms.each_key.all? { |f| f.all? { |b, e| b.is_a?(Num) && e.is_a?(Rational) } } && (constant.is_a?(Integer) || constant.is_a?(Rational))
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def conjugate(base)
|
|
122
|
+
constant, terms = Simplify.termize(base)
|
|
123
|
+
Simplify.rebuild_sum(constant, terms.transform_values { |c| -c })
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|