class SY::Quantity

Quantity.

Constants

RELATIVE_QUANTITY_NAME_SUFFIX

Attributes

Magnitude[R]
MagnitudeModule[R]
Unit[R]
composition[R]
dimension[R]
units[R]

Public Class Methods

dimensionless(*args) click to toggle source

Dimensionless quantity constructor alias.

# 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
Also aliased as: zero
new( relative: nil, composition: nil, of: nil, measure: nil, amount: nil, coerces: [], coerces_to: [], **nn ) click to toggle source

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

# 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
of(*args) click to toggle source

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

# 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 ) click to toggle source

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

# 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
zero(*args)
Alias for: dimensionless

Public Instance Methods

*(q2) click to toggle source

Quantity multiplication.

# 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) click to toggle source

Quantity raising to a number.

# File lib/sy/quantity.rb, line 305
def ** num
  SY::Composition[ self => num ].to_quantity relative: relative?
end
/(q2) click to toggle source

Quantity division.

# 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
absolute() click to toggle source

Absolute quantity related to this quantity.

# File lib/sy/quantity.rb, line 239
def absolute
  absolute? ? self : colleague
end
absolute?() click to toggle source

Is the quantity absolute? (Opposite of relative?)

# File lib/sy/quantity.rb, line 205
def absolute?
  not relative?
end
coerce(other) click to toggle source
# 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) click to toggle source

Quantities explicitly coerced by this quantity.

# 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) click to toggle source

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

# 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
colleague() click to toggle source

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

# File lib/sy/quantity.rb, line 218
def colleague
  @colleague ||= construct_colleague
end
dimensionless?() click to toggle source

Is the quantity dimensionless?

# File lib/sy/quantity.rb, line 311
def dimensionless?
  dimension.zero?
end
inspect() click to toggle source

Inspect string.

# File lib/sy/quantity.rb, line 347
def inspect
  "#<Quantity:#{to_s}>"
end
irreducible?() click to toggle source

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

# File lib/sy/quantity.rb, line 136
def irreducible?
  simple? or protected?
end
magnitude(amount) click to toggle source

Constructs a absolute magnitude of this quantity.

# File lib/sy/quantity.rb, line 251
def magnitude amount
  Magnitude().new( of: self, amount: amount )
end
measure( of: nil ) click to toggle source

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

# 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 ) click to toggle source

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.

# 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!() click to toggle source

Protects quantity from decomposition.

# File lib/sy/quantity.rb, line 119
def protect!
  @protected = true
  @composition ||= SY::Composition.singular self
  return self
end
protected?() click to toggle source

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

# File lib/sy/quantity.rb, line 113
def protected?
  @protected
end
read(magnitude_of_other_quantity) click to toggle source

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

# 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
relative() click to toggle source

Relative quantity related to this quantity.

# File lib/sy/quantity.rb, line 211
def relative
  relative? ? self : colleague
end
relative?() click to toggle source

Is the quantity relative?

# File lib/sy/quantity.rb, line 199
def relative?
  @relative ? true : false
end
set_colleague(q2) click to toggle source

Acts as colleague setter.

# 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) click to toggle source

Acts as composition setter (dimension must match).

# 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) click to toggle source

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

# 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?() click to toggle source

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.

# File lib/sy/quantity.rb, line 87
def simple?
  cᴍ = composition
  cᴍ.empty? || cᴍ.singular? && cᴍ.first[0] == self
end
standard() click to toggle source

Returns the standard quantity for this quantity's dimension.

# File lib/sy/quantity.rb, line 323
def standard
  dimension.standard_quantity
end
standard!() click to toggle source

Make the quantity standard for its dimension.

# File lib/sy/quantity.rb, line 317
def standard!
  SY::Dimension.standard_quantities[ dimension ] = self
end
standard?() click to toggle source

Is the dimension standard?

# File lib/sy/quantity.rb, line 329
def standard?
  self == standard
end
standard_unit() click to toggle source

Reader of standard unit.

# File lib/sy/quantity.rb, line 245
def standard_unit
  Unit().standard
end
standardish?() click to toggle source

Is the dimension or its colleague standard?

# File lib/sy/quantity.rb, line 335
def standardish?
  standard? || colleague.standard?
end
to_s() click to toggle source

A string briefly describing the quantity.

# File lib/sy/quantity.rb, line 341
def to_s
  name.nil? ? "[#{dimension}]" : name.to_s
end
unit(**nn) click to toggle source

Constructs a new unit of this quantity.

# 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!() click to toggle source

Unprotects quantity from decomposition.

# 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) click to toggle source

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

# 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

Private Instance Methods

construct_colleague() click to toggle source
# File lib/sy/quantity.rb, line 437
def construct_colleague
  ɴ = name
  ʀsuffix = SY::Quantity::RELATIVE_QUANTITY_NAME_SUFFIX
  rel = relative?
  # Here, it is impossible to rely on Composition::QUANTITY_TABLE –
  # on the contrary, the table relies on Quantity#colleague.
  constr_ɴ = ->( ɴ, ʀ ) { ç.new composition: composition, ɴ: ɴ, relative: ʀ }
  constr_anon = ->( ʀ ) { ç.new composition: composition, relative: ʀ }
  # enough of preliminaries
  if not rel then
    inst = ɴ ? constr_ɴ.( "#{ɴ}#{ʀsuffix}", true ) : constr_anon.( true )
    inst.aT &:relative?
  elsif ɴ.to_s.ends_with?( ʀsuffix ) && ɴ.size > ʀsuffix.size
    inst = constr_ɴ.( ɴ.to_s[0..ɴ.size-ʀsuffix.size-1], false )
    inst.aT &:absolute?
  else inst = constr_anon.( false ).aT &:absolute? end
  inst.instance_variable_set :@colleague, self
  return inst
end
explain_amount_of_standard_units() click to toggle source
# File lib/sy/quantity.rb, line 461
def explain_amount_of_standard_units
  raise TypeError, "For standard units, :amount is 1, by definition. When" +
    ":amount parameter is supplied to a standard unit constructor, its" +
    "meaning is different: Using a magnitude of the same dimension, but" +
    "different quantity, it establishes conversion relationship between" +
    "the two quantities."
end
same_dimension?(other) click to toggle source
# File lib/sy/quantity.rb, line 457
def same_dimension? other
  dimension == other.dimension
end