簡體   English   中英

無限深度和無限寬度玫瑰樹的懶惰折疊到其邊緣路徑

[英]Lazy Folding of Infinite Depth & Infinite Breadth Rose Tree to its Edge Paths

這個問題包括將玫瑰樹折疊成路徑的代碼折疊玫瑰樹路徑。 我正在嘗試無限的玫瑰樹,我發現所提供的解決方案並不足以在寬度和寬度上無限的玫瑰樹上工作。

考慮像玫瑰樹一樣:

data Rose a = Rose a [Rose a] deriving (Show, Functor)

這是一棵有限的玫瑰樹:

finiteTree = Rose "root" [ 
    Rose "a" [ 
        Rose "d" [], 
        Rose "e" []
    ], 
    Rose "b" [ 
        Rose "f" [] 
    ], 
    Rose "c" [] 
]

邊路徑列表的輸出應為:

[["root","a","d"],["root","a","e"],["root","b","f"],["root","c"]]

這是兩個維度中的無限玫瑰樹:

infiniteRoseTree :: [[a]] -> Rose a
infiniteRoseTree ((root:_):breadthGens) = Rose root (infiniteRoseForest breadthGens)

infiniteRoseForest :: [[a]] -> [Rose a]
infiniteRoseForest (breadthGen:breadthGens) = [ Rose x (infiniteRoseForest breadthGens) | x <- breadthGen ]

infiniteTree = infiniteRoseTree depthIndexedBreadths where
    depthIndexedBreadths = iterate (map (+1)) [0..]

樹看起來像這樣(它只是一個摘錄,有無限的深度和無限的寬度):

      0
      |
      |
    [1,2..]
    /  \
   /    \
  /      \
[2,3..]  [2,3..]

路徑看起來像:

[[0,1,2..]..[0,2,2..]..] 

這是我最近的嘗試(在GHCi上執行此操作會導致無限循環,沒有流輸出):

rosePathsLazy (Rose x []) = [[x]]
rosePathsLazy (Rose x children) = 
    concat [ map (x:) (rosePathsLazy child) | child <- children ]

rosePathsLazy infiniteTree

另一個答案中提供的解決方案也沒有產生任何輸出:

foldRose f z (Rose x []) = [f x z]
foldRose f z (Rose x ns) = [f x y | n <- ns, y <- foldRose f z n]

foldRose (:) [] infiniteTree

上述兩種工作都適用於有限玫瑰樹。

我嘗試了很多變化,但我無法弄清楚邊緣折疊操作是否對於無限的二維玫瑰樹來說是懶惰的。 我覺得它與無限量的concat

由於輸出是二維列表。 我可以同時運行具有深度限制或寬度限制或兩者的二維take和項目!

任何幫助表示贊賞!


在回顧了這里的答案並思考了一下之后。 我又意識到,這是展開的,因為產生的名單是不可數無窮。 這是因為無限深度和寬度玫瑰樹不是二維數據結構,而是無限維數據結構。 每個深度級別都賦予額外的維度。 換句話說,它有點等同於無限維矩陣,想象一個矩陣,其中每個場是另一個矩陣.ad-infinitum。 無限矩陣的基數是infinity ^ infinity ,已被證明(我認為)無窮無盡。 這意味着任何無限維數據結構在有用的意義上都不是真正可計算的。

要將此應用於玫瑰樹,如果我們有無限深度,那么路徑永遠不會枚舉玫瑰樹的最左邊。 就是這棵樹:

      0
      |
      |
    [1,2..]
    /  \
   /    \
  /      \
[2,3..]  [2,3..]

會產生如下路徑: [[0,1,2..], [0,1,2..], [0,1,2..]..] ,我們永遠不會超過[0,1,2..]

或者換句話說,如果我們有一個包含ad-infinitum列表的列表。 我們也可以永遠不會計算(枚舉)它,因為代碼會跳轉到無限量的維度。

這也與實數無關也有一些關系。 在一個懶惰的無限實數列表中,它將無限地產生0.000..並且永遠不會枚舉過去。

我不確定如何形式化上述解釋,但那是我的直覺。 (有關參考,請參閱: https//en.wikipedia.org/wiki/Uncountable_set )看到有人將https://en.wikipedia.org/wiki/Cantor's_diagonal_argument應用於此問題,這很酷。

本書似乎對此進行了擴展: https//books.google.com.au/books?id = OPFoJZeI8MEC&gt = PA140&lpg = PA140&div = haskell +uncountably+infinite&source=bl&ots=Z5hM-mFT6A&sig=ovzWV3AEO16M4scVPCDD-gyFgII&hl=en&sa=X&redir_esc= Y#v = onepage&q =哈斯克爾%20uncountably%20infinite&F =假

出於某種原因,dfeuer刪除了他的答案,其中包括一個非常好的洞察力,只有一個輕微的,容易解決的問題。 下面我討論他很好的見解,並修復容易解決的問題。

他的觀點是,原來的代碼掛原因是因為它並不明顯concat任何參數列表中的元素都是非空。 既然我們可以證明這一點(在Haskell之外,用紙和筆),我們可以稍微欺騙一下來說服編譯器它就是這樣。

不幸的是, concat還不夠好:如果你給concat一個像[[1..], foo]這樣的列表,它永遠不會從foo提取元素。 universe包的集合可以在這里幫助它的diagonal函數,它可以從所有子列表中繪制元素。

總之,這兩個見解導致以下代碼:

import Data.Tree
import Data.Universe.Helpers

paths (Node x []) = [[x]]
paths (Node x children) = map (x:) (p:ps) where
    p:ps = diagonal (map paths children)

如果我們定義一個特定的無限樹:

infTree x = Node x [infTree (x+i) | i <- [1..]]

我們可以看看它在ghci中的表現如何:

> let v = paths (infTree 0)
> take 5 (head v)
[0,1,2,3,4]
> take 5 (map head v)
[0,0,0,0,0]

看起來不錯! 當然,正如ErikR所觀察到的,我們不能在這里擁有所有路徑。 然而,給出的任何有限的前綴p通過一個無限路徑的t ,存在一個有限索引paths t其元素與前綴開始p

不是一個完整的答案,但你可能會對這個關於如何編寫Haskell的permutations函數的詳細答案感興趣,以便它可以在無限列表上運行:

這個列表在Haskell中的排列實現到底是做什么的?

更新

這是創建無限Rose樹的更簡單方法:

iRose x = Rose x [ iRose (x+i) | i <- [1..] ]

rindex (Rose a rs) [] = a
rindex (Rose _ rs) (x:xs) = rindex (rs !! x) xs

例子:

rindex (iRose 0) [0,1,2,3,4,5,6]     -- returns: 26
rindex infiniteTree [0,1,2,3,4,5,6]  -- returns: 13

無限深度

如果Rose樹具有無限深度和非平凡寬度(> 1),則不能使用計數參數列出所有路徑的算法 - 總路徑數不可數。

有限深度和無限寬度

如果Rose樹具有有限的深度,即使樹具有無限寬度,路徑的數量也是可數的,並且存在可以產生所有可能路徑的算法。 觀看此空間以獲取更新。

ErikR解釋了為什么你不能生成一個必須包含所有路徑的列表,但是可以從左邊懶洋洋地列出路徑。 最簡單的技巧,雖然是一個骯臟的技巧,但是要認識到結果永遠不會是空的並且在Haskell上強制這個事實。

paths (Rose x []) = [[x]]
paths (Rose x children) = map (x :) (a : as)
  where
    a : as = concatMap paths children
    -- Note that we know here that children is non-empty, and therefore
    -- the result will not be empty.

為了制作非常無限的玫瑰樹,請考慮

infTree labels = Rose labels (infForest labels)
infForest labels = [Rose labels' (infForest labels')
                      | labels' <- map (: labels) [0..]]

正如chi 指出的那樣 ,雖然這種paths定義是有效的,但在某些情況下,它會永遠地重復最左邊的路徑,而且永遠不會再到達。 哎呀! 因此,為了給出有趣/有用的結果,有必要進行公平或對角遍歷。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM