symath 0.1.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/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +616 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/symath/definition/abs.rb +48 -0
- data/lib/symath/definition/arccos.rb +25 -0
- data/lib/symath/definition/arccot.rb +23 -0
- data/lib/symath/definition/arccsc.rb +24 -0
- data/lib/symath/definition/arcsec.rb +24 -0
- data/lib/symath/definition/arcsin.rb +25 -0
- data/lib/symath/definition/arctan.rb +23 -0
- data/lib/symath/definition/bounds.rb +39 -0
- data/lib/symath/definition/codiff.rb +31 -0
- data/lib/symath/definition/constant.rb +111 -0
- data/lib/symath/definition/cos.rb +17 -0
- data/lib/symath/definition/cot.rb +17 -0
- data/lib/symath/definition/csc.rb +17 -0
- data/lib/symath/definition/curl.rb +27 -0
- data/lib/symath/definition/d.rb +62 -0
- data/lib/symath/definition/div.rb +27 -0
- data/lib/symath/definition/exp.rb +112 -0
- data/lib/symath/definition/fact.rb +55 -0
- data/lib/symath/definition/flat.rb +31 -0
- data/lib/symath/definition/function.rb +197 -0
- data/lib/symath/definition/grad.rb +23 -0
- data/lib/symath/definition/hodge.rb +23 -0
- data/lib/symath/definition/int.rb +75 -0
- data/lib/symath/definition/laplacian.rb +23 -0
- data/lib/symath/definition/lmd.rb +97 -0
- data/lib/symath/definition/ln.rb +45 -0
- data/lib/symath/definition/number.rb +51 -0
- data/lib/symath/definition/operator.rb +228 -0
- data/lib/symath/definition/sec.rb +17 -0
- data/lib/symath/definition/sharp.rb +31 -0
- data/lib/symath/definition/sin.rb +17 -0
- data/lib/symath/definition/sqrt.rb +62 -0
- data/lib/symath/definition/tan.rb +17 -0
- data/lib/symath/definition/trig.rb +95 -0
- data/lib/symath/definition/variable.rb +284 -0
- data/lib/symath/definition/xd.rb +28 -0
- data/lib/symath/definition.rb +205 -0
- data/lib/symath/equation.rb +67 -0
- data/lib/symath/fraction.rb +177 -0
- data/lib/symath/matrix.rb +252 -0
- data/lib/symath/minus.rb +125 -0
- data/lib/symath/operation/differential.rb +167 -0
- data/lib/symath/operation/distributivelaw.rb +367 -0
- data/lib/symath/operation/exterior.rb +64 -0
- data/lib/symath/operation/integration.rb +329 -0
- data/lib/symath/operation/match.rb +166 -0
- data/lib/symath/operation/normalization.rb +458 -0
- data/lib/symath/operation.rb +36 -0
- data/lib/symath/operator.rb +163 -0
- data/lib/symath/parser.rb +473 -0
- data/lib/symath/parser.y +129 -0
- data/lib/symath/poly/dup.rb +835 -0
- data/lib/symath/poly/galois.rb +621 -0
- data/lib/symath/poly.rb +142 -0
- data/lib/symath/power.rb +224 -0
- data/lib/symath/product.rb +183 -0
- data/lib/symath/sum.rb +174 -0
- data/lib/symath/type.rb +282 -0
- data/lib/symath/value.rb +372 -0
- data/lib/symath/version.rb +3 -0
- data/lib/symath/wedge.rb +48 -0
- data/lib/symath.rb +157 -0
- data/symath.gemspec +39 -0
- metadata +160 -0
@@ -0,0 +1,228 @@
|
|
1
|
+
require 'symath/definition'
|
2
|
+
|
3
|
+
module SyMath
|
4
|
+
class Definition::Operator < Definition
|
5
|
+
attr_reader :args
|
6
|
+
attr_reader :exp
|
7
|
+
|
8
|
+
def self.init_builtin()
|
9
|
+
SyMath::Definition::D.new
|
10
|
+
SyMath::Definition::Xd.new
|
11
|
+
SyMath::Definition::Int.new
|
12
|
+
SyMath::Definition::Bounds.new
|
13
|
+
SyMath::Definition::Sharp.new
|
14
|
+
SyMath::Definition::Flat.new
|
15
|
+
SyMath::Definition::Hodge.new
|
16
|
+
SyMath::Definition::Grad.new
|
17
|
+
SyMath::Definition::Curl.new
|
18
|
+
SyMath::Definition::Div.new
|
19
|
+
SyMath::Definition::Laplacian.new
|
20
|
+
SyMath::Definition::CoDiff.new
|
21
|
+
|
22
|
+
expressions = [
|
23
|
+
{ :name => 'laplace',
|
24
|
+
:exp => 'lmd(int(f.(t)*e**(-s*t),d(t),0,oo),s)',
|
25
|
+
:desc => 'laplace transform',
|
26
|
+
},
|
27
|
+
{ :name => 'fourier',
|
28
|
+
:exp => 'lmd(int(f.(x)*e**(-2*pi*i*x*w),d(x),-oo,oo),w)',
|
29
|
+
:desc => 'fourier transform',
|
30
|
+
},
|
31
|
+
{ :name => 'invfourier',
|
32
|
+
:exp => 'lmd(int(f.(w)*e**(2*pi*i*x*w),d(w),-oo,oo),x)',
|
33
|
+
:desc => 'inverse fourier transform',
|
34
|
+
},
|
35
|
+
]
|
36
|
+
|
37
|
+
expressions.each do |e|
|
38
|
+
self.new(e[:name], args: [:f], exp: e[:exp],
|
39
|
+
description: "#{e[:name]}(f) - #{e[:desc]}")
|
40
|
+
end
|
41
|
+
|
42
|
+
e = op(:d, lmd(:f, :t))/op(:d, :t)
|
43
|
+
self.new('dpart', args: [:f, :t], exp: e,
|
44
|
+
description: 'dpart - partial derivative')
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.operators()
|
48
|
+
return self.definitions.select do |d|
|
49
|
+
d.is_operator? and !d.is_function?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize(name, args: [], exp: nil, define_symbol: true,
|
54
|
+
description: nil)
|
55
|
+
if exp and !exp.is_a?(SyMath::Value)
|
56
|
+
exp = exp.to_m
|
57
|
+
end
|
58
|
+
|
59
|
+
@args = args.map { |a| a.to_m }
|
60
|
+
@exp = exp
|
61
|
+
|
62
|
+
super(name, define_symbol: define_symbol, description: description)
|
63
|
+
end
|
64
|
+
|
65
|
+
def compose_with_simplify(*args)
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_args(e)
|
70
|
+
return
|
71
|
+
end
|
72
|
+
|
73
|
+
def arity()
|
74
|
+
return @args.length
|
75
|
+
end
|
76
|
+
|
77
|
+
def ==(other)
|
78
|
+
if !super(other)
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
|
82
|
+
o = other.to_m
|
83
|
+
return false if self.args.length != o.args.length
|
84
|
+
return false if self.exp != o.exp
|
85
|
+
return false if self.args != o.args
|
86
|
+
return true
|
87
|
+
end
|
88
|
+
|
89
|
+
alias eql? ==
|
90
|
+
|
91
|
+
def <=>(other)
|
92
|
+
s = super(other)
|
93
|
+
return s if s != 0
|
94
|
+
|
95
|
+
if arity != other.arity
|
96
|
+
return arity <=> other.arity
|
97
|
+
end
|
98
|
+
|
99
|
+
(0...arity).to_a.each do |i|
|
100
|
+
diff = args[i] <=> other.args[i]
|
101
|
+
if diff != 0
|
102
|
+
return diff
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
return 0
|
107
|
+
end
|
108
|
+
|
109
|
+
# The call method, or the .() operator, returns an operator or function
|
110
|
+
# object representing the operator or function being applied to a list of
|
111
|
+
# arguments.
|
112
|
+
def call(*args)
|
113
|
+
return SyMath::Operator.create(name, args.map { |a| a.nil? ? a : a.to_m })
|
114
|
+
end
|
115
|
+
|
116
|
+
def is_operator?()
|
117
|
+
return true
|
118
|
+
end
|
119
|
+
|
120
|
+
# Evaluate the operator in use
|
121
|
+
def evaluate_call(c)
|
122
|
+
if !exp
|
123
|
+
# Operator has no expression, return it unchanged.
|
124
|
+
return c
|
125
|
+
end
|
126
|
+
|
127
|
+
# Operator has expression. Exand it.
|
128
|
+
res = exp.deep_clone
|
129
|
+
if arity != c.arity
|
130
|
+
raise "Cannot evaluate #{name} with #{c.arity} arguments. Expected #{arity}."
|
131
|
+
end
|
132
|
+
|
133
|
+
map = {}
|
134
|
+
args.each_with_index do |a, i|
|
135
|
+
map[a] = c.args[i]
|
136
|
+
end
|
137
|
+
res.replace(map)
|
138
|
+
|
139
|
+
# Recursively evaluate the expanded formula.
|
140
|
+
res = res.evaluate
|
141
|
+
return res
|
142
|
+
end
|
143
|
+
|
144
|
+
def replace(map)
|
145
|
+
# FIXME: We probably need to filter out the local variables before
|
146
|
+
# replacing
|
147
|
+
if !exp.nil?
|
148
|
+
@exp = exp.replace(map)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Replace all arguments
|
152
|
+
@args = @args.map do |a|
|
153
|
+
a.replace(map)
|
154
|
+
end
|
155
|
+
|
156
|
+
return self
|
157
|
+
end
|
158
|
+
|
159
|
+
def to_s(args = nil)
|
160
|
+
if !args
|
161
|
+
args = @args
|
162
|
+
end
|
163
|
+
|
164
|
+
if args.length > 0
|
165
|
+
arglist = args.map { |a| a.to_s }.join(',')
|
166
|
+
else
|
167
|
+
arglist = "..."
|
168
|
+
end
|
169
|
+
|
170
|
+
return "#{@name}(#{arglist})"
|
171
|
+
end
|
172
|
+
|
173
|
+
def latex_format()
|
174
|
+
return "\\operatorname{#{name}}(%s)"
|
175
|
+
end
|
176
|
+
|
177
|
+
def to_latex(args = nil)
|
178
|
+
if !args
|
179
|
+
args = @args
|
180
|
+
end
|
181
|
+
|
182
|
+
if args.length > 0
|
183
|
+
arglist = args.map { |a| a.to_latex }.join(',')
|
184
|
+
else
|
185
|
+
arglist = "..."
|
186
|
+
end
|
187
|
+
|
188
|
+
return sprintf(latex_format, arglist)
|
189
|
+
end
|
190
|
+
|
191
|
+
def dump(indent = 0)
|
192
|
+
res = super(indent)
|
193
|
+
i = ' '*indent
|
194
|
+
if args
|
195
|
+
arglist = args.map { |a| a.to_s }.join(',')
|
196
|
+
res = "#{res}\n#{i} args: #{arglist}"
|
197
|
+
end
|
198
|
+
if exp
|
199
|
+
res = "#{res}\n#{i} exp: #{exp}"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def op(o, *args)
|
206
|
+
return SyMath::Operator.create(o, args.map { |a| a.nil? ? a : a.to_m })
|
207
|
+
end
|
208
|
+
|
209
|
+
def define_op(name, args, exp = nil)
|
210
|
+
if exp
|
211
|
+
return SyMath::Definition::Operator.new(name, args: args, exp: exp)
|
212
|
+
else
|
213
|
+
return SyMath::Definition::Operator.new(name, args: args)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
require 'symath/definition/d'
|
218
|
+
require 'symath/definition/xd'
|
219
|
+
require 'symath/definition/int'
|
220
|
+
require 'symath/definition/bounds'
|
221
|
+
require 'symath/definition/sharp'
|
222
|
+
require 'symath/definition/flat'
|
223
|
+
require 'symath/definition/hodge'
|
224
|
+
require 'symath/definition/grad'
|
225
|
+
require 'symath/definition/curl'
|
226
|
+
require 'symath/definition/div'
|
227
|
+
require 'symath/definition/laplacian'
|
228
|
+
require 'symath/definition/codiff'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'symath/definition/trig'
|
2
|
+
|
3
|
+
module SyMath
|
4
|
+
class Definition::Sec < Definition::Trig
|
5
|
+
def initialize()
|
6
|
+
super(:sec)
|
7
|
+
end
|
8
|
+
|
9
|
+
def description()
|
10
|
+
return 'sec(x) - trigonometric secant'
|
11
|
+
end
|
12
|
+
|
13
|
+
def reduce_call(c)
|
14
|
+
return reduce_sec_and_csc(c, 0)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'symath/value'
|
2
|
+
require 'symath/definition/operator'
|
3
|
+
|
4
|
+
module SyMath
|
5
|
+
class Definition::Sharp < Definition::Operator
|
6
|
+
def initialize()
|
7
|
+
super(:sharp)
|
8
|
+
end
|
9
|
+
|
10
|
+
def description()
|
11
|
+
return 'sharp(f) - musical raise/sharp/# isomorphic operator'
|
12
|
+
end
|
13
|
+
|
14
|
+
def evaluate_call(c)
|
15
|
+
# Must normalize input, operation depends on factorized vectors
|
16
|
+
return c.args[0].evaluate.normalize.sharp
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s(args = nil)
|
20
|
+
if !args
|
21
|
+
args = @args
|
22
|
+
end
|
23
|
+
|
24
|
+
return "\#(#{args[0]})"
|
25
|
+
end
|
26
|
+
|
27
|
+
def latex_format()
|
28
|
+
return '%s^\sharp'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'symath/definition/trig'
|
2
|
+
|
3
|
+
module SyMath
|
4
|
+
class Definition::Sin < Definition::Trig
|
5
|
+
def initialize()
|
6
|
+
super(:sin)
|
7
|
+
end
|
8
|
+
|
9
|
+
def description()
|
10
|
+
return 'sin(x) - trigonometric sine'
|
11
|
+
end
|
12
|
+
|
13
|
+
def reduce_call(c)
|
14
|
+
return reduce_sin_and_cos(c, 0)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'symath/definition/function'
|
2
|
+
|
3
|
+
module SyMath
|
4
|
+
class Definition::Sqrt < Definition::Function
|
5
|
+
def initialize()
|
6
|
+
super(:sqrt)
|
7
|
+
end
|
8
|
+
|
9
|
+
def description()
|
10
|
+
return 'sqrt(x) - square root'
|
11
|
+
end
|
12
|
+
|
13
|
+
def reduce_call(call)
|
14
|
+
arg = call.args[0]
|
15
|
+
i = 1.to_m
|
16
|
+
|
17
|
+
# Real: sqrt(-n) = NaN
|
18
|
+
# Complex: sqrt(-n) = i*sqrt(n)
|
19
|
+
if arg.is_a?(SyMath::Minus)
|
20
|
+
if SyMath.setting(:complex_arithmetic)
|
21
|
+
i = :i.to_m
|
22
|
+
arg = -arg
|
23
|
+
else
|
24
|
+
return :nan.to_m
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if arg.is_number?
|
29
|
+
# sqrt(n*n) = n
|
30
|
+
# sqrt(-n*n) = i*n
|
31
|
+
if (Math.sqrt(arg.value) % 1).zero?
|
32
|
+
return i*Math.sqrt(arg.value).to_i
|
33
|
+
end
|
34
|
+
elsif arg.is_a?(SyMath::Power)
|
35
|
+
# sqrt(n**(2*a)) = n^a
|
36
|
+
# sqrt(-n**(2*a)) = i*n**a
|
37
|
+
|
38
|
+
# Find coefficient of exponent
|
39
|
+
c = 1
|
40
|
+
arg.exponent.factors.each do |ef|
|
41
|
+
if ef.is_number?
|
42
|
+
c *= ef.value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
if c.even?
|
47
|
+
return i*arg.base**(arg.exponent/2)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if i != 1
|
52
|
+
return i*fn(:sqrt, arg)
|
53
|
+
else
|
54
|
+
return call
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_latex(args = nil)
|
59
|
+
return '\sqrt{'.to_s + args[0].to_latex + '}'.to_s
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'symath/definition/trig'
|
2
|
+
|
3
|
+
module SyMath
|
4
|
+
class Definition::Tan < Definition::Trig
|
5
|
+
def initialize()
|
6
|
+
super(:tan)
|
7
|
+
end
|
8
|
+
|
9
|
+
def description()
|
10
|
+
return 'tan(x) - trigonometric tangent'
|
11
|
+
end
|
12
|
+
|
13
|
+
def reduce_call(c)
|
14
|
+
return reduce_tan_and_cot(c, 0, 1)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'symath/definition/function'
|
2
|
+
|
3
|
+
module SyMath
|
4
|
+
class Definition::Trig < Definition::Function
|
5
|
+
@@trig_reductions = {}
|
6
|
+
|
7
|
+
def self.initialize()
|
8
|
+
sqrt3 = fn(:sqrt, 3)
|
9
|
+
sqrt2 = fn(:sqrt, 2)
|
10
|
+
|
11
|
+
@@trig_reductions = {
|
12
|
+
:sin_div6 => [ 0.to_m, 1.to_m/2, sqrt3/2,
|
13
|
+
1.to_m, sqrt3/2, 1.to_m/2,
|
14
|
+
0.to_m, -(1.to_m/2), -(sqrt3/2),
|
15
|
+
-1.to_m, -(sqrt3/2), -(1.to_m/2)],
|
16
|
+
|
17
|
+
:sin_div4 => [ 0.to_m, sqrt2/2,
|
18
|
+
1.to_m, sqrt2/2,
|
19
|
+
0.to_m, -(sqrt2/2),
|
20
|
+
-1.to_m, -(sqrt2/2)],
|
21
|
+
|
22
|
+
:sec_div6 => [ 1.to_m, 2.to_m*sqrt3/3, 2.to_m,
|
23
|
+
nil, -2.to_m, -(2.to_m*sqrt3/2),
|
24
|
+
-1.to_m, -(2.to_m*sqrt3/3), -2.to_m,
|
25
|
+
nil, 2.to_m, 2.to_m*sqrt3/3],
|
26
|
+
|
27
|
+
:sec_div4 => [ 1.to_m, sqrt2/2,
|
28
|
+
nil, -(sqrt2/2),
|
29
|
+
-1.to_m, -(sqrt2/2),
|
30
|
+
nil, sqrt2/2],
|
31
|
+
|
32
|
+
:tan_div6 => [0.to_m, sqrt3/3, sqrt3,
|
33
|
+
nil, -sqrt3, -(sqrt3/3)],
|
34
|
+
|
35
|
+
:tan_div4 => [0.to_m, 1.to_m,
|
36
|
+
nil, -1.to_m],
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def reduce_sin_and_cos(f, off)
|
41
|
+
c, dc = check_pi_fraction(f.args[0], false)
|
42
|
+
return f if c.nil?
|
43
|
+
|
44
|
+
# Divisor is divisible by 6
|
45
|
+
if 6 % dc == 0
|
46
|
+
return @@trig_reductions[:sin_div6][(off*3 + c*6/dc) % 12]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Divisor is divisible by 4
|
50
|
+
if 4 % dc == 0
|
51
|
+
return @@trig_reductions[:sin_div4][(off*2 + c*4/dc) % 8]
|
52
|
+
end
|
53
|
+
|
54
|
+
return f
|
55
|
+
end
|
56
|
+
|
57
|
+
def reduce_tan_and_cot(f, off, sign)
|
58
|
+
c, dc = check_pi_fraction(f.args[0], false)
|
59
|
+
return f if c.nil?
|
60
|
+
|
61
|
+
# Divisor is divisible by 6
|
62
|
+
if 6 % dc == 0
|
63
|
+
ret = @@trig_reductions[:tan_div6][(off*3 + sign*c*6/dc) % 6]
|
64
|
+
return ret.nil? ? f : ret
|
65
|
+
end
|
66
|
+
|
67
|
+
# Divisor is divisible by 4
|
68
|
+
if 4 % dc == 0
|
69
|
+
ret = @@trig_reductions[:tan_div4][(off*2 + sign*c*4/dc) % 4]
|
70
|
+
return ret.nil? ? f : ret
|
71
|
+
end
|
72
|
+
|
73
|
+
return f
|
74
|
+
end
|
75
|
+
|
76
|
+
def reduce_sec_and_csc(f, off)
|
77
|
+
c, dc = check_pi_fraction(f.args[0], false)
|
78
|
+
return f if c.nil?
|
79
|
+
|
80
|
+
# Divisor is divisible by 6
|
81
|
+
if 6 % dc == 0
|
82
|
+
ret = @@trig_reductions[:sec_div6][(off*3 + c*6/dc) % 12]
|
83
|
+
return ret.nil? ? f : ret
|
84
|
+
end
|
85
|
+
|
86
|
+
# Divisor is divisible by 4
|
87
|
+
if 4 % dc == 0
|
88
|
+
ret = @@trig_reductions[:sec_div4][(off*2 + c*4/dc) % 8]
|
89
|
+
return ret.nil? ? f : ret
|
90
|
+
end
|
91
|
+
|
92
|
+
return f
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|