【问题标题】:Haskell: how to treat big combinatorial Lists?Haskell:如何处理大型组合列表?
【发布时间】:2016-09-12 23:32:44
【问题描述】:

就在最近,我尝试编写一个程序,该程序基本上可以从在线游戏中模拟一个简单的系统。其背后的想法是,让程序计算最有效的项目集,以从一组中获得最大可能的统计效率。为了进一步澄清这一点: 你有 8 个物品槽和 74 种不同的物品,你不能使用任何物品两次,而且哪个物品在哪个槽中都没有关系。我什至还没有尝试计算一组统计数据,我之前就卡住了!

所以这个问题是过滤前(74 ^ 8)和过滤后(74选择8)的可能性数量。 当我尝试 head(permu' 2) 时,我的程序已经开始滞后。 既然我知道 Haskell 应该与无限列表一起使用,那么它如何与 899 万亿条目的列表一起使用?好吧,我显然知道 PC 需要很大的容量,但这就是我在这里问的原因:

如何处理 Haskell 中的大列表以便我可以使用它?

函数简化如下:

quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort [a] = [a]
quicksort (x:xs) = (quicksort [y | y <- xs, y <= x]) ++ [x] ++ (quicksort [z | z <- xs , z > x])

eliminatedouble [] = []
eliminatedouble (x:xs) = if x `elem` xs then eliminatedouble xs else x:(eliminatedouble xs)

permu' n | n>8 = error "8 is max"
         | otherwise = eliminatedouble (filter allSatisfied (generate n))
   where
      generate 0 = [[]]
      generate x = [quicksort (a:xs) | a <- [1..74], xs <- generate (x-1)]
      allSatisfied [] = True
      allSatisfied (x:xs) = (checkConstraint x xs) && (allSatisfied xs)
      checkConstraint x xs = not (doubled x xs)
      doubled x xs = x `elem` xs

知道如何以更便宜的方式做到这一点会很有趣。

提前致谢,问候。

【问题讨论】:

  • 供以后参考:quicksort -> Data.List.sort; eliminatedouble -> Data.List.nubelemdoubled 别名似乎很奇怪。此外,nub 与基于Data.Set 的实现相比通常相当慢,并且allSatisfied 也可能通过使用Data.Set 加速很多。但正如我在回答中所描述的那样,最大的胜利将来自于首先只生成您关心的元素,而不是生成大量您不关心和过滤的东西。

标签: list haskell infinite


【解决方案1】:

你让这件事变得比需要的困难得多。

choose 0 xs = [[]]
choose n [] = []
choose n (x:xs) = map (x:) (choose (n-1) xs) ++ choose n xs

在我的解释器中,choose 5 [1..74] 需要大约 22 秒来计算所有条目,choose 6 [1..74] 需要 273 秒。此外,choose 8 [1..74] 会立即开始尝试组合;我估计将它们全部生成大约需要 6 个小时。注:这是在解释器中,没有进行优化或其他幻想;如果你让 GHC 有机会弄清楚如何做,它可能会更快。

假设您打算对choose 8 [1..74] 的每个元素进行一些重要的计算,我建议您要么安排大量时间,要么考虑不进行详尽搜索的解决方案——也许使用一些启发式方法来获得一个近似的答案,或者弄清楚如何进行一些修剪以删除搜索空间的大片、无趣的大片。

【讨论】:

  • 详尽地检查nCr 74 8 的选择?可能只是在一流的集群上可行,在 PC 上绝对不可行。
  • @leftaroundabout 实际上,在做了一些粗略的计算之后,我更倾向于相信这是可能的......如果你不介意计算几天。取决于用户的目标,我认为!我已经更新了我的答案,让我更有希望。
  • 你说得对,我脑子里也有一个近似值,它实际上太悲观了几个数量级。无论如何,这绝对是一项值得并行的任务。
  • 为什么这比 listcomprehension 快这么多?我对 Haskell 有点陌生,所以我真的不知道......不管怎样,你们认为我应该放弃这个项目,因为拥有 8 有点重要......而且它并不是那么容易删掉结果,因为每个结果都可能很重要,所以从 74 选择 8 中的完整列表将根据对象中的条目进行排序,这些条目基本上是元组,每个元组有 45 个条目......你的函数比我明显使用的要快得多。在像 java 这样的基于对象的程序语言上工作会更成功吗?
  • @nub 速度差异不在于列表理解与不是,而是在于选择更好的算法。比较:我的版本不需要消除重复项、进行任何排序或验证任何特定谓词是否包含元素或整个列表。与您的版本相比,在我的版本中根本不需要完成很多工作。我怀疑放弃 Haskell 会更好——74 选择 8 只是一个很大的数字,你不能通过选择不同的语言来解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-19
  • 2018-02-04
  • 1970-01-01
相关资源
最近更新 更多