Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance haskell矩阵实现性能_Performance_Haskell - Fatal编程技术网

Performance haskell矩阵实现性能

Performance haskell矩阵实现性能,performance,haskell,Performance,Haskell,我听说了很多关于用Haskell编写的程序的惊人性能的事情,我想做一些测试。因此,我为矩阵运算编写了一个“库”,只是为了将它的性能与纯C语言编写的相同内容进行比较。 首先,我测试了500000个矩阵的乘法性能,并注意到它是。。。永无止境(即在10分钟的so之后以内存不足异常结束)!在进一步研究haskell之后,我成功地摆脱了懒惰,我所获得的最好结果是比C语言中的等效速度慢20倍。 所以,问题是:你能回顾一下下面的代码,看看它的性能是否可以再提高一点吗?20次还是让我有点失望 import Pr

我听说了很多关于用Haskell编写的程序的惊人性能的事情,我想做一些测试。因此,我为矩阵运算编写了一个“库”,只是为了将它的性能与纯C语言编写的相同内容进行比较。 首先,我测试了500000个矩阵的乘法性能,并注意到它是。。。永无止境(即在10分钟的so之后以内存不足异常结束)!在进一步研究haskell之后,我成功地摆脱了懒惰,我所获得的最好结果是比C语言中的等效速度慢20倍。 所以,问题是:你能回顾一下下面的代码,看看它的性能是否可以再提高一点吗?20次还是让我有点失望

import Prelude hiding (foldr, foldl, product)
import Data.Monoid
import Data.Foldable

import Text.Printf
import System.CPUTime

import System.Environment

data Vector a = Vec3 a a a
              | Vec4 a a a a
                deriving Show

instance Foldable Vector where
  foldMap f (Vec3 a b c) = f a `mappend` f b `mappend` f c
  foldMap f (Vec4 a b c d) = f a `mappend` f b `mappend` f c `mappend` f d

data Matr a = Matr !a !a !a !a
                   !a !a !a !a
                   !a !a !a !a
                   !a !a !a !a

instance Show a => Show (Matr a) where
  show m = foldr f [] $ matrRows m
            where f a b = show a ++ "\n" ++ b

matrCols (Matr a0 b0 c0 d0 a1 b1 c1 d1 a2 b2 c2 d2 a3 b3 c3 d3)
              = [Vec4 a0 a1 a2 a3, Vec4 b0 b1 b2 b3, Vec4 c0 c1 c2 c3, Vec4 d0 d1 d2 d3]

matrRows (Matr a0 b0 c0 d0 a1 b1 c1 d1 a2 b2 c2 d2 a3 b3 c3 d3)
              = [Vec4 a0 b0 c0 d0, Vec4 a1 b1 c1 d1, Vec4 a2 b2 c2 d2, Vec4 a3 b3 c3 d3]

matrFromList [a0, b0, c0, d0, a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3]
        = Matr a0 b0 c0 d0
               a1 b1 c1 d1
               a2 b2 c2 d2
               a3 b3 c3 d3

matrId :: Matr Double
matrId  = Matr 1 0 0 0
               0 1 0 0
               0 0 1 0
               0 0 0 1

normalise (Vec4 x y z w) = Vec4 (x/w) (y/w) (z/w) 1

mult a b = matrFromList [f r c | r <- matrRows a, c <- matrCols b] where 
            f a b = foldr (+) 0 $ zipWith (*) (toList a) (toList b)
导入前奏隐藏(foldr、foldl、产品) 导入数据.幺半群 导入数据。可折叠 导入文本.Printf 导入系统.CPUTime 导入系统。环境 数据向量a=向量3 a |VEC4A 衍生节目 实例可折叠向量,其中 foldMap f(Vec3 a b c)=f a`mappend`f b`mappend`f c foldMap f(Vec4 a b c d)=f a`mappend`f b`mappend`f c`mappend`f d 数据Matr a=Matr!A.A.A.A. !A.A.A.A. !A.A.A.A. !A.A.A.A. 实例Show a=>Show(Matr a)其中 show m=foldr f[]$matrRows m 其中f a b=显示a++“\n++b 材料工具(材料a0 b0 c0 d0 a1 b1 c1 d1 a2 b2 c2 d2 a3 b3 c3 d3) =[Vec4 a0 a1 a2 a3,Vec4 b0 b1 b2 b3,Vec4 c0 c1 c2 c3,Vec4 d0 d1 d2 d3] 材料(材料a0 b0 c0 d0 a1 b1 c1 d1 a2 b2 c2 d2 a3 b3 c3 d3) =[Vec4 a0 b0 c0 d0,Vec4 a1 b1 c1 d1,Vec4 a2 b2 c2 d2,Vec4 a3 b3 c3 d3] 材料清单[a0、b0、c0、d0、a1、b1、c1、d1、a2、b2、c2、d2、a3、b3、c3、d3] =材料a0 b0 c0 d0 a1 b1 c1 d1 a2 b2 c2 d2 a3 b3 c3 d3 matrId::Matr-Double matrId=Matr 1 0 0 0 1 0 0 0 0 1 0 0 0 0 1 归一化(Vec4 x y z w)=Vec4(x/w)(y/w)(z/w)1
mult a b=材料清单[f r c | r首先,我怀疑您能否通过此实现获得出色的性能。不同表示之间的转换太多。您最好基于类似于包的内容编写代码。此外,您没有提供所有测试代码,因此可能还有其他问题我们无法解决。这是因为se从生产到消费的管道对Haskell的性能有很大的影响,您没有提供任何一端

现在,有两个具体问题:

1) 您的向量被定义为3或4个元素的向量。这意味着对于每个向量,都有一个额外的检查来查看有多少元素在使用。在C中,我想您的实现可能更接近

struct vec {
  double *vec;
  int length;
}
您应该在Haskell中执行类似的操作;例如,
vector
bytestring
就是这样实现的

即使您不更改
向量
定义,也要严格控制字段。您还应该添加
解包
杂注(到向量和矩阵)或使用
-funbox严格字段
编译

2) 将
mult
更改为

mult a b = matrFromList [f r c | r <- matrRows a, c <- matrCols b] where 
            f a b = Data.List.foldl' (+) 0 $ zipWith (*) (toList a) (toList b)

mult a b=matrFromList[f r c | r回答我自己的问题只是为了分享我昨天得到的新结果:

  • 我将ghc升级到最新版本,性能确实没有那么差(只差了约7倍)

  • 此外,我还尝试用一种愚蠢而简单的方式实现这个矩阵(见下面的清单),并获得了真正可以接受的性能——只比C等效语言慢了大约2倍

    data Matr a = Matr ( a, a, a, a
                       , a, a, a, a
                       , a, a, a, a
                       , a, a, a, a) 
    
    mult (Matr (!a0,  !b0,  !c0,  !d0,  
                !a1,  !b1,  !c1,  !d1,  
                !a2,  !b2,  !c2,  !d2,  
                !a3,  !b3,  !c3,  !d3))
         (Matr (!a0', !b0', !c0', !d0', 
                !a1', !b1', !c1', !d1', 
                !a2', !b2', !c2', !d2', 
                !a3', !b3', !c3', !d3'))
         = Matr ( a0'', b0'', c0'', d0''
                , a1'', b1'', c1'', d1''
                , a2'', b2'', c2'', d2''
                , a3'', b3'', c3'', d3'')
            where a0'' = a0 * a0' + b0 * a1' + c0 * a2' + d0 * a3'
                  b0'' = a0 * b0' + b0 * b1' + c0 * b2' + d0 * b3'
                  c0'' = a0 * c0' + b0 * c1' + c0 * c2' + d0 * c3'
                  d0'' = a0 * d0' + b0 * d1' + c0 * d2' + d0 * d3'
    
                  a1'' = a1 * a0' + b1 * a1' + c1 * a2' + d1 * a3'
                  b1'' = a1 * b0' + b1 * b1' + c1 * b2' + d1 * b3'
                  c1'' = a1 * c0' + b1 * c1' + c1 * c2' + d1 * c3'
                  d1'' = a1 * d0' + b1 * d1' + c1 * d2' + d1 * d3'
    
                  a2'' = a2 * a0' + b2 * a1' + c2 * a2' + d2 * a3'
                  b2'' = a2 * b0' + b2 * b1' + c2 * b2' + d2 * b3'
                  c2'' = a2 * c0' + b2 * c1' + c2 * c2' + d2 * c3'
                  d2'' = a2 * d0' + b2 * d1' + c2 * d2' + d2 * d3'
    
                  a3'' = a3 * a0' + b3 * a1' + c3 * a2' + d3 * a3'
                  b3'' = a3 * b0' + b3 * b1' + c3 * b2' + d3 * b3'
                  c3'' = a3 * c0' + b3 * c1' + c3 * c2' + d3 * c3'
                  d3'' = a3 * d0' + b3 * d1' + c3 * d2' + d3 * d3'
    

  • 你的矩阵
    mult
    正在改变矩阵、列表和返回矩阵之间的表示形式。虽然这允许你用两行代码进行计算,但速度会非常非常慢。@stephen tetley:不一定如此。现在的编译器非常擅长内联和分解,所以一个聪明的编译器会在我的测试中,与“快速”手写的展开乘法相比,这种实现并不特别慢(大约慢1.5倍)UPD:我的错误,实际上是双矩阵的6倍慢。在被标记为巨魔的风险下,我认为你不会发现像你正在寻找这些测试的结果。通常最好的Haskell将使性能与良C相媲美。Haskell的巨大优势来自于可读性,与C相比更具表现力,而高级L。像
    STM
    parallel
    这样的库,与大多数其他语言相比,添加并行性非常容易。对于纯数字工作,Haskell的性能很难超过C实现。@John L:在我看来,Haskell最大的性能优势是,你可以多久编写一次简单、朴素的straightforward版本的东西,并让GHC优化它,以提供良好(但不是很好)的性能。@Maxym-我打算让你通过在构造函数上进行模式匹配“手工”进行矩阵乘法,然后链接加法和乘法,根据
    (a*m+b*p+c*s)计算每个元素
    。当然,4x4矩阵的代码很冗长。列表对于矩阵来说完全是“错误的”,因为索引速度慢,它们没有边界,等等。也许数组数据类型更有效。还有unbox(UArray)为了更好的性能,@Wu Xingbo-使用UArray几乎肯定会更好。
    repa
    会更好。
    hmatrix
    包在纯功能设置中提供对BLAS和LAPACK的绑定。数据表示形式是
    data.Vector.Storable
    来自
    Vector
    包e、 您应该会发现,该软件包与C相比,具有Haskell带来的附加好处。将foldr更改为foldl使算法速度慢了两倍。我无法解释原因。@Maxym:
    foldl
    foldl'
    ?它们不一样。添加