# Finite Set
#
# by Shin-ichiro Hara (sinara@blade.nagaokaut.ac.jp)
#
# Version 0.96 (2003.11.06)
#require "algebra/persistence"
module Algebra
class Set
include Enumerable
def self.[](*a)
new(*a)
end
def self.new_a(a)
new(*a)
end
def self.new_h(h)
new.instance_eval do
@body = h
self
end
end
def initialize(*m)
@body = {}
m.each do |x|
@body.store(x, true)
end
end
attr_accessor :body
def self.empty_set
new()
end
class << self
alias phi empty_set
alias null empty_set
end
def self.singleton(x)
new(x)
end
def cast(klass = Set)
x = klass.new_h(@body)
if block_given?
x.instance_eval do
yield
end
end
x
end
def empty_set
self.class.new()
end
alias phi empty_set
alias null empty_set
def singleton(x)
self.class.new(x)
end
def singleton?
size == 1
end
def size
@body.size
end
def empty?
@body.empty?
end
alias phi? empty?
alias empty_set? empty?
alias nul? empty?
def each(&b)
@body.each_key(&b)
end
def separate(&b)
self.class.new(*find_all(&b))
end
alias select_s separate
alias find_all_s separate
def map_s(&b)
self.class.new(*map(&b))
end
def pick
each do |x|
return x
end
nil
end
def shift
(x = @body.shift) && x.first
end
def dup
self.class.new(*to_a)
end
def append!(x)
@body.store(x, true)
self
end
alias push append!
alias << append!
def append(x)
dup.append!(x)
end
def concat(other)
case other
when Set
@body.update other.body
when Array
other.each do |x|
append!(x)
end
else
raise "unknown self.class #{other.class}"
end
self
end
def rehash
@body.rehash
end
def eql?(other)
subset?(other) and superset?(other)
end
alias == eql?
def hash
s = 0
@body.each_key do |k|
s ^= k.hash
end
s
end
def include?(x)
@body.include?(x)
end
alias member? include?
alias has? include?
alias contains? include?
def superset?(other) # self includes other
other.is_a?(Set) and other.all?{|x| member?(x)}
end
alias >= superset?
alias incl? superset?
def subset?(other) # self is a part of other
other.is_a?(Set) and all?{|x| other.member?(x)}
end
alias <= subset?
alias part_of? subset?
def <(other)
self <= other && size < other.size
end
def >(other)
self >= other && size > other.size
end
def union(other = nil)
if other
h = @body.dup
h.update other.body
self.class.new_h(h)
else
u = phi
each do |s|
u = u.union(s)
end
u
end
end
alias | union
alias + union
alias cup union
def difference(other)
h = @body.dup
h.delete_if {|k, v| other.include?(k)}
self.class.new_h(h)
end
alias - difference
def intersection(other = nil)
if other
h = @body.dup
h.delete_if {|k, v| !other.include?(k)}
self.class.new_h(h)
else
i = nil # nil is a universe?
each do |s|
if i.nil?
i = s
else
i = i.intersection(s)
end
end
i
end
end
alias & intersection
alias cap intersection
def each_pair
stock = []
each do |x|
stock.each do |a|
yield a, x
end
stock.push x
end
end
def each_member(n)
if n == 0
yield []
elsif n == 1 #redundant but effective
each do |x|
yield [x]
end
else
stock = self.class[]
each do |x|
stock.each_member(n-1) do |a|
yield a + [x]
end
stock.push x
end
end
end
def each_subset
yield phi
_each_subset do |s|
yield s
end
end
def each_non_trivial_subset # each without empty set and total set
n = size
_each_subset do |x|
yield x unless x.size == n
end
end
def _each_subset
stock = phi
each do |x|
yield self.class[x]
stock._each_subset do |a|
yield a + self.class[x]
end
stock.push x
end
stock
end
protected :_each_subset
def power_set
s = phi
each_subset do |u|
s.append! u
end
s
end
def each_product(other)
each do |x|
other.each do |y|
yield [x, y]
end
end
end
def product(other, s = phi)
if block_given?
each_product(other) do |x, y|
s.append! yield(x, y)
end
else
each_product(other) do |x, y|
s.append! [x, y]
end
end
s
end
alias * product
def equiv_class(equiv = nil)
classes = Set.phi
if equiv && equiv.is_a?(Symbol) && !block_given?
each do |e|
if c = classes.find{|s|
send(equiv, s.pick, e)
}
c.push e
classes.rehash
else
classes.push singleton(e)
end
end
elsif equiv && !block_given?
each do |e|
if c = classes.find{|s|
equiv.call(s.pick, e)
}
c.push e
classes.rehash
else
classes.push singleton(e)
end
end
elsif !equiv && block_given?
each do |e|
if c = classes.find{|s|
yield(s.pick, e)
}
c.push e
classes.rehash
else
classes.push singleton(e)
end
end
else
raise "illegal call `equiv_class'"
end
classes
end
alias / equiv_class
def to_s
"{" + @body.keys.collect{|x| x.inspect}.join(', ') + "}"
end
def inspect
"{" + @body.keys.collect{|x| x.inspect}.join(', ') + "}"
end
def to_a
@body.keys
end
def to_ary
to_a
end
def sort
to_a.sort
end
def power(other)
a = Map.phi(self)
s = [a]
other.each do |x|
tmp = []
each do |y|
s.each do |m|
tmp << m.append(x, y)
end
end
s = tmp
end
self.class[*s]
end
def identity_map
a = Map.phi(self)
each do |x|
a.append!(x, x)
end
a
end
alias ** power
def surjections(other)
(self**other).separate{|m| m.surjective?}
end
def injections0(other)
(self**other).separate{|m| m.injective?}
end
def injections(other)
maps = Set[]
if size < other.size
phi;
elsif other.empty?
maps.push Map.phi(self)
else
each do |x|
a = self - self.class[x]
o = other.dup
h = o.shift
maps.concat a.injections(other)
maps.concat a.injections(o).map_s{|m| m.append(h, x)}
end
end
maps
end
def bijections(other)
size == other.size ? injections(other) : Set[]
end
end
end
module Enumerable
unless instance_methods(true).include?("any?")
def any?
each{|x|
return true if yield(x)
}
false
end
def all?
!any?{|x| !yield(x)}
end
end
end
syntax highlighted by Code2HTML, v. 0.9.1