簡體   English   中英

用於生成無偏圖進行快速檢查的任意實例

[英]Arbitrary instance for generating unbiased graphs for quickcheck

module Main where

import Test.QuickCheck
import Data.Set as Set    

data Edge v = Edge {source :: v, target :: v}
                  deriving (Show,Eq,Ord)

data Graph v = Graph {nodes :: Set v, edges :: Set (Edge v)}
               deriving Show

instance Arbitrary v => Int-> Arbitrary (Edge v) where
    arbitrary = sized aux 
        where aux n = do s <- arbitrary
                         t <- arbitrary `suchThat` (/= s)
                         return $ Edge {source = s, target = t}


instance (Ord v, Arbitrary v) => Arbitrary (Graph v) where
    arbitrary = aux `suchThat` isValid
        where aux = do ns <- arbitrary 
                       es <- arbitrary 
                       return $ Graph {nodes = fromList ns, edges = fromList es}

實例的當前定義正在生成幾乎沒有邊緣的圖,如何更改它以減少偏見並滿足這兩個功能?

-| 函數“ isDAG”測試圖是否為非循環圖。

isDAG :: Ord v => Graph v -> Bool
isDAG g = isValid g && all nocycle (nodes g)
    where nocycle v = all (\a -> v `notMember` reachable g a) $ Set.map target (adj g v)

-| 函數'isForest'測試一個有效的DAG是否是一個小植物(一組樹),換句話說,-如果每個節點(頂點)最多具有一個相鄰節點。

isForest :: Ord v => DAG v -> Bool
isForest g = isDAG g && all (\v -> length (adj g v) <= 1) (nodes g)

首先,您必須弄清楚如何構造滿足這些屬性的圖。

DAG:如果您的節點接受某種排序,並且對於每個邊(u,v)您的u < v則該圖是非循環的。 此排序完全可以是任何排序,因此您可以在圖形中的節點集上制造任意排序。

森林:如果圖形沒有邊,則可以輕松滿足此屬性。 最初,您可以添加源為任何節點的任何邊。 如果添加邊緣,請從其余可用節點中刪除該邊緣的源。

我想最大的問題是如何將其轉換為代碼。 QuickCheck提供了許多組合器,尤其是。 用於從列表中進行選擇,有或沒有替代品,各種尺寸等。

instance (Ord v, Arbitrary v) => Arbitrary (Graph v) where 
  arbitrary = do 
    ns <- Set.fromList <$> liftA2 (++) (replicateM 10 arbitrary) arbitrary

首先,您生成一組隨機節點。

    let ns' = map reverse $ drop 2 $ inits $ Set.toList ns 

對於每個節點,這將計算(大於)該節點“(非空)”的節點集。 在這里,“更大”僅表示根據列表中元素順序產生的任意順序。 這將為您提供DAG屬性。

    es <- sublistOf ns' >>= 
            mapM (\(f:ts) -> Edge f <$> elements ts)

然后,您將獲得該列表的一個隨機子列表(這將為您提供林屬性),並為該隨機子列表中的每個元素創建一條從該集合中“最大”節點指向“較小”節點的邊。

    return $ Graph ns (Set.fromList es) 

這樣就完成了! 像這樣測試:

main = quickCheck $ forAll arbitrary (liftA2 (&&) (isDAG :: Graph Integer -> Bool) isForest)

構造圖的一種自然方法是歸納法,一次添加一個節點。 然后,確保所需的屬性成立變得非常容易:

  • 如果對於每個添加的節點,其邊緣僅指向現有節點(而不指向另一個方向),則確保DAG屬性。
  • 如果一個節點最多有一條邊緣,則確保林屬性。 (由於您未提供adj函數,因此不清楚“森林”是否意味着一個節點一個節點最多有一條邊。)

因此,生成此類圖的過程將如下所示:

  1. 生成隨機節點列表。
  2. 通過一張一張地添加它們來構造圖。 對於每個節點,可以將隨機邊緣添加到已添加的節點之一,或者不添加邊緣(隨機確定)。

此處的主要因素是確定是否添加邊。 通過調整此參數,您可以在森林中獲得更多或更少的樹木。 一種選擇是為此使用frequency

暫無
暫無

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

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