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,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