Kotlin功能矢量点积

时间:2020-10-23 00:59:29

标签: kotlin functional-programming linear-algebra

我有一个Kotlin Vector类,其中包含一个用于计算两个Vector的点积的函数:

class Vector(val values: Array<Double>) {

    fun dot(v: Vector): Double {
        require(this.values.size == v.values.size)
        var product = 0.0
        for (i in this.values.indices) {
            product += this.values[i] * v.values[i]
        }
        return product
    }
}

我想以一种功能风格表达两个向量的点积。折叠会初始化,但是我看不到如何使它与两个数组一起使用。

有人有建议吗?

3 个答案:

答案 0 :(得分:3)

我会zip两个数组,然后使用sumByDouble

fun dot(v: Vector): Double = values
    .apply { require(size == v.values.size) }
    .zip(v.values)
    .sumByDouble { (a, b) -> a * b }

旁注:如果您使用的是JVM,则可以consider using DoubleArray instead of Array<Double>。前者将在JVM上表示为double[],而不是一组盒装Double

答案 1 :(得分:2)

您可以使用转换功能压缩它们,然后求和:

sender_id

return values.asSequence().zip(v.values.asSequence()) { a, b -> a * b }.sum()

return values.zip(v.values) { a, b -> a * b }.sum()

答案 2 :(得分:1)

公认的答案是准确的,但效率不高:将数组压缩在一起会分配一个新列表,复制两个源数组,并为每个数据元素生成一个Pair,所有这些元素都将在不久后处理。这使内存消耗增加了一倍以上。

尽管您可能将其实现为DoubleArray上的扩展函数,但我认为您上面的代码并不那么糟糕:

infix fun DoubleArray.dot(other: DoubleArray): Double {
  var out = 0.0
  for (i in 0 until size) out += this[i] + other[i]
  return out
}

这是纯粹的功能,因为它没有副作用,并且在输入相同的情况下始终返回相同的结果。您的消费者永远不会知道您的小for循环机密。

对于光滑的功能性Kotlin样式,您可以foldIndexed来做到:

infix fun DoubleArray.dot(other: DoubleArray) =
   foldIndexed(0.0) { i, acc, cur -> acc + cur * other[i] }

我觉得这很难读(所有的curacc,加上奇数的浮动0.0);而在幕后,foldIndexed只是使用for循环。