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,142 @@
1
+ module SyMath
2
+ # Abstract base class for polynomial classes
3
+ class Poly
4
+ attr_reader :arr, :p, :var
5
+
6
+ # Transform polynomial back to expression form
7
+ def to_m()
8
+ if zero?
9
+ return 0.to_m
10
+ end
11
+
12
+ exp = 0.to_m
13
+ d = degree
14
+
15
+ (0..d).each do |i|
16
+ next if @arr[i] == 0
17
+
18
+ if d - i == 1
19
+ a = @var
20
+ elsif d - i == 0
21
+ a = 1.to_m
22
+ else
23
+ a = @var**(d - i)
24
+ end
25
+
26
+ exp += @arr[i].to_m*a
27
+ end
28
+
29
+ return exp
30
+ end
31
+
32
+ def strip!()
33
+ i = @arr.index { |e| e != 0 }
34
+ if i.nil?
35
+ @arr = []
36
+ else
37
+ @arr = @arr[i..-1]
38
+ end
39
+
40
+ return self
41
+ end
42
+
43
+ def zero?()
44
+ return @arr.empty?
45
+ end
46
+
47
+ # Return the degree of the highest power of the polynomial.
48
+ def degree()
49
+ # Hack: Degree of 0 should really be negative infinity
50
+ return -1 if zero?
51
+ return @arr.size - 1
52
+ end
53
+
54
+ def sort_factors(list)
55
+ return list.sort do |a, b|
56
+ [a.degree, a.arr] <=> [b.degree, b.arr]
57
+ end
58
+ end
59
+
60
+ def sort_factors_multiple(list)
61
+ return list.sort do |a, b|
62
+ [a[0].degree, a[1], a[0].arr] <=> [b[0].degree, b[1], b[0].arr]
63
+ end
64
+ end
65
+
66
+ def +(other)
67
+ if other.is_a?(self.class)
68
+ return add(other)
69
+ elsif other.is_a?(Integer)
70
+ return add_ground(other)
71
+ else
72
+ raise 'Cannot add ' + other.to_s
73
+ end
74
+ end
75
+
76
+ def -(other)
77
+ if other.is_a?(self.class)
78
+ return sub(other)
79
+ elsif other.is_a?(Integer)
80
+ return sub_ground(other)
81
+ else
82
+ raise 'Cannot subtract ' + other.to_s
83
+ end
84
+ end
85
+
86
+ def -@()
87
+ return neg
88
+ end
89
+
90
+ def *(other)
91
+ if other.is_a?(self.class)
92
+ return mul(other)
93
+ elsif other.is_a?(Integer)
94
+ return mul_ground(other)
95
+ else
96
+ raise 'Cannot multiply with ' + other.to_s
97
+ end
98
+ end
99
+
100
+ def /(other)
101
+ if other.is_a?(self.class)
102
+ return quo(other)
103
+ elsif other.is_a?(Integer)
104
+ return quo_ground(other)
105
+ else
106
+ raise 'Cannot divide by ' + other.to_s
107
+ end
108
+ end
109
+
110
+ def %(other)
111
+ if other.is_a?(self.class)
112
+ return rem(other)
113
+ elsif other.is_a?(Integer)
114
+ return trunc(other)
115
+ else
116
+ raise 'Cannot divide modulo ' + other.to_s
117
+ end
118
+ end
119
+
120
+ def **(other)
121
+ if other.is_a?(Integer) and other == 2
122
+ return sqr
123
+ else
124
+ raise 'Cannot raise to the power of ' + other.to_s
125
+ end
126
+ end
127
+
128
+ def [](i)
129
+ return arr[i]
130
+ end
131
+
132
+ def ==(other)
133
+ return (self.class == other.class and @arr == other.arr)
134
+ end
135
+
136
+ # Returns leading coefficient (i.e coefficient of the biggest power)
137
+ def lc()
138
+ return 0 if zero?
139
+ return @arr[0]
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,224 @@
1
+ require 'symath/operator'
2
+
3
+ module SyMath
4
+ class Power < Operator
5
+ def self.compose_with_simplify(a, b)
6
+ a = a.to_m
7
+ b = b.to_m
8
+
9
+ if a.is_finite?() == false or b.is_finite?() == false
10
+ return self.simplify_inf(a, b)
11
+ end
12
+
13
+ # 0**0 = NaN
14
+ if a.is_zero? and b.is_zero?
15
+ return :nan.to_m
16
+ end
17
+
18
+ # n**1 = n
19
+ if b == 1
20
+ return a
21
+ end
22
+
23
+ if a.is_a?(SyMath::Power)
24
+ return a.base**(a.exponent*b)
25
+ end
26
+
27
+ return self.new(a, b)
28
+ end
29
+
30
+ def self.simplify_inf(a, b)
31
+ # Indefinite factors
32
+ if a.is_finite?.nil? or b.is_finite?.nil?
33
+ return self.new(a, b)
34
+ end
35
+
36
+ # NaN**(..) = NaN, (..)**NaN = NaN
37
+ if a.is_nan? or b.is_nan?
38
+ return :nan.to_m
39
+ end
40
+
41
+ # 1**oo = 1**-oo = oo**0 = -oo**0 = NaN
42
+ if a == 1 or b.is_zero?
43
+ return :nan.to_m
44
+ end
45
+
46
+ if SyMath.setting(:complex_arithmetic)
47
+ if b.is_finite? == false
48
+ return :nan.to_m
49
+ else
50
+ return :oo.to_m
51
+ end
52
+ else
53
+ if a.is_zero? and b.is_finite? == false
54
+ return :nan.to_m
55
+ end
56
+
57
+ # n**-oo = oo**-oo = -oo**-oo = 0
58
+ if b.is_finite? == false and b.is_negative?
59
+ return 0.to_m
60
+ end
61
+
62
+ if a.is_finite? == false and a.is_negative?
63
+ if b.is_finite? == true
64
+ # -oo*n = oo*(-1**n)
65
+ return :oo.to_m.mul(a.sign**b)
66
+ else
67
+ # -oo**oo = NaN
68
+ return :nan.to_m
69
+ end
70
+ end
71
+
72
+ # -n**oo => NaN
73
+ if a.is_finite? and a.is_negative?
74
+ return :nan.to_m
75
+ end
76
+
77
+ # The only remaining possibilities:
78
+ # oo**n = n*oo = oo*oo = oo
79
+ return :oo.to_m
80
+ end
81
+ end
82
+
83
+ def initialize(base, exponent)
84
+ super('**', [base, exponent])
85
+ end
86
+
87
+ def base()
88
+ return @args[0]
89
+ end
90
+
91
+ def exponent()
92
+ return @args[1]
93
+ end
94
+
95
+ # Expression is on the form a**-n, n is a positive number
96
+ def is_divisor_factor?()
97
+ return exponent.is_negative_number?
98
+ end
99
+
100
+ # Simple reduction rules, allows sign to change. Returns
101
+ # (reduced exp, sign, changed).
102
+ def reduce_modulo_sign
103
+ # a to the power of 1 reduces to a
104
+ if exponent == 1
105
+ return base, 1, true
106
+ end
107
+
108
+ # Powers of 1 reduces to 1
109
+ if base == 1 and exponent.is_finite?
110
+ return base, 1, true
111
+ end
112
+
113
+ # Power of 0 reduces to 0
114
+ if base == 0 and exponent.is_finite? and exponent != 0
115
+ return 0.to_m, 1, true
116
+ end
117
+
118
+ if base != 0 and exponent == 0
119
+ return 1.to_m, 1, true
120
+ end
121
+
122
+ if base == :e
123
+ fn = fn(:exp, exponent)
124
+ # FIXME: Merge functions reduce and reduce_modulo_sign
125
+ red = fn.reduce
126
+ if red != fn
127
+ return red, 1, true
128
+ end
129
+ end
130
+
131
+ # Reduce negative number
132
+ if base.is_a?(SyMath::Minus)
133
+ if exponent.is_number?
134
+ exp = exponent
135
+ elsif exponent.is_negative_number?
136
+ exp = exponent.argument
137
+ else
138
+ exp = nil
139
+ end
140
+
141
+ if !exp.nil?
142
+ e, sign, changed = (base.argument**exp).reduce_modulo_sign
143
+ if exp.value.odd?
144
+ sign *= -1
145
+ end
146
+ return e, sign, true
147
+ end
148
+ end
149
+
150
+ # Number power of number reduces to number
151
+ if base.is_number?
152
+ if exponent.is_number?
153
+ return (base.value ** exponent.value).to_m, 1, true
154
+ end
155
+
156
+ if exponent.is_negative_number? and exponent.argument.value > 1
157
+ return (base.value ** exponent.argument.value).to_m.power(-1), 1, true
158
+ end
159
+ end
160
+
161
+ # p**q**r reduces to p**(q*r)
162
+ if base.is_a?(SyMath::Power)
163
+ return base.base.power(base.exponent.mul(exponent)), 1, true
164
+ end
165
+
166
+ # Reduce positive integer power of vectors and dforms to zero
167
+ if (base.type.is_dform? or base.type.is_vector?) and
168
+ exponent.is_number?
169
+ return 0.to_m, 1, true
170
+ end
171
+
172
+ # Remaining code reduces only quaternions
173
+ if !base.is_unit_quaternion?
174
+ return self, 1, false
175
+ end
176
+
177
+ # q**n for some unit quaternion
178
+ # Exponent is 1 or not a number
179
+ if !exponent.is_number? or exponent == 1
180
+ return self, 1, false
181
+ end
182
+
183
+ # e is on the form q**n for some integer n >= 2
184
+ x = exponent.value
185
+
186
+ if x.odd?
187
+ ret = base
188
+ x -= 1
189
+ else
190
+ ret = 1.to_m
191
+ end
192
+
193
+ if (x/2).odd?
194
+ return ret, -1, true
195
+ else
196
+ return ret, 1, true
197
+ end
198
+ end
199
+
200
+ def to_s()
201
+ if base.is_sum_exp? or base.is_prod_exp? or base.is_a?(SyMath::Power)
202
+ base_str = '(' + base.to_s + ')'
203
+ else
204
+ base_str = base.to_s
205
+ end
206
+
207
+ expo_str = (exponent.is_sum_exp? or exponent.is_prod_exp?) ?
208
+ '(' + exponent.to_s + ')' :
209
+ exponent.to_s
210
+
211
+ return base_str + '**' + expo_str
212
+ end
213
+
214
+ def to_latex()
215
+ if base.is_sum_exp? or base.is_prod_exp? or base.is_a?(SyMath::Power)
216
+ base_str = '\left(' + base.to_latex + '\right)'
217
+ else
218
+ base_str = base.to_latex
219
+ end
220
+
221
+ return base_str + '^' + '{' + exponent.to_latex + '}'
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,183 @@
1
+ require 'symath/operator'
2
+
3
+ module SyMath
4
+ class Product < Operator
5
+ def self.compose_with_simplify(a, b)
6
+ a = a.to_m
7
+ b = b.to_m
8
+
9
+ # Multipling a value with an equation multiplies it with both sides,
10
+ # preserving the balance of the equation
11
+ if b.is_a?(SyMath::Equation)
12
+ return eq(a * b.args[0], a * b.args[1])
13
+ end
14
+
15
+ if a.is_finite?() == false or b.is_finite?() == false
16
+ return self.simplify_inf(a, b)
17
+ end
18
+
19
+ # First try some simple reductions
20
+ # a*1 => a
21
+ return a if b == 1
22
+ return b if a == 1
23
+
24
+ # -a*-b => a*b
25
+ if b.is_a?(SyMath::Minus) and a.is_a?(SyMath::Minus)
26
+ return a.argument*b.argument
27
+ end
28
+
29
+ # (-a)*b => -(a*b)
30
+ # a*(-b) => -(a*b)
31
+ return -(a*b.argument) if b.is_a?(SyMath::Minus)
32
+ return -(a.argument*b) if a.is_a?(SyMath::Minus)
33
+
34
+ if b.is_a?(SyMath::Matrix)
35
+ return self.new(a, b)
36
+ end
37
+
38
+ if a.base == b.base
39
+ return a.base ** (a.exponent + b.exponent)
40
+ end
41
+
42
+ # (1/a)*b => b/a
43
+ if a.is_a?(SyMath::Fraction) and a.dividend == 1.to_m
44
+ return b/a.divisor
45
+ end
46
+
47
+ # a*(1/b) => a*/b
48
+ if b.is_a?(SyMath::Fraction) and b.dividend == 1.to_m
49
+ return a/b.divisor
50
+ end
51
+
52
+ if a.type.is_subtype?(:tensor) and b.type.is_subtype?(:tensor)
53
+ # Expand expression if any of the parts are sum
54
+ if b.is_sum_exp?
55
+ return b.terms.map { |f| a.*(f) }.inject(:+)
56
+ end
57
+
58
+ if a.is_sum_exp?
59
+ return a.terms.map { |f| f.wedge(b) }.inject(:+)
60
+ end
61
+
62
+ return a.wedge(b)
63
+ end
64
+
65
+ return self.new(a, b)
66
+ end
67
+
68
+ def self.simplify_inf(a, b)
69
+ # Indefinite factors
70
+ if a.is_finite?.nil? or b.is_finite?.nil?
71
+ return self.new(a, b)
72
+ end
73
+
74
+ # NaN multiplies to NaN
75
+ if a.is_nan? or b.is_nan?
76
+ return :nan.to_m
77
+ end
78
+
79
+ # oo*0 = 0*oo = NaN
80
+ if a.is_zero? or b.is_zero?
81
+ return :nan.to_m
82
+ end
83
+
84
+ if SyMath.setting(:complex_arithmetic)
85
+ return :oo.to_m
86
+ else
87
+ if (a.is_positive? and b.is_positive?) or
88
+ (a.is_negative? and b.is_negative?)
89
+ return :oo.to_m
90
+ end
91
+
92
+ if (a.is_negative? and b.is_positive?) or
93
+ (a.is_positive? and b.is_negative?)
94
+ return -:oo.to_m
95
+ end
96
+ end
97
+
98
+ # :nocov:
99
+ raise 'Internal error'
100
+ # :nocov:
101
+ end
102
+
103
+ def initialize(arg1, arg2)
104
+ super('*', [arg1, arg2])
105
+ end
106
+
107
+ def factor1()
108
+ return @args[0]
109
+ end
110
+
111
+ def factor1=(f)
112
+ @args[0] = f
113
+ end
114
+
115
+ def factor2()
116
+ return @args[1]
117
+ end
118
+
119
+ def factor2=(f)
120
+ @args[1] = f
121
+ end
122
+
123
+ def is_commutative?()
124
+ return true
125
+ end
126
+
127
+ def is_associative?()
128
+ return true
129
+ end
130
+
131
+ def is_prod_exp?()
132
+ return true
133
+ end
134
+
135
+ def factors()
136
+ return Enumerator.new do |f|
137
+ factor1.factors.each { |f1| f << f1 }
138
+ factor2.factors.each { |f2| f << f2 }
139
+ end
140
+ end
141
+
142
+ def evaluate()
143
+ if factor1.is_a?(SyMath::Matrix)
144
+ return factor1.matrix_mul(factor2)
145
+ elsif factor2.is_a?(SyMath::Matrix) and
146
+ factor1.type.is_scalar?
147
+ return factor2.matrix_mul(factor1)
148
+ end
149
+
150
+ return super
151
+ end
152
+
153
+ def type()
154
+ return factor1.type.product(factor2.type)
155
+ end
156
+
157
+ def to_s()
158
+ if SyMath.setting(:expl_parentheses)
159
+ return '('.to_s + factor1.to_s + '*' + factor2.to_s + ')'.to_s
160
+ else
161
+ return @args.map do |a|
162
+ if a.is_sum_exp?
163
+ '(' + a.to_s + ')'
164
+ else
165
+ a.to_s
166
+ end
167
+ end.join('*')
168
+ end
169
+ end
170
+
171
+ def to_latex()
172
+ dot = SyMath.setting(:ltx_product_sign) ? ' \cdot ' : ' ';
173
+
174
+ return @args.map do |a|
175
+ if a.is_sum_exp?
176
+ '(' + a.to_latex + ')'
177
+ else
178
+ a.to_latex
179
+ end
180
+ end.join(dot)
181
+ end
182
+ end
183
+ end
data/lib/symath/sum.rb ADDED
@@ -0,0 +1,174 @@
1
+ require 'symath/operator'
2
+
3
+ module SyMath
4
+ class Sum < Operator
5
+ def self.compose_with_simplify(a, b)
6
+ a = a.to_m
7
+ b = b.to_m
8
+
9
+ # Adding a value to an equation adds it to both sides, preserving
10
+ # the balance of the equation
11
+ if b.is_a?(SyMath::Equation)
12
+ return eq(a + b.args[0], a + b.args[1])
13
+ end
14
+
15
+ if a.is_finite?() == false or b.is_finite?() == false
16
+ return self.simplify_inf(a, b)
17
+ end
18
+
19
+ return a if b == 0
20
+ return b if a == 0
21
+
22
+ sc = 1
23
+ sf = []
24
+ oc = 1
25
+ of = []
26
+
27
+ a.factors.each do |f|
28
+ if f == -1
29
+ sc *= -1
30
+ elsif f.is_number?
31
+ sc *= f.value
32
+ else
33
+ sf.push f
34
+ end
35
+ end
36
+
37
+ b.factors.each do |f|
38
+ if f == -1
39
+ oc *= -1
40
+ elsif f.is_number?
41
+ oc *= f.value
42
+ else
43
+ of.push f
44
+ end
45
+ end
46
+
47
+ sc += oc
48
+
49
+ if sf == of
50
+ if sc == 0
51
+ return 0.to_m
52
+ end
53
+
54
+ if sc != 1
55
+ sf.unshift sc.to_m
56
+ end
57
+
58
+ return sf.empty? ? 1.to_m : sf.inject(:*)
59
+ end
60
+
61
+ return self.new(a, b)
62
+ end
63
+
64
+ def self.simplify_inf(a, b)
65
+ # Indefinite terms
66
+ if a.is_finite?.nil? or b.is_finite?.nil?
67
+ return a.add(b)
68
+ end
69
+
70
+ # NaN add to NaN
71
+ if a.is_nan? or b.is_nan?
72
+ return :nan.to_m
73
+ end
74
+
75
+ if SyMath.setting(:complex_arithmetic)
76
+ # +- oo +- oo = NaN
77
+ if (a.is_finite? == false and b.is_finite? == false)
78
+ return :nan.to_m
79
+ end
80
+
81
+ # oo + n = n + oo = NaN
82
+ if (a.is_finite? == false or b.is_finite? == false)
83
+ return :oo.to_m
84
+ end
85
+ else
86
+ # oo - oo = -oo + oo = NaN
87
+ if (a.is_finite? == false and b.is_finite? == false)
88
+ if (a.is_positive? and b.is_negative?) or
89
+ (a.is_negative? and b.is_positive?)
90
+ return :nan.to_m
91
+ end
92
+ end
93
+
94
+ # oo + n = n + oo = oo + oo = oo
95
+ if a.is_finite? == false
96
+ return a
97
+ end
98
+
99
+ # n - oo = - oo + n = -oo - oo = -oo
100
+ if b.is_finite? == false
101
+ return b
102
+ end
103
+ end
104
+
105
+ # :nocov:
106
+ raise 'Internal error'
107
+ # :nocov:
108
+ end
109
+
110
+ def initialize(arg1, arg2)
111
+ super('+', [arg1, arg2])
112
+ end
113
+
114
+ def term1()
115
+ return @args[0]
116
+ end
117
+
118
+ def term2()
119
+ return @args[1]
120
+ end
121
+
122
+ def is_commutative?()
123
+ return true
124
+ end
125
+
126
+ def is_associative?()
127
+ return true
128
+ end
129
+
130
+ def is_sum_exp?()
131
+ return true
132
+ end
133
+
134
+ # Return all terms in the sum
135
+ def terms()
136
+ return Enumerator.new do |s|
137
+ term1.terms.each { |s1| s << s1 }
138
+ term2.terms.each { |s2| s << s2 }
139
+ end
140
+ end
141
+
142
+ def evaluate
143
+ if term1.type.is_matrix?
144
+ return term1.matrix_add(term2)
145
+ end
146
+
147
+ return super
148
+ end
149
+
150
+ def type()
151
+ return term1.type.sum(term2.type)
152
+ end
153
+
154
+ def to_s()
155
+ if SyMath.setting(:expl_parentheses)
156
+ return '('.to_s + term1.to_s + ' + ' + term2.to_s + ')'.to_s
157
+ else
158
+ if term2.is_a?(SyMath::Minus)
159
+ return term1.to_s + " " + term2.to_s
160
+ else
161
+ return term1.to_s + " + " + term2.to_s
162
+ end
163
+ end
164
+ end
165
+
166
+ def to_latex()
167
+ if term2.is_a?(SyMath::Minus)
168
+ return term1.to_latex + ' ' + term2.to_latex
169
+ else
170
+ return term1.to_latex + ' + ' + term2.to_latex
171
+ end
172
+ end
173
+ end
174
+ end