haskell - Haskell 中的惯用向量代数

标签 haskell

作为在 Haskell 中练习向量库的一种方式,我正在尝试重写我之前用 C 编写的 Nelder-Mead 最小化算法。
到目前为止,我在翻译一些惯用的向量操作时遇到了一些麻烦。

例如,考虑一个函数,它从 n+1 列表中找到 n 个向量的质心(过滤掉一个索引),

在 C 中,这可以写为

static void get_centroid(double **s, int n, int iz,
                         double *C)
{
  for (int i = 0; i < n+1; i++) {
    if (i != iz) {
      for (int j = 0; j < n; j++)
        C[j] += s[i][j];
    }
  }
  for (int j = 0; j < n; j++)
    C[j] /= n;
}

我试着把它翻译成 Haskell,结果如下

import Data.Vector
import qualified Data.Vector as V

type Node = Vector Double

type Simplex = Vector Node

centroid :: Simplex -> Int -> Node
centroid s iz = V.map (/ (fromIntegral $ V.length s)) $ V.zipWith (-) v (s ! iz) 
    where v = V.foldl go V.empty s 
        where go a b = V.zipWith (+) a b

我发现这段代码很不优雅,因为它没有捕捉到正在发生的向量代数的本质(而且效率也更低,因为我正在加减 S[iz])。

一种解决方案是实现某种向量空间类型类或使用更具体的线性代数库,但由于这些是常见的操作,我想知道是否有更惯用的“直接”解决方案。

最佳答案

我会从 dfeuer 的 +1 开始;一个更具体的库几乎肯定会更干净、更高效。

但是,如果您正在寻找的是您的 centroid 的更惯用的实现。功能,我喜欢这个:

centroid' :: Simplex -> Int -> Node
centroid' s iz = let t = foldl1 (V.zipWith (+)) (V.drop iz s)
                     n = fromIntegral (V.length t - 1)
                 in V.map (/ n) t

对您的版本的一般评论:创建“只写”Haskell 代码非常容易。您的第一行内容太多,难以解析。您的 where block 是朝着正确的方向迈出的一步,但我会进一步打破概念组件。

另外,Hoogle .我不知道有函数drop ,但我知道如果它存在,它需要一个 IntVector到一个新的 Vector . Hoogle 没有索引 Vector ,但向量的 API 与列表的 API 非常相似。我搜索了“[a] -> Int -> [a]”和“Int -> [a] -> [a]”,发现 drop .

( Stackage 没有索引 Vector ,所以在那里搜索“Int -> Vector a -> Vector a”有效)

关于haskell - Haskell 中的惯用向量代数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30634449/

相关文章:

sql - Esqueleto:如何使用联接删除项目

haskell - ghci 中的 pretty-print

haskell - 为什么 Haskell monadic 是左结合的?

haskell - 为什么 Haskell 不接受列表的这种语法?

haskell - 使用 Parsec 跳过空白行

haskell - Yesod 1.4 的基本电子邮件/密码身份验证

haskell - 线程无限期阻塞 - Haskell - Acid State

haskell - 在 Haskell 中创建临时目录

haskell - GHCI 中的不同输出

haskell - 随机访问haskell中的一个大文件