我一直在通过实现一个特征选择算法来学习一些Haskell。

我从20秒开始将基准数据集的性能降低到5s,其中C程序在0.5s内处理相同的数据集。 数据集可以在这里找到。 要运行,请调用已编译的二进制文件: ./Mrmr 10 test_nci9_s3.csv

代码在这里 ,我有兴趣优化mutualInfoInnerLoop:

mutualInfoInnerLoop :: Double -> Data.Vector.Unboxed.Vector (Int, Int) -> Double -> (Int, Int, Double) -> Double
mutualInfoInnerLoop n xys !acc (!i, !j, !px_py)
    | n == 0 || px_py == 0 || pxy == 0 = acc
    | otherwise                        = pxy * logBase 2 ( pxy / px_py ) + acc
    where
        pxy = ( fromIntegral . U.foldl' accumEq2 0 $ xys ) / n
        accumEq2 :: Int -> (Int, Int) -> Int
        accumEq2 !acc (!i', !j')
            | i' == i && j' == j = acc + 1
            | otherwise          = acc

剖析器说:

COST CENTRE                    MODULE               %time %alloc

mutualInfoInnerLoop            Main                  75.0   47.9
mutualInfo                     Main                  14.7   32.1
parseCsv                       Main                   5.9   13.1
CAF                            GHC.Float              1.5    0.0
readInt                        Main                   1.5    1.2
doMrmr                         Main                   1.5    4.0

它显示了mutualInfoInnerLoop作为50%的分配,占程序运行时的75%。 分配令人不安。

此外,该功能的核心有一个签名:

mutualInfoInnerLoop_rXG
  :: GHC.Types.Double
     -> Data.Vector.Unboxed.Base.Vector (GHC.Types.Int, GHC.Types.Int)
     -> GHC.Types.Double
     -> (GHC.Types.Int, GHC.Types.Int, GHC.Types.Double)
     -> GHC.Types.Double
[GblId,
 Arity=4,
 Caf=NoCafRefs,
 Str=DmdType U(L)LU(L)U(U(L)U(L)U(L))m]

将大多数参数显示为Lazily评估和装箱(与严格和未装箱相反)。

我尝试过BangPatterns,我尝试过MagicHash,但我似乎无法让它变得更快。

有人有什么建议吗?

===============>>#1 票数:2

到目前为止,我还没有专家,但我确实看到了一个小改进。 在你的来源中我看到了这个:

mutualInfo n ... = foldl' (mutualInfoInnerLoop n $ U.zip xs ys) ...

每次调用函数时都不需要检查n == 0 ,因为在调用函数时从不更改n参数。 xys说法并没有改变,或者说,这意味着pxy不会在调用改变,因为它完全取决于xysn 让我们利用这些东西来确保创建一个只关闭这些东西的闭包。

mutualInfoInnerLoop n xys
  | n == 0 || pxy == 0 = const
  | otherwise          = go
  where pxy = (fromIntegral . U.foldl' accumEq2 0 $ xys) / n
        accumEq2 :: Int -> (Int, Int) -> Int
        accumEq2 !acc (!i', !j')
              | i' == i && j' == j = acc + 1
              | otherwise          = acc
        go !acc (!i, !j, !px_py)
          | px_py == 0 = acc
          | otherwise  = pxy * logBase 2 ( pxy / px_py ) + acc

我不确定GHC是否足够智能自己进行优化,我也不确定这会节省多少时间/空间,但这是我所拥有的最好的。 随着那些爆炸模式遍布各地,我想知道这是否是一个过于严格的情况。

  ask by LanceH translate from so

未解决问题?本站智能推荐:

1回复

如何优化此Haskell限制订单(包含代码,报告,图表)?

我写了一个限制订单簿的haskell版本,引用用C编写的这个版本: https://github.com/jordanbaucke/Limit-Order-Book/blob/master/Others/C%2B%2B/engine.c 限价订单簿是许多股票和货币交易所用于计算货币和
2回复

Haskell中的缓存和显式并行性

我目前正在尝试在Projet Euler上优化我对问题14的解决方案。 我非常喜欢Haskell,我认为它非常适合这类问题,这是我尝试过的三种不同的解决方案: 现在,如果你看一下实际问题,那么缓存很有可能,因为大多数新序列都包含之前已经计算过的子序列。 为了比较,我也在C中写了一
1回复

Haskell参数应用程序通过'map'中的'$ x'到inflix运算符函数列表。 它是如何工作的?

我只是想知道,出于对这种功能的好奇,下面的中间表达是某种优化的结果吗? 我确实知道$实际上是一个函数,仅提供了一个参数。 通过某种方式,通过将此功能应用于“ map”提供的列表中的功能,它设法看到“ $”功能恰恰缺少一个功能,正如我所提到的,“ $ map”提供了该功能。 这种优化行为对带
4回复

冒泡排序算法实现(Haskell与C)

我在C和Haskell中编写了2个冒泡排序算法的实现。 Haskell实现: 我已经比较了这两个实现在文件上运行的大小为20 KiB。 C实现大约花了一秒钟,Haskell - 大约1分10秒。 我还介绍了Haskell应用程序: 编译用于分析: C:\\ Tem
1回复

此功能编程优化称为什么?

考虑以下用于计算第n个斐波那契数的Haskell代码。 此代码很慢。 我们可以通过重构为“迭代地”计算的辅助函数,通过“存储”所有相关数据以在其参数中计算递归以及“告诉我们计算所需时间的”“计数器”来优化它。 似乎这种优化也可以更广泛地应用。 在函数式编程社区或其他地方是否有
4回复

编译器优化的功能代码比命令性代码执行得更好的示例

无副作用, 参照透明的功能编程的一种承诺是,可以广泛地优化此类代码。 引用维基百科 : 在许多情况下,数据的不变性可以通过允许编译器进行以命令式语言进行的不安全假设来提高执行效率,从而增加内联扩展的机会。 我想看看一些示例,其中功能语言编译器通过生成更好的优化代码来胜过命令式
8回复

函数式编程中的有效递归与不同范式中的低效递归

据我所知,递归非常优雅,但在OOP和程序编程方面效率不高(参见精彩的“High Order perl”,Mark Jason Dominus)。 我有一些信息,在函数式编程递归中很快 - 保持其优雅和简洁。 有人可以确认并可能放大这个吗? 我正在考虑XSLT和Haskell(我的下一个语言
3回复

列表理解中的表达式是否被冗余评估?

GHC是否在char == 'o'时评估concat strings ,然后在char == 'a'时再次评估concat strings ? 还是记得concat strings == "foobarbaz"供以后使用? 我意识到我可以通过重构此代码来避免这种不确定性,但是我对代码的
1回复

在Haskell,管道,attoparsec和容器中优化内存

我正在尝试进一步优化我的管道 - attoparsec解析器和存储,但无法获得更低的内存使用率。 给出account-parser.hs 用GHC 8.0.2编译( stack ghc -- -O2 -rtsopts -threaded -Wall account-parser.h
1回复

很难理解Haskell内存分配行为

我偶然发现了Haskell和FP,并对这些可能性感到震惊。 我内心的旧数学书呆子可以毫不费力地为实际有用的目的编写天真的代码。 然而,尽管所有的阅读,我仍然很难理解如何不打出一些令人惊讶的性能瓶颈。 因此,我使用简单的实现编写了非常短的代码片段,然后尝试进行少量更改以查看性能如何响应。