Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
breeze.linalg.SparseVector.scala Maven / Gradle / Ivy
package breeze.linalg
/*
Copyright 2012 David Hall
Licensed under the Apache License, Version 2.0 (the "License")
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import breeze.collection.mutable.SparseArray
import breeze.linalg.operators._
import breeze.linalg.support.CanTraverseValues.ValuesVisitor
import breeze.linalg.support._
import breeze.math._
import breeze.storage.Zero
import breeze.util.ArrayUtil
import scala.collection.mutable
import scala.reflect.ClassTag
import scala.{ specialized => spec }
/**
* A vector backed by binary search (with [[breeze.collection.mutable.SparseArray]]).
* There is a parallel array of ints (in 0 until length) and values, sorted by index value.
* To quickly access all stored values use the following loop:
*
* {{{
* var offset = 0
* while( offset < v.activeSize) {
* val index: Int = v.indexAt(offset)
* val value: E = v.valueAt(offset)
*
* offset += 1
* }
* }}}
*
*@author dlwh
*/
@SerialVersionUID(1)
class SparseVector[@spec(Double, Int, Float, Long) V](val array: SparseArray[V])
(implicit zero: Zero[V])
extends StorageVector[V]
with VectorLike[V, SparseVector[V]] with Serializable {
/** This auxiliary constructor assumes that the index array is already sorted. */
def this(index: Array[Int], data: Array[V], activeSize: Int, length: Int)(implicit value: Zero[V]) = this(new SparseArray(index, data, activeSize, length, value.zero))
/** This auxiliary constructor assumes that the index array is already sorted. */
def this(index: Array[Int], data: Array[V], length: Int)(implicit value: Zero[V]) = this(index, data, index.length, length)
// Don't delete
SparseVector.init()
def data: Array[V] = array.data
def index: Array[Int] = array.index
def activeSize = array.activeSize
def used = activeSize
def length = array.length
def repr: SparseVector[V] = this
def contains(i: Int) = array.contains(i)
def apply(i: Int): V = {
if(i < 0 || i >= size) throw new IndexOutOfBoundsException(i + " not in [0,"+size+")")
array(i)
}
def update(i: Int, v: V): Unit = {
if(i < 0 || i >= size) throw new IndexOutOfBoundsException(i + " not in [0,"+size+")")
array(i) = v
}
def activeIterator: Iterator[(Int, V)] = activeKeysIterator zip activeValuesIterator
def activeValuesIterator: Iterator[V] = data.iterator.take(activeSize)
def activeKeysIterator: Iterator[Int] = index.iterator.take(activeSize)
// TODO: allow this to vary
/** This is always assumed to be equal to 0, for now. */
def default: V = zero.zero
override def equals(p1: Any) = p1 match {
case x: Vector[_] =>
this.length == x.length &&
(valuesIterator sameElements x.valuesIterator)
case _ => false
}
def isActive(rawIndex: Int) = array.isActive(rawIndex)
override def toString = {
activeIterator.mkString(s"SparseVector($length)(",", ", ")")
}
def copy: SparseVector[V] = {
new SparseVector[V](ArrayUtil.copyOf(index, index.length), ArrayUtil.copyOf(data, index.length), activeSize, size)
}
def reserve(nnz: Int): Unit = {
array.reserve(nnz)
}
def compact(): Unit = {
//ToDo 3: will require changes if non-zero defaults are implemented
array.compact()
}
/**
* Sets the underlying sparse array to use this data
* @param index must be a sorted list of indices
* @param data values corresponding to the index
* @param activeSize number of active elements. The first activeSize will be used.
*/
def use(index: Array[Int], data: Array[V], activeSize: Int): Unit = {
require(activeSize <= size, "Can't have more elements in the array than length!")
require(activeSize >= 0, "activeSize must be non-negative")
require(data.length >= activeSize, "activeSize must be no greater than array length...")
array.use(index, data, activeSize)
}
/**
* same as data(i). Gives the value at the underlying offset.
* @param i index into the data array
* @return
*/
def valueAt(i: Int): V = data(i)
/**
* Gives the logical index from the physical index.
* @param i
* @return
*/
def indexAt(i: Int): Int = index(i)
/**
* Only gives true if isActive would return true for all i. (May be false anyway)
* @return
*/
def allVisitableIndicesActive: Boolean = true
@deprecated("Used asCSCRow instead", "0.12")
def asCSCMatrix(implicit man: ClassTag[V]): CSCMatrix[V] = {
asCscRow
}
def asCscRow(implicit man: ClassTag[V]): CSCMatrix[V] = {
// zero SV
if (index.length == 0)
CSCMatrix.zeros[V](1, length)
else {
var ii = 0
val nIndex = Array.tabulate[Int](length + 1)( (cp: Int) =>
if (ii < used && cp == index(ii)) {ii += 1; ii - 1}
else ii )
assert(ii == used)
new CSCMatrix[V](data, 1, length, nIndex, activeSize, Array.fill[Int](data.length)(0))
}
}
def asCscColumn(implicit man: ClassTag[V]): CSCMatrix[V] = {
// zero SV
if (index.length == 0)
CSCMatrix.zeros[V](length, 1)
else {
new CSCMatrix[V](data.clone(), length, 1, Array(0, used), activeSize, index)
}
}
}
object SparseVector extends SparseVectorOps
with DenseVector_SparseVector_Ops
with SparseVector_DenseMatrixOps
with SparseVector_DenseVector_Ops {
def zeros[@spec(Double, Int, Float, Long) V: ClassTag:Zero](size: Int) = new SparseVector(Array.empty, Array.empty[V], 0, size)
def apply[@spec(Double, Int, Float, Long) V:Zero](values: Array[V]) = new SparseVector(Array.range(0,values.length), values, values.length, values.length)
def apply[V:ClassTag:Zero](values: V*):SparseVector[V] = apply(values.toArray)
def fill[@spec(Double, Int, Float, Long) V:ClassTag:Zero](size: Int)(v: =>V):SparseVector[V] = apply(Array.fill(size)(v))
def tabulate[@spec(Double, Int, Float, Long) V:ClassTag:Zero](size: Int)(f: Int=>V):SparseVector[V]= apply(Array.tabulate(size)(f))
def apply[V:ClassTag:Zero: Semiring](length: Int)(values: (Int, V)*): SparseVector[V] = {
val b = new VectorBuilder[V](length)
for( (i, v) <- values) {
b.add(i, v)
}
b.toSparseVector
}
def vertcat[V:Zero:ClassTag](vectors: SparseVector[V]*): SparseVector[V] = {
val resultArray = vectors.map(_.array).foldLeft(new SparseArray[V](0))(_ concatenate _)
new SparseVector(resultArray)
}
def horzcat[V:Zero:ClassTag](vectors: SparseVector[V]*): CSCMatrix[V] ={
if(!vectors.forall(_.size==vectors(0).size))
throw new IllegalArgumentException("vector lengths must be equal, but got: " + vectors.map(_.length).mkString(", "))
val rows = vectors(0).length
val cols = vectors.length
val data = new Array[V](vectors.map(_.data.length).sum)
val rowIndices = new Array[Int](data.length)
val colPtrs = new Array[Int](vectors.length + 1)
val used = data.length
var vec = 0
var off = 0
while(vec < vectors.length) {
colPtrs(vec) = off
System.arraycopy(vectors(vec).data, 0, data, off, vectors(vec).activeSize)
System.arraycopy(vectors(vec).index, 0, rowIndices, off, vectors(vec).activeSize)
off += vectors(vec).activeSize
vec += 1
}
colPtrs(vec) = off
new CSCMatrix(data, rows, cols, colPtrs, used, rowIndices)
}
// implicits
class CanCopySparseVector[@spec(Double, Int, Float, Long) V:ClassTag:Zero] extends CanCopy[SparseVector[V]] {
def apply(v1: SparseVector[V]) = {
v1.copy
}
}
implicit def canCopySparse[@spec(Double, Int, Float, Long) V: ClassTag: Zero] = new CanCopySparseVector[V]
implicit def canMapValues[V, V2: ClassTag: Zero]:CanMapValues[SparseVector[V], V, V2, SparseVector[V2]] = {
new CanMapValues[SparseVector[V], V, V2, SparseVector[V2]] {
/**Maps all key-value pairs from the given collection. */
override def apply(from: SparseVector[V], fn: (V) => V2): SparseVector[V2] = {
SparseVector.tabulate(from.length)(i => fn(from(i)))
}
}
}
implicit def canMapActiveValues[V, V2: ClassTag: Zero]:CanMapActiveValues[SparseVector[V], V, V2, SparseVector[V2]] = {
new CanMapActiveValues[SparseVector[V], V, V2, SparseVector[V2]] {
/**Maps all active key-value pairs from the given collection. */
override def apply(from: SparseVector[V], fn: (V) => V2): SparseVector[V2] = {
val out = new Array[V2](from.activeSize)
var i = 0
while(i < from.activeSize) {
out(i) = fn(from.data(i))
i += 1
}
new SparseVector(from.index.take(from.activeSize), out, from.activeSize, from.length)
}
}
}
implicit def scalarOf[T]: ScalarOf[SparseVector[T], T] = ScalarOf.dummy
implicit def canIterateValues[V]: CanTraverseValues[SparseVector[V], V] = {
new CanTraverseValues[SparseVector[V],V] {
def isTraversableAgain(from: SparseVector[V]): Boolean = true
/** Iterates all key-value pairs from the given collection. */
def traverse(from: SparseVector[V], fn: ValuesVisitor[V]): Unit = {
fn.zeros(from.size - from.activeSize, from.default)
fn.visitArray(from.data, 0, from.activeSize, 1)
}
}
}
implicit def canTraverseKeyValuePairs[V]:CanTraverseKeyValuePairs[SparseVector[V], Int, V] = {
new CanTraverseKeyValuePairs[SparseVector[V], Int, V] {
def isTraversableAgain(from: SparseVector[V]): Boolean = true
/** Iterates all key-value pairs from the given collection. */
def traverse(from: SparseVector[V], fn: CanTraverseKeyValuePairs.KeyValuePairsVisitor[Int, V]): Unit = {
import from._
fn.visitArray(index, data, 0, activeSize, 1)
if(activeSize != size) {
fn.zeros(size - activeSize, Iterator.range(0, size).filterNot(index contains _), from.default)
}
}
}
}
implicit def canCreateZeros[V:ClassTag:Zero]: CanCreateZeros[SparseVector[V], Int] = {
new CanCreateZeros[SparseVector[V], Int] {
def apply(d: Int): SparseVector[V] = {
zeros[V](d)
}
}
}
implicit def canCreateZerosLike[V:ClassTag:Zero]: CanCreateZerosLike[SparseVector[V], SparseVector[V]] = {
new CanCreateZerosLike[SparseVector[V], SparseVector[V]] {
def apply(d: SparseVector[V]): SparseVector[V] = {
zeros[V](d.length)
}
}
}
implicit def canTransformValues[V:Zero:ClassTag]:CanTransformValues[SparseVector[V], V] = {
new CanTransformValues[SparseVector[V], V] {
val z = implicitly[Zero[V]]
/**Transforms all key-value pairs from the given collection. */
def transform(from: SparseVector[V], fn: (V) => V): Unit = {
val newData = mutable.ArrayBuilder.make[V]()
val newIndex = mutable.ArrayBuilder.make[Int]()
var used = 0
var i = 0
while(i < from.length) {
val vv = fn(from(i))
if(vv != z) {
newData += vv
newIndex += i
used += 1
}
i += 1
}
from.array.use(newIndex.result(), newData.result(), used)
}
/**Transforms all active key-value pairs from the given collection. */
def transformActive(from: SparseVector[V], fn: (V) => V): Unit = {
var i = 0
while(i < from.activeSize) {
from.data(i) = fn(from.data(i))
i += 1
}
}
}
}
implicit def canMapPairs[V, V2: ClassTag: Zero]:CanMapKeyValuePairs[SparseVector[V], Int, V, V2, SparseVector[V2]] = {
new CanMapKeyValuePairs[SparseVector[V], Int, V, V2, SparseVector[V2]] {
/**Maps all key-value pairs from the given collection. */
def map(from: SparseVector[V], fn: (Int, V) => V2): SparseVector[V2] = {
SparseVector.tabulate(from.length)(i => fn(i, from(i)))
}
/**Maps all active key-value pairs from the given collection. */
def mapActive(from: SparseVector[V], fn: (Int, V) => V2): SparseVector[V2] = {
val out = new Array[V2](from.used)
var i = 0
while(i < from.used) {
out(i) = fn(from.index(i), from.data(i))
i += 1
}
new SparseVector(from.index.take(from.used), out, from.used, from.length)
}
}
}
// implicit def canTranspose[V:ClassTag:Zero]: CanTranspose[SparseVector[V], CSCMatrix[V]] = {
// new CanTranspose[SparseVector[V], CSCMatrix[V]] {
// def apply(from: SparseVector[V]): CSCMatrix[V] = {
// val transposedMtx: CSCMatrix[V] = CSCMatrix.zeros[V](1, from.length)
// var i = 0
// while (i < from.activeSize) {
// val c = from.index(i)
// transposedMtx(0, c) = from.data(i)
// i += 1
// }
// transposedMtx
// }
// }
// }
implicit def canTransposeComplex: CanTranspose[SparseVector[Complex], CSCMatrix[Complex]] = {
new CanTranspose[SparseVector[Complex], CSCMatrix[Complex]] {
def apply(from: SparseVector[Complex]) = {
val transposedMtx: CSCMatrix[Complex] = CSCMatrix.zeros[Complex](1, from.length)
var i = 0
while (i < from.activeSize) {
val c = from.index(i)
transposedMtx(0, c) = from.data(i).conjugate
i += 1
}
transposedMtx
}
}
}
implicit def canDim[E]: dim.Impl[SparseVector[E],Int] = new dim.Impl[SparseVector[E],Int] {
def apply(v: SparseVector[E]): Int = v.size
}
implicit def canTabulate[E:ClassTag:Zero]: CanTabulate[Int, SparseVector[E], E] = new CanTabulate[Int,SparseVector[E],E] {
def apply(d: Int, f: (Int) => E): SparseVector[E] = tabulate[E](d)(f)
}
implicit def space[E: Field : ClassTag : Zero]: MutableFiniteCoordinateField[SparseVector[E], Int, E] = {
MutableFiniteCoordinateField.make[SparseVector[E], Int, E]
}
@noinline
private def init() = {}
}