【问题标题】:Memoization of Haskell FunctionHaskell 函数的记忆
【发布时间】:2022-01-29 03:39:35
【问题描述】:

我在 Haskell 中编写了一个函数来计算矩阵的行列式,它工作得很好,但速度非常慢,所以我试着像 Haskell Wiki does with the Fibonacci function 一样记住它。

但不知何故,我的记忆函数比非记忆函数花费的时间略长,即使在计算单位矩阵的行列式时也是如此,这应该从记忆中受益匪浅。

我也尝试使用 Map 来缓存结果,但没有办法将修改后的 Map 传递给递归函数的下一次迭代。

我该如何解决这个问题?

-- Non-Memoized version
det :: (Num a, Eq a) => [[a]] -> a
det x
    | fst s == 0 = 0
    | fst s == 1 = head $ head x
    | fst s == 2 = (head (head x) * ((x !! 1) !! 1)) 
                    - ((head x !! 1) * head (x !! 1))
    | F.allEqual x = 0
    | otherwise = sum [((-1) ^ (i + 1)) * head (x !! (i - 1)) 
                                        * det (sub x i 1) 
                       | i <- [1..(fst s)]]
    where
        s = shape x

-- Memoized version
mDet :: (Num a, Eq a) => [[a]] -> a
mDet x = sum [((-1) ^ (i + 1)) * head (x !! (i - 1)) 
                               * det' (sub x i 1) 
              | i <- [1..(fst $ shape x)]]
    where
        det' y
            | fst s == 0 = 0
            | fst s == 1 = head $ head y
            | fst s == 2 = (head (head y) * ((y !! 1) !! 1)) 
                            - ((head y !! 1) * head (y !! 1))
            | F.allEqual y = 0
            | otherwise = mDet y
            where
                s = shape y

【问题讨论】:

  • 你忘了定义 shape 和 F.allEqual。
  • 我认为这很明显,shape 是一个具有矩阵维度的元组,allEqual 检查列表的所有元素是否相等,正如我在问题中所说,该函数有效,唯一的问题是它的记忆
  • 这不是记忆。没有存储中间结果以供重用的数据结构。这看起来完全一样的功能,只是递归分为两步。
  • 是的,确实没有正确记忆,但这就是我首先问的原因

标签: haskell recursion linear-algebra memoization determinants


【解决方案1】:

There are much more efficient algorithms to compute the determinant via factorization.

即使有记忆,在朴素的行列式公式中也有指数级的子矩阵,所以这有点毫无意义。

【讨论】:

    【解决方案2】:

    仅供参考,你的函数重写以避免!!访问变成

    -- Non-Memoized version
    
    det :: (Num a, Eq a) => [[a]] -> a
    det []  =  0
    det [r] =  head r
    det [r,q] =  case [r,q] of 
              [[a,b],[c,d]]  -> a*d - b*c    -- error out on wrong shape
    det x | or [ or [a==b | b <- bs]         -- quadratic test
                 | (a:bs) <- tails x ]       --    (must be "collinear",
            =  0  -- "any", not "all"!       --          not "==", anyway)
    det x   =  sum $ [s * head r * det ([reverse a,b] >>= map tail)
                       | (a,r,b) <- picks3 x
                       | s <- cycle [1,-1]]
    
    picks3 :: [a] -> [([a], a, [a])]
    picks3 xs = unfoldr (\case {  (_,[]) -> Nothing ;
                                (a,x:xs) -> Just ((a,x,xs), (x:a,xs)) })
                        ([],xs)
    

    这里没有什么可以立即记住的。

    【讨论】:

      猜你喜欢
      • 2013-08-20
      • 2016-04-11
      • 1970-01-01
      • 1970-01-01
      • 2020-10-25
      • 2011-03-13
      • 2012-09-05
      • 1970-01-01
      • 2018-09-08
      相关资源
      最近更新 更多