620

# 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.

July 08, 2009

## Transcript

2. ### I used to try to be a mathematician but now

I try to be a programmer
3. ### Theory: Use ideas from abstract algebra in your Ruby programs,

because mathematicians are programmers too

5. ### Theory:

is the subject area of mathematics that studies algebraic structures, such as groups, rings, ﬁelds, modules, vector spaces, and algebras.

structure consists of one or more sets closed under one or more operations, satisfying some axioms.

10. ### “sets closed under one or more operations” “classes with one

or more methods”
11. ### These structures have been well-studied and are well-understood Satisfy the

axioms and you get some properties
12. ### It’s all about abstraction The idea of encapsulating some well-deﬁned

operations is familiar

14. ### 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).
15. ### For each (non-strict) total order ≤ there is an associated

asymmetric (hence irreﬂexive) relation <, called a strict total order, which can equivalently be deﬁned 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 {<, >, ≤, ≥}.

17. None

19. ### (P.S. deﬁne #<=> instead of #<= because it guarantees some

axioms and makes implementation more efﬁcient)

21. ### This all works because core Ruby implements a mathematical structure

with known properties
22. ### We shouldn’t be afraid to look further aﬁeld for other

structures that might help us out

24. ### 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

is the subject area of mathematics that studies algebraic structures, such as groups, rings, ﬁelds, modules, vector spaces, and algebras.

27. ### 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)

30. ### Axiom Signiﬁcation 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 ﬁeld addition (a + b)v = av + bv. Compatibility of scalar multiplication with ﬁeld multiplication a(bv) = (ab)v Identity element of scalar multiplication 1v = v, where 1 denotes the multiplicative identity in F.
31. ### 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.

33. ### A vector space abstracts the idea of manipulating multiple independent

values simultaneously

39. ### Vector arithmetic (0, +, –, ÷) Scalar arithmetic (×, ÷)

Partial order (product, lexicographic)
40. ### 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
41. ### 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
42. ### >> 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
43. None

45. None
46. ### 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
47. ### 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
48. ### >> 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
49. ### This is all pretty trivial but it makes things drastically

simpler when you need to nest vectors
50. ### 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
51. ### >> 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

currency

“how many?”

and Credits