Class: SY::Quantity

Inherits:
Object
  • Object
show all
Includes:
NameMagic
Defined in:
lib/sy/quantity.rb

Overview

Quantity.

Constant Summary collapse

RELATIVE_QUANTITY_NAME_SUFFIX =
"±"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(relative: nil, composition: nil, of: nil, measure: nil, amount: nil, coerces: [], coerces_to: [], **nn) ⇒ Quantity

Standard constructor of a metrological quantity. A quantity may have a name and a dimension.



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

def initialize( relative: nil,
                composition: nil,
                of: nil,
                measure: nil,
                amount: nil,
                coerces: [],
                coerces_to: [],
                **nn )
  @units = [] # array of units as favored by this quantity
  @relative = relative
  if composition.nil? then
    @dimension = SY.Dimension( of )
  else
    @composition = SY::Composition[ composition ]
    @dimension = @composition.dimension
  end
  @measure = measure.is_a?( SY::Measure ) ? measure :
    if measure.nil? then
      if amount.nil? then nil else
        SY::Measure.simple_scale( amount )
      end
    else
      fail ArgumentError, ":amount and :measure shouldn't be both supplied" unless amount.nil?
      SY::Measure.simple_scale( measure )
    end
  coerces( *Array( coerces ) )
  Array( coerces_to ).each { |qnt| qnt.coerces self }
end

Instance Attribute Details

#compositionObject (readonly)

Creates a composition from a dimension, or acts as composition getter if this has already been specified.



143
144
145
# File 'lib/sy/quantity.rb', line 143

def composition
  @composition
end

#dimensionObject (readonly)

Returns the value of attribute dimension.



11
12
13
# File 'lib/sy/quantity.rb', line 11

def dimension
  @dimension
end

#unitsObject (readonly)

Returns the value of attribute units.



11
12
13
# File 'lib/sy/quantity.rb', line 11

def units
  @units
end

Class Method Details

.dimensionless(*args) ⇒ Object Also known as: zero

Dimensionless quantity constructor alias.

Raises:

  • (TErr)


42
43
44
45
46
47
# File 'lib/sy/quantity.rb', line 42

def dimensionless *args
   = args.extract_options!
  raise TErr, "Dimension not zero!" unless [:dimension].zero? if
    .has? :dimension, syn!: :of
  new( *( args << .merge!( of: SY::Dimension.zero ) ) ).protect!
end

.of(*args) ⇒ Object

Dimension-based quantity constructor. Examples: Quantity.of Dimension.new( "L.T⁻²" ) Quantity.of "L.T⁻²"



18
19
20
21
22
23
24
25
26
27
# File 'lib/sy/quantity.rb', line 18

def of *args
   = args.extract_options!
  dim = case args.size
        when 0 then
          .must_have :dimension
          .delete :dimension
        else args.shift end
  args << .merge!( of: SY::Dimension.new( dim ) )
  return new( *args ).protect!
end

.standard(of: nil) ⇒ Object

Standard quantity. Example: Quantity.standard of: Dimension.new( "L.T⁻²" ) or <tt>Quantity.standard of: “L.T⁻²” (Both should give Acceleration as their result.)



35
36
37
38
# File 'lib/sy/quantity.rb', line 35

def standard( of: nil )
  fail ArgumentError, "Dimension (:of argument) must be given!" if of.nil?
  return SY.Dimension( of ).standard_quantity
end

Instance Method Details

#*(q2) ⇒ Object

Quantity multiplication.



289
290
291
292
293
# File 'lib/sy/quantity.rb', line 289

def * q2
  rel = [ self, q2 ].any? &:relative
  ( SY::Composition[ self => 1 ] + SY::Composition[ q2 => 1 ] )
    .to_quantity relative: rel
end

#**(num) ⇒ Object

Quantity raising to a number.



305
306
307
# File 'lib/sy/quantity.rb', line 305

def ** num
  SY::Composition[ self => num ].to_quantity relative: relative?
end

#/(q2) ⇒ Object

Quantity division.



297
298
299
300
301
# File 'lib/sy/quantity.rb', line 297

def / q2
  rel = [ self, q2 ].any? &:relative?
  ( SY::Composition[ self => 1 ] - SY::Composition[ q2 => 1 ] )
    .to_quantity relative: rel
end

#absoluteObject

Absolute quantity related to this quantity.



239
240
241
# File 'lib/sy/quantity.rb', line 239

def absolute
  absolute? ? self : colleague
end

#absolute?Boolean

Is the quantity absolute? (Opposite of #relative?)

Returns:

  • (Boolean)


205
206
207
# File 'lib/sy/quantity.rb', line 205

def absolute?
  not relative?
end

#coerce(other) ⇒ Object



351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'lib/sy/quantity.rb', line 351

def coerce other
  case other
  when Numeric then
    return SY::Amount.relative, self
  when SY::Quantity then
    # By default, coercion between quantities doesn't exist. The basic
    # purpose of having quantities is to avoid mutual mixing of
    # incompatible magnitudes, as in "one cannot sum pears with apples".
    # 
    if other == self then
      return other, self
    else
      raise SY::QuantityError, "#{other} and #{self} do not mix!"
    end
  else
    raise TErr, "#{self} cannot be coerced into a #{other.class}!"
  end
end

#coerces(*other_quantities) ⇒ Object

Quantities explicitly coerced by this quantity.



94
95
96
97
98
# File 'lib/sy/quantity.rb', line 94

def coerces *other_quantities
  if other_quantities.empty? then @coerces ||= [] else
    other_quantities.each { |qnt| coerces << qnt }
  end
end

#coerces?(other) ⇒ Boolean

Is the quantity supplied as the argument coerced by this quantity?

Returns:

  • (Boolean)


102
103
104
105
106
107
108
# File 'lib/sy/quantity.rb', line 102

def coerces? other
  other == self || coerces.include?( other ) ||
    colleague.coerces.include?( other.colleague ) ||
    if simple? then false else
      composition.coerces? other.composition
    end
end

#colleagueObject

For an absolute quantity, colleague is the corresponding relative quantity. Vice-versa, for a relative quantity, colleague is its absolute quantity.



218
219
220
# File 'lib/sy/quantity.rb', line 218

def colleague
  @colleague ||= construct_colleague
end

#dimensionless?Boolean

Is the quantity dimensionless?

Returns:

  • (Boolean)


311
312
313
# File 'lib/sy/quantity.rb', line 311

def dimensionless?
  dimension.zero?
end

#inspectObject

Inspect string.



347
348
349
# File 'lib/sy/quantity.rb', line 347

def inspect
  "#<Quantity:#{to_s}>"
end

#irreducible?Boolean

Irreducible quantity is one which cannot or should not be reduced to its components in the process of quantity simplification.

Returns:

  • (Boolean)


136
137
138
# File 'lib/sy/quantity.rb', line 136

def irreducible?
  simple? or protected?
end

#magnitude(amount) ⇒ Object

Constructs a absolute magnitude of this quantity.



251
252
253
# File 'lib/sy/quantity.rb', line 251

def magnitude amount
  Magnitude().new( of: self, amount: amount )
end

#measure(of: nil) ⇒ Object

Creates a measure of a specified other quantity. If no :of is specified, simply acts as a getter of @measure attribute.



183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/sy/quantity.rb', line 183

def measure( of: nil )
  return @measure if of.nil? # act as simple getter if :of not specified
  return SY::Measure.identity if of == self or of == colleague
  fail SY::DimensionError, "#{self} vs. #{of}!" unless same_dimension? of
  return of.measure( of: of.standard ).inverse if standardish?
  m = begin
        measure || colleague.measure || composition.infer_measure
      rescue NoMethodError
        fail SY::QuantityError, "Measure of #{of} by #{self} impossible!"
      end
  return m if of.standardish?
  return m * standard.measure( of: of )
end

#new_standard_unit(amount: nil, measure: nil, **nn) ⇒ Object

Constructor of a new standard unit (replacing current @standard_unit). For standard units, amount is implicitly 1. So :amount argument here has different meaning – it sets the measure of the quantity. Measure can also be specified more explicitly by :measure named argument.



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/sy/quantity.rb', line 268

def new_standard_unit( amount: nil, measure: nil, **nn )
  explain_amount_of_standard_units if amount.is_a? Numeric # n00b help
  # For standard units, amount has special meaning of setting up mapping.
  if measure then
    raise ArgumentError, "When :measure is specified, :amount must not be " +
      "expliticly specified." unless amount.nil?
    raise TypeError, ":measure argument must be a SY::Measure!" unless
      measure.is_a? SY::Measure
    set_measure( measure )
  else
    set_measure( SY::Measure.simple_scale( amount.nil? ? 1 : amount.amount ) )
  end
  # Replace @standard_unit with the newly constructed unit.
  Unit().instance_variable_set( :@standard,
                                unit( **nn ).tap do |u|
                                  ( units.unshift u ).uniq!
                                end )
end

#protect!Object

Protects quantity from decomposition.



119
120
121
122
123
# File 'lib/sy/quantity.rb', line 119

def protect!
  @protected = true
  @composition ||= SY::Composition.singular self
  return self
end

#protected?Boolean

Protected quantity is not allowed to be decomposed in the process of quantity simplification.

Returns:

  • (Boolean)


113
114
115
# File 'lib/sy/quantity.rb', line 113

def protected?
  @protected
end

#read(magnitude_of_other_quantity) ⇒ Object

Converts magnitude of another quantity to a magnitude of this quantity.



167
168
169
170
171
# File 'lib/sy/quantity.rb', line 167

def read magnitude_of_other_quantity
  other_quantity = magnitude_of_other_quantity.quantity
  other_amount = magnitude_of_other_quantity.amount
  magnitude measure( of: other_quantity ).r.( other_amount )
end

#relativeObject

Relative quantity related to this quantity.



211
212
213
# File 'lib/sy/quantity.rb', line 211

def relative
  relative? ? self : colleague
end

#relative?Boolean

Is the quantity relative?

Returns:

  • (Boolean)


199
200
201
# File 'lib/sy/quantity.rb', line 199

def relative?
  @relative ? true : false
end

#set_colleague(q2) ⇒ Object

Acts as colleague setter.

Raises:



224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/sy/quantity.rb', line 224

def set_colleague q2
  raise SY::DimensionError, "Mismatch: #{self}, #{q2}!" unless
    same_dimension? q2
  raise SY::QuantityError, "#{self} an #{q2} are both " +
    "{relative? ? 'relative' : 'absolute'}!" if relative? == q2.relative?
  if measure && q2.measure then
    raise SY::QuantityError, "Measure mismatch: #{self}, #{q2}!" unless
      measure == q2.measure
  end
  @colleague = q2
  q2.instance_variable_set :@colleague, self
end

#set_composition(comp) ⇒ Object

Acts as composition setter (dimension must match).



149
150
151
152
153
# File 'lib/sy/quantity.rb', line 149

def set_composition comp
  @composition = SY::Composition[ comp ]
    .aT "composition, when redefined after initialization,",
        "match the dimension" do |comp| comp.dimension == dimension end
end

#set_measure(measure) ⇒ Object

Acts as setter of measure (of the pertinent standard quantity).



157
158
159
160
161
162
163
# File 'lib/sy/quantity.rb', line 157

def set_measure measure
  @measure = if measure.is_a?( SY::Measure ) then
               measure
             else
               SY::Measure.simple_scale( measure )
             end
end

#simple?Boolean

Simple quantity is one with simple composition. If nontrivial composition is known for the colleague, it is assumed that the same composition would apply for this quantity, so it is not simple.

Returns:

  • (Boolean)


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

def simple?
  cᴍ = composition
  cᴍ.empty? || cᴍ.singular? && cᴍ.first[0] == self
end

#standardObject

Returns the standard quantity for this quantity’s dimension.



323
324
325
# File 'lib/sy/quantity.rb', line 323

def standard
  dimension.standard_quantity
end

#standard!Object

Make the quantity standard for its dimension.



317
318
319
# File 'lib/sy/quantity.rb', line 317

def standard!
  SY::Dimension.standard_quantities[ dimension ] = self
end

#standard?Boolean

Is the dimension standard?

Returns:

  • (Boolean)


329
330
331
# File 'lib/sy/quantity.rb', line 329

def standard?
  self == standard
end

#standard_unitObject

Reader of standard unit.



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

def standard_unit
  Unit().standard
end

#standardish?Boolean

Is the dimension or its colleague standard?

Returns:

  • (Boolean)


335
336
337
# File 'lib/sy/quantity.rb', line 335

def standardish?
  standard? || colleague.standard?
end

#to_sObject

A string briefly describing the quantity.



341
342
343
# File 'lib/sy/quantity.rb', line 341

def to_s
  name.nil? ? "[#{dimension}]" : name.to_s
end

#unit(**nn) ⇒ Object

Constructs a new unit of this quantity.



257
258
259
260
261
# File 'lib/sy/quantity.rb', line 257

def unit **nn
  u = Unit().new( nn.update( of: self ) )
  ( units << u ).uniq! # Add it to @units array.
  return u
end

#unprotect!Object

Unprotects quantity from decomposition.



127
128
129
130
131
# File 'lib/sy/quantity.rb', line 127

def unprotect!
  @protected = false
  @composition = nil if @composition == SY::Composition.singular( self )
  return self
end

#write(amount_of_this_quantity, other_quantity) ⇒ Object

Converts an amount of this quantity to a magnitude of other quantity.



175
176
177
178
# File 'lib/sy/quantity.rb', line 175

def write amount_of_this_quantity, other_quantity
  measure( of: other_quantity )
    .write( magnitude( amount_of_this_quantity ), other_quantity )
end