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
data/lib/symath/type.rb
ADDED
@@ -0,0 +1,282 @@
|
|
1
|
+
module SyMath
|
2
|
+
class Type
|
3
|
+
# Type name
|
4
|
+
attr_reader :name
|
5
|
+
# Matrix dimensions
|
6
|
+
attr_reader :dimn, :dimm
|
7
|
+
# Tensor indexes (array of 'h' amd 'l')
|
8
|
+
attr_reader :indexes
|
9
|
+
|
10
|
+
# Type hierarchy with generic types at the top level and more specific
|
11
|
+
# types further down.
|
12
|
+
@@hierarchy = {
|
13
|
+
# Non numbers
|
14
|
+
:nonfinite => 1,
|
15
|
+
# Operators
|
16
|
+
:operator => {
|
17
|
+
# Linear operators
|
18
|
+
:linop => {
|
19
|
+
# Matrices
|
20
|
+
:matrix => {
|
21
|
+
:column => 1,
|
22
|
+
:row => 1,
|
23
|
+
},
|
24
|
+
# Vector types (one dimension param)
|
25
|
+
:tensor => {
|
26
|
+
:nvector => {
|
27
|
+
:vector => 1,
|
28
|
+
},
|
29
|
+
:nform => {
|
30
|
+
:covector => {
|
31
|
+
:dform => 1,
|
32
|
+
},
|
33
|
+
},
|
34
|
+
},
|
35
|
+
# Scalar types
|
36
|
+
:quaternion => {
|
37
|
+
:scalar => {
|
38
|
+
:complex => {
|
39
|
+
:real => {
|
40
|
+
:rational => {
|
41
|
+
:integer => {
|
42
|
+
:natural => 1
|
43
|
+
}
|
44
|
+
}
|
45
|
+
},
|
46
|
+
:imaginary => 1,
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
# Create a transitively closed subtype hash for quicker subtype lookup
|
55
|
+
@@subtype = {}
|
56
|
+
|
57
|
+
def self.fill_subtype_hash(hiera, bases = [])
|
58
|
+
hiera.keys.each do |k|
|
59
|
+
bases.each do |b|
|
60
|
+
if !@@subtype.key?(k)
|
61
|
+
@@subtype[k] = {}
|
62
|
+
end
|
63
|
+
@@subtype[k][b] = 1
|
64
|
+
end
|
65
|
+
|
66
|
+
next unless hiera[k].is_a?(Hash)
|
67
|
+
|
68
|
+
fill_subtype_hash(hiera[k], bases + [k])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
fill_subtype_hash(@@hierarchy)
|
73
|
+
|
74
|
+
@@types = {}
|
75
|
+
|
76
|
+
def self.types
|
77
|
+
return @@types
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize(name, dimn: nil, dimm: nil, indexes: nil)
|
81
|
+
@name = name.to_sym
|
82
|
+
@dimn = dimn
|
83
|
+
@dimm = dimm
|
84
|
+
@indexes = indexes
|
85
|
+
end
|
86
|
+
|
87
|
+
# Hash of simple types, for faster instansiations.
|
88
|
+
@@types = {
|
89
|
+
:natural => SyMath::Type.new(:natural),
|
90
|
+
:integer => SyMath::Type.new(:integer),
|
91
|
+
:rational => SyMath::Type.new(:rational),
|
92
|
+
:real => SyMath::Type.new(:real),
|
93
|
+
:complex => SyMath::Type.new(:complex),
|
94
|
+
:imaginary => SyMath::Type.new(:imaginary),
|
95
|
+
:quaternion => SyMath::Type.new(:quaternion),
|
96
|
+
:vector => SyMath::Type.new(:vector, indexes: ['u']),
|
97
|
+
:covector => SyMath::Type.new(:covector, indexes: ['l']),
|
98
|
+
:dform => SyMath::Type.new(:dform, indexes: ['l']),
|
99
|
+
}
|
100
|
+
|
101
|
+
# Check if a type is a subtype of another
|
102
|
+
def is_subtype?(other)
|
103
|
+
# Allow input as type or as string
|
104
|
+
other = other.to_t
|
105
|
+
|
106
|
+
# Types are not compatible if they have different attributes.
|
107
|
+
# FIXME: What is the correct way to define subtypes of matrices
|
108
|
+
# with respect to dimensions?
|
109
|
+
return false if @dim1 != other.dimn
|
110
|
+
return false if @dim2 != other.dimm
|
111
|
+
|
112
|
+
# Same types,
|
113
|
+
return true if @name == other.name
|
114
|
+
|
115
|
+
# This is a subtype of other
|
116
|
+
return true if @@subtype.key?(@name) and @@subtype[@name].key?(other.name)
|
117
|
+
|
118
|
+
# Fallback to false
|
119
|
+
return false
|
120
|
+
end
|
121
|
+
|
122
|
+
def common_parent(other)
|
123
|
+
if other.is_subtype?(self)
|
124
|
+
return self
|
125
|
+
elsif is_subtype?(other)
|
126
|
+
return other
|
127
|
+
elsif is_subtype?(@@types[:complex]) and
|
128
|
+
other.is_subtype?(@@types[:complex])
|
129
|
+
return @@types[:complex]
|
130
|
+
else
|
131
|
+
raise "No common type for #{self} and #{other}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Determine the type of a sum
|
136
|
+
def sum(other)
|
137
|
+
if is_subtype?('quaternion') and
|
138
|
+
other.is_subtype?('quaternion')
|
139
|
+
return common_parent(other)
|
140
|
+
elsif self == other
|
141
|
+
return self
|
142
|
+
elsif self.is_subtype?('tensor') or other.is_subtype?('tensor')
|
143
|
+
# FIXME: Hack. This is probably not true.
|
144
|
+
return self
|
145
|
+
else
|
146
|
+
raise "Types #{self} and #{other} cannot be summed."
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Determine the type of a product
|
151
|
+
def product(other)
|
152
|
+
scalar = is_scalar?
|
153
|
+
oscalar = other.is_scalar?
|
154
|
+
|
155
|
+
if scalar and oscalar
|
156
|
+
return common_parent(other)
|
157
|
+
elsif scalar
|
158
|
+
return other
|
159
|
+
elsif oscalar
|
160
|
+
return self
|
161
|
+
elsif is_subtype?('matrix') and
|
162
|
+
other.is_subtype?('matrix') and
|
163
|
+
dimn == other.dimm
|
164
|
+
return 'matrix'.to_t(dimm: dimm, dimn: other.dimn)
|
165
|
+
else
|
166
|
+
raise "Types #{self} and #{other} cannot be multiplied"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Return tensor degree (rank)
|
171
|
+
def degree()
|
172
|
+
return @indexes.length
|
173
|
+
end
|
174
|
+
|
175
|
+
# True if type is a scalar value
|
176
|
+
def is_scalar?()
|
177
|
+
return is_subtype?('scalar')
|
178
|
+
end
|
179
|
+
|
180
|
+
def is_vector?()
|
181
|
+
return is_subtype?('vector')
|
182
|
+
end
|
183
|
+
|
184
|
+
# True if type is a linear combination of blades
|
185
|
+
def is_nvector?()
|
186
|
+
return is_subtype?('nvector')
|
187
|
+
end
|
188
|
+
|
189
|
+
def is_matrix?()
|
190
|
+
return ([:matrix, :colum, :row].include?(@name))
|
191
|
+
end
|
192
|
+
|
193
|
+
# True if type is a pseudovector. We use the notion of a pseudovector
|
194
|
+
# both for N-1 dimensional nvectors and nforms (N being the dimensionality
|
195
|
+
# of the default vector space)
|
196
|
+
def is_pseudovector?()
|
197
|
+
if !is_subtype?('nvector') and !is_subtype?('nform')
|
198
|
+
return false
|
199
|
+
end
|
200
|
+
|
201
|
+
return degree == SyMath.get_variable(:basis).ncols - 1
|
202
|
+
end
|
203
|
+
|
204
|
+
# True if type is a pseudoscalar. We use the notion of a pseudoscalar
|
205
|
+
# both for N dimensional nvectors and nforms (N being the dimensionality
|
206
|
+
# of the default vector space)
|
207
|
+
def is_pseudoscalar?()
|
208
|
+
if !is_subtype?('nvector') and !is_subtype?('nform')
|
209
|
+
return false
|
210
|
+
end
|
211
|
+
|
212
|
+
return degree == SyMath.get_variable(:basis).ncols
|
213
|
+
end
|
214
|
+
|
215
|
+
# True if type is the dual of an nvector
|
216
|
+
def is_nform?()
|
217
|
+
return is_subtype?('nform')
|
218
|
+
end
|
219
|
+
|
220
|
+
# FIXME: What is the difference between a covector and a dform?
|
221
|
+
def is_covector?()
|
222
|
+
return is_subtype?('covector')
|
223
|
+
end
|
224
|
+
|
225
|
+
def is_dform?()
|
226
|
+
return is_subtype?('dform')
|
227
|
+
end
|
228
|
+
|
229
|
+
# Return index list as a string coded with upper indices as ' and lower
|
230
|
+
# indices as .
|
231
|
+
def index_str()
|
232
|
+
return @indexes.map do |i|
|
233
|
+
if i == 'u'
|
234
|
+
'\''
|
235
|
+
elsif i == 'l'
|
236
|
+
'.'
|
237
|
+
end
|
238
|
+
end.join('')
|
239
|
+
end
|
240
|
+
|
241
|
+
def ==(other)
|
242
|
+
return false if @dim1 != other.dimn
|
243
|
+
return false if @dim2 != other.dimm
|
244
|
+
return false if @indexes != other.indexes
|
245
|
+
return @name == other.name
|
246
|
+
end
|
247
|
+
|
248
|
+
def to_s()
|
249
|
+
if !@dimn.nil?
|
250
|
+
return @name.to_s + '[' + @dimm.to_s + 'x' + @dimn.to_s + ']'
|
251
|
+
elsif !@indexes.nil?
|
252
|
+
return @name.to_s + '[' + @indexes.join('') + ']'
|
253
|
+
else
|
254
|
+
return @name.to_s
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def to_t(*args)
|
259
|
+
return self
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
class String
|
265
|
+
def to_t(**args)
|
266
|
+
if args.empty? and SyMath::Type.types.key?(self.to_sym)
|
267
|
+
return SyMath::Type.types[self.to_sym]
|
268
|
+
end
|
269
|
+
|
270
|
+
return SyMath::Type.new(self, **args)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class Symbol
|
275
|
+
def to_t(**args)
|
276
|
+
if args.empty? and SyMath::Type.types.key?(self)
|
277
|
+
return SyMath::Type.types[self]
|
278
|
+
end
|
279
|
+
|
280
|
+
return SyMath::Type.new(self, **args)
|
281
|
+
end
|
282
|
+
end
|
data/lib/symath/value.rb
ADDED
@@ -0,0 +1,372 @@
|
|
1
|
+
require 'symath/operation'
|
2
|
+
require 'symath/operation/match'
|
3
|
+
require 'symath/operation/normalization'
|
4
|
+
require 'symath/operation/distributivelaw'
|
5
|
+
require 'symath/operation/differential'
|
6
|
+
require 'symath/operation/integration'
|
7
|
+
require 'symath/operation/exterior'
|
8
|
+
|
9
|
+
module SyMath
|
10
|
+
class Value
|
11
|
+
include Operation::Match
|
12
|
+
include Operation::Normalization
|
13
|
+
include Operation::DistributiveLaw
|
14
|
+
include Operation::Differential
|
15
|
+
include Operation::Integration
|
16
|
+
include Operation::Exterior
|
17
|
+
|
18
|
+
@@class_order = [
|
19
|
+
'SyMath::Definition::Number',
|
20
|
+
'SyMath::Definition::Constant',
|
21
|
+
'SyMath::Definition::Variable',
|
22
|
+
'SyMath::Definition::Function',
|
23
|
+
'SyMath::Definition::Operator',
|
24
|
+
'SyMath::Definition',
|
25
|
+
'SyMath::Minus',
|
26
|
+
'SyMath::Power',
|
27
|
+
'SyMath::Wedge',
|
28
|
+
'SyMath::Fraction',
|
29
|
+
'SyMath::Product',
|
30
|
+
'SyMath::Sum',
|
31
|
+
'SyMath::Operator',
|
32
|
+
]
|
33
|
+
|
34
|
+
@@class_order_hash = {}
|
35
|
+
|
36
|
+
@@class_order.each_with_index do |e, i|
|
37
|
+
@@class_order_hash[e] = i
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.create(definition, *args)
|
41
|
+
if !definition.is_a?(SyMath::Value)
|
42
|
+
definition = SyMath::Definition.get(definition)
|
43
|
+
end
|
44
|
+
|
45
|
+
if SyMath.setting(:compose_with_simplify)
|
46
|
+
return self.compose_with_simplify(definition, *args)
|
47
|
+
else
|
48
|
+
return self.new(definition, *args)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Compose with simplify. Defaults to composition with no reductions
|
53
|
+
def self.compose_with_simplify(*args)
|
54
|
+
return self.new(*args)
|
55
|
+
end
|
56
|
+
|
57
|
+
def deep_clone()
|
58
|
+
return Marshal.load(Marshal.dump(self))
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sorting/ordering operator. The ordering is used by the normalization to
|
62
|
+
# order the parts of a sum, product etc.
|
63
|
+
def <=>(other)
|
64
|
+
return @@class_order_hash[self.class.name] <=>
|
65
|
+
@@class_order_hash[other.class.name]
|
66
|
+
end
|
67
|
+
|
68
|
+
def <(other)
|
69
|
+
return (self <=> other) < 0
|
70
|
+
end
|
71
|
+
|
72
|
+
def >(other)
|
73
|
+
return (self <=> other) > 0
|
74
|
+
end
|
75
|
+
|
76
|
+
def <=(other)
|
77
|
+
return (self <=> other) <= 0
|
78
|
+
end
|
79
|
+
|
80
|
+
def >=(other)
|
81
|
+
return (self <=> other) >= 0
|
82
|
+
end
|
83
|
+
|
84
|
+
# Default properties for operators
|
85
|
+
# Note: Returning nil here means neither true or false, but unknown.
|
86
|
+
def is_nan?()
|
87
|
+
return
|
88
|
+
end
|
89
|
+
|
90
|
+
def is_finite?()
|
91
|
+
return
|
92
|
+
end
|
93
|
+
|
94
|
+
def is_positive?()
|
95
|
+
return
|
96
|
+
end
|
97
|
+
|
98
|
+
def is_negative?()
|
99
|
+
if is_nan?
|
100
|
+
return false
|
101
|
+
end
|
102
|
+
|
103
|
+
return (is_positive? == false and is_zero? == false)
|
104
|
+
end
|
105
|
+
|
106
|
+
def is_number?()
|
107
|
+
return false
|
108
|
+
end
|
109
|
+
|
110
|
+
def is_negative_number?()
|
111
|
+
return false
|
112
|
+
end
|
113
|
+
|
114
|
+
def is_zero?()
|
115
|
+
return
|
116
|
+
end
|
117
|
+
|
118
|
+
def is_divisor_factor?()
|
119
|
+
return false
|
120
|
+
end
|
121
|
+
|
122
|
+
def is_unit_quaternion?()
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
|
126
|
+
# Reduce expression if possible. Defaults to no reduction
|
127
|
+
def reduce()
|
128
|
+
return self
|
129
|
+
end
|
130
|
+
|
131
|
+
# Evaluate expression. Defaults to no evaluation
|
132
|
+
def evaluate()
|
133
|
+
return self
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# Compositional math operator methods. No reductions are performed.
|
138
|
+
##
|
139
|
+
def add(other)
|
140
|
+
return SyMath::Sum.new(self, other.to_m)
|
141
|
+
end
|
142
|
+
|
143
|
+
def sub(other)
|
144
|
+
return SyMath::Sum.new(self, SyMath::Minus.new(other.to_m))
|
145
|
+
end
|
146
|
+
|
147
|
+
def neg()
|
148
|
+
return SyMath::Minus.new(self)
|
149
|
+
end
|
150
|
+
|
151
|
+
def mul(other)
|
152
|
+
return SyMath::Product.new(self, other.to_m)
|
153
|
+
end
|
154
|
+
|
155
|
+
def div(other)
|
156
|
+
return SyMath::Fraction.new(self, other.to_m)
|
157
|
+
end
|
158
|
+
|
159
|
+
def power(other)
|
160
|
+
return SyMath::Power.new(self, other.to_m)
|
161
|
+
end
|
162
|
+
|
163
|
+
def wedge(other)
|
164
|
+
return SyMath::Wedge.new(self, other.to_m)
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Overridden object operators.
|
169
|
+
# These operations do some simple reductions.
|
170
|
+
##
|
171
|
+
def +(other)
|
172
|
+
return SyMath::Sum.create(self, other)
|
173
|
+
end
|
174
|
+
|
175
|
+
def -(other)
|
176
|
+
return self + (- other)
|
177
|
+
end
|
178
|
+
|
179
|
+
def -@()
|
180
|
+
return SyMath::Minus.create(self)
|
181
|
+
end
|
182
|
+
|
183
|
+
def *(other)
|
184
|
+
return SyMath::Product.create(self, other)
|
185
|
+
end
|
186
|
+
|
187
|
+
def /(other)
|
188
|
+
return SyMath::Fraction.create(self, other)
|
189
|
+
end
|
190
|
+
|
191
|
+
def inv()
|
192
|
+
return 1/self
|
193
|
+
end
|
194
|
+
|
195
|
+
def **(other)
|
196
|
+
return SyMath::Power.create(self, other)
|
197
|
+
end
|
198
|
+
|
199
|
+
def ^(other)
|
200
|
+
# Identical with *. We apply * or ^ depending on what
|
201
|
+
# the arguments are.
|
202
|
+
return self*other
|
203
|
+
end
|
204
|
+
|
205
|
+
##
|
206
|
+
# Helper methods for the normalization operation. These are overridden by
|
207
|
+
# the subclasses. Default behaviour is defined here.
|
208
|
+
##
|
209
|
+
|
210
|
+
# Value is a sum or unitary minus
|
211
|
+
def is_sum_exp?()
|
212
|
+
return false
|
213
|
+
end
|
214
|
+
|
215
|
+
# Value is a product, fraction or unitary minus
|
216
|
+
def is_prod_exp?()
|
217
|
+
return false
|
218
|
+
end
|
219
|
+
|
220
|
+
# Returns the terms of a sum in an array.
|
221
|
+
# Defaults to self for non-sums.
|
222
|
+
def terms()
|
223
|
+
return [self]
|
224
|
+
end
|
225
|
+
|
226
|
+
# Returns the base of a power expression.
|
227
|
+
# Defaults to self for non-powers.
|
228
|
+
def base()
|
229
|
+
return self
|
230
|
+
end
|
231
|
+
|
232
|
+
# Returns the exponent of a power expression.
|
233
|
+
# Defaults to self for non-powers.
|
234
|
+
def exponent()
|
235
|
+
return 1.to_m
|
236
|
+
end
|
237
|
+
|
238
|
+
# Return factors in enumerator
|
239
|
+
def factors()
|
240
|
+
return [self].to_enum
|
241
|
+
end
|
242
|
+
|
243
|
+
# Returns the accumulated sign of a product.
|
244
|
+
# Defaults to 1 for positive non-sum expressions.
|
245
|
+
def sign()
|
246
|
+
return 1
|
247
|
+
end
|
248
|
+
|
249
|
+
# Simple reduction rules, allows sign to change. Returns
|
250
|
+
# (reduced exp, sign, changed). Defaults to no change
|
251
|
+
def reduce_modulo_sign
|
252
|
+
return self, 1, false
|
253
|
+
end
|
254
|
+
|
255
|
+
# By default, assume an unknown expression to be scalar
|
256
|
+
def type()
|
257
|
+
return 'scalar'.to_t
|
258
|
+
end
|
259
|
+
|
260
|
+
alias eql? ==
|
261
|
+
|
262
|
+
def to_m()
|
263
|
+
return self
|
264
|
+
end
|
265
|
+
|
266
|
+
def inspect()
|
267
|
+
if SyMath.setting(:inspect_to_s)
|
268
|
+
return self.to_s
|
269
|
+
else
|
270
|
+
return super.inspect
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def dump(indent = 0)
|
275
|
+
i = ' '*indent
|
276
|
+
return "#{i}#{self.class}: #{self}"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
class Integer
|
282
|
+
alias_method :super_add, :+
|
283
|
+
alias_method :super_sub, :-
|
284
|
+
alias_method :super_mul, :*
|
285
|
+
alias_method :super_div, :/
|
286
|
+
alias_method :super_pow, :**
|
287
|
+
alias_method :super_wedge, :^
|
288
|
+
|
289
|
+
def +(other)
|
290
|
+
if other.class.method_defined?(:to_m) and !other.is_a?(Integer)
|
291
|
+
return self.to_m + other.to_m
|
292
|
+
else
|
293
|
+
return self.super_add(other)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def -(other)
|
298
|
+
if other.class.method_defined?(:to_m) and !other.is_a?(Integer)
|
299
|
+
return self.to_m - other.to_m
|
300
|
+
else
|
301
|
+
return self.super_sub(other)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def *(other)
|
306
|
+
if other.class.method_defined?(:to_m) and !other.is_a?(Integer)
|
307
|
+
return self.to_m*other.to_m
|
308
|
+
else
|
309
|
+
return self.super_mul(other)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def /(other)
|
314
|
+
if other.class.method_defined?(:to_m) and !other.is_a?(Integer)
|
315
|
+
return self.to_m/other.to_m
|
316
|
+
else
|
317
|
+
return self.super_div(other)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def **(other)
|
322
|
+
if other.class.method_defined?(:to_m) and !other.is_a?(Integer)
|
323
|
+
return self.to_m**other.to_m
|
324
|
+
else
|
325
|
+
return self.super_pow(other)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def ^(other)
|
330
|
+
if other.class.method_defined?(:to_m) and !other.is_a?(Integer)
|
331
|
+
return self.to_m^other.to_m
|
332
|
+
else
|
333
|
+
return self.super_wedge(other)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
class Symbol
|
339
|
+
def +(other)
|
340
|
+
return self.to_m + other.to_m
|
341
|
+
end
|
342
|
+
|
343
|
+
def -(other)
|
344
|
+
return self.to_m - other.to_m
|
345
|
+
end
|
346
|
+
|
347
|
+
def -@()
|
348
|
+
return - self.to_m
|
349
|
+
end
|
350
|
+
|
351
|
+
def *(other)
|
352
|
+
return self.to_m*other.to_m
|
353
|
+
end
|
354
|
+
|
355
|
+
def /(other)
|
356
|
+
return self.to_m/other.to_m
|
357
|
+
end
|
358
|
+
|
359
|
+
def **(other)
|
360
|
+
return self.to_m**other.to_m
|
361
|
+
end
|
362
|
+
|
363
|
+
def ^(other)
|
364
|
+
return self.to_m^other.to_m
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
class String
|
369
|
+
def to_m()
|
370
|
+
return SyMath.parse(self)
|
371
|
+
end
|
372
|
+
end
|
data/lib/symath/wedge.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'symath/product'
|
2
|
+
|
3
|
+
module SyMath
|
4
|
+
class Wedge < Product
|
5
|
+
def initialize(arg1, arg2)
|
6
|
+
super(arg1, arg2)
|
7
|
+
@name = '^'
|
8
|
+
end
|
9
|
+
|
10
|
+
def type()
|
11
|
+
if factor1.type.is_subtype?('tensor') and
|
12
|
+
factor2.type.is_subtype?('tensor')
|
13
|
+
# Wedge product of two tensor-like object. Determine index signature
|
14
|
+
# and subtype.
|
15
|
+
indexes = factor1.type.indexes + factor2.type.indexes
|
16
|
+
if (indexes - ['u']).empty?
|
17
|
+
type = 'nvector'
|
18
|
+
elsif (indexes - ['l']).empty?
|
19
|
+
type = 'nform'
|
20
|
+
else
|
21
|
+
type = 'tensor'
|
22
|
+
end
|
23
|
+
|
24
|
+
return type.to_t(indexes: indexes)
|
25
|
+
else
|
26
|
+
return factor1.type.sum(factor2.type)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s()
|
31
|
+
if SyMath.setting(:expl_parentheses)
|
32
|
+
return '('.to_s + factor1.to_s + '^' + factor2.to_s + ')'.to_s
|
33
|
+
else
|
34
|
+
return @args.map do |a|
|
35
|
+
if a.is_sum_exp?
|
36
|
+
'(' + a.to_s + ')'
|
37
|
+
else
|
38
|
+
a.to_s
|
39
|
+
end
|
40
|
+
end.join('^')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_latex()
|
45
|
+
return @args.map { |a| a.to_latex }.join('\wedge')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|