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.



189
190
191
# File 'lib/sy/composition.rb', line 189

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

#+(other) ⇒ Object

Merges two compositions.



177
178
179
# File 'lib/sy/composition.rb', line 177

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

#+@Object

Returns a new instance with same hash.



165
166
167
# File 'lib/sy/composition.rb', line 165

def +@
  self.class[ self ]
end

#-(other) ⇒ Object

Subtracts two compositions.



183
184
185
# File 'lib/sy/composition.rb', line 183

def - other
  self + -other
end

#-@Object

Negates hash exponents.



171
172
173
# File 'lib/sy/composition.rb', line 171

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

#/(number) ⇒ Object

Division by a number.



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

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
# File 'lib/sy/composition.rb', line 132

def atomic?
  singular? && first[0].dimension.base?
end

#coerces?(other) ⇒ Boolean

Whether this composition coerces another compotision.

Returns:

  • (Boolean)


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

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.



228
229
230
# File 'lib/sy/composition.rb', line 228

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

#expandObject

Try to simplify the composition by decomposing its quantities.



256
257
258
259
260
261
262
263
264
265
266
# File 'lib/sy/composition.rb', line 256

def expand
  return self if irreducible?
  self.class[ reduce( self.class.empty ) { |cᴍ, pair|
                qnt, exp = pair
                ( cᴍ + if qnt.irreducible? then
                       self.class.singular( qnt ) * exp
                     else
                       qnt.composition * exp
                     end )
              } ]
end

#infer_measureObject

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



235
236
237
238
239
240
241
# File 'lib/sy/composition.rb', line 235

def infer_measure
  map do |qnt, exp|
    if qnt.standardish? then SY::Measure.identity else
      qnt.measure( of: qnt.standard ) ** exp
    end
  end.reduce( SY::Measure.identity, :* )
end

#irreducible?Boolean

Whether it is possible to expand this

Returns:

  • (Boolean)


250
251
252
# File 'lib/sy/composition.rb', line 250

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.



222
223
224
# File 'lib/sy/composition.rb', line 222

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)


245
246
247
# File 'lib/sy/composition.rb', line 245

def simple?
  empty? or singular?
end

#simplifyObject

Simplifies a quantity hash by applying simplification rules.



205
206
207
208
209
# File 'lib/sy/composition.rb', line 205

def simplify
   = self.to_hash
  SIMPLIFICATION_RULES.each { |rule| rule.(  ) }
  self.class[  ]
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.



213
214
215
216
# File 'lib/sy/composition.rb', line 213

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