Class: SyMath::Definition::Variable

Inherits:
SyMath::Definition show all
Defined in:
lib/symath/definition/variable.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from SyMath::Definition

#arity, define, defined?, definitions, get, #hash, init_builtin, #inspect, #is_function?, #is_operator?, #reduce_call, undefine

Methods inherited from Value

#*, #**, #+, #-, #-@, #/, #<, #<=, #>, #>=, #^, #add, #base, compose_with_simplify, create, #deep_clone, #div, #dump, #evaluate, #exponent, #factors, #inspect, #inv, #is_divisor_factor?, #is_finite?, #is_nan?, #is_negative?, #is_negative_number?, #is_number?, #is_positive?, #is_prod_exp?, #is_sum_exp?, #is_unit_quaternion?, #is_zero?, #mul, #neg, #power, #reduce, #reduce_modulo_sign, #sign, #sub, #terms, #to_m, #wedge

Methods included from Operation::Exterior

#flat, #hodge, #sharp

Methods included from Operation::Integration

#anti_derivative, #get_linear_constants, initialize, #int_constant, #int_failure, #int_function, #int_inv, #int_pattern, #int_power, #int_product, #int_sum, #integral_bounds

Methods included from Operation::Differential

#_d_wedge, #d, #d_failure, #d_fraction, #d_function, #d_function_def, #d_power, #d_product, initialize

Methods included from Operation

#iterate, #recurse

Methods included from Operation::DistributiveLaw

#combfrac_add_term, #combfrac_sum, #combine_fractions, #expand, #expand_product, #expand_single_pass, #factorize, #factorize_integer_poly, #factorize_simple, #has_fractional_terms?

Methods included from Operation::Normalization

#combine_factors, #compare_factors_and_swap, #normalize, #normalize_matrix, #normalize_power, #normalize_product, #normalize_single_pass, #normalize_sum, #order_product, #product_on_fraction_form, #reduce_constant_factors, #replace_combined_factors, #swap_factors

Methods included from Operation::Match

#build_assoc_op, #match, #match_assoc, #match_replace

Constructor Details

#initialize(name, t = 'real') ⇒ Variable

Returns a new instance of Variable.



131
132
133
134
# File 'lib/symath/definition/variable.rb', line 131

def initialize(name, t = 'real')
  @type = t.to_t
  super(name, define_symbol: false)
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



128
129
130
# File 'lib/symath/definition/variable.rb', line 128

def name
  @name
end

#typeObject (readonly)

Returns the value of attribute type.



129
130
131
# File 'lib/symath/definition/variable.rb', line 129

def type
  @type
end

Class Method Details

.hodge_dual(exp) ⇒ Object

Return the hodge dual of an expression consisting only of basis vectors or basis dforms



120
121
122
123
124
125
126
# File 'lib/symath/definition/variable.rb', line 120

def self.hodge_dual(exp)
  if !@@hodge_map.key?(exp)
    raise 'No hodge dual for ' + exp.to_s
  end

  return @@hodge_map[exp]
end

.permutation_parity(perm) ⇒ Object

Return parity of permutation. Even number of permutations give 1 and odd number gives -1



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/symath/definition/variable.rb', line 9

def self.permutation_parity(perm)
  # perm is an array of indexes representing the permutation
  # Put permutation list into disjoint cycles form
  cycles = {}
  (0..perm.length-1).each do |i|
    cycles[perm[i]] = i
  end

  sign = 0

  # Count the number even cycles.
  (0..perm.length-1).each do |i|
    next if !cycles.key?(i)

    count = 0
    while cycles.key?(i)
      count += 1
      j = cycles[i]
      cycles.delete(i)
      i = j
    end

    if (count % 2) == 0
      sign += 1
    end
  end

  # Even => 1, Odd => -1
  sign = (1 - (sign % 2)*2).to_m
end

.recalc_basis_vectorsObject

Re-calculate various auxiliary data structured based on the given basis This does not scale for higher dimensions, but that will most probably be out of scope for this library anyway.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/symath/definition/variable.rb', line 43

def self.recalc_basis_vectors()
  b = SyMath.get_variable(:basis)
  g = SyMath.get_variable(:g)

  brow = b.row(0)
  dim = brow.length

  dmap = brow.map do |bb|
    "d#{bb.name}".to_sym.to_m('dform')
  end

  vmap = brow.map do |bb|
    bb.name.to_sym.to_m('vector')
  end

  # Hash up the order of the basis vectors
  @@basis_order = {}

  (0..dim - 1).each do |i|
    @@basis_order[brow[i].name.to_sym] = i
    @@basis_order["d#{brow[i].name}".to_sym] = i
  end

  # Calculate all possible permutations of all possible combinations of
  # the basis vectors (including no vectors).
  @@norm_map = {}
  @@hodge_map = {}
  (0..dim).each do |d|
    (0..dim - 1).to_a.permutation(d).each do |p|
      if p.length == 0
        @@norm_map[1.to_m] = 1.to_m
        @@hodge_map[1.to_m] = dmap.inject(:^)
        next
      end

      # Hash them to the normalized expression (including the sign).
      # Do this both for vectors and dforms.      
      norm = p.sort
      sign = permutation_parity(p)

      dform = p.map { |i| dmap[i] }.inject(:^)
      vect = p.map { |i| vmap[i] }.inject(:^)

      dnorm = sign*(norm.map { |i| dmap[i] }.inject(:^))
      vnorm = sign*(norm.map { |i| vmap[i] }.inject(:^))

      @@norm_map[dform] = dnorm
      @@norm_map[vect] = vnorm

      # Hash them to their hodge dual
      dual = (0..dim - 1).to_a - norm
      dsign = permutation_parity(p + dual)
      
      if dual.length == 0
        hdd = sign
        hdv = sign
      else
        hdd = sign*dsign*(dual.map { |i| dmap[i] }.inject(:^))
        hdv = sign*dsign*(dual.map { |i| vmap[i] }.inject(:^))
      end

      @@hodge_map[dform] = hdd
      @@hodge_map[vect] = hdv
    end
  end

  # Calculate the musical isomorphisms. Hash up the mappings both ways.
  flat = (g*SyMath::Matrix.new(dmap).transpose).evaluate.normalize.col(0)
  sharp = (g.inverse*SyMath::Matrix.new(vmap).transpose).evaluate.
            normalize.col(0)

  @@flat_map = (0..dim - 1).map { |i| [vmap[i], flat[i]] }.to_h
  @@sharp_map = (0..dim - 1).map { |i| [dmap[i], sharp[i]] }.to_h
end

Instance Method Details

#<=>(other) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/symath/definition/variable.rb', line 150

def <=>(other)
  if self.class.name != other.class.name
    return super(other)
  end

  if type.name != other.type.name
    return type.name <=> other.type.name
  end
  # Order basis vectors and basis dforms by basis order
  if type.is_subtype?('vector') or type.is_subtype?('dform')
    bv1 = @@basis_order.key?(@name)
    bv2 = @@basis_order.key?(other.name)

    if !bv1 and bv2
      # Order basis vectors higher than other vectors
      return 1
    elsif bv1 and !bv2
      # Order basis vectors higher than other vectors
      return -1
    elsif bv1 and bv2
      return @@basis_order[@name] <=> @@basis_order[other.name]
    end
  end

  return @name.to_s <=> other.name.to_s
end

#==(other) ⇒ Object Also known as: eql?



144
145
146
147
148
# File 'lib/symath/definition/variable.rb', line 144

def ==(other)
  return false if self.class.name != other.class.name
  return false if @type != other.type
  return @name == other.name
end

#call(*args) ⇒ Object



140
141
142
# File 'lib/symath/definition/variable.rb', line 140

def call(*args)
  return SyMath::Operator.create(self, args.map { |a| a.nil? ? a : a.to_m })
end

#descriptionObject



136
137
138
# File 'lib/symath/definition/variable.rb', line 136

def description()
  return "#{name} - free variable"
end

#is_constant?(vars = nil) ⇒ Boolean

Returns:

  • (Boolean)


177
178
179
180
# File 'lib/symath/definition/variable.rb', line 177

def is_constant?(vars = nil)
  return false if vars.nil?
  return !(vars.member?(self))
end

#is_d?Boolean

Returns true if variable is a differential form

Returns:

  • (Boolean)


183
184
185
# File 'lib/symath/definition/variable.rb', line 183

def is_d?()
  return @type.is_dform?
end

#lower_vectorObject

Return the dform dual of the vector



211
212
213
214
215
216
217
# File 'lib/symath/definition/variable.rb', line 211

def lower_vector()
  if !@@flat_map.key?(self)
    raise 'No dform dual for ' + to_s
  end

  return @@flat_map[self]
end

#raise_dformObject

Return the vector dual of the dform



202
203
204
205
206
207
208
# File 'lib/symath/definition/variable.rb', line 202

def raise_dform()
  if !@@sharp_map.key?(self)
    raise 'No vector dual for ' + to_s
  end

  return @@sharp_map[self]
end

#replace(map) ⇒ Object



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/symath/definition/variable.rb', line 223

def replace(map)
  if is_d?
    u = undiff
    if map.key?(u)
      return op(:d, map[u].deep_clone)
    else
      return self
    end
  end

  if map.key?(self)
    return map[self].deep_clone
  else
    return self
  end
end

#to_dObject



197
198
199
# File 'lib/symath/definition/variable.rb', line 197

def to_d()
  return "d#{@name}".to_sym.to_m(:dform)
end

#to_latexObject



254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/symath/definition/variable.rb', line 254

def to_latex()
  if type.is_dform?
    return '\mathrm{d}' + undiff.to_latex
  elsif @type.is_vector?
    return '\vec{'.to_s + @name.to_s + '}'.to_s
  elsif @type.is_covector?
    # What is the best way to denote a covector without using indexes?
    return '\vec{'.to_s + @name.to_s + '}'.to_s
  elsif @type.is_subtype?('tensor')
    return @name.to_s + '['.to_s + @type.index_str + ']'.to_s
  else
    return @name.to_s
  end
end

#to_sObject



240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/symath/definition/variable.rb', line 240

def to_s()
  if @type.is_dform?
    return SyMath.setting(:d_symbol) + undiff.to_s
  elsif @type.is_vector?
    return @name.to_s + SyMath.setting(:vector_symbol)
  elsif @type.is_covector?
    return @name.to_s + SyMath.setting(:covector_symbol)
  elsif @type.is_subtype?('tensor')
    return @name.to_s + '['.to_s + @type.index_str + ']'.to_s
  else
    return @name.to_s
  end
end

#undiffObject

Returns variable which differential is based on



188
189
190
191
192
193
194
195
# File 'lib/symath/definition/variable.rb', line 188

def undiff()
  n = "#{@name}"
  if n[0] == 'd'
    n = n[1..-1]
  end

  n.to_sym.to_m(:real)
end

#variablesObject



219
220
221
# File 'lib/symath/definition/variable.rb', line 219

def variables()
  return [@name]
end