如何在Ruby on Rails中实现无向图?

时间:2009-02-23 15:46:00

标签: ruby-on-rails ruby algorithm

我需要在Ruby on Rails中实现无向图G =(V,E)并考虑构建 Vertex Edge 模型,其中 Vertex has_many Edges

由于边缘恰好连接了两个顶点,您将如何在Rails中强制执行此操作?

你知道任何有助于实现这种图形的宝石或图书馆(对重新发明轮子不感兴趣; - ))?

1 个答案:

答案 0 :(得分:9)

不知道在ActiveRecord之上提供图形逻辑的任何现有库。

您可能必须实现自己的Vertex,Edge ActiveRecord支持的模型(请参阅Rails安装的vertex.rb目录中的edge.rbrails/activerecord/test/fixtures),例如

### From Rails: ###

# This class models an edge in a directed graph.
class Edge < ActiveRecord::Base
  belongs_to :source, :class_name => 'Vertex', :foreign_key => 'source_id'
  belongs_to :sink,   :class_name => 'Vertex', :foreign_key => 'sink_id'
end

# This class models a vertex in a directed graph.
class Vertex < ActiveRecord::Base
  has_many :sink_edges, :class_name => 'Edge', :foreign_key => 'source_id'
  has_many :sinks, :through => :sink_edges

  has_and_belongs_to_many :sources,
    :class_name => 'Vertex', :join_table => 'edges',
    :foreign_key => 'sink_id', :association_foreign_key => 'source_id'
end

要使上述内容表现为 adirected 图形,请考虑插入边缘时插入互补边缘。另请注意,现在不建议使用has_and_belongs_to_many,您可以使用has_many :sources ... :through => :edges代替[source_id,sink_id]。任何强制执行都可以通过验证(即顶点没有自身边缘)和/或数据库约束(edgesActiveRecord上的unicity约束/索引确保顶点V1 ---&gt; ; V2不由多于一个有向边连接,并且顶点V1&lt; --- V2也不由一个以上的有向边连接。)

此时您有两个选项,具体取决于图表的大小以及您希望在任何给定时间点遍历的图表数量:

  1. 使用vertex1.edges.first.sink.edges关系(例如RGL ...)在上述模型之上编写应用程序所需的最少量图形逻辑;这个导致对数据库进行大量往返
  2. import edges = Edge.find(:all) dg = RGL::AdjacencyGraph.new(edges.inject([]) { |adj,edge| adj << edge.source_id << edge.sink_id }) # have fun with dg # e.g. isolate a subset of vertex id's using dg, then # load additional info from the DB for those vertices: vertices = Vertex.find(vertex_ids) ;选择从DB到RGL的所有顶点和边,并使用RGL进行图遍历,例如
  3. Edge.find(:all)

    以上将SQL语句的总数(在只读操作中)降为2,但如果图形(red)很大,可能会对数据库或内存造成压力 - 此时你可能会考虑进一步限制实际需要的数据量,例如只关心 Edge.find(:all, :joins => :sources, # or sinks; indifferent since symmetric :conditions => [ 'vertices.red = ?', true ] ) 顶点的连接:

    {{1}}