Groups with Ruby

This image was generated by Vladimir Bulatov's Polyhedra Stellations Applet: http://bulatov.org/polyhedra/stellation_applet

This image was generated by Vladimir Bulatov’s Polyhedra Stellations Applet: http://bulatov.org/polyhedra/stellation_applet

I’ve started writing some functions for verifying introductory group theory results in order to gain a better understanding of group theory. So far, my Group class is able to determine whether a particular discrete set and operator combination is a group.

Corrections or suggestions for more functionality would be appreciated. I plan on adding functions to calculate cosets and verify Lagrange’s theorem.

class Group

  def initialize(set, block)
    @set = set
    @block = block
  end

  def isGroup?
    has_identity = self.has_identity?
    is_associative = self.is_associative?
    is_closed = self.is_closed?
    has_inverses = self.has_inverses?
    isGroup = has_identity && is_associative && is_closed && has_inverses
    if not has_identity
      p 'No identity'
    end
    if not is_associative
      p 'Not associative'
    end
    if not is_closed
      p 'Not closed'
    end
    if not has_inverses
      p 'Missing inverses'
    end
    return isGroup
  end

  def is_closed?
    is_closed = true
    @set.each do |element|
      @set.each do |other_element|
        next_element = @block.call(element, other_element)
        if not @set.include?(next_element)
          is_closed = false
        end
      end
    end
    return is_closed
  end

  def has_identity?
    @set.each do |element|
      candidate_identity = true
      @set.each do |other_element|
        next_element = @block.call(element, other_element)
        if not next_element == other_element
          candidate_identity = false
        end
      end
      if candidate_identity == true
        return true
      end
    end
    return false
  end

  def identity
    has_identity = false
    @set.each do |element|
      candidate_identity = true
      @set.each do |other_element|
        next_element = @block.call(element, other_element)
        if not next_element == other_element
          candidate_identity = false
        end
      end
      if candidate_identity == true
        return element
      end
    end
    puts 'No identity exists'
    return nil
  end

  def is_associative?
    is_associative = true
    @set.each do |a|
      @set.each do |b|
        @set.each do |c|
        element_ab_c = @block.call(@block.call(a, b), c)
        element_a_bc = @block.call(a, @block.call(b,c))
        if not element_ab_c == element_a_bc
          is_associative = false
        end
        end
      end
    end
    return is_associative
  end

  def has_inverses?
    has_inverses = true
    id = self.identity
    @set.each do |element|
      found_inverse = false
      @set.each do |other_element|
        next_element = @block.call(element, other_element)
        if next_element == id
          found_inverse = true
        end
      end
      if found_inverse == false
        has_inverses = false
      end
    end
    return has_inverses
  end

end

Unit tests:

require './group'
require 'test/unit'

class TestGroup < Test::Unit::TestCase

	def test_add_mod10_int_mod10_isGroup
	  int_mod10 = [0,1,2,3,4,5,6,7,8,9]
	  add_mod10 = Proc.new{ |a,b| (a+b)%10 }
	  add_int_mod10 = Group.new(int_mod10, add_mod10)
	  assert_equal true, add_int_mod10.isGroup?
	end

	def test_mult_int_mod10_isNotGroup
	  int_mod10 = [0,1,2,3,4,5,6,7,8,9]
	  mult = Proc.new{ |a,b| a*b }
	  mult_int_mod10 = Group.new(int_mod10, mult)
	  assert_equal false, mult_int_mod10.isGroup?
	end

	def test_add_bool_isNotGroup
		bool = [0,1]
		add = Proc.new{ |a,b| a+b }
		add_bool = Group.new(bool, add)
		assert_equal false, add_bool.isGroup?
	end

	def test_add_mod2_bool_isGroup
		bool = [0,1]
		add_mod2 = Proc.new{ |a,b| (a+b)%2 }
		add_mod2_bool = Group.new(bool, add_mod2)
		assert_equal true, add_mod2_bool.isGroup?
	end

end