symath 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|