clojure - 如何使用 test.check 生成随机图?

标签 clojure test.check

我正在尝试以邻接列表形式生成随机图,以便进行生成测试。示例图如下:

{:a #{:a :b}, :b #{:a :b}}

(邻接列表作为集合实现。)

我的第一个想法是:

(def vertex-gen (tcgen/fmap (comp keyword str) tcgen/char-alpha-numeric))

(def random-graph-gen-1
  (tcgen/let [vertices (tcgen/set vertex-gen {:min-elements 1})]
             (tcgen/map (tcgen/elements vertices)
                        (tcgen/set (tcgen/elements vertices)))))

({min-elements 1} 是必需的,因为 tcgen/elements 不适用于空集。)

但是,这存在生成诸如此类的图表的风险

{:a #{:a :b}}

其中 :b 是为 :a 的邻接列表随机选择的,但不是为图本身选择的。因此 :a 有一个不存在的邻居。

另一个选择是

(def random-graph-gen-2
  (tcgen/let [vertices (tcgen/set vertex-gen)]
             (->> vertices
                  (map #(->> vertices
                             (tcgen/elements)
                             (tcgen/set)
                             (tcgen/generate)
                             (vector %)))
                  (into {}))))

它迭代所有顶点并为每个顶点显式生成一个随机邻接列表。这保证了所有顶点都会出现在图中,但缺点是 test.check 看不到正在生成的邻接列表。所以我担心这会搞乱收缩逻辑。

有没有一种解决方案可以避免这两个陷阱?

最佳答案

这是另一种方法:

(def graph-gen
  (gen/let [vertices (gen/set vertex-gen {:min-elements 1})
            edges (-> vertices
                      (gen/elements)
                      (gen/set)
                      (gen/vector (count vertices)))]
    (zipmap vertices edges)))

这引入了第二个生成器,它为每个顶点生成一组边,然后将顶点和边压缩到单个 map 中。

在第二个示例中使用generate会引入不受整个生成器大小限制的随机性。从生成文档字符串:

Note that this function is a dev helper and is not meant to be used to build other generators.

但是您可以使用generate从生成器中采样不同大小的样本:

(gen/generate graph-gen 2)
=> {:F #{}, :e #{}, :S #{:e}}
(gen/generate graph-gen 10)
=>
{:L #{:n :7 :8 :H},
 :n #{:L :n :7 :C :8 :b :H :V},
 :7 #{:L :7 :C :8 :9 :b},
 :C #{:L :9 :V},
 :8 #{:L :n :7 :C :8 :9 :b :V},
 :9 #{:L :b :a},
 :b #{:n :V},
 :H #{:a},
 :V #{:n :C :b :H},
 :a #{}}

关于clojure - 如何使用 test.check 生成随机图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53083757/

相关文章:

clojure - 在 clojure 中,如何从一个大的惰性序列中惰性地计算多个子序列?

clojure - 如何使用 `clojure.spec/+` 限制生成样本的大小?

clojure - 规范 : partially overriding generators in a map spec

clojure - test.check 中的循环和状态管理

clojure - 进入列表

functional-programming - 哪个函数在堆栈使用效率和时间方面最好

unit-testing - 在 Clojure 中使用时间戳值测试 map

concurrency - Clojure:并行计算产生的数据访问速度似乎要慢得多

unit-testing - 如何在 test.check 中生成随机电子邮件地址?