Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure &引用;“可重读”;纯功能树数据结构_Clojure_Tree_Functional Programming_Purely Functional_Phylogeny - Fatal编程技术网

Clojure &引用;“可重读”;纯功能树数据结构

Clojure &引用;“可重读”;纯功能树数据结构,clojure,tree,functional-programming,purely-functional,phylogeny,Clojure,Tree,Functional Programming,Purely Functional,Phylogeny,我最近购买了约瑟夫·费尔森斯坦(Joseph Felsenstein)的书,这是一本关于推断系统发育树的数学和计算方法的好书,并且一直在尝试实现它描述的一些算法 具体来说,我感兴趣的是在具有持久数据结构的功能设置中使用,因为很多方法都涉及到遍历可能的树空间,如果能够通过结构共享廉价地记住我们所处的历史,那将是一件很好的事(a láaphyr在中对“世界”所做的事情),轻松缓存以前计算的子树值等 问题是,很多方法都涉及到“重排”树,我无法想出如何以一种纯粹的功能性方式廉价地完成这项工作。基本上,我

我最近购买了约瑟夫·费尔森斯坦(Joseph Felsenstein)的书,这是一本关于推断系统发育树的数学和计算方法的好书,并且一直在尝试实现它描述的一些算法

具体来说,我感兴趣的是在具有持久数据结构的功能设置中使用,因为很多方法都涉及到遍历可能的树空间,如果能够通过结构共享廉价地记住我们所处的历史,那将是一件很好的事(a láaphyr在中对“世界”所做的事情),轻松缓存以前计算的子树值等

问题是,很多方法都涉及到“重排”树,我无法想出如何以一种纯粹的功能性方式廉价地完成这项工作。基本上,我需要一些方法来捕捉以下每一个概念(使用clojure符号,将树表示为向量):

表示相同的数据,仅在根的位置不同;它们各自代表无根树:

a   b
 \ /
  |
 / \
c   d
我希望能够使用拉链导航到这些树中的一个,然后调用函数
reroot
,该函数将返回一个新的树,该树的拉链方式使根位于当前的
loc

在这本书中,Felsenstein描述了一个便宜的可重读树的数据结构,它看起来像下面匆忙绘制的图表

其中圆是结构,箭头是指针。结构的环是树上的内部节点,一旦我们有了一个对它的引用,我们就可以通过做一些指针交换将根移动到那里。不幸的是,这是一个变异操作,需要相互引用,这两者在纯功能设置中都是不可能的

我觉得应该有办法用拉链来做我想做的事情,但我已经玩了一段时间了,但一无所获

是否有人知道这样的实现,或者对我应该阅读的内容/我应该看的论文/如何做到这一点的想法有什么建议

谢谢

无根树是具有以下特征的图:

  • 它是对称的/无向的-它是它自己的逆
  • 它是紧密相连的——你可以从任何地方到任何地方
  • 要回到你的家乡,唯一的办法就是回到你的家乡 步骤
表示图形的标准方法是将每个节点的邻居集表示为一个映射。这就是它的作用,尽管它的操作被大量冗余的
defstruct
所掩盖

例如,地图是

{:I #{:a :b :c :d}, :a #{:I}, :b #{:I}, :c #{:I}, :d #{:I}}
这是一个无向图,当它是自己的
逆图时,其中

(defn inverse [g]
  (apply merge-with clojure.set/union
         (for [[x xs] g, y xs] {y #{x}})))
你不需要做任何事情来根除它。正如@noisesmith所说,根只是开始枚举的节点。从图表上看,费尔森斯坦的数据结构也是如此

如图所示,如果只有内部节点是多重连接的,则可以通过将每个外部节点直接映射到其唯一的邻居来节省一些空间。你的榜样会变成

{:I #{:a :b :c :d}, :a :I, :b :I, :c :I, :d :I}
也许最好用两张地图来表达:

{:internals {:I #{:a :b :c :d}}, :externals {:a :I, :b :I, :c :I, :d :I}}

jvm实际上并不允许我们访问指针,这样我们就可以直接操作指针。但我们有几个选项来表示双链接结构

这看起来很像一个图,对于这样的稀疏图,一个经典的表示是。邻接列表的一个优点是,它们按名称取消引用,而不依赖于指针/对象标识,因此,我们可以在结构中表示任意循环或自引用路径,而无需任何变异

按字母顺序从左到右/从上到下命名节点:

{:a [:c]
 :b [:d]
 :c [:a :d :e]
 :d [:b :c :e]
 :e [:c :d :g]
 :f [:h]
 :g [:e :h :i]
 :h [:f :g :i]
 :i [:g :h]}
网络中的元素按名称查找,从该元素中出来的箭头由向量表示为关联值。遍历可以实现为一个递归函数,在每次迭代中查找要单步执行的节点。“根”只是用于开始遍历的元素(图中的
:i

可以使用
conj
updatein
assoc
等进行各种插入/拆分重排,因为哈希映射文本是一种常规的clojure持久数据结构。

如果使用集合而不是向量/列表来收集相邻节点,则该结构更容易(更快)适应。
{:a [:c]
 :b [:d]
 :c [:a :d :e]
 :d [:b :c :e]
 :e [:c :d :g]
 :f [:h]
 :g [:e :h :i]
 :h [:f :g :i]
 :i [:g :h]}