breeze.linalg.DenseVector 用法示例源码详解
构造函数
构造函数 | 描述 |
---|---|
new DenseVector(data: Array[E], offset: Int) | 创建一个具有给定数据和偏移量的稠密向量。 |
new DenseVector(data: Array[E]) | 创建一个具有给定数据的稠密向量,偏移量为0。 |
new DenseVector(data: Array[E], offset: Int, stride: Int, length: Int) | 创建一个具有给定数据、偏移量、步幅和长度的稠密向量。 |
以上是DenseVector
类的实例构造函数及其描述。这些构造函数用于创建新的DenseVector
对象,并根据提供的参数初始化向量的属性。
方法总结
方法 | 描述 |
---|---|
%(b) | 对每个元素取模,当 b 是标量时的别名。 |
%=(b) | 对每个元素进行取模并将结果赋值给当前向量,当 b 是标量时的别名。 |
&(b) | 对每个元素进行逻辑与操作,对所有的 b 都是 :&&(b) 的别名。 |
&=(b) | 将当前向量和 b 逐元素进行与运算,并将结果赋值给当前向量。 |
*(b) | 矩阵乘法。 |
*=(b) | 当 b 是标量时,将当前向量每个元素与 b 相乘并将结果赋值给当前向量的每个元素,即逐元素乘法。 |
+(b) | 对每个元素进行求和,对所有的 b 都是 :+(b) 的别名。 |
+=(b) | 将当前向量和 b 逐元素相加,并将结果赋值给当前向量。 |
-(b) | 对每个元素进行求差,对所有的 b 都是 :-(b) 的别名。 |
-=(b) | 将当前向量和 b 逐元素相减,并将结果赋值给当前向量。 |
/(b) | 对每个元素进行求商,当 b 是标量时的别名。 |
/=(b) | 将当前向量每个元素除以 b 并将结果赋值给当前向量的每个元素,即逐元素除法。 |
:!=(b) | 对当前向量和 b 进行逐元素不等比较。 |
%(b) | 对当前向量和 b 进行逐元素取模。 |
%=(b) | 将当前向量每个元素取模并将结果赋值给当前向量的每个元素,即逐元素取模。 |
&(b) | 对当前向量和 b 进行逐元素与运算,返回 true 如果对应元素都非零。 |
&=(b) | 将当前向量和 b 逐元素进行与运算,并将结果赋值给当前向量。 |
*(b) | 对当前向量和 b 进行逐元素乘法。 |
*=(b) | 当 b 是标量时,将当前向量每个元素与 b 相乘并将结果赋值给当前向量的每个元素,即逐元素乘法。 |
+(b) | 对当前向量和 b 进行逐元素加法。 |
+=(b) | 将当前向量和 b 逐元素相加,并将结果赋值给当前向量。 |
-(b) | 对当前向量和 b 进行逐元素减法。 |
-=(b) | 将当前向量和 b 逐元素相减,并将结果赋值给当前向量。 |
/(b) | 对当前向量和 b 进行逐元素除法,当 b 是标量时的别名。 |
/=(b) | 将当前向量每个元素除以 b 并将结果赋值给当前向量的每个元素,即逐元素除法。 |
:!=(b) | 对当前向量和 b 进行逐元素不等比较。 |
:%(b) | 对当前向量和 b 进行逐元素取模。 |
:%=(b) | 将当前向量每个元素取模并将结果赋值给当前向量的每个元素,即逐元素取模。 |
:&(b) | 对当前向量和 b 进行逐元素与运算,返回 true 如果对应元素都非零。 |
:&=(b) | 将当前向量和 b 逐元素进行与运算,并将结果赋值给当前向量。 |
:*(b) | 对当前向量和 b 进行逐元素乘法。 |
:*=(b) | 当 b 是标量时,将当前向量每个元素与 b 相乘并将结果赋值给当前向量的每个元素,即逐元素乘法。 |
:+(b) | 对当前向量和 b 进行逐元素加法。 |
:+=(b) | 将当前向量和 b 逐元素相加,并将结果赋值给当前向量。 |
:-(b) | 对当前向量和 b 进行逐元素减法。 |
:-=(b) | 将当前向量和 b 逐元素相减,并将结果赋值给当前向量。 |
:/(b) | 对当前向量和 b 进行逐元素除法,当 b 是标量时的别名。 |
:/=(b) | 将当前向量每个元素除以 b 并将结果赋值给当前向量的每个元素,即逐元素除法。 |
:!=(b) | 对当前向量和 b 进行逐元素不等比较。 |
:<(b) | 对当前向量和 b 进行逐元素小于比较。 |
:<=(b) | 对当前向量和 b 进行逐元素小于等于比较。 |
:=(b) | 将当前向量每个元素赋值为 b 并将结果赋值给当前向量的每个元素,即逐元素赋值。 |
:==(b) | 对当前向量和 b 进行逐元素等于比较。 |
:>(b) | 对当前向量和 b 进行逐元素大于比较。 |
:>=(b) | 对当前向量和 b 进行逐元素大于等于比较。 |
:^ (b)` | 对当前向量和 b 进行逐元素幂运算。 |
:^=(b) | 将当前向量每个元素的幂指数设为 b 并将结果赋值给当前向量的每个元素,即逐元素幂运算。 |
:^^(b) | 对当前向量和 b 进行逐元素异或运算。 |
:^^=(b) | 将当前向量和 b 逐元素进行异或运算,并将结果赋值给当前向量。 |
`: | (b) |
`: | =(b)` |
\[TT >: DenseVector[E], B, That](b: B) | 求解方程组。 |
:^^ (b)` | 对当前向量和 b 进行逐元素异或运算。 |
:^^=(b) | 将当前向量和 b 逐元素进行异或运算,并将结果赋值给当前向量。 |
active | 返回一个表示稀疏向量中非零元素的 TensorActive 对象。 |
activeIterator | 返回迭代器,遍历稀疏向量中的非零元素。 |
activeKeysIterator | 返回迭代器,遍历稀疏向量中非零元素的索引。 |
activeSize | 返回稀疏向量中非零元素的数量。 |
apply(i) | 获取指定索引位置的元素。 |
apply[Slice1, Slice2, Result](slice1, slice2) | 切片操作,针对矩阵进行了优化。 |
apply[Result](a: Int, slice: Int*) | 对一系列元素进行切片。 |
apply[Slice, Result](slice) | 对张量进行切片。 |
argmax | 返回向量中最大元素的索引。 |
argmin | 返回向量中最小元素的索引。 |
argsort | 返回向量按升序排序后的索引序列。 |
argtopk(k) | 返回最大的 k 个元素的索引。 |
asDenseMatrix | 创建一个表示当前向量的 1xlength 的 DenseMatrix 视图。 |
copy | 返回当前向量的副本。 |
data | 返回底层数据数组。 |
dot(b) | 计算当前向量和另一个向量 b 的内积。 |
equals(p1) | 检查当前向量是否与另一个对象相等。 |
findAll(f) | 返回满足给定条件的元素的索引序列。 |
forall(fn) | 判断是否对所有元素都满足给定的条件。 |
forallValues(fn) | 判断是否对所有元素的值都满足给定的条件。 |
foreach(fn) | 对每个元素应用指定的函数,更快的迭代方式。 |
foreachKey(fn) | 对张量中的每个键应用给定的函数。 |
foreachPair(fn) | 对张量中的每个键值对应用给定的函数。 |
foreachValue(fn) | 对张量中的每个值应用给定的函数。 |
indexAt(i) | 根据物理索引返回逻辑索引。 |
isActive(i) | 始终返回 true。 |
iterableSize | 返回需要使用 valueAt 或 indexAt 进行迭代的元素数量。 |
iterator | 返回一个迭代器,遍历稀疏向量中的键值对。 |
keySet | 返回稀疏向量中非零元素的索引集合。 |
keys | 返回表示稀疏向量键的 TensorKeys 对象。 |
keysIterator | 返回迭代器,遍历稀疏向量中非零元素的索引。 |
length | 返回向量的长度。 |
map(fn) | 对当前向量的每个元素应用给定的函数,并返回结果向量。 |
mapActivePairs(f) | 对稀疏向量中的每对非零键值对进行映射。 |
mapActiveValues(f) | 对稀疏向量中的每个非零值进行映射。 |
mapPairs(f) | 创建一个包含对当前向量每个键值对应用给定函数的新向量。 |
mapValues(f) | 创建一个包含对当前向量每个值应用给定函数的新向量。 |
max | 返回向量中的最大值。 |
min | 返回向量中的最小值。 |
norm(b) | 计算向量的范数。 |
norm() | 计算向量的“自然”范数,对于不支持任意范数的类型使用。 |
offset | 返回第一个元素的索引。 |
pairs | 返回表示稀疏向量键值对的 TensorPairs 对象。 |
repr | 返回当前向量的副本。 |
size | 返回稀疏向量中非零元素的数量。 |
slice(start, end, stride) | 对向量进行切片操作。 |
stride | 返回元素之间的分隔距离。 |
sum | 返回向量中所有元素的总和。 |
t | 返回转置后的当前对象。 |
toArray | 将当前向量转换为数组。 |
toDenseMatrix | 创建一个表示当前向量的 1xlength 的 DenseMatrix 的副本。 |
toDenseVector | 返回当前向量的副本。 |
toString() | 返回向量的字符串表示形式。 |
unary_! | 对当前向量应用逻辑非运算。 |
unary_- | 对当前向量应用一元负运算。 |
update(i, v) | 更新指定索引位置的元素。 |
valueAt(i) | 获取指定索引位置的元素。 |
values | 返回表示稀疏向量值的 TensorValues 对象。 |
valuesIterator | 返回迭代器,遍历稀疏向量中的值。 |
` | (b)` |
` | =(b)` |
以上是DenseVector
类中可用的方法及其描述。这些方法可以对DenseVector
对象执行各种操作,如数学运算、切片、迭代等。
示例
package org.example.spark
import breeze.numerics.pow
object BreezeDenseVectorTest {
import breeze.linalg._
def main(args: Array[String]): Unit = {
// 示例1:创建稠密向量
val vec1 = DenseVector(1, 2, 3, 4, 5)
// 示例2:向量加法
val vec2 = DenseVector(2, 4, 6, 8, 10)
val sum = vec1 + vec2
// 示例3:点积运算
val dotProduct = vec1 dot vec2
// 示例4:逐元素乘法
val elementWiseProduct = vec1 :* vec2
// 示例5:切片操作
val slicedVec = vec1(1 to 3)
// 示例6:范数计算
val norm = breeze.linalg.norm(vec1)
// 示例7:元素求和
val vec3 = DenseVector(1, 2, 3, 4, 5)
val sumElements = breeze.linalg.sum(vec3)
// 示例8:最大值和最小值
val maxVal = breeze.linalg.max(vec1)
val minVal = breeze.linalg.min(vec1)
// 示例9:判断所有元素是否满足条件
val allEven = vec1.forall(_ % 2 == 0)
// 示例10:遍历向量
vec1.foreach(println)
// 示例11:取反
val negVec = -vec1
// 示例12:除法
val divided = vec2 / 2
// 示例15:查找元素的索引
val index = vec1.findAll( x => x > 3)
// 示例17:拷贝向量
val copyVec = copy(vec1)
// 示例18:转换为数组
val array = vec1.toArray
// 示例19:转置向量
val transposed = vec1.t
// 示例20:判断向量相等
val equal = vec1 == vec2
// 示例21:获取指定索引位置的元素
val elementAtIndex = vec1(2)
// 示例22:更新指定索引位置的元素
vec1(3) = 10
// 示例23:获取非零元素的数量
val activeSize = vec1.activeSize
// 示例24:获取所有非零元素的索引
val activeKeys = vec1.activeKeysIterator.toIndexedSeq
// 示例25:获取所有非零元素的值
val activeValues = vec1.activeValuesIterator.toIndexedSeq
// 示例26:对所有非零元素进行迭代
vec1.activeIterator.foreach(println)
// 示例27:对非零元素应用函数
val mappedActive = vec1.activeValuesIterator.map(_ * 2).toIndexedSeq
// 示例28:获取向量的长度
val length = vec1.length
// 示例31:将稠密向量转换为稀疏向量并返回非零元素的数量
val nnz = vec1.activeSize
// 示例32:计算向量的平方
val squaredVec = vec1.mapValues(x => x * x)
// 示例33:对每个元素应用函数并生成新的向量
val mappedVec = vec1.map(_ * 2)
// 示例34:获取最大元素的索引
val argmax = breeze.linalg.argmax(vec1)
// 示例35:获取最小元素的索引
val argmin = breeze.linalg.argmin(vec1)
// 示例36:判断所有元素是否都满足条件
val allPositive = vec1.forall(_ > 0)
// 示例37:判断是否存在满足条件的元素
val existsEven = vec1.exists(_ % 2 == 0)
// 示例38:返回非零元素的副本
val activeCopy = vec1.active
// 示例39:根据索引获取元素
val valueAtIndex = vec1.apply(2)
// 示例40:判断两个向量是否逐元素相等
val isEqual = vec1 == vec2
// 示例41:对向量进行求和
val totalSum = breeze.linalg.sum(vec1)
// 示例42:对向量进行求差
val diff = vec1 - vec2
// 示例43:对向量进行求积
val product = vec1 * vec2
// 示例44:对向量进行取模
val modResult = vec1 % 3
// 示例45:对向量进行乘方
val powResult = pow(vec1, 2)
// 示例46:判断两个向量是否逐元素不等
val notEqual = vec1 :!= vec2
// 示例47:将向量转换为字符串
val str = vec1.toString()
// 示例48:将向量转换为数组
val arrayVec = vec1.toArray
// 示例49:获取向量的维度
val dim = vec1.size
// 示例50:将向量转置
val transposedVec = vec1.t
// 输出结果
println("vec1: " + vec1)
println("vec2: " + vec2)
println("sum: " + sum)
println("dotProduct: " + dotProduct)
println("elementWiseProduct: " + elementWiseProduct)
println("slicedVec: " + slicedVec)
println("norm: " + norm)
println("sumElements: " + sumElements)
println("maxVal: " + maxVal)
println("minVal: " + minVal)
println("allEven: " + allEven)
println("negVec: " + negVec)
println("divided: " + divided)
println("index: " + index)
println("copyVec: " + copyVec)
println("array: " + array.mkString(", "))
println("transposed: " + transposed)
println("equal: " + equal)
println("elementAtIndex: " + elementAtIndex)
println("activeSize: " + activeSize)
println("activeKeys: " + activeKeys.mkString(", "))
println("activeValues: " + activeValues.mkString(", "))
println("mappedActive: " + mappedActive.mkString(", "))
println("length: " + length)
println("nnz: " + nnz)
println("squaredVec: " + squaredVec)
println("mappedVec: " + mappedVec)
println("argmax: " + argmax)
println("argmin: " + argmin)
println("allPositive: " + allPositive)
println("existsEven: " + existsEven)
println("activeCopy: " + activeCopy)
println("valueAtIndex: " + valueAtIndex)
println("isEqual: " + isEqual)
println("totalSum: " + totalSum)
println("diff: " + diff)
println("product: " + product)
println("modResult: " + modResult)
println("powResult: " + powResult)
println("notEqual: " + notEqual)
println("str: " + str)
println("arrayVec: " + arrayVec.mkString(", "))
println("dim: " + dim)
println("transposedVec: " + transposedVec)
}
}
//1
//2
//3
//4
//5
//(0,1)
//(1,2)
//(2,3)
//(3,10)
//(4,5)
//vec1: DenseVector(1, 2, 3, 10, 5)
//vec2: DenseVector(2, 4, 6, 8, 10)
//sum: DenseVector(3, 6, 9, 12, 15)
//dotProduct: 110
//elementWiseProduct: DenseVector(2, 8, 18, 32, 50)
//slicedVec: DenseVector(2, 3, 10)
//norm: 7.416198487095663
//sumElements: 15
//maxVal: 5
//minVal: 1
//allEven: false
//negVec: DenseVector(-1, -2, -3, -4, -5)
//divided: DenseVector(1, 2, 3, 4, 5)
//index: Vector(3, 4)
//copyVec: DenseVector(1, 2, 3, 4, 5)
//array: 1, 2, 3, 4, 5
//transposed: Transpose(DenseVector(1, 2, 3, 10, 5))
//equal: false
//elementAtIndex: 3
//activeSize: 5
//activeKeys: 0, 1, 2, 3, 4
//activeValues: 1, 2, 3, 10, 5
//mappedActive: 2, 4, 6, 20, 10
//length: 5
//nnz: 5
//squaredVec: DenseVector(1, 4, 9, 100, 25)
//mappedVec: DenseVector(2, 4, 6, 20, 10)
//argmax: 3
//argmin: 0
//allPositive: true
//existsEven: true
//activeCopy: breeze.linalg.support.TensorActive@6a370f4
//valueAtIndex: 3
//isEqual: false
//totalSum: 21
//diff: DenseVector(-1, -2, -3, 2, -5)
//product: DenseVector(2, 8, 18, 80, 50)
//modResult: DenseVector(1, 2, 0, 1, 2)
//powResult: DenseVector(1, 4, 9, 100, 25)
//notEqual: BitVector(0, 1, 2, 3, 4)
//str: DenseVector(1, 2, 3, 10, 5)
//arrayVec: 1, 2, 3, 10, 5
//dim: 5
//transposedVec: Transpose(DenseVector(1, 2, 3, 10, 5))
源码
import breeze.generic.UFunc.SinkImpl2
import scala.{specialized=>spec}
import breeze.generic._
import breeze.linalg.support._
import breeze.linalg.operators._
import breeze.math._
import breeze.util.{ArrayUtil, Isomorphism}
import breeze.storage.Zero
import scala.reflect.ClassTag
import com.github.fommil.netlib.BLAS.{getInstance => blas}
import breeze.macros.expand
import scala.math.BigInt
import spire.syntax.cfor._
import CanTraverseValues.ValuesVisitor
import CanZipAndTraverseValues.PairValuesVisitor
import java.io.ObjectStreamException
import scalaxy.debug._
/**
* 一个DenseVector是Vector的一种"明显"实现,但有一个区别。
* 底层数据可能比Vector有更多的数据,使用数组的偏移量(offset)和步长(stride)表示(对于第0个元素)。
*
* 第i个元素在offset + i * stride位置
*
* @param data 数据数组
* @param offset 第0个元素的索引
* @param stride 元素之间的间隔
* @param length 元素数量
*/
@SerialVersionUID(1L) // TODO: scala doesn't propagate this to specialized subclasses. Sigh.
class DenseVector[@spec(Double, Int, Float, Long) V](val data: Array[V],
val offset: Int,
val stride: Int,
val length: Int) extends StorageVector[V]
with VectorLike[V, DenseVector[V]] with Serializable{
def this(data: Array[V]) = this(data, 0, 1, data.length)
def this(data: Array[V], offset: Int) = this(data, offset, 1, data.length)
def this(length: Int)(implicit man: ClassTag[V]) = this(new Array[V](length), 0, 1, length)
// 确保所有运算符都加载了
DenseVector.init()
def repr: DenseVector[V] = this
def activeSize = length
def apply(i: Int): V = {
if(i < - size || i >= size) throw new IndexOutOfBoundsException(i + " not in [-"+size+","+size+")")
val trueI = if(i<0) i+size else i
if (noOffsetOrStride) {
data(trueI)
} else {
data(offset + trueI * stride)
}
}
def update(i: Int, v: V): Unit = {
if(i < - size || i >= size) throw new IndexOutOfBoundsException(i + " not in [-"+size+","+size+")")
val trueI = if(i<0) i+size else i
if (noOffsetOrStride) {
data(trueI) = v
} else {
data(offset + trueI * stride) = v
}
}
private[linalg] val noOffsetOrStride = offset == 0 && stride == 1
@deprecated("This isn't actually any faster any more", "0.12-SNAPSHOT")
def unsafeUpdate(i: Int, v: V): Unit = if (noOffsetOrStride) data(i) = v else data(offset+i*stride) = v
private def checkIfSpecialized(): Unit = {
if(data.isInstanceOf[Array[Double]] && getClass.getName() == "breeze.linalg.DenseVector") throw new Exception("...")
}
// uncomment to debug places where specialization fails
// checkIfSpecialized()
def activeIterator: Iterator[(Int, V)] = iterator
def activeValuesIterator: Iterator[V] = valuesIterator
def activeKeysIterator: Iterator[Int] = keysIterator
override def equals(p1: Any) = p1 match {
case y: DenseVector[_] =>
y.length == length && ArrayUtil.nonstupidEquals(data, offset, stride, length, y.data, y.offset, y.stride, y.length)
case _ => super.equals(p1)
}
// TODO: this is only consistent if the hashcode of inactive elements is 0!!!
override def hashCode(): Int = ArrayUtil.zeroSkippingHashCode(data, offset, stride, length)
override def toString = {
valuesIterator.mkString("DenseVector(",", ", ")")
}
/**
* 返回此DenseVector的副本。步长将始终为1,偏移量将始终为0。
* @return
*/
def copy: DenseVector[V] = {
if (stride == 1) {
val newData = ArrayUtil.copyOfRange(data, offset, offset + length)
new DenseVector(newData)
} else {
implicit val man = ClassTag[V](data.getClass.getComponentType.asInstanceOf[Class[V]])
val r = new DenseVector(new Array[V](length))
r := this
r
}
}
/**
* 同apply(i)。给出底层偏移处的值。
* @param i 数据数组的索引
* @return apply(i)
*/
def valueAt(i: Int): V = apply(i)
/**
* 上面的不安全版本,用于跳过检查的方法。
*/
@deprecated("This isn't actually any faster any more", "0.12-SNAPSHOT")
def unsafeValueAt(i: Int): V = data(offset + i * stride)
/**
* 给出物理索引的逻辑索引。
* @param i
* @return i
*/
def indexAt(i: Int): Int = i
/**
* 总是返回true。
*
* 一些存储(特别是HashStorage)可能没有活动的索引打包。这让你知道该箱是否正在使用中。
* @param i 索引到索引/数据数组
* @return
*/
def isActive(i: Int): Boolean = true
/**
* 总是返回true。
* @return
*/
def allVisitableIndicesActive: Boolean = true
/**
* 更快的foreach
* @param fn
* @tparam U
*/
override def foreach[@spec(Unit) U](fn: (V) => U): Unit = {
if (stride == 1) { // ABCE stuff
cforRange(offset until (offset + length)) { j =>
fn(data(j))
}
} else {
var i = offset
cforRange(0 until length) { j =>
fn(data(i))
i += stride
}
}
}
/**
* 切片DenseVector,在[start,end]范围内以步长stride。
* @param start
* @param end
* @param stride
*/
def slice(start: Int, end: Int, stride: Int=1): DenseVector[V] = {
if(start > end || start < 0) throw new IllegalArgumentException("Slice arguments " + start +", " +end +" invalid.")
if(end > length || end < 0) throw new IllegalArgumentException("End " + end + "is out of bounds for slice of DenseVector of length " + length)
new DenseVector(data, start * this.stride + offset, stride * this.stride, (end-start)/stride)
}
// <editor-fold defaultstate="collapsed" desc=" Conversions (DenseMatrix, Array, Scala Vector) ">
/** Creates a copy of this DenseVector that is represented as a 1 by length DenseMatrix */
def toDenseMatrix: DenseMatrix[V] = {
copy.asDenseMatrix
}
/** Creates a view of this DenseVector that is represented as a 1 by length DenseMatrix */
def asDenseMatrix: DenseMatrix[V] = {
new DenseMatrix[V](1, length, data, offset, stride)
}
override def toArray(implicit cm: ClassTag[V]): Array[V] = if(stride == 1){
ArrayUtil.copyOfRange(data, offset, offset + length)
} else {
val arr = new Array[V](length)
var i = 0
var off = offset
while(i < length) {
arr(i) = data(off)
off += stride
i += 1
}
arr
}
/**Returns copy of this [[breeze.linalg.DenseVector]] as a [[scala.Vector]]*/
def toScalaVector()(implicit cm: ClassTag[V]): scala.Vector[V] = this.toArray.toVector
// </editor-fold>
@throws(classOf[ObjectStreamException])
protected def writeReplace(): Object = {
new DenseVector.SerializedForm(data, offset, stride, length)
}
}
object DenseVector extends VectorConstructors[DenseVector]
with DenseVector_GenericOps
with DenseVectorOps
with DenseVector_OrderingOps
with DenseVector_SpecialOps {
def zeros[@spec(Double, Int, Float, Long) V: ClassTag : Zero](size: Int): DenseVector[V] = {
val data = new Array[V](size)
if(size != 0 && data(0) != implicitly[Zero[V]].zero)
ArrayUtil.fill(data, 0, data.length, implicitly[Zero[V]].zero)
apply(data)
}
def apply[@spec(Double, Int, Float, Long) V](values: Array[V]): DenseVector[V] = {
// ensure we get specialized implementations even from non-specialized calls
(values:AnyRef) match {
case v: Array[Double] => new DenseVector(v).asInstanceOf[DenseVector[V]]
case v: Array[Float] => new DenseVector(v).asInstanceOf[DenseVector[V]]
case v: Array[Int] => new DenseVector(v).asInstanceOf[DenseVector[V]]
case v: Array[Long] => new DenseVector(v).asInstanceOf[DenseVector[V]]
case _ => new DenseVector(values)
}
}
/**
*
* 使用提供的数组创建一个新的DenseVector(不进行复制!)。在通用环境中,最好使用这个(或apply)而不是`new DenseVector[V](data, offset, stride, length)`,因为一般情况下不能得到专门化的实现。
* @param rows
* @param cols
* @param data
* @tparam V
* @return
*/
def create[V](data: Array[V], offset: Int, stride: Int, length: Int): DenseVector[V] = {
(data:AnyRef) match {
case v: Array[Double] => new DenseVector(v, offset = offset, stride = stride, length = length).asInstanceOf[DenseVector[V]]
case v: Array[Float] => new DenseVector(v, offset = offset, stride = stride, length = length).asInstanceOf[DenseVector[V]]
case v: Array[Int] => new DenseVector(v, offset = offset, stride = stride, length = length).asInstanceOf[DenseVector[V]]
case v: Array[Long] => new DenseVector(v, offset = offset, stride = stride, length = length).asInstanceOf[DenseVector[V]]
case _ => new DenseVector(data, offset = offset, stride = stride, length = length)
}
}
def ones[@spec(Double, Int, Float, Long) V: ClassTag:Semiring](size: Int): DenseVector[V] = fill[V](size, implicitly[Semiring[V]].one)
def fill[@spec(Double, Int, Float, Long) V: ClassTag:Semiring](size: Int, v: V): DenseVector[V] = {
val r = apply(new Array[V](size))
assert(r.stride == 1)
ArrayUtil.fill(r.data, r.offset, r.length, v)
r
}
// concatenation
/**
* 将两个或多个向量水平连接成一个矩阵。
* @throws IllegalArgumentException 如果向量大小不同
*/
def horzcat[V: ClassTag:Zero](vectors: DenseVector[V]*): DenseMatrix[V] = {
val size = vectors.head.size
if (!(vectors forall (_.size == size)))
throw new IllegalArgumentException("All vectors must have the same size!")
val result = DenseMatrix.zeros[V](size, vectors.size)
for ((v, col) <- vectors.zipWithIndex)
result(::, col) := v
result
}
/**
* 将两个或多个列向量垂直连接成一个大向量。
*/
def vertcat[V](vectors: DenseVector[V]*)(implicit canSet: OpSet.InPlaceImpl2[DenseVector[V], DenseVector[V]], vman: ClassTag[V], zero: Zero[V]): DenseVector[V] = {
val size = vectors.foldLeft(0)(_ + _.size)
val result = zeros[V](size)
var offset = 0
for (v <- vectors) {
result.slice(offset, offset + v.size) := v
offset += v.size
}
result
}
// capabilities
implicit def canCreateZerosLike[V:ClassTag:Zero]:CanCreateZerosLike[DenseVector[V], DenseVector[V]] =
new CanCreateZerosLike[DenseVector[V], DenseVector[V]] {
def apply(v1: DenseVector[V]): DenseVector[V] = {
zeros[V](v1.length)
}
}
implicit def canCopyDenseVector[V:ClassTag]: CanCopy[DenseVector[V]] = {
new CanCopy[DenseVector[V]] {
def apply(v1: DenseVector[V]): DenseVector[V] = {
v1.copy
}
}
}
implicit def negFromScale[V](implicit scale: OpMulScalar.Impl2[DenseVector[V], V, DenseVector[V]], field: Ring[V]) = {
new OpNeg.Impl[DenseVector[V], DenseVector[V]] {
override def apply(a : DenseVector[V]): DenseVector[V] = {
scale(a, field.negate(field.one))
}
}
}
implicit def canMapValues[@specialized(Int, Float, Double) V, @specialized(Int, Float, Double) V2](implicit man: ClassTag[V2]): CanMapValues[DenseVector[V], V, V2, DenseVector[V2]] = {
new CanMapValues[DenseVector[V], V, V2, DenseVector[V2]] {
/**Maps all key-value pairs from the given collection. */
def apply(from: DenseVector[V], fn: (V) => V2): DenseVector[V2] = {
val out = new Array[V2](from.length)
// threeway fork, following benchmarks and hotspot docs on Array Bounds Check Elimination (ABCE)
// https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
if (from.noOffsetOrStride) {
fastestPath(out, fn, from.data)
} else if (from.stride == 1) {
mediumPath(out, fn, from.data, from.offset)
} else {
slowPath(out, fn, from.data, from.offset, from.stride)
}
DenseVector[V2](out)
}
private def mediumPath(out: Array[V2], fn: (V) => V2, data: Array[V], off: Int): Unit = {
cforRange(0 until out.length) { j =>
out(j) = fn(data(j + off))
}
}
private def fastestPath(out: Array[V2], fn: (V) => V2, data: Array[V]): Unit = {
cforRange(0 until out.length) { j =>
out(j) = fn(data(j))
}
}
final private def slowPath(out: Array[V2], fn: (V) => V2, data: Array[V], off: Int, stride: Int): Unit = {
var i = 0
var j = off
while (i < out.length) {
out(i) = fn(data(j))
i += 1
j += stride
}
}
}
}
implicit def canMapValuesToSink[@specialized(Int, Float, Double) V, @specialized(Int, Float, Double) V2]: mapValues.SinkImpl2[DenseVector[V2], DenseVector[V], V =>V2] = {
new mapValues.SinkImpl2[DenseVector[V2], DenseVector[V], V=>V2] {
/**Maps all key-value pairs from the given collection. */
def apply(sink: DenseVector[V2], from: DenseVector[V], fn: (V) => V2) = {
require(sink.length == from.length)
// threeway fork, following benchmarks and hotspot docs on Array Bounds Check Elimination (ABCE)
// https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
if (sink.noOffsetOrStride && from.noOffsetOrStride) {
fastestPath(sink, fn, from.data)
} else if (sink.stride == 1 && from.stride == 1) {
mediumPath(sink, fn, from.data, from.offset)
} else {
slowPath(sink, fn, from.data, from.offset, from.stride)
}
}
private def mediumPath(sink: DenseVector[V2], fn: (V) => V2, data: Array[V], off: Int): Unit = {
val out = sink.data
val ooff = sink.offset
cforRange(0 until sink.length) { j =>
out(j + ooff) = fn(data(j + off))
}
}
private def fastestPath(sink: DenseVector[V2], fn: (V) => V2, data: Array[V]): Unit = {
val out = sink.data
cforRange(0 until sink.length) { j =>
out(j) = fn(data(j))
}
}
final private def slowPath(out: DenseVector[V2], fn: (V) => V2, data: Array[V], off: Int, stride: Int): Unit = {
var i = 0
var j = off
while (i < out.length) {
out(i) = fn(data(j))
i += 1
j += stride
}
}
}
}
implicit def scalarOf[T]: ScalarOf[DenseVector[T], T] = ScalarOf.dummy
implicit def canIterateValues[V]: CanTraverseValues[DenseVector[V], V] =
new CanTraverseValues[DenseVector[V], V] {
def isTraversableAgain(from: DenseVector[V]): Boolean = true
/** 遍历给定集合的所有键值对。 */
def traverse(from: DenseVector[V], fn: ValuesVisitor[V]): Unit = {
fn.visitArray(from.data, from.offset, from.length, from.stride)
}
}
implicit def canTraverseZipValues[V,W]: CanZipAndTraverseValues[DenseVector[V], DenseVector[W], V,W] =
new CanZipAndTraverseValues[DenseVector[V], DenseVector[W], V,W] {
/** 遍历给定集合的所有键值对。 */
def traverse(from1: DenseVector[V], from2: DenseVector[W], fn: PairValuesVisitor[V,W]): Unit = {
if (from1.size != from2.size) {
throw new IllegalArgumentException("Vectors to be zipped must have same size")
}
cfor(0)(i => i < from1.size, i => i+1)(i => {
fn.visit(from1(i), from2(i))
})
}
}
implicit def canTraverseKeyValuePairs[V]: CanTraverseKeyValuePairs[DenseVector[V], Int, V] =
new CanTraverseKeyValuePairs[DenseVector[V], Int, V] {
def isTraversableAgain(from: DenseVector[V]): Boolean = true
def traverse(from: DenseVector[V], fn: CanTraverseKeyValuePairs.KeyValuePairsVisitor[Int, V]): Unit = {
import from._
fn.visitArray((ind: Int)=> (ind - offset)/stride, data, offset, length, stride)
}
}
implicit def canTransformValues[@specialized(Int, Float, Double) V]: CanTransformValues[DenseVector[V], V] =
new CanTransformValues[DenseVector[V], V] {
def transform(from: DenseVector[V], fn: (V) => V) {
val data = from.data
val length = from.length
val stride = from.stride
val offset = from.offset
if (stride == 1) {
cforRange(offset until offset + length) { j =>
data(j) = fn(data(j))
}
} else {
slowPath(fn, data, length, stride, offset)
}
}
private def slowPath(fn: (V) => V, data: Array[V], length: Int, stride: Int, offset: Int): Unit = {
val end = offset + stride * length
var j = offset
while (j != end) {
data(j) = fn(data(j))
j += stride
}
}
def transformActive(from: DenseVector[V], fn: (V) => V) {
transform(from, fn)
}
}
implicit def canMapPairs[V, V2](implicit man: ClassTag[V2]):CanMapKeyValuePairs[DenseVector[V], Int, V, V2, DenseVector[V2]] =
new CanMapKeyValuePairs[DenseVector[V], Int, V, V2, DenseVector[V2]] {
/**Maps all key-value pairs from the given collection. */
def map(from: DenseVector[V], fn: (Int, V) => V2): DenseVector[V2] = {
// slow: DenseVector.tabulate(from.length)(i => fn(i, from(i)))
val arr = new Array[V2](from.length)
val d = from.data
val stride = from.stride
var i = 0
var j = from.offset
while(i < arr.length) {
arr(i) = fn(i, d(j))
i += 1
j += stride
}
DenseVector[V2](arr)
}
/**Maps all active key-value pairs from the given collection. */
def mapActive(from: DenseVector[V], fn: (Int, V) => V2): DenseVector[V2] = {
map(from, fn)
}
}
// 切片
// 特殊化以获得好的类
implicit def canSlice[V]: CanSlice[DenseVector[V], Range, DenseVector[V]] = {
new CanSlice[DenseVector[V], Range, DenseVector[V]] {
def apply(v: DenseVector[V], re: Range): DenseVector[V] = {
val range: Range = re.getRangeWithoutNegativeIndexes( v.length )
require(range.isEmpty || range.last < v.length)
require(range.isEmpty || range.start >= 0)
DenseVector.create(v.data, offset = v.offset + v.stride * range.start, stride = v.stride * range.step, length = range.length)
}
}
}
implicit def canTransposeComplex: CanTranspose[DenseVector[Complex], DenseMatrix[Complex]] = {
new CanTranspose[DenseVector[Complex], DenseMatrix[Complex]] {
def apply(from: DenseVector[Complex]): DenseMatrix[Complex] = {
new DenseMatrix(data = from.data map { _.conjugate },
offset = from.offset,
cols = from.length,
rows = 1,
majorStride = from.stride)
}
}
}
class CanZipMapValuesDenseVector[@spec(Double, Int, Float, Long) V, @spec(Int, Double) RV:ClassTag] extends CanZipMapValues[DenseVector[V],V,RV,DenseVector[RV]] {
def create(length : Int) = DenseVector(new Array[RV](length))
/**Maps all corresponding values from the two collection. */
def map(from: DenseVector[V], from2: DenseVector[V], fn: (V, V) => RV): DenseVector[RV] = {
require(from.length == from2.length, s"Vectors must have same length")
val result = create(from.length)
var i = 0
while (i < from.length) {
result.data(i) = fn(from(i), from2(i))
i += 1
}
result
}
}
implicit def zipMap[V, R:ClassTag]: CanZipMapValuesDenseVector[V, R] = new CanZipMapValuesDenseVector[V, R]
implicit val zipMap_d: CanZipMapValuesDenseVector[Double, Double] = new CanZipMapValuesDenseVector[Double, Double]
implicit val zipMap_f: CanZipMapValuesDenseVector[Float, Float] = new CanZipMapValuesDenseVector[Float, Float]
implicit val zipMap_i: CanZipMapValuesDenseVector[Int, Int] = new CanZipMapValuesDenseVector[Int, Int]
class CanZipMapKeyValuesDenseVector[@spec(Double, Int, Float, Long) V, @spec(Int, Double) RV:ClassTag] extends CanZipMapKeyValues[DenseVector[V],Int, V,RV,DenseVector[RV]] {
def create(length : Int) = DenseVector(new Array[RV](length))
/**Maps all corresponding values from the two collection. */
def map(from: DenseVector[V], from2: DenseVector[V], fn: (Int, V, V) => RV): DenseVector[RV] = {
require(from.length == from2.length, "Vector lengths must match!")
val result = create(from.length)
var i = 0
while (i < from.length) {
result.data(i) = fn(i, from(i), from2(i))
i += 1
}
result
}
override def mapActive(from: DenseVector[V], from2: DenseVector[V], fn: ((Int), V, V) => RV): DenseVector[RV] = {
map(from, from2, fn)
}
}
implicit def zipMapKV[V, R:ClassTag]: CanZipMapKeyValuesDenseVector[V, R] = new CanZipMapKeyValuesDenseVector[V, R]
implicit val canAddIntoD: OpAdd.InPlaceImpl2[DenseVector[Double], DenseVector[Double]] = {
new OpAdd.InPlaceImpl2[DenseVector[Double], DenseVector[Double]] {
def apply(a: DenseVector[Double], b: DenseVector[Double]) = {
canDaxpy(a, 1.0, b)
}
implicitly[BinaryUpdateRegistry[Vector[Double], Vector[Double], OpAdd.type]].register(this)
}
}
implicit object canDaxpy extends scaleAdd.InPlaceImpl3[DenseVector[Double], Double, DenseVector[Double]] with Serializable {
def apply(y: DenseVector[Double], a: Double, x: DenseVector[Double]) {
require(x.length == y.length, s"Vectors must have same length")
// using blas here is always a bad idea.
if (x.noOffsetOrStride && y.noOffsetOrStride) {
val ad = x.data
val bd = y.data
cforRange(0 until x.length) { i =>
bd(i) += ad(i) * a
}
} else {
cforRange(0 until x.length) { i =>
y(i) += x(i) * a
}
}
}
}
implicitly[TernaryUpdateRegistry[Vector[Double], Double, Vector[Double], scaleAdd.type]].register(canDaxpy)
implicit val canAddD: OpAdd.Impl2[DenseVector[Double], DenseVector[Double], DenseVector[Double]] = {
pureFromUpdate_Double(canAddIntoD)
}
implicitly[BinaryRegistry[Vector[Double], Vector[Double], OpAdd.type, Vector[Double]]].register(canAddD)
implicit val canSubIntoD: OpSub.InPlaceImpl2[DenseVector[Double], DenseVector[Double]] = {
new OpSub.InPlaceImpl2[DenseVector[Double], DenseVector[Double]] {
def apply(a: DenseVector[Double], b: DenseVector[Double]) = {
canDaxpy(a, -1.0, b)
}
implicitly[BinaryUpdateRegistry[Vector[Double], Vector[Double], OpSub.type]].register(this)
}
}
implicit val canSubD: OpSub.Impl2[DenseVector[Double], DenseVector[Double], DenseVector[Double]] = {
pureFromUpdate_Double(canSubIntoD)
}
implicitly[BinaryRegistry[Vector[Double], Vector[Double], OpSub.type, Vector[Double]]].register(canSubD)
implicit object canDotD extends OpMulInner.Impl2[DenseVector[Double], DenseVector[Double], Double] {
def apply(a: DenseVector[Double], b: DenseVector[Double]) = {
require(a.length == b.length, s"Vectors must have same length")
if (a.noOffsetOrStride && b.noOffsetOrStride && a.length < DenseVectorSupportMethods.MAX_SMALL_DOT_PRODUCT_LENGTH) {
DenseVectorSupportMethods.smallDotProduct_Double(a.data, b.data, a.length)
} else {
blasPath(a, b)
}
}
val UNROLL_FACTOR = 6
private def blasPath(a: DenseVector[Double], b: DenseVector[Double]): Double = {
if ((a.length <= 300 || !usingNatives) && a.stride == 1 && b.stride == 1) {
DenseVectorSupportMethods.dotProduct_Double(a.data, a.offset, b.data, b.offset, a.length)
} else {
val boff = if (b.stride >= 0) b.offset else (b.offset + b.stride * (b.length - 1))
val aoff = if (a.stride >= 0) a.offset else (a.offset + a.stride * (a.length - 1))
blas.ddot(
a.length, b.data, boff, b.stride, a.data, aoff, a.stride)
}
}
}
implicitly[BinaryRegistry[Vector[Double], Vector[Double], OpMulInner.type, Double]].register(canDotD)
/*
TODO: scaladoc crashes on this. I don't know why. It makes me want to die a little.
返回此向量的k-范数。
*/
@expand
@expand.valify
implicit def canNorm[@expand.args(Int, Float, Long, BigInt, Complex) T]: norm.Impl2[DenseVector[T], Double, Double] = {
new norm.Impl2[DenseVector[T], Double, Double] {
def apply(v: DenseVector[T], n: Double): Double = {
import v._
if (n == 1) {
var sum = 0.0
foreach (v => sum += v.abs.toDouble )
sum
} else if (n == 2) {
var sum = 0.0
foreach (v => { val nn = v.abs.toDouble; sum += nn * nn })
math.sqrt(sum)
} else if (n == Double.PositiveInfinity) {
var max = 0.0
foreach (v => { val nn = v.abs.toDouble; if (nn > max) max = nn })
max
} else {
var sum = 0.0
foreach (v => { val nn = v.abs.toDouble; sum += math.pow(nn,n) })
math.pow(sum, 1.0 / n)
}
}
}
}
/**
* 返回此向量的p-范数(特殊化为Double)。
*/
implicit def canNorm_Double: norm.Impl2[DenseVector[Double], Double, Double] = {
new norm.Impl2[DenseVector[Double], Double, Double] {
def apply(v: DenseVector[Double], p: Double): Double = {
if (p == 2) {
var sq = 0.0
v.foreach (x => sq += x * x)
math.sqrt(sq)
} else if (p == 1) {
var sum = 0.0
v.foreach (x => sum += math.abs(x))
sum
} else if (p == Double.PositiveInfinity) {
var max = 0.0
v.foreach (x => max = math.max(max, math.abs(x)))
max
} else if (p == 0) {
var nnz = 0
v.foreach (x => if (x != 0) nnz += 1)
nnz
} else {
var sum = 0.0
v.foreach (x => sum += math.pow(math.abs(x), p))
math.pow(sum, 1.0 / p)
}
}
}
}
implicit def canDim[E]: dim.Impl[DenseVector[E],Int] = new dim.Impl[DenseVector[E],Int] {
def apply(v: DenseVector[E]): Int = v.length
}
// this produces bad spaces for builtins (inefficient because of bad implicit lookup)
implicit def space[E](implicit field: Field[E], man: ClassTag[E]): MutableFiniteCoordinateField[DenseVector[E],Int,E] = {
import field._
implicit val cmv = canMapValues[E,E]
MutableFiniteCoordinateField.make[DenseVector[E],Int,E]
}
implicit val space_Double: MutableFiniteCoordinateField[DenseVector[Double], Int, Double] = {
MutableFiniteCoordinateField.make[DenseVector[Double],Int,Double]
}
implicit val space_Float: MutableFiniteCoordinateField[DenseVector[Float], Int, Float] = {
MutableFiniteCoordinateField.make[DenseVector[Float],Int,Float]
}
implicit val space_Int: MutableFiniteCoordinateField[DenseVector[Int], Int, Int] = {
MutableFiniteCoordinateField.make[DenseVector[Int],Int,Int]
}
implicit val space_Long: MutableFiniteCoordinateField[DenseVector[Long], Int, Long] = {
MutableFiniteCoordinateField.make[DenseVector[Long],Int,Long]
}
object TupleIsomorphisms {
implicit object doubleIsVector extends Isomorphism[Double,DenseVector[Double]] {
def forward(t: Double) = DenseVector(t)
def backward(t: DenseVector[Double]) = { assert(t.size == 1); t(0)}
}
implicit object pdoubleIsVector extends Isomorphism[(Double,Double),DenseVector[Double]] {
def forward(t: (Double,Double)) = DenseVector(t._1,t._2)
def backward(t: DenseVector[Double]) = { assert(t.size == 2); (t(0),t(1))}
}
}
/**
* This class exists because @specialized instances don't respect the serial
* @param data
* @param offset
* @param stride
* @param length
*/
@SerialVersionUID(1L)
case class SerializedForm(data: Array[_],
offset: Int,
stride: Int,
length: Int) extends Serializable {
@throws(classOf[ObjectStreamException])
def readResolve():Object = {
data match {//switch to make specialized happy
case x: Array[Int] => new DenseVector(x, offset, stride, length)
case x: Array[Long] => new DenseVector(x, offset, stride, length)
case x: Array[Double] => new DenseVector(x, offset, stride, length)
case x: Array[Float] => new DenseVector(x, offset, stride, length)
case x: Array[Short] => new DenseVector(x, offset, stride, length)
case x: Array[Byte] => new DenseVector(x, offset, stride, length)
case x: Array[Char] => new DenseVector(x, offset, stride, length)
case x: Array[_] => new DenseVector(x, offset, stride, length)
}
}
}
// used to make sure the operators are loaded
@noinline
private def init() = {}
}