A Ruby library for treating multidimensional values as elements of a vector space.
Ruby
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib
LICENSE
README.markdown
TODO
vector_space.gemspec

README.markdown

VectorSpace

A Ruby library for treating multidimensional values as elements of a vector space.

Examples

A simple vector space:

class Round < VectorSpace::SimpleVector
  has_dimension :hoegaarden
  has_dimension :franziskaner
  has_dimension :fruli
  has_dimension :water
end

>> Round.new
=> 0 and 0 and 0 and 0

>> Round.new :hoegaarden => 5, :fruli => 3
=> 5 and 0 and 3 and 0

With custom descriptions:

class Round < VectorSpace::SimpleVector
  has_dimension :hoegaarden,    :describe => lambda { |n| "#{n} Hoegaardens" unless n.zero? }
  has_dimension :franziskaner,  :describe => lambda { |n| "#{n} Franziskaners" unless n.zero? }
  has_dimension :fruli,         :describe => lambda { |n| "#{n} Frülis" unless n.zero? }
  has_dimension :water,         :describe => lambda { |n| "#{n} waters" unless n.zero? }
  has_zero_description 'no drinks'
end

>> Round.new
=> no drinks

>> Round.new :hoegaarden => 5, :fruli => 3
=> 5 Hoegaardens and 3 Frülis

>> Round.new(:hoegaarden => 2, :franziskaner => 3) + Round.new(:water => 2, :fruli => 2, :hoegaarden => 1)
=> 3 Hoegaardens and 3 Franziskaners and 2 Frülis and 2 waters

>> (Round.new(:hoegaarden => 2, :franziskaner => 3) * 2) - Round.new(:hoegaarden => 1)
=> 3 Hoegaardens and 6 Franziskaners

An indexed family of vector spaces with custom descriptions:

class Cocktail < VectorSpace::SimpleIndexedVector
  indexed_by :units
  has_dimension :gin,       :describe => lambda { |units, n| "#{n}#{units} gin" unless n.zero? }
  has_dimension :vermouth,  :describe => lambda { |units, n| "#{n}#{units} vermouth" unless n.zero? }
  has_dimension :whisky,    :describe => lambda { |units, n| "#{n}#{units} whisky" unless n.zero? }
  has_dimension :vodka,     :describe => lambda { |units, n| "#{n}#{units} vodka" unless n.zero? }
  has_dimension :kahlua,    :describe => lambda { |units, n| "#{n}#{units} Kahlúa" unless n.zero? }
  has_dimension :cream,     :describe => lambda { |units, n| "#{n}#{units} cream" unless n.zero? }
end

>> martini = Cocktail.new :units => :cl, :gin => 5.5, :vermouth => 1.5
=> 5.5cl gin and 1.5cl vermouth

>> manhattan = Cocktail.new :units => :cl, :whisky => 5, :vermouth => 2
=> 2cl vermouth and 5cl whisky

>> white_russian = Cocktail.new :units => :oz, :vodka => 2, :kahlua => 1, :cream => 1.5
=> 2oz vodka and 1oz Kahlúa and 1.5oz cream

>> martini * 2
=> 11cl gin and 3cl vermouth

>> martini + manhattan
=> 5.5cl gin and 3.5cl vermouth and 5cl whisky

>> martini + white_russian
ArgumentError: can't add 5.5cl gin and 1.5cl vermouth to 2oz vodka and 1oz Kahlúa and 1.5oz cream

A real (one-dimensional) example:

class Money < VectorSpace::SimpleIndexedVector
  indexed_by :currency, :default => Currency::GBP
  has_dimension :cents,
    :coerce   => lambda { |n| n.round }, # or just :coerce => :round if you have Symbol#to_proc
    :describe => lambda { |currency, cents| "#{currency.symbol}#{cents / 100}.#{sprintf('%02d', cents % 100)}" }
end

>> a = Money.new(:currency => Currency::GBP, :cents => 9900)
=> £99.00

>> b = Money.new(:currency => Currency::GBP, :cents => 1500)
=> £15.00

>> a < b
=> false

>> a > b
=> true

>> a + b
=> £114.00

>> c = Money.new(:currency => Currency::USD, :cents => 99)
=> $0.99

>> a < c
=> false

>> c < a
=> false

>> a + c
ArgumentError: can't add $0.99 to £99.00