NAME

Sidef::Types::Array::Vector - Mathematical vector operations in Sidef

DESCRIPTION

This class implements mathematical vectors with support for common vector operations including arithmetic, geometric distances, and angle calculations. A Vector is a subclass of Sidef::Types::Array::Array -- it's just an ordered array of elements, conventionally numeric, though this is a convention only and isn't enforced by the constructor.

For every arithmetic operator below, the other operand is treated as "vector-like" -- triggering per-element behavior instead of scalar-broadcast behavior -- if it's a Vector or a plain Array. This matters because a few of these operators behave quite differently depending on whether the other operand is a plain number or a vector/array: see "SPECIAL-CASE ARITHMETIC" below in particular.

SYNOPSIS

# Create vectors
var v1 = Vector(1, 2, 3)
var v2 = Vector(4, 5, 6)

# Element-wise arithmetic (vector or scalar operand)
say(v1 + v2)      #=> Vector(5, 7, 9)
say(v1 - v2)      #=> Vector(-3, -3, -3)
say(v1 + 5)       #=> Vector(6, 7, 8)

# '*', '/', and '**' behave differently with a vector operand --
# see SPECIAL-CASE ARITHMETIC below
say(v1 * 2)       #=> Vector(2, 4, 6)     # scalar: element-wise
say(v1 * v2)      #=> 32                  # vector: dot product (a scalar!)

# Norms and distances
say(v1.norm)      #=> 14                  # sum of squares (NOT the magnitude)
say(v1.abs)        # sqrt(14) -- the actual Euclidean magnitude
say(v1.dist(v2))   # Euclidean distance between v1 and v2

# Create special vectors
var zeros = Vector.zero(5)  #=> Vector(0, 0, 0, 0, 0)

INHERITS

Inherits methods from Sidef::Types::Array::Array.

CONSTRUCTION

new

Vector(*elements)
Vector.new(*elements)

Creates a new Vector from elements, in order. Nothing enforces that elements are actually numeric -- that's a convention the rest of this class relies on, not a runtime check.

var v1 = Vector.new(1, 2, 3)
var v2 = Vector(1, 2, 3)     # same as above

Aliases: call

zero

Vector.zero(n)

Creates a new vector of length n with every element set to 0.

say(Vector.zero(3))   #=> Vector(0, 0, 0)

ELEMENT-WISE ARITHMETIC

These operators behave consistently element-wise regardless of whether the other operand is a scalar or a vector/array: with a scalar, the same value is applied to every element; with a vector/array, corresponding elements are combined pairwise. If the two vectors have different lengths, only the overlapping range (up to the shorter one's length) contributes -- see the note under "SPECIAL-CASE ARITHMETIC" for how the distance/norm methods handle this too.

add

self.add(other)
self + other

Adds other to every element (if other is a scalar), or adds corresponding elements together (if other is a vector/array).

say(Vector(1, 2, 3) + 5)                #=> Vector(6, 7, 8)
say(Vector(1, 2, 3) + Vector(4, 5, 6))  #=> Vector(5, 7, 9)

Aliases: operator +

sub

self.sub(other)
self - other

Subtracts other from every element (if other is a scalar), or subtracts corresponding elements (if other is a vector/array).

say(Vector(5, 7, 9) - 2)                #=> Vector(3, 5, 7)
say(Vector(5, 7, 9) - Vector(1, 2, 3))  #=> Vector(4, 5, 6)

Aliases: operator -

and

self.and(other)
self & other

Bitwise ANDs every element with other (if other is a scalar), or ANDs corresponding elements together (if other is a vector/array).

say(Vector(5, 7, 3) & Vector(3, 5, 1))  #=> Vector(1, 5, 1)

Aliases: operator &

or

self.or(other)
self | other

Bitwise ORs every element with other (if other is a scalar), or ORs corresponding elements together (if other is a vector/array).

say(Vector(5, 7, 3) | Vector(3, 5, 1))  #=> Vector(7, 7, 3)

Aliases: operator |

xor

self.xor(other)
self ^ other

Bitwise XORs every element with other (if other is a scalar), or XORs corresponding elements together (if other is a vector/array).

say(Vector(5, 7, 3) ^ Vector(3, 5, 1))  #=> Vector(6, 2, 2)

Aliases: operator ^

SPECIAL-CASE ARITHMETIC

Unlike "ELEMENT-WISE ARITHMETIC" above, these three operators give a different kind of result when the other operand is a vector/array instead of a plain scalar -- not just a per-element version of the scalar case.

mul

self.mul(other)
self * other

If other is a scalar, scales every element by it, returning a new Vector. If other is a vector/array, returns their dot product instead -- the sum of the products of corresponding elements, as a single Number, not a per-element (Hadamard) product.

say(Vector(1, 2, 3) * 2)                 #=> Vector(2, 4, 6)
say(Vector(1, 2, 3) * Vector(2, 3, 4))   #=> 20   # 1*2 + 2*3 + 3*4, a Number

Aliases: operator *

div

self.div(other)
self / other

If other is a scalar, divides every element by it, returning a new Vector. If other is a vector/array, this is computed as self dotted with the element-wise reciprocal of other (self.mul(other's element-wise inverse)) -- again a single Number, not a per-element division.

say(Vector(10, 20, 30) / 2)                  #=> Vector(5, 10, 15)
say(Vector(10, 20, 30) / Vector(2, 4, 5))    #=> 16   # 10/2 + 20/4 + 30/5, a Number

Aliases: operator /, operator ÷

pow

self.pow(other)
self ** other

If other is a scalar, raises every element to that power, returning a new Vector. If other is a vector/array, returns the full outer-product Matrix of the two -- a matrix whose entry at row i, column j is self[i] ** other[j] -- not a per-element (matching-index) power.

say(Vector(2, 3, 4) ** 2)                #=> Vector(4, 9, 16)
say(Vector(2, 3) ** Vector(1, 2))
#=> Matrix([2, 4],
#=>        [3, 9])          # row i, col j = v1[i] ** v2[j]

Aliases: operator **

UNARY TRANSFORMATIONS

neg

self.neg

Returns a new vector with every element negated. Equivalent to multiplying by -1.

say(Vector(1, -2, 3).neg)   #=> Vector(-1, 2, -3)

not

self.not

Returns a new vector with the bitwise complement of every element.

say(Vector(5, 7, 3).not)

floor

self.floor

Returns a new vector with every element rounded down to the nearest integer.

say(Vector(1.8, 2.3, -0.5).floor)   #=> Vector(1, 2, -1)

ceil

self.ceil

Returns a new vector with every element rounded up to the nearest integer.

say(Vector(1.2, 2.8, -0.5).ceil)   #=> Vector(2, 3, 0)

round

self.round(digits)

Returns a new vector with every element rounded to digits decimal places (or to the nearest integer, if digits is omitted).

say(Vector(1.234, 2.567, 3.891).round)     #=> Vector(1, 3, 4)
say(Vector(1.234, 2.567, 3.891).round(2))  #=> Vector(1.23, 2.57, 3.89)

NORMS AND DISTANCES

norm

self.norm

Returns the sum of the squares of every element. Despite the name, this is not the vector's magnitude/length -- for that, see "abs".

say(Vector(3, 4).norm)   #=> 25   # 3**2 + 4**2, not the magnitude 5

abs

self.abs

Returns the vector's Euclidean magnitude (length): the square root of "norm".

say(Vector(3, 4).abs)       #=> 5
say(Vector(1, 2, 3).abs)    # sqrt(14) ≈ 3.742

manhattan_norm

self.manhattan_norm

Returns the Manhattan (L1) norm of the vector: the sum of the absolute values of all elements.

say(Vector(1, -2, 3).manhattan_norm)   #=> 6

dist_norm

self.dist_norm(other)

Returns the sum of the squares of the differences between corresponding elements of self and other (the squared Euclidean distance -- no square root is taken). If the vectors have different lengths, only their overlapping prefix (up to the shorter one's length) is used.

say(Vector(1, 2, 3).dist_norm(Vector(4, 5, 6)))   #=> 27

dist

self.dist(other)

Returns the Euclidean distance between self and other: the square root of "dist_norm".

say(Vector(1, 2, 3).dist(Vector(4, 5, 6)))   # sqrt(27) ≈ 5.196

manhattan_dist

self.manhattan_dist(other)

Returns the Manhattan (L1, taxicab) distance between self and other: the sum of the absolute differences between corresponding elements. If the vectors have different lengths, only their overlapping prefix is used.

say(Vector(1, 2, 3).manhattan_dist(Vector(4, 5, 6)))   #=> 9

chebyshev_dist

self.chebyshev_dist(other)

Returns the Chebyshev (L∞, chessboard) distance between self and other: the maximum absolute difference between corresponding elements (0 if the overlapping range is empty). If the vectors have different lengths, only their overlapping prefix is used.

say(Vector(1, 2, 3).chebyshev_dist(Vector(4, 5, 6)))   #=> 3

atan2

self.atan2(other)

Returns the angle (in radians, as a plain Number) between self and other -- not an element-wise arctangent. For vectors of exactly 2 elements, this is computed directly from their dot and cross products, giving a signed angle. For any other dimension, it's computed by projecting other onto self's direction and taking the angle between the projection and the leftover perpendicular component -- which is always non-negative (between 0 and π), since it relies on "abs".

say(Vector(1, 0).atan2(Vector(0, 1)))   # pi/2 (~1.5708) -- a right angle

CONVERSION

to_array

self.to_array

Converts the vector to a plain Array, preserving all elements in order.

say(Vector(1, 2, 3).to_array)   #=> [1, 2, 3]

Aliases: to_a

dump

self.dump

Returns a String representation of the vector, in the format Vector(element, element, ...).

say(Vector(1, 2, 3).dump)   #=> "Vector(1, 2, 3)"

Aliases: to_s, to_str

EXAMPLES

Basic vector arithmetic

var v1 = Vector(1, 2, 3)
var v2 = Vector(4, 5, 6)

say(v1 + v2)      #=> Vector(5, 7, 9)
say(v1 * 2)       #=> Vector(2, 4, 6)      # scalar: element-wise
say(v1 * v2)      #=> 32                   # vector: dot product

Norms and distances

var v1 = Vector(1, 2, 3)
var v2 = Vector(4, 5, 6)

say(v1.norm)             #=> 14            # sum of squares
say(v1.abs)              # sqrt(14) ≈ 3.742 -- the real magnitude
say(v1.manhattan_norm)   #=> 6
say(v1.dist(v2))         # sqrt(27) ≈ 5.196
say(v1.manhattan_dist(v2))   #=> 9
say(v1.chebyshev_dist(v2))   #=> 3

Angle between two vectors

var right  = Vector(1, 0)
var up     = Vector(0, 1)
var diag   = Vector(1, 1)

say(right.atan2(up))     # pi/2  ≈ 1.5708 -- perpendicular
say(right.atan2(diag))   # pi/4  ≈ 0.7854 -- 45 degrees

Component-wise transformations

var v = Vector(1.234, -2.567, 3.891)

say(v.round(2))   #=> Vector(1.23, -2.57, 3.89)
say(v.floor)      #=> Vector(1, -3, 3)
say(v.ceil)       #=> Vector(2, -2, 4)
say(v.neg)        #=> Vector(-1.234, 2.567, -3.891)

SEE ALSO

Sidef::Types::Array::Array, Sidef::Types::Array::Matrix