Feature/tensors performance #497
@ -19,6 +19,7 @@
|
|||||||
- Complex power
|
- Complex power
|
||||||
- Separate methods for UInt, Int and Number powers. NaN safety.
|
- Separate methods for UInt, Int and Number powers. NaN safety.
|
||||||
- Tensorflow prototype
|
- Tensorflow prototype
|
||||||
|
- `ValueAndErrorField`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Exponential operations merged with hyperbolic functions
|
- Exponential operations merged with hyperbolic functions
|
||||||
@ -50,6 +51,7 @@
|
|||||||
- Tensor algebra takes read-only structures as input and inherits AlgebraND
|
- Tensor algebra takes read-only structures as input and inherits AlgebraND
|
||||||
- `UnivariateDistribution` renamed to `Distribution1D`
|
- `UnivariateDistribution` renamed to `Distribution1D`
|
||||||
- Rework of histograms.
|
- Rework of histograms.
|
||||||
|
- `UnivariateFunction` -> `Function1D`, `MultivariateFunction` -> `FunctionND`
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
- Specialized `DoubleBufferAlgebra`
|
- Specialized `DoubleBufferAlgebra`
|
||||||
|
@ -13,7 +13,7 @@ import kotlin.math.pow
|
|||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
//Define a function
|
//Define a function
|
||||||
val function: UnivariateFunction<Double> = { x -> 3 * x.pow(2) + 2 * x + 1 }
|
val function: Function1D<Double> = { x -> 3 * x.pow(2) + 2 * x + 1 }
|
||||||
|
|
||||||
//get the result of the integration
|
//get the result of the integration
|
||||||
val result = DoubleField.gaussIntegrator.integrate(0.0..10.0, function = function)
|
val result = DoubleField.gaussIntegrator.integrate(0.0..10.0, function = function)
|
||||||
|
@ -18,7 +18,7 @@ import space.kscience.plotly.scatter
|
|||||||
|
|
||||||
@OptIn(UnstablePlotlyAPI::class)
|
@OptIn(UnstablePlotlyAPI::class)
|
||||||
fun main() {
|
fun main() {
|
||||||
val function: UnivariateFunction<Double> = { x ->
|
val function: Function1D<Double> = { x ->
|
||||||
if (x in 30.0..50.0) {
|
if (x in 30.0..50.0) {
|
||||||
1.0
|
1.0
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.BufferFactory
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
import space.kscience.kmath.structures.DoubleBuffer
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
@ -53,7 +52,7 @@ public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
|
|||||||
*/
|
*/
|
||||||
private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapInline(
|
private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapInline(
|
||||||
buffer: Buffer<T>,
|
buffer: Buffer<T>,
|
||||||
crossinline block: A.(T) -> T
|
crossinline block: A.(T) -> T,
|
||||||
): Buffer<T> = bufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) }
|
): Buffer<T> = bufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +60,7 @@ private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapInline(
|
|||||||
*/
|
*/
|
||||||
private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapIndexedInline(
|
private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapIndexedInline(
|
||||||
buffer: Buffer<T>,
|
buffer: Buffer<T>,
|
||||||
crossinline block: A.(index: Int, arg: T) -> T
|
crossinline block: A.(index: Int, arg: T) -> T,
|
||||||
): Buffer<T> = bufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) }
|
): Buffer<T> = bufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,7 +69,7 @@ private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapIndexedInline(
|
|||||||
private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.zipInline(
|
private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.zipInline(
|
||||||
l: Buffer<T>,
|
l: Buffer<T>,
|
||||||
r: Buffer<T>,
|
r: Buffer<T>,
|
||||||
crossinline block: A.(l: T, r: T) -> T
|
crossinline block: A.(l: T, r: T) -> T,
|
||||||
): Buffer<T> {
|
): Buffer<T> {
|
||||||
require(l.size == r.size) { "Incompatible buffer sizes. left: ${l.size}, right: ${r.size}" }
|
require(l.size == r.size) { "Incompatible buffer sizes. left: ${l.size}, right: ${r.size}" }
|
||||||
return bufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) }
|
return bufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) }
|
||||||
@ -127,13 +126,13 @@ public fun <T, A : ExponentialOperations<T>> BufferAlgebra<T, A>.atanh(arg: Buff
|
|||||||
mapInline(arg) { atanh(it) }
|
mapInline(arg) { atanh(it) }
|
||||||
|
|
||||||
public fun <T, A : PowerOperations<T>> BufferAlgebra<T, A>.pow(arg: Buffer<T>, pow: Number): Buffer<T> =
|
public fun <T, A : PowerOperations<T>> BufferAlgebra<T, A>.pow(arg: Buffer<T>, pow: Number): Buffer<T> =
|
||||||
mapInline(arg) {it.pow(pow) }
|
mapInline(arg) { it.pow(pow) }
|
||||||
|
|
||||||
|
|
||||||
public open class BufferRingOps<T, A: Ring<T>>(
|
public open class BufferRingOps<T, A : Ring<T>>(
|
||||||
override val elementAlgebra: A,
|
override val elementAlgebra: A,
|
||||||
override val bufferFactory: BufferFactory<T>,
|
override val bufferFactory: BufferFactory<T>,
|
||||||
) : BufferAlgebra<T, A>, RingOps<Buffer<T>>{
|
) : BufferAlgebra<T, A>, RingOps<Buffer<T>> {
|
||||||
|
|
||||||
override fun add(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l + r }
|
override fun add(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l + r }
|
||||||
override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l * r }
|
override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l * r }
|
||||||
@ -152,10 +151,11 @@ public val ShortRing.bufferAlgebra: BufferRingOps<Short, ShortRing>
|
|||||||
public open class BufferFieldOps<T, A : Field<T>>(
|
public open class BufferFieldOps<T, A : Field<T>>(
|
||||||
elementAlgebra: A,
|
elementAlgebra: A,
|
||||||
bufferFactory: BufferFactory<T>,
|
bufferFactory: BufferFactory<T>,
|
||||||
) : BufferRingOps<T, A>(elementAlgebra, bufferFactory), BufferAlgebra<T, A>, FieldOps<Buffer<T>>, ScaleOperations<Buffer<T>> {
|
) : BufferRingOps<T, A>(elementAlgebra, bufferFactory), BufferAlgebra<T, A>, FieldOps<Buffer<T>>,
|
||||||
|
ScaleOperations<Buffer<T>> {
|
||||||
|
|
||||||
override fun add(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l + r }
|
// override fun add(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l + r }
|
||||||
override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l * r }
|
// override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l * r }
|
||||||
override fun divide(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l / r }
|
override fun divide(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l / r }
|
||||||
|
|
||||||
override fun scale(a: Buffer<T>, value: Double): Buffer<T> = a.map { scale(it, value) }
|
override fun scale(a: Buffer<T>, value: Double): Buffer<T> = a.map { scale(it, value) }
|
||||||
@ -168,7 +168,7 @@ public open class BufferFieldOps<T, A : Field<T>>(
|
|||||||
public class BufferField<T, A : Field<T>>(
|
public class BufferField<T, A : Field<T>>(
|
||||||
elementAlgebra: A,
|
elementAlgebra: A,
|
||||||
bufferFactory: BufferFactory<T>,
|
bufferFactory: BufferFactory<T>,
|
||||||
override val size: Int
|
override val size: Int,
|
||||||
) : BufferFieldOps<T, A>(elementAlgebra, bufferFactory), Field<Buffer<T>>, WithSize {
|
) : BufferFieldOps<T, A>(elementAlgebra, bufferFactory), Field<Buffer<T>>, WithSize {
|
||||||
|
|
||||||
override val zero: Buffer<T> = bufferFactory(size) { elementAlgebra.zero }
|
override val zero: Buffer<T> = bufferFactory(size) { elementAlgebra.zero }
|
||||||
|
@ -7,6 +7,6 @@ package space.kscience.kmath.functions
|
|||||||
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
|
||||||
public typealias UnivariateFunction<T> = (T) -> T
|
public typealias Function1D<T> = (T) -> T
|
||||||
|
|
||||||
public typealias MultivariateFunction<T> = (Buffer<T>) -> T
|
public typealias FunctionND<T> = (Buffer<T>) -> T
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.stat
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.Field
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A combination of a random [value] and its [dispersion].
|
||||||
|
*
|
||||||
|
* [dispersion] must be positive.
|
||||||
|
*/
|
||||||
|
public data class ValueAndError(val value: Double, val dispersion: Double) {
|
||||||
|
init {
|
||||||
|
require(dispersion >= 0) { "Dispersion must be non-negative" }
|
||||||
|
}
|
||||||
|
|
||||||
|
val error: Double get() = sqrt(dispersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An algebra for double value + its error combination. The multiplication assumes linear error propagation
|
||||||
|
*/
|
||||||
|
public object ValueAndErrorField : Field<ValueAndError> {
|
||||||
|
|
||||||
|
override val zero: ValueAndError = ValueAndError(0.0, 0.0)
|
||||||
|
|
||||||
|
override val one: ValueAndError = ValueAndError(1.0, 0.0)
|
||||||
|
|
||||||
|
override fun add(left: ValueAndError, right: ValueAndError): ValueAndError =
|
||||||
|
ValueAndError(left.value + right.value, left.dispersion + right.dispersion)
|
||||||
|
|
||||||
|
override fun ValueAndError.unaryMinus(): ValueAndError =
|
||||||
|
ValueAndError(-value, dispersion)
|
||||||
|
|
||||||
|
//TODO study performance impact of pow(2). On JVM it does not exist: https://stackoverflow.com/questions/29144275/xx-vs-math-powx-2-java-performance
|
||||||
|
|
||||||
|
override fun multiply(left: ValueAndError, right: ValueAndError): ValueAndError {
|
||||||
|
val value = left.value * right.value
|
||||||
|
val dispersion = (left.dispersion / left.value.pow(2) + right.dispersion / right.value.pow(2)) * value.pow(2)
|
||||||
|
return ValueAndError(value, dispersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun divide(left: ValueAndError, right: ValueAndError): ValueAndError {
|
||||||
|
val value = left.value / right.value
|
||||||
|
val dispersion = (left.dispersion / left.value.pow(2) + right.dispersion / right.value.pow(2)) * value.pow(2)
|
||||||
|
return ValueAndError(value, dispersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun scale(a: ValueAndError, value: Double): ValueAndError =
|
||||||
|
ValueAndError(a.value * value, a.dispersion * value.pow(2))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user