#--
# Copyright (c) 2006 Shawn Patrick Garbett
# Copyright (c) 2002,2004,2005 by Horst Duchene
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice(s),
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of the Shawn Garbett nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#++
module GRATR
# Edge includes classes for representing egdes of directed and
# undirected graphs. There is no need for a Vertex class, because any ruby
# object can be a vertex of a graph.
#
# Edge's base is a Struct with a :source, a :target and a :label
Struct.new("EdgeBase",:source, :target, :label)
class Edge < Struct::EdgeBase
def initialize(p_source,p_target,p_label=nil)
super(p_source, p_target, p_label)
end
# Ignore labels for equality
def eql?(other) self.class == other.class and target==other.target and source==other.source; end
# Alias for eql?
alias == eql?
# Returns (v,u) if self == (u,v).
def reverse() self.class.new(target, source, label); end
# Sort support
def <=>(rhs) [source,target] <=> [rhs.source,rhs.target]; end
# Edge.new[1,2].to_s => "(1-2 'label')"
def to_s
l = label ? " '#{label.to_s}'" : ''
"(#{source}-#{target}#{l})"
end
# Hash is defined in such a way that label is not
# part of the hash value
def hash() source.hash ^ (target.hash+1); end
# Shortcut constructor. Instead of Edge.new(1,2) one can use Edge[1,2]
def self.[](p_source, p_target, p_label=nil)
new(p_source, p_target, p_label)
end
def inspect() "#{self.class.to_s}[#{source.inspect},#{target.inspect},#{label.inspect}]"; end
end
# An undirected edge is simply an undirected pair (source, target) used in
# undirected graphs. UndirectedEdge[u,v] == UndirectedEdge[v,u]
class UndirectedEdge < Edge
# Equality allows for the swapping of source and target
def eql?(other) super or (self.class == other.class and target==other.source and source==other.target); end
# Alias for eql?
alias == eql?
# Hash is defined such that source and target can be reversed and the
# hash value will be the same
#
# This will cause problems with self loops
def hash() source.hash ^ target.hash; end
# Sort support
def <=>(rhs)
[[source,target].max,[source,target].min] <=>
[[rhs.source,rhs.target].max,[rhs.source,rhs.target].min]
end
# UndirectedEdge[1,2].to_s == "(1=2 'label)"
def to_s
l = label ? " '#{label.to_s}'" : ''
s = source.to_s
t = target.to_s
"(#{[s,t].min}=#{[s,t].max}#{l})"
end
end
# This module provides for internal numbering of edges for differentiating between mutliple edges
module EdgeNumber
attr_accessor :number # Used to differentiate between mutli-edges
def initialize(p_source,p_target,p_number,p_label=nil)
self.number = p_number
super(p_source, p_target, p_label)
end
# Returns (v,u) if self == (u,v).
def reverse() self.class.new(target, source, number, label); end
def hash() super ^ number.hash; end
def to_s() super + "[#{number}]"; end
def <=>(rhs) (result = super(rhs)) == 0 ? number <=> rhs.number : result; end
def inspect() "#{self.class.to_s}[#{source.inspect},#{target.inspect},#{number.inspect},#{label.inspect}]"; end
def eql?(rhs) super(rhs) and (rhs.number.nil? or number.nil? or number == rhs.number); end
def ==(rhs) eql?(rhs); end
# Shortcut constructor. Instead of Edge.new(1,2) one can use Edge[1,2]
def self.included(cl)
def cl.[](p_source, p_target, p_number=nil, p_label=nil)
new(p_source, p_target, p_number, p_label)
end
end
end
class MultiEdge < Edge
include EdgeNumber
end
class MultiUndirectedEdge < UndirectedEdge
include EdgeNumber
end
end
syntax highlighted by Code2HTML, v. 0.9.1