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.
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,31 @@
1
+ require 'symath/value'
2
+ require 'symath/definition/operator'
3
+
4
+ module SyMath
5
+ class Definition::Flat < Definition::Operator
6
+ def initialize()
7
+ super(:flat)
8
+ end
9
+
10
+ def description()
11
+ return 'flat(f) - musical lower/flat/b 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.flat
17
+ end
18
+
19
+ def to_s(args = nil)
20
+ if !args
21
+ args = @args
22
+ end
23
+
24
+ return "b(#{args[0]})"
25
+ end
26
+
27
+ def latex_format()
28
+ return '%s^\flat'
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,197 @@
1
+ require 'symath/definition'
2
+
3
+ module SyMath
4
+ class Definition::Function < Definition::Operator
5
+ def self.init_builtin()
6
+ # Define the builtin functions
7
+ SyMath::Definition::Sqrt.new
8
+ SyMath::Definition::Sin.new
9
+ SyMath::Definition::Cos.new
10
+ SyMath::Definition::Tan.new
11
+ SyMath::Definition::Sec.new
12
+ SyMath::Definition::Csc.new
13
+ SyMath::Definition::Cot.new
14
+ SyMath::Definition::Arcsin.new
15
+ SyMath::Definition::Arccos.new
16
+ SyMath::Definition::Arctan.new
17
+ SyMath::Definition::Arcsec.new
18
+ SyMath::Definition::Arccsc.new
19
+ SyMath::Definition::Arccot.new
20
+ SyMath::Definition::Ln.new
21
+ SyMath::Definition::Exp.new
22
+ SyMath::Definition::Abs.new
23
+ SyMath::Definition::Fact.new
24
+
25
+ # Functions defined by an expression
26
+ expressions = [
27
+ { :name => 'sinh',
28
+ :exp => '(e**x - e**-x)/2',
29
+ :desc => 'hyperbolic sine',
30
+ },
31
+ { :name => 'cosh',
32
+ :exp => '(e**x + e**-x)/2',
33
+ :desc => 'hyperbolic cosine',
34
+ },
35
+ { :name => 'tanh',
36
+ :exp => '(e**x - e**-x)/(e**x + e**-x)',
37
+ :desc => 'hyperbolic tangent',
38
+ },
39
+ { :name => 'coth',
40
+ :exp => '(e**x + e**-x)/(e**x - e**-x)',
41
+ :desc => 'hyperbolic cotangent',
42
+ },
43
+ { :name => 'sech',
44
+ :exp => '2/(e**x + e**-x)',
45
+ :desc => 'hyperbolic secant',
46
+ },
47
+ { :name => 'csch',
48
+ :exp => '2/(e**x - e**-x)',
49
+ :desc => 'hyperbolic cosecant',
50
+ },
51
+ { :name => 'arsinh',
52
+ :exp => 'ln(x + sqrt(x**2 + 1))',
53
+ :desc => 'inverse hyperbolic sine',
54
+ },
55
+ { :name => 'arcosh',
56
+ :exp => 'ln(x + sqrt(x**2 - 1))',
57
+ :desc => 'inverse hyperbolic cosine',
58
+ },
59
+ { :name => 'artanh',
60
+ :exp => 'ln((1 + x)/(1 - x))/2',
61
+ :desc => 'inverse hyperbolic tangent',
62
+ },
63
+ { :name => 'arcoth',
64
+ :exp => 'ln((x + 1)/(x - 1))/2',
65
+ :desc => 'inverse hyperbolic cotangent',
66
+ },
67
+ { :name => 'arsech',
68
+ :exp => 'ln((1/x + sqrt(x**-2 - 1)))',
69
+ :desc => 'inverse hyperbolic secant',
70
+ },
71
+ { :name => 'arcsch',
72
+ :exp => 'ln((1/x + sqrt(x**-2 + 1)))',
73
+ :desc => 'inverse hyperbolic cosecant',
74
+ },
75
+ ]
76
+
77
+ expressions.each do |e|
78
+ self.new(e[:name], args: [:x], exp: e[:exp],
79
+ description: "#{e[:name]}(x) - #{e[:desc]}")
80
+ end
81
+ end
82
+
83
+ @@not_mentioned_funcs = {
84
+ :+ => true,
85
+ :- => true,
86
+ :* => true,
87
+ :/ => true,
88
+ :** => true,
89
+ :'=' => true,
90
+ }
91
+
92
+ def self.functions()
93
+ return self.definitions.select { |f|
94
+ f.is_function? and !@@not_mentioned_funcs[f.name]
95
+ }
96
+ end
97
+
98
+ @reductions = {}
99
+
100
+ def reduce_call(c, reductions = nil)
101
+ if reductions.nil?
102
+ reductions = @reductions
103
+ end
104
+
105
+ if reductions.has_key?(c.args[0])
106
+ return reductions[c.args[0]]
107
+ end
108
+
109
+ return c
110
+ end
111
+
112
+ # Check if expression is a constant fraction of pi and optionally
113
+ # i (imaginary unit)
114
+ def check_pi_fraction(e, im)
115
+ gotpi = false
116
+ gotim = !im
117
+ c = 1
118
+ dc = 1
119
+
120
+ # Check that factors are only constant, divisor constant and pi.
121
+ # Note: This code is similar to 'reduce_constant_factors'. Refactor?
122
+ e.factors.each do |f|
123
+ if f.is_divisor_factor?
124
+ if f.base.is_number?
125
+ dc *= f.base.value**f.exponent.argument.value
126
+ next
127
+ end
128
+ end
129
+
130
+ if f.is_negative_number?
131
+ c *= - f.argument.value
132
+ next
133
+ end
134
+
135
+ if f.is_number?
136
+ c *= f.value
137
+ next
138
+ end
139
+
140
+ if !gotpi and f == :pi
141
+ gotpi = true
142
+ next
143
+ end
144
+
145
+ if !gotim and f == :i
146
+ gotim = true
147
+ next
148
+ end
149
+
150
+ return nil
151
+ end
152
+
153
+ return nil if !gotpi and !gotim and c != 0
154
+
155
+ return c, dc
156
+ end
157
+
158
+ def is_function?()
159
+ return true
160
+ end
161
+
162
+ def latex_format()
163
+ return "#{name}(%s)"
164
+ end
165
+ end
166
+ end
167
+
168
+ def fn(f, *args)
169
+ return SyMath::Operator.create(f, args.map { |a| a.nil? ? a : a.to_m })
170
+ end
171
+
172
+ def define_fn(name, args, exp = nil)
173
+ if exp
174
+ return SyMath::Definition::Function.new(name, args: args, exp: exp)
175
+ else
176
+ return SyMath::Definition::Function.new(name, args: args)
177
+ end
178
+ end
179
+
180
+ require 'symath/definition/sin'
181
+ require 'symath/definition/cos'
182
+ require 'symath/definition/tan'
183
+ require 'symath/definition/sec'
184
+ require 'symath/definition/csc'
185
+ require 'symath/definition/cot'
186
+ require 'symath/definition/arcsin'
187
+ require 'symath/definition/arccos'
188
+ require 'symath/definition/arctan'
189
+ require 'symath/definition/arcsec'
190
+ require 'symath/definition/arccsc'
191
+ require 'symath/definition/arccot'
192
+ require 'symath/definition/ln'
193
+ require 'symath/definition/exp'
194
+ require 'symath/definition/abs'
195
+ require 'symath/definition/sqrt'
196
+ require 'symath/definition/fact'
197
+ require 'symath/definition/lmd'
@@ -0,0 +1,23 @@
1
+ require 'symath/value'
2
+ require 'symath/definition/operator'
3
+
4
+ module SyMath
5
+ class Definition::Grad < Definition::Operator
6
+ def initialize()
7
+ # Grad is defined as (dF)#
8
+ super(:grad, args: [:f], exp: '#(xd(f))')
9
+ end
10
+
11
+ def description()
12
+ return 'grad(f) - gradient of scalar field f'
13
+ end
14
+
15
+ def to_latex(args)
16
+ if !args
17
+ args = @args
18
+ end
19
+
20
+ return "\\nabla #{args[0].to_latex}"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'symath/value'
2
+ require 'symath/definition/operator'
3
+
4
+ module SyMath
5
+ class Definition::Hodge < Definition::Operator
6
+ def initialize()
7
+ super(:hodge)
8
+ end
9
+
10
+ def description()
11
+ return 'hodge(f) - hodge star 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.hodge
17
+ end
18
+
19
+ def latex_format()
20
+ return '\star %s'
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,75 @@
1
+ require 'symath/value'
2
+ require 'symath/definition/operator'
3
+
4
+ module SyMath
5
+ class Definition::Int < Definition::Operator
6
+ def initialize()
7
+ super(:int)
8
+ end
9
+
10
+ def description()
11
+ return 'int(f, a, b) - integral of f [from a to b]'
12
+ end
13
+
14
+ def validate_args(e)
15
+ a = e.args[1]
16
+ b = e.args[2]
17
+
18
+ if (!a.nil? and b.nil?) or (a.nil? and !b.nil?)
19
+ raise "A cannot be defined without b and vica versa."
20
+ end
21
+ end
22
+
23
+ def get_variable(exp)
24
+ if exp.is_a?(SyMath::Operator) and
25
+ exp.definition.is_function? and
26
+ exp.definition.args.length > 0
27
+ v = exp.definition.args[0]
28
+ else
29
+ v = (exp.variables)[0].to_m
30
+ end
31
+
32
+ return v.to_d
33
+ end
34
+
35
+ def evaluate_call(c)
36
+ exp = c.args[0]
37
+ var = get_variable(exp)
38
+ a = c.args[1]
39
+ b = c.args[2]
40
+
41
+ exp = exp.evaluate
42
+
43
+ if a.nil?
44
+ ret = exp.normalize.anti_derivative(var)
45
+ return ret.nil? ? nil : ret + :C.to_m
46
+ else
47
+ int = exp.normalize.anti_derivative(var)
48
+ # TODO: Setting for evaluating the bounds expression?
49
+ return op(:bounds, lmd(int, var.undiff), a, b).evaluate
50
+ end
51
+ end
52
+
53
+ def to_latex(args)
54
+ if !args
55
+ args = @args
56
+ end
57
+
58
+ if args[0].is_sum_exp?
59
+ exp = "\\left(#{args[0].to_latex}\\right)"
60
+ else
61
+ exp = args[0].to_latex
62
+ end
63
+
64
+ var = get_variable(args[0])
65
+ a = args[1]
66
+ b = args[2]
67
+
68
+ if a.nil?
69
+ return "\\int #{exp}\\,#{var.to_latex}"
70
+ else
71
+ return "\\int_{#{a.to_latex}}^{#{b.to_latex}} #{exp}\\,#{var.to_latex}"
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,23 @@
1
+ require 'symath/value'
2
+ require 'symath/definition/operator'
3
+
4
+ module SyMath
5
+ class Definition::Laplacian < Definition::Operator
6
+ def initialize()
7
+ # The laplacian is defined as *d*dF
8
+ super(:laplacian, args: [:f], exp: 'hodge(xd(hodge(xd(f))))')
9
+ end
10
+
11
+ def description()
12
+ return 'laplacian(f) - laplacian of function f'
13
+ end
14
+
15
+ def to_latex(args)
16
+ if !args
17
+ args = @args
18
+ end
19
+
20
+ return "\\nabla^2 #{args[0].to_latex}"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,97 @@
1
+ require 'symath/value'
2
+ require 'symath/definition/function'
3
+
4
+ module SyMath
5
+ class Definition::Lmd < Definition::Function
6
+ def initialize(exp, *vars)
7
+ super('', args: vars, exp: exp, define_symbol: false)
8
+ end
9
+
10
+ def description()
11
+ return "{self.to_s} - Lambda function of expression #{exp}"
12
+ end
13
+
14
+ def compose_with_simplify(exp, vars)
15
+ vars.each do |v|
16
+ if !v.is_a?(SyMath::Definition::Variable)
17
+ raise "Expected variable, got #{v.class.name}"
18
+ end
19
+
20
+ if v.is_d?
21
+ raise "Var is not allowed to br differential, got #{v}"
22
+ end
23
+ end
24
+
25
+ # Simplify lmd(f(*args), *args) to f(*args)
26
+ if !exp.is_a?(SyMath::Operator)
27
+ return
28
+ end
29
+
30
+ if !exp.definition.is_function?
31
+ return
32
+ end
33
+
34
+ if exp.arity != vars.length
35
+ return
36
+ end
37
+
38
+ exp.args.each do |a|
39
+ if !a.is_a?(SyMath::Definition::Variable)
40
+ return
41
+ end
42
+
43
+ if a.is_d?
44
+ return
45
+ end
46
+ end
47
+
48
+ return exp
49
+ end
50
+
51
+ # Evaluate the operator definition
52
+ # FIXME: Is it right to evaluate the definition exp?
53
+ def evaluate()
54
+ if name == '' and !exp.nil?
55
+ e = exp.evaluate
56
+ return lmd(e, self.args)
57
+ end
58
+
59
+ return self
60
+ end
61
+
62
+ # For a lambda function, the call returns a function with a reference
63
+ # to our own lambda function definition.
64
+ def call(*args)
65
+ args = args.map { |a| a.nil? ? a : a.to_m }
66
+ return SyMath::Operator.new(self, args)
67
+ end
68
+
69
+ def reduce()
70
+ # FIXME: Reduce if lmd is just a wrapper around a function.
71
+ return self
72
+ end
73
+
74
+ def to_s(args = nil)
75
+ if !args
76
+ args = @args
77
+ end
78
+
79
+ if args.length > 0
80
+ arglist = args.map { |a| a.to_s }.join(',')
81
+ else
82
+ arglist = "..."
83
+ end
84
+
85
+ return "(#{exp}).(#{arglist})"
86
+ end
87
+
88
+ def latex_format()
89
+ return "(#{exp}).(%s)"
90
+ end
91
+ end
92
+ end
93
+
94
+ def lmd(exp, *args)
95
+ # Create a lamda (nameless) function.
96
+ return SyMath::Definition::Lmd.new(exp, *args)
97
+ end
@@ -0,0 +1,45 @@
1
+ require 'symath/definition/function'
2
+
3
+ module SyMath
4
+ class Definition::Ln < Definition::Function
5
+ def initialize()
6
+ super(:ln)
7
+
8
+ @reductions_real = {
9
+ 1.to_m => 0.to_m,
10
+ :e.to_m => 1.to_m,
11
+ 0.to_m => -:oo.to_m,
12
+ :oo.to_m => :oo.to_m,
13
+ }
14
+
15
+ @reductions_complex = {
16
+ 1.to_m => 0.to_m,
17
+ :e.to_m => 1.to_m,
18
+ -1.to_m => :pi.to_m*:i,
19
+ -:e.to_m => 1.to_m + :pi.to_m*:i,
20
+ :i.to_m => :pi.to_m*:i/2,
21
+ :e.to_m*:i => 1.to_m + :pi.to_m*:i/2,
22
+ -:i.to_m => -:pi.to_m*:i/2,
23
+ -:e.to_m*:i => 1.to_m - :pi.to_m*:i/2,
24
+ }
25
+ end
26
+
27
+ def description()
28
+ return 'ln(x) - natural logarithm'
29
+ end
30
+
31
+ def reduce_call(c)
32
+ arg = c.args[0]
33
+
34
+ if SyMath.setting(:complex_arithmetic)
35
+ return super(c, @reductions_complex)
36
+ else
37
+ if arg.is_a?(SyMath::Minus)
38
+ return :nan.to_m
39
+ end
40
+
41
+ return super(c, @reductions_real)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,51 @@
1
+ require 'symath/definition'
2
+
3
+ module SyMath
4
+ class Definition::Number < Definition
5
+ def initialize(name)
6
+ super(name.to_s, define_symbol: false)
7
+ end
8
+
9
+ def description()
10
+ return "#{name} - natural number"
11
+ end
12
+
13
+ def value()
14
+ return self.name.to_s.to_i
15
+ end
16
+
17
+ def is_nan?()
18
+ return false
19
+ end
20
+
21
+ def is_finite?()
22
+ return true
23
+ end
24
+
25
+ def is_positive?()
26
+ return value() > 0
27
+ end
28
+
29
+ def is_number?()
30
+ return true
31
+ end
32
+
33
+ def is_zero?()
34
+ return value() == 0
35
+ end
36
+
37
+ def type()
38
+ return :natural.to_t
39
+ end
40
+ end
41
+ end
42
+
43
+ class Integer
44
+ def to_m()
45
+ if self < 0
46
+ return SyMath::Definition::Number.new(-self).neg
47
+ else
48
+ return SyMath::Definition::Number.new(self)
49
+ end
50
+ end
51
+ end