Skip to content

Instantly share code, notes, and snippets.

@chadbrewbaker
Created January 15, 2013 23:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chadbrewbaker/4542999 to your computer and use it in GitHub Desktop.
Save chadbrewbaker/4542999 to your computer and use it in GitHub Desktop.
Iowa Ruby Brigade kata showing Roman numeral computation is a monoid.
# Roman Numeral Evaluation is a Monoid
# Chad Brewbaker | Software Engineer | Telligen.org
# crb002@gmail.com
# Initial release January 15, 2013
class RomanMonoid
attr_accessor :prefix, :prefix_size, :suffix, :suffix_size, :suffix_credit, :sum, :homo
def initialize(val)
#Monoid identity values
@prefix ='I'
@prefix_size = 0
@suffix = 'I'
@suffix_size =0
@suffix_credit =1
@sum = 0
@homo = true
if (not (val.nil?))
values = [1, 5, 10, 50, 100, 500, 1000]
indexh = {'I' => 0, 'V'=> 1, 'X'=>2, 'L'=>3, 'C'=>4, 'D'=>5, 'M'=>6}
@prefix=val
@suffix=val
@suffix_credit = 1
@prefix_size=1
@suffix_size=1
@homo = true #When a Roman monoid stops being homogeneous the suffix credit value is known
@sum = values[indexh[val]]
end
end
def add_right(elt)
values = [1, 5, 10, 50, 100, 500, 1000]
indexh = {'I' => 0, 'V'=> 1, 'X'=>2, 'L'=>3, 'C'=>4, 'D'=>5, 'M'=>6}
same_bonus=0
# Adding a hetero
if elt.homo == false
if(@prefix == elt.suffix)
if elt.suffix_credit < 0
@sum = @sum - (@prefix_size * values[indexh[@prefix]]*2)
end
elsif (indexh[@prefix] < indexh[elt.suffix])
@sum = @sum - (@prefix_size * values[indexh[@prefix]]*2)
if @homo
@suffix_credit = -1
end
end
@homo =false
# Adding a homo
elsif elt.homo == true
if(@prefix == elt.suffix)
same_bonus = @prefix_size
elsif (indexh[@prefix] < indexh[elt.suffix])
@sum = @sum - (@prefix_size * values[indexh[@prefix]]*2)
if(@homo)
@suffix_credit = -1
end
@homo =false
elsif (indexh[@prefix] > indexh[elt.suffix])
@homo =false
end
end
@prefix_size = elt.prefix_size + same_bonus
@sum = @sum + elt.sum
@prefix = elt.prefix
end
end
def convert_monoid(input)
tmparr = input.chars.to_a
arr = Array.new(input.size) { |i| RomanMonoid.new(tmparr[i]) }
last = RomanMonoid.new(nil)
while (arr.size >0)
v = arr.pop
v.add_right(last)
last = v
end
return last.sum
end
def convert_credit(input)
# Rule 1) The last element is always a credit.
# Rule 2) A repeat shares the debit/credit value of it's right neighbor.
# Rule 3) A greater left elt makes this elt a credit.
# Rule 4) A lesser left elt make this elt a debit.
values = [1, 5, 10, 50, 100, 500, 1000]
indexh = {'I' => 0, 'V'=> 1, 'X'=>2, 'L'=>3, 'C'=>4, 'D'=>5, 'M'=>6}
arr = input.chars.to_a
last_val = 'I'
last_mult = 1
sum = 0
while (arr.size >0)
v = arr.pop
mult = last_mult
if(indexh[v] < indexh[last_val])
mult = -1
end
if(indexh[v] > indexh[last_val])
mult = 1
end
sum = sum + (mult* values[indexh[v]])
last_val = v
last_mult = mult
end
return sum
end
puts "Should be 1999"
puts convert_credit("MDCCCCLXXXXVIIII")
puts convert_credit("MCMXCIX")
puts convert_credit("MIM")
puts "-----------------------------------"
puts convert_monoid("MDCCCCLXXXXVIIII")
puts convert_monoid("MCMXCIX")
puts convert_monoid("MIM")
@enricopolanski
Copy link

enricopolanski commented Jan 29, 2020

I'm lost, how can roman numbers be a monoid if there's no identity element? There's no 0.

@chadbrewbaker
Copy link
Author

Look at initialize(). That struct of seven variables is the monoid identity. For complex monoids you have to do a lot of book-keeping variables.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment