-
Notifications
You must be signed in to change notification settings - Fork 50
URFunc
URFuncs are "Universal Reduction Functions," which, like UFuncs are designed to be able to be applied to pretty much anything via implicit type classes. URFuncs, however, are for "reducing" or "collapsing" values down into one. So, operations like summing or finding the mean or variance are all things that should be URFuncs:
val r = DenseMatrix.rand(5,5)
// sum all elements
sum(r):Double
// mean of each row into a single column
mean(r, Axis._1): DenseVector[Double]
// sum of each column into a single row
sum(r, Axis._0): DenseMatrix[Double]
// also have variance, normalize
URFuncs are more complicated than UFuncs in two ways. First, they expose more methods so that the implementing type-classes can use more efficient implementations. Second, they can also selectively collapse one "Axis" or another of Matrixs or Counter2s. The interface is defined as:
trait URFunc[A, +B] {
def apply(cc: TraversableOnce[A]):B
def apply(as: A*):B = apply(as)
def apply[T](c: T)(implicit urable: UReduceable[T, A]):B = {
urable(c, this)
}
def apply(arr: Array[A]):B = apply(arr, arr.length)
def apply(arr: Array[A], length: Int):B = apply(arr, 0, 1, length, {_ => true})
def apply(arr: Array[A], offset: Int, stride: Int, length: Int, isUsed: Int=>Boolean):B = {
apply((0 until length).filter(isUsed).map(i => arr(offset + i * stride)))
}
def apply[T2, Axis, TA, R](c: T2, axis: Axis)
(implicit collapse: CanCollapseAxis[T2, Axis, TA, B, R],
ured: UReduceable[TA, A]): R = // ...
}
The first method is the only method that has to be implemented. However, sometimes you can have a more efficient implementation if you know the length in advance, or you can just write a tight loop for arrays. That gives you the block of methods in the middle. The third method is the way you usually call URFuncs, as in the example above. The last method gives you "collapsing operations," which allow you to reduce the rows and/or columns of a Matrix at once.