Class: SY::Composition

Inherits:
Hash
  • Object
show all
Defined in:
lib/sy/composition.rb

Overview

Composition of quantities.

Constant Summary collapse

SR =

Simplification rules for quantity combinations.

SIMPLIFICATION_RULES = []
QUANTITY_TABLE =

Cache for quantity construction.

Hash.new { |, args|
  if args.keys.include? [:name] || args.keys.include?(  ) then
    ɴ = args.delete( :name ) || args.delete(  ) # won't cache name
    [args].tap { |ɪ| ɪ.name = ɴ }                # recursion
  elsif args.keys.include? :mapping then
     = args.delete( :mapping )                   # won't cache mapping
    [args].tap { |ɪ| ɪ.set_mapping  }           # recursion
  elsif args.keys.include? :relative then
    ʀ = args.delete( :relative ) ? true : false   # won't cache :relative
    [args].send ʀ ? :relative : :absolute        # recursion
  else
    cᴍ = SY::Composition[ args ].simplify
    [args] = if cᴍ != args then [ cᴍ ]          # recursion while #simplify
              else x = cᴍ.expand # we'll try to #expand now
                if x != cᴍ then [ x ]            # recursion while #expand
                else
                  if x.empty? then                # use std. ∅ quantity
                    SY.Dimension( :∅ ).standard_quantity
                  elsif x.singular? then
                    x.first[0]                    # unwrap the quantity
                  else # create new quantity
                    SY::Quantity.new composition: x
                  end
                end
              end
  end
}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.emptyObject



88
89
90
# File 'lib/sy/composition.rb', line 88

def empty
  self[]
end

.singular(quantity) ⇒ Object



84
85
86
# File 'lib/sy/composition.rb', line 84

def singular quantity
  self[ SY.Quantity( quantity ) => 1 ]
end

Instance Method Details

#*(number) ⇒ Object

Multiplication by a number.



191
192
193
# File 'lib/sy/composition.rb', line 191

def * number
  self.class[ self.with_values do |v| v * number end ]
end

#+(other) ⇒ Object

Merges two compositions.



179
180
181
# File 'lib/sy/composition.rb', line 179

def + other
  self.class[ self.merge( other ) { |_, v1, v2| v1 + v2 } ]
end

#+@Object

Returns a new instance with same hash.



167
168
169
# File 'lib/sy/composition.rb', line 167

def +@
  self.class[ self ]
end

#-(other) ⇒ Object

Subtracts two compositions.



185
186
187
# File 'lib/sy/composition.rb', line 185

def - other
  self + -other
end

#-@Object

Negates hash exponents.



173
174
175
# File 'lib/sy/composition.rb', line 173

def -@
  self.class[ self.with_values do |v| -v end ]
end

#/(number) ⇒ Object

Division by a number.



197
198
199
200
201
202
203
# File 'lib/sy/composition.rb', line 197

def / number
  self.class[ self.with_values do |val|
                    raise TErr, "Compositions with rational exponents " +
                      "not implemented!" if val % number != 0
                    val / number
                  end ]
end

#atomic?Boolean

Atomic compositions are singular compositions, whose quantity dimension is a base dimension.

Returns:

  • (Boolean)


132
133
134
135
136
# File 'lib/sy/composition.rb', line 132

def atomic?
  puts "composition is #{self}" if SY::DEBUG
  puts "first[0].dimension is #{first[0].dimension}" if SY::DEBUG
  singular? && first[0].dimension.base?
end

#coerces?(other) ⇒ Boolean

Whether this composition coerces another compotision.

Returns:

  • (Boolean)


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/sy/composition.rb', line 140

def coerces? other
  # TODO: Think about caching. One way, ie. no way back, once something
  # coerces something else, so only false results would have to be re-checked,
  # and that only at most once each time after coerces / coerced_by method is
  # tampered.
  if singular? then
    other.singular? && self.first[0].coerces?( other.first[0] )
  else
    # simplify the compositions a bit
    rslt = [].tap do |ary|
      find { |qnt, e|
        other.find { |qnt2, e2|
          ( ( e > 0 && e2 > 0 || e < 0 && e2 < 0 ) && qnt.coerces?( qnt2 ) )
            .tap { |rslt| [] << qnt << qnt2 << ( e > 0 ? -1 : 1 ) if rslt }
        }
      }
    end
    # and ask recursively
    if rslt.empty? then return false else
      q, q2, e = rslt
      ( self + q.composition * e ).coerces? ( other + q2.composition * e )
    end
  end
end

#dimensionObject

Dimension of a composition is the sum of its member quantities’ dimensions.



231
232
233
# File 'lib/sy/composition.rb', line 231

def dimension
  map { |qnt, exp| qnt.dimension * exp }.reduce SY::Dimension.zero, :+
end

#expandObject

Try to simplify the composition by decomposing its quantities.



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/sy/composition.rb', line 266

def expand
  return self if irreducible?
  puts "#expand: #{self} not irreducible" if SY::DEBUG
  self.class[ reduce( self.class.empty ) { |cᴍ, pair|
                qnt, exp = pair
                puts "#expand: qnt: #{qnt}, exp: #{exp}" if SY::DEBUG
                puts "cᴍ is #{cᴍ}" if SY::DEBUG
                ( cᴍ + if qnt.irreducible? then
                       self.class.singular( qnt ) * exp
                     else
                       qnt.composition * exp
                     end.tap { |x| puts "Adding #{x}." if SY::DEBUG }
                  ).tap { |x| puts "Result is #{x}." if SY::DEBUG }
              } ]
    .tap{ |rslt| puts "#expand: result is #{rslt}" if SY::DEBUG }
end

#infer_measureObject

Infers the measure of the composition’s quantity. (‘Measure’ means measure of the pertinent standard quantity.)



238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/sy/composition.rb', line 238

def infer_measure
  puts "#infer_measure; hash is #{self}" if SY::DEBUG
  map do |qnt, exp|
    puts "#infer_measure: doing quantity #{qnt} with exponent #{exp}!" if SY::DEBUG
    if qnt.standardish? then
      puts "#{qnt} standardish" if SY::DEBUG
      SY::Measure.identity
    else
      puts "#{qnt} not standardish" if SY::DEBUG
      puts "its measure is #{qnt.measure}, class #{qnt.measure.class}" if SY::DEBUG
      qnt.measure( of: qnt.standard ) ** exp
    end
  end.reduce( SY::Measure.identity, :* )
end

#irreducible?Boolean

Whether it is possible to expand this

Returns:

  • (Boolean)


260
261
262
# File 'lib/sy/composition.rb', line 260

def irreducible?
  all? { |qnt, exp| qnt.irreducible? }
end

#new_quantity(args = {}) ⇒ Object

Directly (without attempts to simplify) creates a new quantity from self. If self is empty or singular, SY::Amount, resp. the singular quantity in question is returned.



225
226
227
# File 'lib/sy/composition.rb', line 225

def new_quantity args={}
  SY::Quantity.new args.merge( composition: self )
end

#simple?Boolean

Simple composition is one that is either empty or singular.

Returns:

  • (Boolean)


255
256
257
# File 'lib/sy/composition.rb', line 255

def simple?
  empty? or singular?
end

#simplifyObject

Simplifies a quantity hash by applying simplification rules.



207
208
209
210
211
212
# File 'lib/sy/composition.rb', line 207

def simplify
   = self.to_hash
  puts "simplifying #{}" if SY::DEBUG
  SIMPLIFICATION_RULES.each { |rule| rule.(  ) }
  self.class[  ].tap { |_| puts "result is #{_}" if SY::DEBUG }
end

#singular?Boolean

Singular compositions consist of only one quantity.

Returns:

  • (Boolean)


125
126
127
# File 'lib/sy/composition.rb', line 125

def singular?
  size == 1 && first[1] == 1
end

#to_quantity(args = {}) ⇒ Object

Returns the quantity appropriate to this composition.



216
217
218
219
# File 'lib/sy/composition.rb', line 216

def to_quantity args={}
  # All the work is delegated to the quantity table:
  QUANTITY_TABLE[ args.merge( self ) ]
end