Class: VectorNumber

Inherits:
Object
  • Object
show all
Includes:
Comparable, Enumerable
Defined in:
lib/vector_number.rb,
lib/vector_number/mathing.rb,
lib/vector_number/version.rb,
lib/vector_number/querying.rb,
lib/vector_number/comparing.rb,
lib/vector_number/vectoring.rb,
lib/vector_number/converting.rb,
lib/vector_number/enumerating.rb,
lib/vector_number/special_unit.rb,
lib/vector_number/stringifying.rb,
lib/vector_number/math_converting.rb,
lib/vector_number/numeric_refinements.rb

Overview

VectorNumber provides a Numeric-like experience for doing arithmetics on heterogeneous objects, with more advanced operations based on real vector spaces available when needed.

VectorNumber inherits from Object and includes Enumerable and Comparable. It implements mostly the same interface as Numeric classes, but can #coerce any value. Its behavior follows Complex when possible.

All instances are frozen after creation.

Creation

Comparing

  • #==: test for equal value

  • #eql?: test for equal value and type

  • #<=>: compare real values

  • #hash: calculate hash value for use in Hashes

Querying

Arithmetic operations

  • #-@/#neg: negate value

  • #coerce: convert any object to a VectorNumber

  • #+/#add: add object (vector addition)

  • #-/#sub: subtract object (vector subtraction)

  • #*/#mult: multiply (scale) by a real number

  • #//#quo: divide (scale) by a real number

  • #fdiv: divide (scale) by a real number, using fdiv

  • #div: perform integer division, rounding towards -∞

  • #ceildiv: perform integer division, rounding towards +∞

  • #%/#modulo: return modulus from integer division (#div)

  • #divmod: combination of #div and #modulo

  • #remainder: return remainder from integer division

Rounding

  • #round: round each coefficient

  • #ceil: round each coefficient up towards +∞

  • #floor: round each coefficient down towards -∞

  • #truncate: truncate each coefficient towards 0

Vector operations

Type conversion

  • #real: return real part

  • #imag/#imaginary: return imaginary part

  • #to_i/#to_int: convert to Integer if possible

  • #to_f: convert to Float if possible

  • #to_r: convert to Rational if possible

  • #to_d: convert to BigDecimal if possible

  • #to_c: convert to Complex if possible

Hash-like operations

Miscellaneous methods

Since:

  • 0.1.0

Defined Under Namespace

Modules: NumericRefinements Classes: SpecialUnit

Constant Summary collapse

NUMERIC_UNITS =

List of special numeric unit constants.

Since:

  • 0.6.0

[SpecialUnit.new("1", "").freeze, SpecialUnit.new("i", "i").freeze].freeze
R =

Constant for real unit (1).

Its string representation is an empty string.

Since:

  • 0.6.0

I =

Constant for imaginary unit (i).

Its string representation is “i”.

Since:

  • 0.6.0

VERSION =

Returns:

  • (String)

Since:

  • 0.1.0

"0.6.1"
MULT_STRINGS =

Predefined symbols for multiplication to display between unit and coefficient.

Returns:

  • (Hash{Symbol => String})

Since:

  • 0.1.0

{
  asterisk: "*", # U+002A
  cross: "×", # U+00D7
  dot: "", # U+22C5
  invisible: "", # U+2062, zero-width multiplication operator
  space: " ",
  none: "",
}.freeze

Miscellaneous methods collapse

Creation collapse

Miscellaneous methods collapse

Arithmetic operations collapse

Querying collapse

Comparing collapse

Vector operations collapse

Type conversion collapse

Hash-like operations collapse

Constructor Details

#initialize(values = nil) {|coefficient| ... } ⇒ VectorNumber

Create new VectorNumber from values, possibly modifying coefficients with a block.

Using VectorNumber.new() directly is more efficient than VectorNumber[values...].

values can be:

  • an array of values (see []);

  • a VectorNumber to copy;

  • a hash in the format returned by #to_h;

  • nil to specify a 0-sized vector (same as an empty array or hash).

Using a hash as values is an advanced technique which allows to quickly construct a VectorNumber with desired units and coefficients, but it can also lead to unexpected results if care is not taken to provide only valid keys and values.

Examples:

VectorNumber.new(1, 2, 3) # ArgumentError
VectorNumber.new([1, 2, 3]) # => (6)
VectorNumber.new(["b", VectorNumber::I]) # => (1⋅"b" + 1i)
VectorNumber.new # => (0)

with a block

VectorNumber.new(["a", "b", "c", 3]) { _1 * 2 } # => (2⋅"a" + 2⋅"b" + 2⋅"c" + 6)
VectorNumber.new(["a", "b", "c", 3], &:-@) # => (-1⋅"a" - 1⋅"b" - 1⋅"c" - 3)
VectorNumber.new(["a", "b", "c", 3], &:digits) # RangeError

using hash for values

v = VectorNumber.new({VectorNumber::R => 15, "a" => 3.4, nil => -3})
  # => (15 + 3.4⋅"a" - 3⋅nil)
v.to_h # => {unit/1 => 15, "a" => 3.4, nil => -3}

Parameters:

  • values (Array, VectorNumber, Hash{Object => Numeric}, nil) (defaults to: nil)

    values for this vector

Yield Parameters:

  • coefficient (Numeric)

    a real number

Yield Returns:

  • (Numeric)

    new coefficient

Raises:

  • (RangeError)

    if a block is used and it returns a non-number or non-real number

Since:

  • 0.1.0



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

def initialize(values = nil, **nil, &transform)
  initialize_from(values)
  apply_transform(&transform)
  finalize_contents
  @data.freeze
  freeze
end

Instance Attribute Details

#sizeInteger (readonly)

Number of non-zero dimensions.

Returns:

  • (Integer)

Since:

  • 0.1.0



164
165
166
# File 'lib/vector_number.rb', line 164

def size
  @size
end

Class Method Details

.[](*values) ⇒ Object

Create new VectorNumber from a list of values.

Examples:

VectorNumber[1, 2, 3] # => (6)
VectorNumber[[1, 2, 3]] # => (1⋅[1, 2, 3])
VectorNumber[] # => (0)
VectorNumber["b", VectorNumber["b"]] # => (2⋅'b')
VectorNumber["a", "b", "a"] # => (2⋅'a' + 1⋅'b')

Parameters:

  • values (Array<Object>)

    values to put in the number

Raises:

  • (ArgumentError)

Since:

  • 0.1.0



136
137
138
139
140
# File 'lib/vector_number.rb', line 136

def self.[](*values, **nil)
  raise ArgumentError, "no block accepted" if block_given?

  new(values)
end

.numeric_unit?(unit) ⇒ Boolean

Check if an object is a unit representing a numeric dimension (real or imaginary unit).

Examples:

VectorNumber.numeric_unit?(VectorNumber::R) # => true
VectorNumber.numeric_unit?(VectorNumber::I) # => true
VectorNumber.numeric_unit?(:i) # => false

Parameters:

  • unit (Object)

Returns:

  • (Boolean)

Since:

  • 0.6.0



157
158
159
# File 'lib/vector_number.rb', line 157

def self.numeric_unit?(unit)
  NUMERIC_UNITS.include?(unit)
end

Instance Method Details

#%(other) ⇒ VectorNumber Also known as: modulo

Return the modulus of dividing self by a real other as a vector.

This is equal to self - other * (self/other).floor, or, alternatively, self - other * self.div(other).

Examples:

VectorNumber[10] % 3 # => (1)
VectorNumber["a", "b", 6].modulo(2) # => (1⋅"a" + 1⋅"b")
-VectorNumber["a"] % VectorNumber[2] # => (1⋅"a")
# Can't divide by a non-real:
VectorNumber["a"] % VectorNumber["b"] # RangeError

numeric types can be divided in reverse

3 % VectorNumber[10] # => (3)
# Can't divide by a non-real:
3 % VectorNumber["a"] # RangeError

compare to #remainder

VectorNumber[-5] % 3 # => (1)
VectorNumber[-5].remainder(3) # => (-2)

Parameters:

Returns:

Raises:

  • (RangeError)

    if other is not a number or is not a real number

  • (ZeroDivisionError)

    if other is zero

See Also:

Since:

  • 0.2.6



294
295
296
297
298
299
300
# File 'lib/vector_number/mathing.rb', line 294

def %(other)
  check_divisibility(other)

  other = other.real
  # @type var other: Float
  new { _1 % other }
end

#*(other) ⇒ VectorNumber Also known as: mult

Multiply all coefficients by a real other, returning new vector.

This effectively multiplies #magnitude by other.

Examples:

VectorNumber[5] * 2 # => (10)
VectorNumber["a", "b", 6].mult(2) # => (2⋅"a" + 2⋅"b" + 12)
VectorNumber["a"] * VectorNumber[2] # => (2⋅"a")
# Can't multiply by a non-real:
VectorNumber["a"] * VectorNumber["b"] # RangeError

numeric types can be multiplied in reverse

2 * VectorNumber[5] # => (10)
2 * VectorNumber["a"] # => (2⋅"a")

Parameters:

Returns:

Raises:

  • (RangeError)

    if other is not a number or other can’t be multiplied by this one

Since:

  • 0.2.1



115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/vector_number/mathing.rb', line 115

def *(other)
  if real_number?(other)
    other = other.real
    # @type var other: Float
    new { _1 * other }
  elsif real_number?(self) && VectorNumber === other
    # @type var other: untyped
    other * self
  else
    raise RangeError, "can't multiply #{self} and #{other}"
  end
end

#+(other) ⇒ VectorNumber Also known as: add

Return new vector as a sum of this and other value. This is analogous to [].

Examples:

VectorNumber[5] + 10 # => (15)
VectorNumber["a"].add(VectorNumber["b"]) # => (1⋅"a" + 1⋅"b")
VectorNumber["a"] + "b" # => (1⋅"a" + 1⋅"b")

numeric types can be added in reverse

10 + VectorNumber[5] # => (15)
10 + VectorNumber["a"] # => (10 + 1⋅"a")

Parameters:

  • other (Object)

Returns:

Since:

  • 0.2.0



66
67
68
# File 'lib/vector_number/mathing.rb', line 66

def +(other)
  new([self, other])
end

#+@VectorNumber Also known as: dup

Return self.

Returns:

Since:

  • 0.2.0



217
218
# File 'lib/vector_number.rb', line 217

def +@ = self
# @since 0.2.4

#-(other) ⇒ VectorNumber Also known as: sub

Return new vector as a sum of this and additive inverse of other value.

This is implemented through #+ and #-@.

Examples:

VectorNumber[5] - 3 # => (2)
VectorNumber["a"].sub(VectorNumber["b"]) # => (1⋅"a" - 1⋅"b")
VectorNumber["a"] - "b" # => (1⋅"a" - 1⋅"b")

numeric types can be subtracted in reverse

3 - VectorNumber[5] # => (-2)
3 - VectorNumber["a"] # => (3 - 1⋅"a")

Parameters:

  • other (Object)

Returns:

Since:

  • 0.2.0



89
90
91
# File 'lib/vector_number/mathing.rb', line 89

def -(other)
  self + new([other], &:-@)
end

#-@VectorNumber Also known as: neg

Return new vector with negated coefficients (additive inverse).

Examples:

-VectorNumber[12, "i"] # => (-12 - 1⋅"i")
VectorNumber["a", "b", "a"].neg # => (-2⋅"a" - 1⋅"b")
-VectorNumber["a"] + VectorNumber["a"] # => (0)

Returns:

Since:

  • 0.2.0



44
45
46
# File 'lib/vector_number/mathing.rb', line 44

def -@
  new(&:-@)
end

#/(other) ⇒ VectorNumber Also known as: quo

Note:

This method never does integer division.

Divide all coefficients by a real other, returning new vector.

This effectively multiplies #magnitude by reciprocal of other.

Examples:

VectorNumber[10] / 2 # => (5)
VectorNumber["a", "b", 6].quo(2) # => (1/2⋅"a" + 1/2⋅"b" + 3/1)
VectorNumber["a"] / VectorNumber[2] # => (1/2⋅"a")
# Can't divide by a non-real:
VectorNumber["a"] / VectorNumber["b"] # RangeError

numeric types can be divided in reverse

2 / VectorNumber[10] # => (1/5)
# Can't divide by a non-real:
2 / VectorNumber["a"] # RangeError

Parameters:

Returns:

Raises:

  • (RangeError)

    if other is not a number or is not a real number

  • (ZeroDivisionError)

    if other is zero

Since:

  • 0.2.1



153
154
155
156
157
158
159
160
161
# File 'lib/vector_number/mathing.rb', line 153

def /(other)
  check_divisibility(other)

  other = other.real
  # Prevent integer division, but without loss of accuracy.
  other = Rational(other) if other.integer?
  # @type var other: Float
  new { _1 / other }
end

#<=>(other) ⇒ Integer?

Compare to other and return -1, 0, or 1 if self is less than, equal, or larger than other on real number line, or nil if any or both values are non-real.

Most VectorNumbers are non-real and therefore not comparable with this method.

Examples:

VectorNumber[130] <=> 12 # => 1
1 <=> VectorNumber[13] # => -1
VectorNumber[12.1] <=> Complex(12.1, 0) # => 0
# This doesn't work as expected without NumericRefinements:
Complex(12.1, 0) <=> VectorNumber[12.1] # => nil

# Any non-real comparison returns nil:
VectorNumber[12.1] <=> Complex(12.1, 1) # => nil
VectorNumber[12.1i] <=> 2 # => nil
VectorNumber["a"] <=> 2 # => nil

Parameters:

  • other (Object)

Returns:

  • (Integer)
  • (nil)

    if self or other isn’t a real number.

See Also:

Since:

  • 0.2.0



116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/vector_number/comparing.rb', line 116

def <=>(other)
  return nil unless numeric?(1)

  case other
  when VectorNumber
    other.numeric?(1) ? real <=> other.real : nil
  when Numeric
    other.imaginary.zero? ? real <=> other.real : nil
  else
    nil
  end
end

#==(other) ⇒ Boolean

Test whether other has the same value with == semantics.

Values are considered equal if

  • other is a VectorNumber and it has the same units and equal coefficients, or

  • other is a Numeric equal in value to this (real or complex) number.

Examples:

VectorNumber[3.13] == 3.13 # => true
VectorNumber[1.4, 1.5i] == Complex(1.4, 1.5) # => true
VectorNumber["a", "b", "c"] == VectorNumber["c", "b", "a"] # => true
VectorNumber["a", 14] == 14 # => false
VectorNumber["a"] == "a" # => false

Parameters:

  • other (Object)

Returns:

  • (Boolean)

Since:

  • 0.2.0



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/vector_number/comparing.rb', line 32

def ==(other)
  return true if equal?(other)

  case other
  when VectorNumber
    size == other.size && @data == other.to_h
  when Numeric
    numeric?(2) && other.real == real && other.imaginary == imaginary
  else
    # Can't compare a number-like value to a non-number.
    false
  end
end

#[](unit) ⇒ Numeric

Get the coefficient for the unit.

If the unit?(unit) is false, 0 is returned. Note that units for real and imaginary parts are VectorNumber::R and VectorNumber::I respectively.

Examples:

VectorNumber["a", "b", 6]["a"] # => 1
VectorNumber["a", "b", 6]["c"] # => 0

Parameters:

  • unit (Object)

Returns:

  • (Numeric)

Since:

  • 0.2.4



98
# File 'lib/vector_number/enumerating.rb', line 98

def [](unit) = @data[unit]

#abs2Numeric

Calculate the square of absolute value.

Examples:

VectorNumber[5.3].abs2 # => 5.3
VectorNumber[-5.3i].abs2 # => 5.3
VectorNumber[-5.3i, "i"].abs2 # => 29.09

Returns:

  • (Numeric)

Since:

  • 0.2.2



35
36
37
# File 'lib/vector_number/vectoring.rb', line 35

def abs2
  @data.values.sum(&:abs2)
end

#angle(other) ⇒ Numeric

Calculate the angle between this vector and other vector in radians.

If other is not a VectorNumber, it is automatically promoted.

Examples:

v = VectorNumber[2, "a"]
v.angle(v) # => 0.0
v.angle(1) # => 0.7853981633974483
v.angle("b") # => 1.5707963267948966
v.angle(-v) # => 3.141592653589793
v.angle(0) # ZeroDivisionError
VectorNumber[0].angle(v) # ZeroDivisionError

Parameters:

Returns:

  • (Numeric)

Raises:

  • (ZeroDivisionError)

    if self or other is a zero vector

Since:

  • <<next>>



183
184
185
186
187
188
189
190
191
192
# File 'lib/vector_number/vectoring.rb', line 183

def angle(other)
  has_direction?
  return 0.0 if equal?(other)

  other = new([other]) unless VectorNumber === other
  has_direction?(other)
  return Math::PI / 2.0 if (product = dot_product(other)).zero?

  Math.acos(product / magnitude / other.magnitude)
end

#ceil(digits = 0) ⇒ VectorNumber

Return a new vector with every coefficient rounded using their #ceil.

Examples:

VectorNumber[5.39].ceil # => (6)
VectorNumber[-5.35i].ceil # => (-5i)
VectorNumber[-5.35i, "i"].ceil # => (-5i + 1⋅"i")
VectorNumber[-5.35i, "i"].ceil(1) # => (-5.3i + 1⋅"i")
VectorNumber[-5.35i, "i"].ceil(-1) # => (10⋅"i")

Parameters:

  • digits (Integer) (defaults to: 0)

Returns:

Since:

  • 0.2.2



36
37
38
# File 'lib/vector_number/math_converting.rb', line 36

def ceil(digits = 0)
  new { _1.ceil(digits) }
end

#ceildiv(other) ⇒ VectorNumber

Divide all coefficients by a real other, converting results to integers using #ceil.

This is equal to (self / other).ceil.

Examples:

VectorNumber[10].ceildiv(3) # => (4)
VectorNumber["a"].ceildiv(2) # => (1⋅"a")
(VectorNumber["a"] - 3).ceildiv(2) # => (1⋅"a" - 1)
VectorNumber[-10, "string"].ceildiv(100) # => (1⋅"string")
# Can't divide by a non-real:
VectorNumber["a"].ceildiv(VectorNumber["b"]) # RangeError

Parameters:

Returns:

Raises:

  • (RangeError)

    if other is not a number or is not a real number

  • (ZeroDivisionError)

    if other is zero

See Also:

Since:

  • <<next>>



255
256
257
258
259
260
261
262
# File 'lib/vector_number/mathing.rb', line 255

def ceildiv(other)
  check_divisibility(other)

  other = other.real
  other = Rational(other) if other.integer?
  # @type var other: Float
  new { (_1 / other).ceil }
end

#clone(freeze: true) ⇒ VectorNumber

Return self.

Returns:

Raises:

  • (ArgumentError)

    if freeze is not true or nil.

Since:

  • 0.2.4



227
228
229
230
231
232
233
234
235
236
237
# File 'lib/vector_number.rb', line 227

def clone(freeze: true)
  case freeze
  when true, nil
    self
  when false
    raise ArgumentError, "can't unfreeze VectorNumber"
  else
    raise ArgumentError,
          "unexpected value for freeze: #{Kernel.instance_method(:class).bind_call(freeze)}"
  end
end

#coefficientsArray<Numeric> Also known as: values

Get a list of non-zero coefficients.

Examples:

VectorNumber["a", "b", 6].coefficients # => [1, 1, 6]
VectorNumber.new.values # => []

Returns:

  • (Array<Numeric>)

Since:

  • 0.1.0



62
# File 'lib/vector_number/enumerating.rb', line 62

def coefficients = @data.values

#coerce(other) ⇒ Array(VectorNumber, VectorNumber)

The coerce method provides support for Ruby type coercion.

Unlike other numeric types, VectorNumber can coerce anything.

Examples:

VectorNumber["a"].coerce(5) # => [(5), (1⋅"a")]
VectorNumber[7].coerce([]) # => [(1⋅[]), (7)]
VectorNumber["a"] + 5 # => (1⋅"a" + 5)
# Direct reverse coercion doesn't work, but Numeric types know how to call #coerce:
5.coerce(VectorNumber["a"]) # RangeError
5 + VectorNumber["a"] # => (5 + 1⋅"a")

Parameters:

  • other (Object)

Returns:

Since:

  • 0.2.0



25
26
27
28
29
30
31
32
# File 'lib/vector_number/mathing.rb', line 25

def coerce(other)
  case other
  when VectorNumber
    [other, self]
  else
    [new([other]), self]
  end
end

#div(other) ⇒ VectorNumber

Divide all coefficients by a real other, converting results to integers using #floor.

This is equal to (self / other).floor.

Examples:

VectorNumber[10].div(3) # => (3)
VectorNumber["a"].div(2) # => (0)
VectorNumber["a"].div(VectorNumber[2]) # => (0)
VectorNumber[-10, "string"].div(100) # => (-1)
# Can't divide by a non-real:
VectorNumber["a"].div(VectorNumber["b"]) # RangeError

numeric types can be divided in reverse

2.div(VectorNumber[10]) # => (0)
# Can't divide by a non-real:
2.div(VectorNumber["a"]) # RangeError

Parameters:

Returns:

Raises:

  • (RangeError)

    if other is not a number or is not a real number

  • (ZeroDivisionError)

    if other is zero

See Also:

Since:

  • 0.2.6



224
225
226
227
228
229
230
# File 'lib/vector_number/mathing.rb', line 224

def div(other)
  check_divisibility(other)

  other = other.real
  # @type var other: Float
  new { _1.div(other) }
end

#divmod(other) ⇒ Array(VectorNumber, VectorNumber)

Return the quotient and modulus of dividing self by a real other. There is no performance benefit compared to calling #div and #% separately.

Examples:

VectorNumber[10].divmod(3) # => [(3), (1)]
VectorNumber["a"].divmod(2) # => [(0), (1⋅"a")]
VectorNumber["a"].divmod(VectorNumber[2]) # => [(0), (1⋅"a")]
# Can't divide by a non-real:
VectorNumber["a"].divmod(VectorNumber["b"]) # RangeError

numeric types can be divided in reverse

3.divmod(VectorNumber[10]) # => [(0), (3)]
# Can't divide by a non-real:
3.divmod(VectorNumber["a"]) # RangeError

Parameters:

Returns:

Raises:

  • (RangeError)

    if other is not a number or is not a real number

  • (ZeroDivisionError)

    if other is zero

See Also:

Since:

  • 0.2.6



328
329
330
# File 'lib/vector_number/mathing.rb', line 328

def divmod(other)
  [div(other), modulo(other)]
end

#dot_product(other) ⇒ Numeric Also known as: inner_product, scalar_product

Calculate the dot product (inner product/scalar product) of this vector with other vector.

If other is not a VectorNumber, it is automatically promoted.

Examples:

VectorNumber[2].dot_product(VectorNumber[3]) # => 6
v = VectorNumber[2, "a"]
v.dot_product(VectorNumber[3, "s"]) # => 6
v.inner_product(3) # => 6
v.scalar_product("b") # => 0.0
v.dot_product(0) # => 0.0
v.inner_product(2 * VectorNumber[-0.5, "a"]) # => 0.0
VectorNumber[0].scalar_product(v) # => 0.0
v.dot_product(v) == v.abs2 # => true

Parameters:

Returns:

  • (Numeric)

Since:

  • <<next>>



150
151
152
153
154
155
156
157
158
# File 'lib/vector_number/vectoring.rb', line 150

def dot_product(other)
  return 0.0 if zero?
  return abs2 if equal?(other)

  other = new([other]) unless VectorNumber === other
  return 0.0 if other.zero?

  @data.sum { |u, c| c * other[u] }
end

#each {|unit, coefficient| ... } ⇒ VectorNumber #eachEnumerator Also known as: each_pair

Iterate through every pair of unit and coefficient. Returns Enumerator (with set size) if no block is given.

Examples:

v = VectorNumber["a", "b", 6]
units = []
v.each { |u, c| units << u unless VectorNumber.numeric_unit?(u) } # => (1⋅"a" + 1⋅"b" + 6)
units # => ["a", "b"]

Enumerator

v.each.size # => 3
(v.each + [["d", 0]]).map(&:first) # => ["a", "b", unit/1, "d"]
v.each_pair.peek # => ["a", 1]

Overloads:

  • #each {|unit, coefficient| ... } ⇒ VectorNumber

    Returns self.

    Yield Parameters:

    • unit (Object)
    • coefficient (Numeric)

    Yield Returns:

    • (void)

    Returns:

  • #eachEnumerator

    Returns:

    • (Enumerator)

See Also:

  • Enumerable
  • Enumerator

Since:

  • 0.1.0



35
36
37
38
39
40
# File 'lib/vector_number/enumerating.rb', line 35

def each(&block)
  return to_enum { size } unless block_given?

  @data.each(&block)
  self
end

#eql?(other) ⇒ Boolean

Test whether other is VectorNumber and has the same value with eql? semantics.

Values are considered equal only if other is a VectorNumber and it has exactly the same units and coefficients, though possibly in a different order. Additionally, ‘a.eql?(b)` implies `a.hash == b.hash`.

Examples:

VectorNumber["a", "b", "c"].eql? VectorNumber["c", "b", "a"] # => true
VectorNumber[3.13].eql? 3.13 # => false
VectorNumber[1.4, 1.5i].eql? Complex(1.4, 1.5) # => false
VectorNumber["a", 14].eql? 14 # => false
VectorNumber["a"].eql? "a" # => false

Parameters:

  • other (Object)

Returns:

  • (Boolean)

Since:

  • 0.1.0



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/vector_number/comparing.rb', line 61

def eql?(other)
  return true if equal?(other)
  return false unless self.class == other.class

  size.eql?(other.size) && @data.eql?(other.to_h)
rescue NoMethodError => e
  # :nocov:
  raise unless e.receiver.equal?(other)
  # :nocov:

  # Should only happen if `other.class` is undefined.
  false
end

#fdiv(other) ⇒ VectorNumber

Divide all coefficients by a real other using fdiv, returning new vector with decimal coefficients.

There isn’t much benefit to this method, as #/ doesn’t do integer division, but it is provided for consistency.

Examples:

VectorNumber[10].fdiv(2) # => (5.0)
VectorNumber["a", "b", 6].fdiv(2) # => (0.5⋅"a" + 0.5⋅"b" + 3.0)
VectorNumber["a"].fdiv(VectorNumber[2]) # => (0.5⋅"a")
# Can't divide by a non-real:
VectorNumber["a"].fdiv(VectorNumber["b"]) # RangeError

reverse division may return non-vector results

2.fdiv(VectorNumber[10]) # => 0.2 (Float)
2.0.fdiv(VectorNumber[10]) # => (0.2) (VectorNumber)

Parameters:

Returns:

Raises:

  • (RangeError)

    if other is not a number or is not a real number

  • (ZeroDivisionError)

    if other is zero

Since:

  • 0.2.1



189
190
191
192
193
194
195
# File 'lib/vector_number/mathing.rb', line 189

def fdiv(other)
  check_divisibility(other)

  other = other.real
  # @type var other: Float
  new { _1.fdiv(other) }
end

#finite?Boolean

Returns true if all coefficients are finite, false otherwise.

Examples:

VectorNumber[2].finite? # => true
VectorNumber[Float::NAN].finite? # => false
VectorNumber["a"].mult(Float::INFINITY).finite? # => false

Returns:

  • (Boolean)

Since:

  • 0.1.0



60
61
62
# File 'lib/vector_number/querying.rb', line 60

def finite?
  all? { |_u, v| v.finite? }
end

#floor(digits = 0) ⇒ VectorNumber

Return a new vector with every coefficient rounded using their #floor.

Examples:

VectorNumber[5.39].floor # => (5)
VectorNumber[-5.35i].floor # => (-6i)
VectorNumber[-5.35i, "i"].floor # => (-6i + 1⋅"i")
VectorNumber[-5.35i, "i"].floor(1) # => (-5.4i + 1⋅"i")
VectorNumber[-5.35i, "i"].floor(-1) # => (-10i)

Parameters:

  • digits (Integer) (defaults to: 0)

Returns:

Since:

  • 0.2.2



53
54
55
# File 'lib/vector_number/math_converting.rb', line 53

def floor(digits = 0)
  new { _1.floor(digits) }
end

#hashInteger

Generate an Integer hash value for self.

Examples:

VectorNumber["b", "a"].hash # => 3081872088394655324
VectorNumber["a", "b"].hash # => 3081872088394655324
VectorNumber["b", "c"].hash # => -1002381358514682371

Returns:

  • (Integer)

Since:

  • 0.4.2



85
86
87
# File 'lib/vector_number/comparing.rb', line 85

def hash
  [self.class, @data].hash
end

#imaginaryNumeric Also known as: imag

Return imaginary part of the number.

Examples:

VectorNumber[23, "a"].imaginary # => 0
VectorNumber["a", Complex(1, 2r)].imag # => (2/1)

Returns:

  • (Numeric)

Since:

  • 0.1.0



22
# File 'lib/vector_number/converting.rb', line 22

def imaginary = @data[I]

#infinite?1?

Returns 1 if any coefficients are non-finite, nil otherwise.

This behavior is the same as Complex‘s.

Examples:

VectorNumber[2].infinite? # => nil
VectorNumber[Float::NAN].infinite? # => 1
VectorNumber["a"].mult(-Float::INFINITY).infinite? # => 1

Returns:

  • (1, nil)

Since:

  • 0.1.0



74
75
76
# File 'lib/vector_number/querying.rb', line 74

def infinite?
  finite? ? nil : 1 # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
end

#inspectString

Return string representation of the vector suitable for display.

This is similar to Complex#inspect — it returns result of #to_s in round brackets.

Examples:

VectorNumber[5, :s].inspect # => "(5 + 1⋅:s)"

Returns:

  • (String)

See Also:

Since:

  • 0.1.0



68
69
70
# File 'lib/vector_number/stringifying.rb', line 68

def inspect
  "(#{self})"
end

#integer?false

Always returns false, as vectors are not Integers.

Returns:

  • (false)

Since:

  • 0.2.1



149
# File 'lib/vector_number/querying.rb', line 149

def integer? = false

#magnitudeNumeric Also known as: abs

Calculate the magnitude of the vector (its length/absolute value).

This is also known as Euclidean norm or 2-norm.

Examples:

VectorNumber[5.3].magnitude # => 5.3
VectorNumber[-5.3i].magnitude # => 5.3
VectorNumber[-5.3i, "i"].abs # => 5.3935146240647205

Returns:

  • (Numeric)

Since:

  • 0.2.2



18
19
20
# File 'lib/vector_number/vectoring.rb', line 18

def magnitude
  abs2**0.5
end

#maximum_normNumeric Also known as: infinity_norm

Calculate the maximum norm (infinity norm) of the vector.

Examples:

VectorNumber[5.3].maximum_norm # => 5.3
VectorNumber[-5.3i].maximum_norm # => 5.3
VectorNumber[-5.3i, "i"].maximum_norm # => 5.3
VectorNumber["a", "s"].maximum_norm # => 1

Returns:

  • (Numeric)

Since:

  • <<next>>



67
68
69
70
71
# File 'lib/vector_number/vectoring.rb', line 67

def maximum_norm
  return 0 if zero?

  @data.values.map(&:abs).max
end

#negative?Boolean

Returns true if number is non-zero and all non-zero coefficients are negative, and false otherwise.

Examples:

VectorNumber["a"].neg.negative? # => true
VectorNumber[-2].neg.negative? # => false
(VectorNumber["1"] - VectorNumber[1]).negative? # => false
VectorNumber[0].negative? # => false

Returns:

  • (Boolean)

Since:

  • 0.1.0



131
132
133
# File 'lib/vector_number/querying.rb', line 131

def negative?
  !zero? && all? { |_u, c| c.negative? }
end

#nonnumeric?(dimensions = 2) ⇒ Boolean

Returns true if this VectorNumber contains any non-zero dimensions with non-numeric units, and false otherwise.

This is exactly the opposite of #numeric?.

Examples:

VectorNumber[2].nonnumeric? # => false
VectorNumber[2, 3i].nonnumeric? # => false
VectorNumber[2, "a"].nonnumeric? # => true
VectorNumber[2, 3i].nonnumeric?(1) # => true

Parameters:

  • dimensions (Integer) (defaults to: 2)

    number of dimensions to consider “numeric”

    • 0 — zero

    • 1 — real number

    • 2 — complex number

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)

    if dimensions is negative

Since:

  • 0.2.1



50
# File 'lib/vector_number/querying.rb', line 50

def nonnumeric?(dimensions = 2) = !numeric?(dimensions)

#nonzero?VectorNumber?

Returns self if there are any non-zero coefficients, nil otherwise.

This is synonymous with size not being equal to 0. Behavior of returning self or nil is the same as Numeric‘s.

Examples:

VectorNumber["ab", "cd"].nonzero? # => (1⋅"ab" + 1⋅"cd")
VectorNumber[].nonzero? # => nil

Returns:

See Also:

Since:

  • 0.1.0



103
104
105
# File 'lib/vector_number/querying.rb', line 103

def nonzero?
  zero? ? nil : self # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
end

#numeric?(dimensions = 2) ⇒ Boolean

Returns true if all non-zero dimensions in this VectorNumber are numeric (real or complex), and false otherwise.

This is exactly the opposite of #nonnumeric?.

Examples:

VectorNumber[2].numeric? # => true
VectorNumber[2, 3i].numeric? # => true
VectorNumber[2, "a"].numeric? # => false
VectorNumber[2, 3i].numeric?(1) # => false

Parameters:

  • dimensions (Integer) (defaults to: 2)

    number of dimensions to consider “numeric”

    • 0 — zero

    • 1 — real number

    • 2 — complex number

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)

    if dimensions is negative

Since:

  • 0.2.0



27
28
29
30
31
32
# File 'lib/vector_number/querying.rb', line 27

def numeric?(dimensions = 2)
  raise ArgumentError, "`dimensions` must be non-negative" unless dimensions >= 0

  size <= dimensions &&
    (0...dimensions).count { (unit = NUMERIC_UNITS[_1]) && @data[unit].nonzero? } == size
end

#p_norm(p) ⇒ Numeric

Calculate the p-norm of the vector.

Examples:

VectorNumber[5.3].p_norm(2) # => 5.3
VectorNumber[-5.3i].p_norm(2) # => 5.3
VectorNumber[-5.3i, "i"].p_norm(2) # => 5.3935146240647205
VectorNumber[-5.3i, "i"].p_norm(1) # => 6.3
VectorNumber[-5.3i, "i"].p_norm(0.5) # => 10.904345773288535

Parameters:

  • p (Numeric)

Returns:

  • (Numeric)

Since:

  • <<next>>



52
53
54
# File 'lib/vector_number/vectoring.rb', line 52

def p_norm(p) # rubocop:disable Naming/MethodParameterName
  @data.values.sum { _1.abs**p }**(1.0 / p)
end

#positive?Boolean

Returns true if number is non-zero and all non-zero coefficients are positive, and false otherwise.

Examples:

VectorNumber["a"].positive? # => true
VectorNumber[2].neg.positive? # => false
(VectorNumber["1"] - VectorNumber[1]).positive? # => false
VectorNumber[0].positive? # => false

Returns:

  • (Boolean)

Since:

  • 0.1.0



117
118
119
# File 'lib/vector_number/querying.rb', line 117

def positive?
  !zero? && all? { |_u, c| c.positive? }
end

#realNumeric

Return real part of the number.

Examples:

VectorNumber[23, "a"].real # => 23
VectorNumber["a"].real # => 0

Returns:

  • (Numeric)

Since:

  • 0.1.0



13
# File 'lib/vector_number/converting.rb', line 13

def real = @data[R]

#real?false

Always returns false, as vectors are not real numbers.

This behavior is the same as Complex‘s.

Returns:

  • (false)

See Also:

Since:

  • 0.1.0



142
# File 'lib/vector_number/querying.rb', line 142

def real? = false

#remainder(other) ⇒ VectorNumber

Return the remainder of dividing self by a real other as a vector.

This is equal to self - other * (self/other).truncate.

Examples:

VectorNumber[10].remainder(3) # => (1)
VectorNumber["a"].remainder(2) # => (1⋅"a")
-VectorNumber["a"].remainder(VectorNumber[2]) # => (-1⋅"a")
# Can't divide by a non-real:
VectorNumber["a"].remainder(VectorNumber["b"]) # RangeError

numeric types can be divided in reverse

3.remainder(VectorNumber[10]) # => (3)
# Can't divide by a non-real:
3.remainder(VectorNumber["a"]) # RangeError

compare to #%

VectorNumber[-5] % 3 # => (1)
VectorNumber[-5].remainder(3) # => (-2)

Parameters:

Returns:

Raises:

  • (RangeError)

    if other is not a number or is not a real number

  • (ZeroDivisionError)

    if other is zero

See Also:

  • #%
  • Numeric#remainder

Since:

  • 0.2.6



359
360
361
362
363
364
365
# File 'lib/vector_number/mathing.rb', line 359

def remainder(other)
  check_divisibility(other)

  other = other.real
  # @type var other: Float
  new { _1.remainder(other) }
end

#round(digits = 0, half: :up) ⇒ VectorNumber

Return a new vector with every coefficient rounded using their #round.

In the case of BigDecimal coefficients, the half parameter is converted to the corresponding BigDecimal rounding mode (one of :half_up, :half_down, or :half_even). Other modes can not be specified.

Examples:

VectorNumber[-4.5i, "i"].round(half: :up) # => (-5i + 1⋅"i")
VectorNumber[-4.5i, "i"].round(half: :even) # => (-4i + 1⋅"i")
VectorNumber[-5.5i, "i"].round(half: :even) # => (-6i + 1⋅"i")
VectorNumber[-5.5i, "i"].round(half: :down) # => (-5i + 1⋅"i")
VectorNumber[-5.35i, "i"].round(1) # => (-5.4i + 1⋅"i")
VectorNumber[-5.35i, "i"].round(-1) # => (-10i)

Parameters:

  • digits (Integer) (defaults to: 0)
  • half (Symbol, nil) (defaults to: :up)

    one of :up, :down or :even, see Float#round for meaning

Returns:

See Also:

  • Float#round

Since:

  • 0.2.2



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/vector_number/math_converting.rb', line 80

def round(digits = 0, half: :up)
  if defined?(BigDecimal)
    bd_mode =
      case half
      when :down then :half_down
      when :even then :half_even
      else :half_up
      end
    new { (BigDecimal === _1) ? _1.round(digits, bd_mode) : _1.round(digits, half: half) }
  # :nocov:
  else
    new { _1.round(digits, half: half) }
  end
  # :nocov:
end

#scalar_projection(other) ⇒ Numeric

Calculate the scalar projection of this vector onto other vector.

Absolute value of scalar projection is equal to #magnitude of #vector_projection. Sign of scalar projection depends on the #angle between vectors. If other is not a VectorNumber, it is automatically promoted.

Examples:

v = VectorNumber[2, "a"]
v.scalar_projection(v) # => 2.23606797749979
v.scalar_projection(1) # => 2.0
v.scalar_projection("b") # => 0.0
v.scalar_projection(-v) # => -2.23606797749979
v.scalar_projection(2 * VectorNumber[-0.5, "a"]) # => 0.0
VectorNumber[0].scalar_projection(v) # => 0
v.scalar_projection(0) # ZeroDivisionError

Parameters:

Returns:

  • (Numeric)

Raises:

  • (ZeroDivisionError)

    if other is a zero vector

Since:

  • <<next>>



243
244
245
246
247
248
249
250
# File 'lib/vector_number/vectoring.rb', line 243

def scalar_projection(other)
  return magnitude if equal?(other) && has_direction?

  other = new([other]) unless VectorNumber === other
  has_direction?(other)

  dot_product(other) / other.magnitude
end

#scalar_rejection(other) ⇒ Numeric

Calculate the scalar rejection of this vector from other vector.

Scalar rejection is equal to #magnitude of #vector_rejection, and is always non-negative. If other is not a VectorNumber, it is automatically promoted.

Examples:

v = VectorNumber[2, "a"]
v.scalar_rejection(v) # => 0.0
v.scalar_rejection(1) # => 1.0
v.scalar_rejection("b") # => 2.23606797749979
v.scalar_rejection(-v) # => 0.0
v.scalar_rejection(2 * VectorNumber[-0.5, "a"]) # => 2.23606797749979
VectorNumber[0].scalar_rejection(v) # => 0.0
v.scalar_rejection(0) # ZeroDivisionError

Parameters:

Returns:

  • (Numeric)

Raises:

  • (ZeroDivisionError)

    if other is a zero vector

Since:

  • <<next>>



302
303
304
305
306
307
308
309
# File 'lib/vector_number/vectoring.rb', line 302

def scalar_rejection(other)
  return 0.0 if equal?(other) && has_direction?

  other = new([other]) unless VectorNumber === other
  has_direction?(other)

  (abs2 - dot_product(other)**2 / other.abs2)**0.5
end

#subspace_basisArray<VectorNumber>

Return an array of vectors forming orthonormal basis of linear subspace this vector belongs to.

Examples:

v = VectorNumber[1.2, "a"] * 2 - "s" # => (2.4 + 2⋅"a" - 1⋅"s")
v.subspace_basis # => [(1), (1⋅"a"), (1⋅"s")]
VectorNumber[0].subspace_basis # => []

Returns:

See Also:

Since:

  • <<next>>



88
89
90
# File 'lib/vector_number/vectoring.rb', line 88

def subspace_basis
  units.map { new([_1]) }
end

#to_cComplex

Return value as a Complex if only real and/or imaginary parts are non-zero.

Examples:

VectorNumber[13.5].to_c # => (13.5+0i)
VectorNumber[13r/12].to_c # => ((13/12)+0i)
VectorNumber[2, 2i].to_c # => (2+2i)
VectorNumber[2, :i].to_c # RangeError

Complex(VectorNumber[2]) # => (2+0i)
Complex(VectorNumber[2, "i"]) # RangeError

Returns:

  • (Complex)

Raises:

  • (RangeError)

    if any non-real, non-imaginary part is non-zero

Since:

  • 0.1.0



131
132
133
134
135
# File 'lib/vector_number/converting.rb', line 131

def to_c
  raise_convert_error(Complex) unless numeric?(2)

  Complex(real, imaginary)
end

#to_d(ndigits = nil) ⇒ BigDecimal

Return value as a BigDecimal if only real part is non-zero.

Examples:

VectorNumber[13.5].to_d # => 0.135e2
VectorNumber[13r/12].to_d # ArgumentError
VectorNumber[13r/12].to_d(5) # => 0.10833e1
VectorNumber[2, 2i].to_d # RangeError
VectorNumber[2, :i].to_d # RangeError

# This does't work without NumericRefinements:
BigDecimal(VectorNumber[2]) # TypeError
# #to_s can be used as a workaround if refinements aren't used:
BigDecimal(VectorNumber[2].to_s) # => 0.2e1
BigDecimal(VectorNumber[2, "i"].to_s) # => ArgumentError

Parameters:

  • ndigits (Integer) (defaults to: nil)

    precision

Returns:

  • (BigDecimal)

Raises:

  • (RangeError)

    if any non-real part is non-zero

  • (NameError)

    if BigDecimal is not defined

See Also:

Since:

  • 0.1.0



109
110
111
112
113
114
115
116
# File 'lib/vector_number/converting.rb', line 109

def to_d(ndigits = nil)
  raise_convert_error(BigDecimal) unless numeric?(1)

  return BigDecimal(real, ndigits) if ndigits
  return BigDecimal(real, Float::DIG) if Float === real

  BigDecimal(real)
end

#to_fFloat

Return value as a Float if only real part is non-zero.

Examples:

VectorNumber[13.5].to_f # => 13.5
VectorNumber[13r/12].to_f # => 1.0833333333333333
VectorNumber[2, 2i].to_f # RangeError
VectorNumber[2, :i].to_f # RangeError

Float(VectorNumber[2]) # => 2.0
Float(VectorNumber[2, "i"]) # RangeError

Returns:

  • (Float)

Raises:

  • (RangeError)

    if any non-real part is non-zero

Since:

  • 0.1.0



62
63
64
65
66
# File 'lib/vector_number/converting.rb', line 62

def to_f
  raise_convert_error(Float) unless numeric?(1)

  real.to_f
end

#to_h(&block) ⇒ Hash{Object => Numeric}

Get mutable hash with vector’s data.

Returned hash has a default value of 0.

Examples:

VectorNumber["a", "b", 6, 1i].to_h # => {"a" => 1, "b" => 1, unit/1 => 6, unit/i => 1}
VectorNumber["a", "b", 6, 1i].to_h["c"] # => 0

Returns:

  • (Hash{Object => Numeric})

Since:

  • 0.1.0



75
76
77
78
79
80
81
82
# File 'lib/vector_number/enumerating.rb', line 75

def to_h(&block)
  # TODO: Remove block argument.
  if block_given?
    @data.to_h(&block)
  else
    @data.dup
  end
end

#to_iInteger Also known as: to_int

Return value as an Integer, truncating it, if only real part is non-zero.

Examples:

VectorNumber[13.5].to_i # => 13
VectorNumber[13r/12].to_int # => 1
[1.1, 2.2, 3.3][VectorNumber[2]] # => 3.3
VectorNumber[2, 2i].to_i # RangeError
VectorNumber[2, :i].to_f # RangeError

Integer(VectorNumber[2]) # => 2
Integer(VectorNumber[2, "i"]) # RangeError

Returns:

  • (Integer)

Raises:

  • (RangeError)

    if any non-real part is non-zero

Since:

  • 0.1.0



41
42
43
44
45
# File 'lib/vector_number/converting.rb', line 41

def to_i
  raise_convert_error(Integer) unless numeric?(1)

  real.to_i
end

#to_rRational

Return value as a Rational if only real part is non-zero.

Examples:

VectorNumber[13.5].to_r # => (27/2)
VectorNumber[13r/12].to_r # => (13/12)
VectorNumber[2, 2i].to_r # RangeError
VectorNumber[2, :i].to_r # RangeError

Rational(VectorNumber[2]) # => (2/1)
Rational(VectorNumber[2, "i"]) # RangeError

Returns:

  • (Rational)

Raises:

  • (RangeError)

    if any non-real part is non-zero

Since:

  • 0.1.0



81
82
83
84
85
# File 'lib/vector_number/converting.rb', line 81

def to_r
  raise_convert_error(Rational) unless numeric?(1)

  real.to_r
end

#to_s(mult: :dot) {|unit, coefficient, index, operator| ... } ⇒ String

Return string representation of the vector suitable for output.

An optional block can be supplied to provide customized substrings for each unit and coefficient pair. Care needs to be taken in handling VectorNumber::R and VectorNumber::I units. numeric_unit? can be used to check if a particular unit needs special handling.

Examples:

VectorNumber[5, "s"].to_s # => "5 + 1⋅\"s\""
VectorNumber["s", 5].to_s # => "1⋅\"s\" + 5"

with :mult argument

VectorNumber[5, :s].to_s(mult: :asterisk) # => "5 + 1*:s"
(-VectorNumber[5, :s]).to_s(mult: "~~~") # => "-5 - 1~~~:s"

with a block

VectorNumber[5, :s].to_s { |k, v| "#{format("%+.0f", v)}%#{k}" } # => "+5%1+1%s"
VectorNumber[5, :s].to_s(mult: :cross) { |k, v, i, op|
  "#{',' unless i.zero?}#{v}#{op+k.inspect unless k == VectorNumber::R}"
} # => "5,1×:s"

Parameters:

  • mult (Symbol, String) (defaults to: :dot)

    text to use between coefficient and unit, can be one of the keys in MULT_STRINGS or an arbitrary string

Yield Parameters:

  • unit (Object)
  • coefficient (Numeric)
  • index (Integer)
  • operator (String)

Yield Returns:

  • (String)

    a string for this unit and coefficient

Returns:

  • (String)

Raises:

  • (ArgumentError)

    if mult is not a String and is not in MULT_STRINGS‘s keys

Since:

  • 0.1.0



48
49
50
51
52
53
54
55
56
# File 'lib/vector_number/stringifying.rb', line 48

def to_s(mult: :dot, &block)
  if !(String === mult) && !MULT_STRINGS.key?(mult)
    raise ArgumentError, "unknown key #{mult.inspect}", caller
  end
  return "0" if zero?

  operator = (String === mult) ? mult : MULT_STRINGS[mult]
  build_string(operator, &block)
end

#truncate(digits = 0) ⇒ VectorNumber

Return a new vector with every coefficient truncated using their #truncate.

Examples:

VectorNumber[5.39].truncate # => (5)
VectorNumber[-5.35i].truncate # => (-5i)
VectorNumber[-5.35i, "i"].truncate # => (-5i + 1⋅"i")
VectorNumber[-5.35i, "i"].truncate(1) # => (-5.3i + 1⋅"i")
VectorNumber[-5.35i, "i"].truncate(-1) # => (0)

Parameters:

  • digits (Integer) (defaults to: 0)

Returns:

Since:

  • 0.2.1



19
20
21
# File 'lib/vector_number/math_converting.rb', line 19

def truncate(digits = 0)
  new { _1.truncate(digits) }
end

#uniform_vectorVectorNumber

Return a new vector with the same non-zero dimensions, but with coefficients equal to 1.

Resulting vector is equal to self.subspace_basis.sum.

Examples:

v = VectorNumber[1.2, "a"] * 2 - "s" # => (2.4 + 2⋅"a" - 1⋅"s")
v.uniform_vector # => (1 + 1⋅"a" + 1⋅"s")
VectorNumber[0].uniform_vector # => (0)

Returns:

See Also:

Since:

  • <<next>>



107
108
109
# File 'lib/vector_number/vectoring.rb', line 107

def uniform_vector
  new { 1 }
end

#unit?(unit) ⇒ Boolean Also known as: key?

Check if a unit has a non-zero coefficient.

Examples:

VectorNumber["a", "b", 6].unit?("a") # => true
VectorNumber["a", "b", 6].key?("c") # => false

Parameters:

  • unit (Object)

Returns:

  • (Boolean)

Since:

  • 0.2.4



110
# File 'lib/vector_number/enumerating.rb', line 110

def unit?(unit) = @data.key?(unit)

#unit_vectorVectorNumber

Return a unit vector (vector with magnitude 1) in the direction of this vector.

Magnitude of resulting vector may not be exactly 1 due to rounding errors.

Examples:

v = VectorNumber[1.2, "a"] * 2 - "s" # => (2.4 + 2⋅"a" - 1⋅"s")
v.unit_vector # => (0.7316529130196309 + 0.6097107608496924⋅"a" - 0.3048553804248462⋅"s")
v.unit_vector.magnitude # => 1.0
VectorNumber[0].unit_vector # ZeroDivisionError

Returns:

Raises:

  • (ZeroDivisionError)

    if self is a zero vector

Since:

  • <<next>>



125
126
127
128
129
# File 'lib/vector_number/vectoring.rb', line 125

def unit_vector
  has_direction?

  self / magnitude
end

#unitsArray<Object> Also known as: keys

Get a list of units with non-zero coefficients.

Examples:

VectorNumber["a", "b", 6].units # => ["a", "b", unit/1]
VectorNumber.new.keys # => []

Returns:

  • (Array<Object>)

Since:

  • 0.1.0



51
# File 'lib/vector_number/enumerating.rb', line 51

def units = @data.keys

#vector_projection(other) ⇒ VectorNumber

Calculate the vector projection of this vector onto other vector.

If other is not a VectorNumber, it is automatically promoted.

Examples:

v = VectorNumber[2, "a"]
v.vector_projection(v) # => (2.0 + 1.0⋅"a")
v.vector_projection(1) # => (2.0)
v.vector_projection("b") # => (0)
v.vector_projection(-v) # => (-2.0 - 1.0⋅"a")
v.vector_projection(2 * VectorNumber[-0.5, "a"]) # => (0)
VectorNumber[0].vector_projection(v) # => (0)
v.vector_projection(0) # ZeroDivisionError

Parameters:

Returns:

Raises:

  • (ZeroDivisionError)

    if other is a zero vector

Since:

  • <<next>>



213
214
215
216
217
218
219
220
# File 'lib/vector_number/vectoring.rb', line 213

def vector_projection(other)
  return self if equal?(other) && has_direction?

  other = new([other]) unless VectorNumber === other
  has_direction?(other)

  other * dot_product(other) / other.abs2
end

#vector_rejection(other) ⇒ VectorNumber

Calculate the vector rejection of this vector from other vector.

Vector rejection is equal to self - self.vector_projection(other). If other is not a VectorNumber, it is automatically promoted.

Examples:

v = VectorNumber[2, "a"]
v.vector_rejection(v) # => (0)
v.vector_rejection(1) # => (1⋅"a")
v.vector_rejection("b") # => (2 + 1⋅"a")
v.vector_rejection(-v) # => (0)
v.vector_rejection(2 * VectorNumber[-0.5, "a"]) # => (2 + 1⋅"a")
VectorNumber[0].vector_rejection(v) # => (0)
v.vector_rejection(0) # ZeroDivisionError

Parameters:

Returns:

Raises:

  • (ZeroDivisionError)

    if other is a zero vector

Since:

  • <<next>>



272
273
274
275
276
277
278
279
# File 'lib/vector_number/vectoring.rb', line 272

def vector_rejection(other)
  return VectorNumber[0] if equal?(other) && has_direction?

  other = new([other]) unless VectorNumber === other
  has_direction?(other)

  self - vector_projection(other)
end

#zero?Boolean

Returns true if there are no non-zero coefficients, and false otherwise.

This is synonymous with size being 0.

Examples:

VectorNumber["c"].zero? # => false
VectorNumber[].zero? # => true

Returns:

  • (Boolean)

See Also:

Since:

  • 0.1.0



89
# File 'lib/vector_number/querying.rb', line 89

def zero? = size.zero?