Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Do Mix Your Drinks

Do Mix Your Drinks

A talk about how abstract algebra is useful for Ruby programmers, both when writing everyday programs and when going to the pub afterwards. As an example I show how to use my VectorSpace library to compare and manipulate structured data for free.

Given at the July 2009 LRUG meeting (http://lrug.org/meetings/2009/06/17/july-2009-meeting/). There's a video of this talk at http://skillsmatter.com/podcast/ajax-ria/do-mix-your-drinks.

Tom Stuart

July 08, 2009
Tweet

More Decks by Tom Stuart

Other Decks in Programming

Transcript

  1. Theory: Use ideas from abstract algebra in your Ruby programs,

    because mathematicians are programmers too
  2. WIKIPEDIA Abstract algebra From Wikipedia, the free encyclopedia Abstract algebra

    is the subject area of mathematics that studies algebraic structures, such as groups, rings, fields, modules, vector spaces, and algebras.
  3. WIKIPEDIA Algebraic structure From Wikipedia, the free encyclopedia An algebraic

    structure consists of one or more sets closed under one or more operations, satisfying some axioms.
  4. A total order is a binary relation (here denoted by

    infix ≤) on some set X. A set paired with a total order is called a totally ordered set. WIKIPEDIA Total order From Wikipedia, the free encyclopedia
  5. If X is totally ordered under ≤, then the following

    statements hold for all a, b and c in X: If a ≤ b and b ≤ a then a = b (antisymmetry); If a ≤ b and b ≤ c then a ≤ c (transitivity); a ≤ b or b ≤ a (totality).
  6. For each (non-strict) total order ≤ there is an associated

    asymmetric (hence irreflexive) relation <, called a strict total order, which can equivalently be defined in two ways: ▪a < b if and only if a ≤ b and a ≠ b ▪a < b if and only if not b ≤ a (i.e., < is the inverse of the complement of ≤) Properties: ▪The relation is transitive: a < b and b < c implies a < c. ▪The relation is trichotomous: exactly one of a < b, b < a and a = b is true. ▪The relation is a strict weak order, where the associated equivalence is equality. Two more associated orders are the complements ≥ and >, completing the quadruple {<, >, ≤, ≥}.
  7. (P.S. define #<=> instead of #<= because it guarantees some

    axioms and makes implementation more efficient)
  8. I needed to manipulate multidimensional values I realised the manipulations

    were just operations in a vector space I wrote a tiny library for modelling multidimensional values as vectors
  9. WIKIPEDIA Abstract algebra From Wikipedia, the free encyclopedia Abstract algebra

    is the subject area of mathematics that studies algebraic structures, such as groups, rings, fields, modules, vector spaces, and algebras.
  10. A vector space over F is a set equipped with

    two binary operations: vector addition (between two elements of the set), and scalar multiplication (between an element of the set and a scalar)
  11. + =

  12. Axiom Signification Associativity of addition u + (v + w)

    = (u + v) + w. Commutativity of addition v + w = w + v. Identity element of addition There exists an element 0 ∈ V, called the zero vector, such that v + 0 = v for all v ∈ V. Inverse elements of addition For all v ∈ V, there exists an element w ∈ V, called the additive inverse of v, such that v + w = 0. The additive inverse is denoted −v. Distributivity of scalar multiplication with respect to vector addition   a(v + w) = av + aw. Distributivity of scalar multiplication with respect to field addition (a + b)v = av + bv. Compatibility of scalar multiplication with field multiplication a(bv) = (ab)v Identity element of scalar multiplication 1v = v, where 1 denotes the multiplicative identity in F.
  13. These axioms entail that subtraction of two vectors and division

    by a (non-zero) scalar can be performed via v − w = v + (−w), v / a = (1 / a) · v.
  14. Vector arithmetic (0, +, –, ÷) Scalar arithmetic (×, ÷)

    Partial order (product, lexicographic)
  15. 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
  16. 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
  17. >> 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
  18. class Cocktail < VectorSpace::SimpleIndexedVector indexed_by :units has_dimension :gin has_dimension :vermouth

    has_dimension :whisky has_dimension :vodka has_dimension :kahlua has_dimension :cream end
  19. 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
  20. >> 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
  21. This is all pretty trivial but it makes things drastically

    simpler when you need to nest vectors
  22. 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_dimension :cocktail, :describe => lambda { |c| "a cocktail of #{c}" unless c.zero? } has_zero_description 'no drinks' end
  23. >> Round.new(:hoegaarden => 2, :cocktail => martini) + Round.new(:fruli =>

    3, :cocktail => manhattan) => 2 Hoegaardens and 3 Frülis and a cocktail of 5.5cl gin and 3.5cl vermouth and 5cl whisky
  24. If you liked this: • Download VectorSpace from http://github.com/tomstuart •

    Follow @tomstuart on Twitter • Round.new :hoegaarden => 1 Thanks!