【问题标题】:Graph with sets as vertices以集合为顶点的图
【发布时间】:2013-12-04 02:29:10
【问题描述】:

我有一个小语法,表示为变体类型term,其中的字符串是标记/标记的一部分(type term)。 给定语法中的表达式,我从表达式中收集所有字符串并将它们打包成集合(function vars)。最后,我想创建一些以这些集合为顶点的图形(第 48-49 行)。

由于某种原因,以这种复杂方式创建的图无法识别包含相同变量的集合,并创建具有相同内容的多个顶点。我真的不明白为什么会这样。

这是具有此行为的最小工作示例:

(* demo.ml *)
type term =
  | Var of string
  | List of term list * string option
  | Tuple of term list

module SSet = Set.Make(
  struct
    let compare = String.compare
    type t = string
  end)

let rec vars = function
  | Var v -> SSet.singleton v
  | List (x, tail) ->
    let tl = match tail with
    | None -> SSet.empty 
    | Some var -> SSet.singleton var in
    SSet.union tl (List.fold_left SSet.union SSet.empty (List.map vars x))
  | Tuple x -> List.fold_left SSet.union SSet.empty (List.map vars x)

module Node = struct
  type t = SSet.t
  let compare = SSet.compare
  let equal = SSet.equal
  let hash = Hashtbl.hash
end

module G = Graph.Imperative.Digraph.ConcreteBidirectional(Node)

(* dot output for the graph for illustration purposes *)
module Dot = Graph.Graphviz.Dot(struct
  include G
  let edge_attributes _ = []
  let default_edge_attributes _ = []
  let get_subgraph _ = None
  let vertex_attributes _ = []
  let vertex_name v = Printf.sprintf "{%s}" (String.concat ", " (SSet.elements v))
  let default_vertex_attributes _ = []
  let graph_attributes _ = []
end)

let _ =
  (* creation of two terms *)
  let a, b = List ([Var "a"], Some "b"), Tuple [Var "a"; Var "b"] in
  (* get strings from terms packed into sets *)
  let avars, bvars = vars a, vars b in
  let g = G.create () in
  G.add_edge g avars bvars;
  Printf.printf "The content is the same: [%s] [%s]\n"
    (String.concat ", " (SSet.elements avars))
    (String.concat ", " (SSet.elements bvars));
  Printf.printf "compare/equal output: %d %b\n"
    (SSet.compare avars bvars)
    (SSet.equal avars bvars);
  Printf.printf "Hash values are different: %d %d\n"
    (Hashtbl.hash avars) (Hashtbl.hash bvars);
  Dot.fprint_graph Format.str_formatter g;
  Printf.printf "Graph representation:\n%s" (Format.flush_str_formatter ())

为了编译,输入ocamlc -c -I +ocamlgraph demo.ml; ocamlc -I +ocamlgraph graph.cma demo.cmo。当程序执行时,你会得到这个输出:

The content is the same: [a, b] [a, b]
compare/equal output: 0 true
Hash values are different: 814436103 1017954833
Graph representation:
digraph G {
  {a, b};
  {a, b};


  {a, b} -> {a, b};
  {a, b} -> {a, b};

  }

总而言之,我很好奇为什么集合的哈希值不相等,并且在图中创建了两个相同的顶点,尽管事实上这些集合在所有其他方面都是相等的。

【问题讨论】:

    标签: graph set ocaml


    【解决方案1】:

    我怀疑一般的答案是 OCaml 的内置散列基于值的相当物理属性,而集合相等是一个更抽象的概念。如果您将集合表示为有序二叉树,则有许多树表示相同的集合(众所周知)。这些将作为集合相等,但很可能散列为不同的值。

    如果您希望散列对集合起作用,您可能必须提供自己的函数。

    【讨论】:

    • 看来你是对的。但是,如果标准的不起作用,为什么不在Set模块中提供hash功能呢?
    • 我希望在 OCaml 标准库中有很多这样的东西。 CoreBatteries Included 等较新的库正在填补空白。
    【解决方案2】:

    正如 Jeffrey 指出的那样,问题似乎在于作为 Node 模块一部分的哈希函数的定义。

    将其更改为 let hash x = Hashtbl.hash (SSet.elements x) 解决了该问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-25
      • 1970-01-01
      • 1970-01-01
      • 2012-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多