一些好的表示方式标准包括:
- 效率:它们不会被用于大数据集的常量处理,但我不想花费几个小时计算结果,如果有更好的设计只需要几分钟就能完成。 - Java互操作性:可以轻松地在两种语言之间传递数据。 - 易于并行化:如果我可以通过将map替换为pmap来使用所有可用的内核,那将是很好的。 - 适合使用reduce:看起来我正在做的很多计算都非常适合使用reduce。 - 能够以矩阵行的形式表示图像扫描线:不是非常重要,但这将是很好的。
有什么想法吗?
Incanter 提供了对一些Parallel Colt 的封装,其中包括看起来相当不错的快速并行稠密矩阵实现,可与Clojure的基于seq的库进行接口交互。我没有使用过它,但它应该是您正在寻找的。
示例。
core.matrix
及其各种实现,例如vectorz-clj
)。 - mikeraRich Hickey的Clojure是一种基于JVM的Lisp,它使用32分支树来表示PersistentVector(而不是PersistentList)。
如果您想编写自己的矩阵类型,我会使用PersistentVector,否则最好选择Parallel Colt与Incanter一起使用。
我最近编写了一些需要矩阵数学的代码,最初使用的是向量嵌套、映射和约简。但是当我回到这段代码时发现很难理解(我对Clojure不太熟悉)。使用Incanter让相同的代码变得非常简洁易懂(标准矩阵运算),而且速度也快了很多。
答案可能需要更新,因为已经过去了8年。快速的谷歌搜索显示,如果你需要与Clojure core.matrix API兼容,你可以使用core.matrix本身或其他实现,比如vectorz-clj。
此外,我还发现了Neanderthal,它是针对GPU进行优化的。
我不是专家,但这是我的意见 :)
list-of-lists 可能是表示矩阵最自然的 Clojure 习惯用语。这种结构也很适合 map/reduce 类型的操作。Clojure 处理序列的效率也相当高 - 可能比大多数替代方案都要好。
我不能保证这一点,但我认为我看到过 Clojure 在我的 3 或 4 个 CPU 上工作,这些程序风格是函数式的,但没有尝试并行处理。我怀疑编译器正在自己找到一些并行处理的机会。
我认为 Clojure 创建的序列类型将作为 Java 中的 Lists,或者至少是 Iterable。对于你想要的东西来说,这可能已经足够好了,尽管如果你尝试将这些结构视为可修改的 Java 对象时,可能会遇到问题。
Lists 最好按顺序访问。如果你计划在矩阵中跳来跳去,使用 vector-of-vectors 可能会更好一些,从性能上讲。我怀疑这比使用 nth 函数要好。
作为一名前C程序员,我曾经简要考虑过可以将矩阵实现为一维结构(即直接序列或更好的向量),并进行自己的索引计算以找到正确的元素。您可以使用partition函数遍历它... 嗯,虽然这可能被处理,但我怀疑有非常充分的理由不这样做。