symath 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +8 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +616 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/lib/symath/definition/abs.rb +48 -0
  13. data/lib/symath/definition/arccos.rb +25 -0
  14. data/lib/symath/definition/arccot.rb +23 -0
  15. data/lib/symath/definition/arccsc.rb +24 -0
  16. data/lib/symath/definition/arcsec.rb +24 -0
  17. data/lib/symath/definition/arcsin.rb +25 -0
  18. data/lib/symath/definition/arctan.rb +23 -0
  19. data/lib/symath/definition/bounds.rb +39 -0
  20. data/lib/symath/definition/codiff.rb +31 -0
  21. data/lib/symath/definition/constant.rb +111 -0
  22. data/lib/symath/definition/cos.rb +17 -0
  23. data/lib/symath/definition/cot.rb +17 -0
  24. data/lib/symath/definition/csc.rb +17 -0
  25. data/lib/symath/definition/curl.rb +27 -0
  26. data/lib/symath/definition/d.rb +62 -0
  27. data/lib/symath/definition/div.rb +27 -0
  28. data/lib/symath/definition/exp.rb +112 -0
  29. data/lib/symath/definition/fact.rb +55 -0
  30. data/lib/symath/definition/flat.rb +31 -0
  31. data/lib/symath/definition/function.rb +197 -0
  32. data/lib/symath/definition/grad.rb +23 -0
  33. data/lib/symath/definition/hodge.rb +23 -0
  34. data/lib/symath/definition/int.rb +75 -0
  35. data/lib/symath/definition/laplacian.rb +23 -0
  36. data/lib/symath/definition/lmd.rb +97 -0
  37. data/lib/symath/definition/ln.rb +45 -0
  38. data/lib/symath/definition/number.rb +51 -0
  39. data/lib/symath/definition/operator.rb +228 -0
  40. data/lib/symath/definition/sec.rb +17 -0
  41. data/lib/symath/definition/sharp.rb +31 -0
  42. data/lib/symath/definition/sin.rb +17 -0
  43. data/lib/symath/definition/sqrt.rb +62 -0
  44. data/lib/symath/definition/tan.rb +17 -0
  45. data/lib/symath/definition/trig.rb +95 -0
  46. data/lib/symath/definition/variable.rb +284 -0
  47. data/lib/symath/definition/xd.rb +28 -0
  48. data/lib/symath/definition.rb +205 -0
  49. data/lib/symath/equation.rb +67 -0
  50. data/lib/symath/fraction.rb +177 -0
  51. data/lib/symath/matrix.rb +252 -0
  52. data/lib/symath/minus.rb +125 -0
  53. data/lib/symath/operation/differential.rb +167 -0
  54. data/lib/symath/operation/distributivelaw.rb +367 -0
  55. data/lib/symath/operation/exterior.rb +64 -0
  56. data/lib/symath/operation/integration.rb +329 -0
  57. data/lib/symath/operation/match.rb +166 -0
  58. data/lib/symath/operation/normalization.rb +458 -0
  59. data/lib/symath/operation.rb +36 -0
  60. data/lib/symath/operator.rb +163 -0
  61. data/lib/symath/parser.rb +473 -0
  62. data/lib/symath/parser.y +129 -0
  63. data/lib/symath/poly/dup.rb +835 -0
  64. data/lib/symath/poly/galois.rb +621 -0
  65. data/lib/symath/poly.rb +142 -0
  66. data/lib/symath/power.rb +224 -0
  67. data/lib/symath/product.rb +183 -0
  68. data/lib/symath/sum.rb +174 -0
  69. data/lib/symath/type.rb +282 -0
  70. data/lib/symath/value.rb +372 -0
  71. data/lib/symath/version.rb +3 -0
  72. data/lib/symath/wedge.rb +48 -0
  73. data/lib/symath.rb +157 -0
  74. data/symath.gemspec +39 -0
  75. 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