Add mandatory MutableBufferFactory to Algebra #477

This commit is contained in:
Alexander Nozik 2022-07-16 16:27:11 +03:00
parent 68add4cb5f
commit 3eef778f60
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
25 changed files with 187 additions and 180 deletions

View File

@ -3,6 +3,7 @@
## [Unreleased] ## [Unreleased]
### Added ### Added
- Autodiff for generic algebra elements in core! - Autodiff for generic algebra elements in core!
- Algebra now has an obligatory `bufferFactory` (#477).
### Changed ### Changed
- Kotlin 1.7 - Kotlin 1.7

View File

@ -16,7 +16,6 @@ import space.kscience.kmath.linear.linearSpace
import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.multik.multikAlgebra
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.tensorflow.produceWithTF import space.kscience.kmath.tensorflow.produceWithTF
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.tensorAlgebra import space.kscience.kmath.tensors.core.tensorAlgebra
@ -84,7 +83,7 @@ internal class DotBenchmark {
} }
@Benchmark @Benchmark
fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace(Buffer.Companion::auto)) { fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace) {
blackhole.consume(matrix1 dot matrix2) blackhole.consume(matrix1 dot matrix2)
} }

View File

@ -20,7 +20,6 @@ import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.nd.one import space.kscience.kmath.nd.one
import space.kscience.kmath.nd4j.nd4j import space.kscience.kmath.nd4j.nd4j
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensor
import space.kscience.kmath.tensors.core.one import space.kscience.kmath.tensors.core.one
import space.kscience.kmath.tensors.core.tensorAlgebra import space.kscience.kmath.tensors.core.tensorAlgebra
@ -28,12 +27,6 @@ import space.kscience.kmath.viktor.viktorAlgebra
@State(Scope.Benchmark) @State(Scope.Benchmark)
internal class NDFieldBenchmark { internal class NDFieldBenchmark {
@Benchmark
fun autoFieldAdd(blackhole: Blackhole) = with(autoField) {
var res: StructureND<Double> = one(shape)
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@Benchmark @Benchmark
fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) { fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) {
@ -95,9 +88,8 @@ internal class NDFieldBenchmark {
private const val dim = 1000 private const val dim = 1000
private const val n = 100 private const val n = 100
private val shape = intArrayOf(dim, dim) private val shape = intArrayOf(dim, dim)
private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto)
private val specializedField = DoubleField.ndAlgebra private val specializedField = DoubleField.ndAlgebra
private val genericField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) private val genericField = BufferedFieldOpsND(DoubleField)
private val nd4jField = DoubleField.nd4j private val nd4jField = DoubleField.nd4j
private val multikField = DoubleField.multikAlgebra private val multikField = DoubleField.multikAlgebra
private val viktorField = DoubleField.viktorAlgebra private val viktorField = DoubleField.viktorAlgebra

View File

@ -10,25 +10,19 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope import kotlinx.benchmark.Scope
import kotlinx.benchmark.State import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.nd.* import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.nd.one
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.viktor.ViktorFieldND import space.kscience.kmath.viktor.ViktorFieldND
@State(Scope.Benchmark) @State(Scope.Benchmark)
internal class ViktorBenchmark { internal class ViktorBenchmark {
@Benchmark
fun automaticFieldAddition(blackhole: Blackhole) {
with(autoField) {
var res: StructureND<Double> = one(shape)
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
}
@Benchmark @Benchmark
fun realFieldAddition(blackhole: Blackhole) { fun doubleFieldAddition(blackhole: Blackhole) {
with(realField) { with(doubleField) {
var res: StructureND<Double> = one(shape) var res: StructureND<Double> = one(shape)
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
blackhole.consume(res) blackhole.consume(res)
@ -58,8 +52,7 @@ internal class ViktorBenchmark {
private val shape = Shape(dim, dim) private val shape = Shape(dim, dim)
// automatically build context most suited for given type. // automatically build context most suited for given type.
private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) private val doubleField = DoubleField.ndAlgebra
private val realField = DoubleField.ndAlgebra
private val viktorField = ViktorFieldND(dim, dim) private val viktorField = ViktorFieldND(dim, dim)
} }
} }

View File

@ -10,19 +10,17 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope import kotlinx.benchmark.Scope
import kotlinx.benchmark.State import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.nd.BufferedFieldOpsND
import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.nd.one import space.kscience.kmath.nd.one
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.viktor.ViktorFieldND import space.kscience.kmath.viktor.ViktorFieldND
@State(Scope.Benchmark) @State(Scope.Benchmark)
internal class ViktorLogBenchmark { internal class ViktorLogBenchmark {
@Benchmark @Benchmark
fun realFieldLog(blackhole: Blackhole) { fun realFieldLog(blackhole: Blackhole) {
with(realField) { with(doubleField) {
val fortyTwo = structureND(shape) { 42.0 } val fortyTwo = structureND(shape) { 42.0 }
var res = one(shape) var res = one(shape)
repeat(n) { res = ln(fortyTwo) } repeat(n) { res = ln(fortyTwo) }
@ -54,8 +52,7 @@ internal class ViktorLogBenchmark {
private val shape = Shape(dim, dim) private val shape = Shape(dim, dim)
// automatically build context most suited for given type. // automatically build context most suited for given type.
private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) private val doubleField = DoubleField.ndAlgebra
private val realField = DoubleField.ndAlgebra
private val viktorField = ViktorFieldND(dim, dim) private val viktorField = ViktorFieldND(dim, dim)
} }
} }

View File

@ -7,7 +7,6 @@ package space.kscience.kmath.operations
import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.algebra import space.kscience.kmath.complex.algebra
import space.kscience.kmath.complex.bufferAlgebra
import space.kscience.kmath.complex.ndAlgebra import space.kscience.kmath.complex.ndAlgebra
import space.kscience.kmath.nd.BufferND import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.StructureND
@ -18,7 +17,7 @@ fun main() = Complex.algebra {
println(complex * 8 - 5 * i) println(complex * 8 - 5 * i)
//flat buffer //flat buffer
val buffer = with(bufferAlgebra){ val buffer = with(bufferAlgebra) {
buffer(8) { Complex(it, -it) }.map { Complex(it.im, it.re) } buffer(8) { Complex(it, -it) }.map { Complex(it.im, it.re) }
} }
println(buffer) println(buffer)
@ -30,7 +29,7 @@ fun main() = Complex.algebra {
println(element) println(element)
// 1d element operation // 1d element operation
val result: StructureND<Complex> = ndAlgebra{ val result: StructureND<Complex> = ndAlgebra {
val a = structureND(8) { (it) -> i * it - it.toDouble() } val a = structureND(8) { (it) -> i * it - it.toDouble() }
val b = 3 val b = 3
val c = Complex(1.0, 1.0) val c = Complex(1.0, 1.0)

View File

@ -32,12 +32,10 @@ fun main() {
val shape = Shape(dim, dim) val shape = Shape(dim, dim)
// automatically build context most suited for given type.
val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto)
// specialized nd-field for Double. It works as generic Double field as well. // specialized nd-field for Double. It works as generic Double field as well.
val realField = DoubleField.ndAlgebra val doubleField = DoubleField.ndAlgebra
//A generic boxing field. It should be used for objects, not primitives. //A generic field. It should be used for objects, not primitives.
val boxingField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) val genericField = BufferedFieldOpsND(DoubleField)
// Nd4j specialized field. // Nd4j specialized field.
val nd4jField = DoubleField.nd4j val nd4jField = DoubleField.nd4j
//viktor field //viktor field
@ -46,14 +44,14 @@ fun main() {
val parallelField = DoubleField.ndStreaming(dim, dim) val parallelField = DoubleField.ndStreaming(dim, dim)
measureAndPrint("Boxing addition") { measureAndPrint("Boxing addition") {
boxingField { genericField {
var res: StructureND<Double> = one(shape) var res: StructureND<Double> = one(shape)
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
} }
} }
measureAndPrint("Specialized addition") { measureAndPrint("Specialized addition") {
realField { doubleField {
var res: StructureND<Double> = one(shape) var res: StructureND<Double> = one(shape)
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
} }
@ -80,15 +78,8 @@ fun main() {
} }
} }
measureAndPrint("Automatic field addition") {
autoField {
var res: StructureND<Double> = one(shape)
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Lazy addition") { measureAndPrint("Lazy addition") {
val res = realField.one(shape).mapAsync(GlobalScope) { val res = doubleField.one(shape).mapAsync(GlobalScope) {
var c = 0.0 var c = 0.0
repeat(n) { repeat(n) {
c += 1.0 c += 1.0

View File

@ -10,10 +10,7 @@ import space.kscience.kmath.memory.MemorySpec
import space.kscience.kmath.memory.MemoryWriter import space.kscience.kmath.memory.MemoryWriter
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.*
import space.kscience.kmath.structures.MemoryBuffer
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableMemoryBuffer
import kotlin.math.* import kotlin.math.*
/** /**
@ -54,6 +51,9 @@ public object ComplexField :
Norm<Complex, Complex>, Norm<Complex, Complex>,
NumbersAddOps<Complex>, NumbersAddOps<Complex>,
ScaleOperations<Complex> { ScaleOperations<Complex> {
override val bufferFactory: MutableBufferFactory<Complex> = MutableBufferFactory { size, init ->
MutableMemoryBuffer.create(Complex, size, init)
}
override val zero: Complex = 0.0.toComplex() override val zero: Complex = 0.0.toComplex()
override val one: Complex = 1.0.toComplex() override val one: Complex = 1.0.toComplex()

View File

@ -56,11 +56,6 @@ public sealed class ComplexFieldOpsND : BufferedFieldOpsND<Complex, ComplexField
public companion object : ComplexFieldOpsND() public companion object : ComplexFieldOpsND()
} }
@UnstableKMathAPI
public val ComplexField.bufferAlgebra: BufferFieldOps<Complex, ComplexField>
get() = bufferAlgebra(Buffer.Companion::complex)
@OptIn(UnstableKMathAPI::class) @OptIn(UnstableKMathAPI::class)
public class ComplexFieldND(override val shape: Shape) : public class ComplexFieldND(override val shape: Shape) :
ComplexFieldOpsND(), FieldND<Complex, ComplexField>, ComplexFieldOpsND(), FieldND<Complex, ComplexField>,

View File

@ -78,9 +78,9 @@ public val <T, A : Ring<T>> DS<T, A>.value: T get() = data[0]
@UnstableKMathAPI @UnstableKMathAPI
public abstract class DSAlgebra<T, A : Ring<T>>( public abstract class DSAlgebra<T, A : Ring<T>>(
public val algebra: A, public val algebra: A,
public val bufferFactory: MutableBufferFactory<T>,
public val order: Int, public val order: Int,
bindings: Map<Symbol, T>, bindings: Map<Symbol, T>,
public val valueBufferFactory: MutableBufferFactory<T> = algebra.bufferFactory,
) : ExpressionAlgebra<T, DS<T, A>>, SymbolIndexer { ) : ExpressionAlgebra<T, DS<T, A>>, SymbolIndexer {
/** /**
@ -90,6 +90,7 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
*/ */
@PublishedApi @PublishedApi
internal val compiler: DSCompiler<T, A> by lazy { internal val compiler: DSCompiler<T, A> by lazy {
val numberOfVariables = bindings.size
// get the cached compilers // get the cached compilers
val cache: Array<Array<DSCompiler<T, A>?>>? = null val cache: Array<Array<DSCompiler<T, A>?>>? = null
@ -115,7 +116,7 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
newCache[p][o] = DSCompiler( newCache[p][o] = DSCompiler(
algebra, algebra,
bufferFactory, valueBufferFactory,
p, p,
o, o,
valueCompiler, valueCompiler,
@ -139,16 +140,13 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
} }
override val symbols: List<Symbol> = bindings.map { it.key } override val symbols: List<Symbol> = bindings.map { it.key }
public val numberOfVariables: Int get() = symbols.size
private fun bufferForVariable(index: Int, value: T): Buffer<T> { private fun bufferForVariable(index: Int, value: T): Buffer<T> {
val buffer = bufferFactory(compiler.size) { algebra.zero } val buffer = valueBufferFactory(compiler.size) { algebra.zero }
buffer[0] = value buffer[0] = value
if (compiler.order > 0) { if (compiler.order > 0) {
// the derivative of the variable with respect to itself is 1. // the derivative of the variable with respect to itself is 1.
val indexOfDerivative = compiler.getPartialDerivativeIndex(*IntArray(numberOfVariables).apply { val indexOfDerivative = compiler.getPartialDerivativeIndex(*IntArray(symbols.size).apply {
set(index, 1) set(index, 1)
}) })
@ -209,7 +207,7 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
} }
public override fun const(value: T): DS<T, A> { public override fun const(value: T): DS<T, A> {
val buffer = bufferFactory(compiler.size) { algebra.zero } val buffer = valueBufferFactory(compiler.size) { algebra.zero }
buffer[0] = value buffer[0] = value
return DS(buffer) return DS(buffer)
@ -245,10 +243,10 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
@UnstableKMathAPI @UnstableKMathAPI
public open class DSRing<T, A>( public open class DSRing<T, A>(
algebra: A, algebra: A,
bufferFactory: MutableBufferFactory<T>,
order: Int, order: Int,
bindings: Map<Symbol, T>, bindings: Map<Symbol, T>,
) : DSAlgebra<T, A>(algebra, bufferFactory, order, bindings), valueBufferFactory: MutableBufferFactory<T>,
) : DSAlgebra<T, A>(algebra, order, bindings, valueBufferFactory),
Ring<DS<T, A>>, ScaleOperations<DS<T, A>>, Ring<DS<T, A>>, ScaleOperations<DS<T, A>>,
NumericAlgebra<DS<T, A>>, NumericAlgebra<DS<T, A>>,
NumbersAddOps<DS<T, A>> where A : Ring<T>, A : NumericAlgebra<T>, A : ScaleOperations<T> { NumbersAddOps<DS<T, A>> where A : Ring<T>, A : NumericAlgebra<T>, A : ScaleOperations<T> {
@ -263,14 +261,14 @@ public open class DSRing<T, A>(
*/ */
protected inline fun DS<T, A>.transformDataBuffer(block: A.(MutableBuffer<T>) -> Unit): DS<T, A> { protected inline fun DS<T, A>.transformDataBuffer(block: A.(MutableBuffer<T>) -> Unit): DS<T, A> {
require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" }
val newData = bufferFactory(compiler.size) { data[it] } val newData = valueBufferFactory(compiler.size) { data[it] }
algebra.block(newData) algebra.block(newData)
return DS(newData) return DS(newData)
} }
protected fun DS<T, A>.mapData(block: A.(T) -> T): DS<T, A> { protected fun DS<T, A>.mapData(block: A.(T) -> T): DS<T, A> {
require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" }
val newData: Buffer<T> = data.map(bufferFactory) { val newData: Buffer<T> = data.map(valueBufferFactory) {
algebra.block(it) algebra.block(it)
} }
return DS(newData) return DS(newData)
@ -278,7 +276,7 @@ public open class DSRing<T, A>(
protected fun DS<T, A>.mapDataIndexed(block: (Int, T) -> T): DS<T, A> { protected fun DS<T, A>.mapDataIndexed(block: (Int, T) -> T): DS<T, A> {
require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" }
val newData: Buffer<T> = data.mapIndexed(bufferFactory, block) val newData: Buffer<T> = data.mapIndexed(valueBufferFactory, block)
return DS(newData) return DS(newData)
} }
@ -327,19 +325,19 @@ public open class DSRing<T, A>(
@UnstableKMathAPI @UnstableKMathAPI
public class DerivativeStructureRingExpression<T, A>( public class DerivativeStructureRingExpression<T, A>(
public val algebra: A, public val algebra: A,
public val bufferFactory: MutableBufferFactory<T>, public val elementBufferFactory: MutableBufferFactory<T> = algebra.bufferFactory,
public val function: DSRing<T, A>.() -> DS<T, A>, public val function: DSRing<T, A>.() -> DS<T, A>,
) : DifferentiableExpression<T> where A : Ring<T>, A : ScaleOperations<T>, A : NumericAlgebra<T> { ) : DifferentiableExpression<T> where A : Ring<T>, A : ScaleOperations<T>, A : NumericAlgebra<T> {
override operator fun invoke(arguments: Map<Symbol, T>): T = override operator fun invoke(arguments: Map<Symbol, T>): T =
DSRing(algebra, bufferFactory, 0, arguments).function().value DSRing(algebra, 0, arguments, elementBufferFactory).function().value
override fun derivativeOrNull(symbols: List<Symbol>): Expression<T> = Expression { arguments -> override fun derivativeOrNull(symbols: List<Symbol>): Expression<T> = Expression { arguments ->
with( with(
DSRing( DSRing(
algebra, algebra,
bufferFactory,
symbols.size, symbols.size,
arguments arguments,
elementBufferFactory
) )
) { function().derivative(symbols) } ) { function().derivative(symbols) }
} }
@ -354,10 +352,10 @@ public class DerivativeStructureRingExpression<T, A>(
@UnstableKMathAPI @UnstableKMathAPI
public class DSField<T, A : ExtendedField<T>>( public class DSField<T, A : ExtendedField<T>>(
algebra: A, algebra: A,
bufferFactory: MutableBufferFactory<T>,
order: Int, order: Int,
bindings: Map<Symbol, T>, bindings: Map<Symbol, T>,
) : DSRing<T, A>(algebra, bufferFactory, order, bindings), ExtendedField<DS<T, A>> { valueBufferFactory: MutableBufferFactory<T>,
) : DSRing<T, A>(algebra, order, bindings, valueBufferFactory), ExtendedField<DS<T, A>> {
override fun number(value: Number): DS<T, A> = const(algebra.number(value)) override fun number(value: Number): DS<T, A> = const(algebra.number(value))
override fun divide(left: DS<T, A>, right: DS<T, A>): DS<T, A> = left.transformDataBuffer { result -> override fun divide(left: DS<T, A>, right: DS<T, A>): DS<T, A> = left.transformDataBuffer { result ->
@ -441,18 +439,18 @@ public class DSField<T, A : ExtendedField<T>>(
@UnstableKMathAPI @UnstableKMathAPI
public class DSFieldExpression<T, A : ExtendedField<T>>( public class DSFieldExpression<T, A : ExtendedField<T>>(
public val algebra: A, public val algebra: A,
public val bufferFactory: MutableBufferFactory<T>, private val valueBufferFactory: MutableBufferFactory<T> = algebra.bufferFactory,
public val function: DSField<T, A>.() -> DS<T, A>, public val function: DSField<T, A>.() -> DS<T, A>,
) : DifferentiableExpression<T> { ) : DifferentiableExpression<T> {
override operator fun invoke(arguments: Map<Symbol, T>): T = override operator fun invoke(arguments: Map<Symbol, T>): T =
DSField(algebra, bufferFactory, 0, arguments).function().value DSField(algebra, 0, arguments, valueBufferFactory).function().value
override fun derivativeOrNull(symbols: List<Symbol>): Expression<T> = Expression { arguments -> override fun derivativeOrNull(symbols: List<Symbol>): Expression<T> = Expression { arguments ->
DSField( DSField(
algebra, algebra,
bufferFactory,
symbols.size, symbols.size,
arguments, arguments,
valueBufferFactory,
).run { function().derivative(symbols) } ).run { function().derivative(symbols) }
} }
} }

View File

@ -11,13 +11,12 @@ import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.asND import space.kscience.kmath.nd.asND
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferFactory
import space.kscience.kmath.structures.VirtualBuffer import space.kscience.kmath.structures.VirtualBuffer
import space.kscience.kmath.structures.indices import space.kscience.kmath.structures.indices
public class BufferedLinearSpace<T, out A : Ring<T>>( public class BufferedLinearSpace<T, out A : Ring<T>>(
private val bufferAlgebra: BufferAlgebra<T, A> private val bufferAlgebra: BufferAlgebra<T, A>,
) : LinearSpace<T, A> { ) : LinearSpace<T, A> {
override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
@ -91,5 +90,5 @@ public class BufferedLinearSpace<T, out A : Ring<T>>(
} }
public fun <T, A : Ring<T>> A.linearSpace(bufferFactory: BufferFactory<T>): BufferedLinearSpace<T, A> = public val <T, A : Ring<T>> A.linearSpace: BufferedLinearSpace<T, A>
BufferedLinearSpace(BufferRingOps(this, bufferFactory)) get() = BufferedLinearSpace(BufferRingOps(this))

View File

@ -11,12 +11,9 @@ import space.kscience.kmath.nd.Structure2D
import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.nd.StructureFeature
import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as1D
import space.kscience.kmath.operations.BufferRingOps import space.kscience.kmath.operations.BufferRingOps
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferFactory
import space.kscience.kmath.structures.DoubleBuffer
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
@ -187,18 +184,9 @@ public interface LinearSpace<T, out A : Ring<T>> {
* A structured matrix with custom buffer * A structured matrix with custom buffer
*/ */
public fun <T : Any, A : Ring<T>> buffered( public fun <T : Any, A : Ring<T>> buffered(
algebra: A, algebra: A
bufferFactory: BufferFactory<T> = BufferFactory(Buffer.Companion::boxing), ): LinearSpace<T, A> = BufferedLinearSpace(BufferRingOps(algebra))
): LinearSpace<T, A> = BufferedLinearSpace(BufferRingOps(algebra, bufferFactory))
@Deprecated("use DoubleField.linearSpace")
public val double: LinearSpace<Double, DoubleField> = buffered(DoubleField, ::DoubleBuffer)
/**
* Automatic buffered matrix, unboxed if it is possible
*/
public inline fun <reified T : Any, A : Ring<T>> auto(ring: A): LinearSpace<T, A> =
buffered(ring, Buffer.Companion::auto)
} }
} }

View File

@ -10,7 +10,6 @@ package space.kscience.kmath.nd
import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.BufferFactory
public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> { public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
public val indexerBuilder: (IntArray) -> ShapeIndexer public val indexerBuilder: (IntArray) -> ShapeIndexer
@ -60,7 +59,7 @@ public inline fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.mapInline(
return BufferND( return BufferND(
indexes, indexes,
bufferAlgebra.run { bufferAlgebra.run {
bufferFactory(buffer.size) { elementAlgebra.transform(buffer[it]) } elementBufferFactory(buffer.size) { elementAlgebra.transform(buffer[it]) }
} }
) )
} }
@ -74,7 +73,7 @@ internal inline fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.mapIndexedInline(
return BufferND( return BufferND(
indexes, indexes,
bufferAlgebra.run { bufferAlgebra.run {
bufferFactory(buffer.size) { elementAlgebra.transform(indexes.index(it), buffer[it]) } elementBufferFactory(buffer.size) { elementAlgebra.transform(indexes.index(it), buffer[it]) }
} }
) )
} }
@ -91,7 +90,7 @@ internal inline fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.zipInline(
return BufferND( return BufferND(
indexes, indexes,
bufferAlgebra.run { bufferAlgebra.run {
bufferFactory(lbuffer.size) { elementAlgebra.block(lbuffer[it], rbuffer[it]) } elementBufferFactory(lbuffer.size) { elementAlgebra.block(lbuffer[it], rbuffer[it]) }
} }
) )
} }
@ -116,9 +115,8 @@ public open class BufferedFieldOpsND<T, out A : Field<T>>(
public constructor( public constructor(
elementAlgebra: A, elementAlgebra: A,
bufferFactory: BufferFactory<T>,
indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
) : this(BufferFieldOps(elementAlgebra, bufferFactory), indexerBuilder) ) : this(BufferFieldOps(elementAlgebra), indexerBuilder)
@OptIn(PerformancePitfall::class) @OptIn(PerformancePitfall::class)
override fun scale(a: StructureND<T>, value: Double): StructureND<T> = a.map { it * value } override fun scale(a: StructureND<T>, value: Double): StructureND<T> = a.map { it * value }

View File

@ -120,7 +120,7 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
*/ */
public fun <T> buffered( public fun <T> buffered(
strides: Strides, strides: Strides,
bufferFactory: BufferFactory<T> = BufferFactory(Buffer.Companion::boxing), bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
initializer: (IntArray) -> T, initializer: (IntArray) -> T,
): BufferND<T> = BufferND(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) }) ): BufferND<T> = BufferND(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) })
@ -140,7 +140,7 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
public fun <T> buffered( public fun <T> buffered(
shape: IntArray, shape: IntArray,
bufferFactory: BufferFactory<T> = BufferFactory(Buffer.Companion::boxing), bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
initializer: (IntArray) -> T, initializer: (IntArray) -> T,
): BufferND<T> = buffered(DefaultStrides(shape), bufferFactory, initializer) ): BufferND<T> = buffered(DefaultStrides(shape), bufferFactory, initializer)

View File

@ -8,12 +8,7 @@ package space.kscience.kmath.operations
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Ring.Companion.optimizedPower import space.kscience.kmath.operations.Ring.Companion.optimizedPower
import space.kscience.kmath.structures.MutableBufferFactory
/**
* Stub for DSL the [Algebra] is.
*/
@DslMarker
public annotation class KMathContext
/** /**
* Represents an algebraic structure. * Represents an algebraic structure.
@ -21,6 +16,12 @@ public annotation class KMathContext
* @param T the type of element of this structure. * @param T the type of element of this structure.
*/ */
public interface Algebra<T> { public interface Algebra<T> {
/**
* Provide a factory for buffers, associated with this [Algebra]
*/
public val bufferFactory: MutableBufferFactory<T> get() = MutableBufferFactory.boxing()
/** /**
* Wraps a raw string to [T] object. This method is designed for three purposes: * Wraps a raw string to [T] object. This method is designed for three purposes:
* *

View File

@ -10,7 +10,6 @@ import space.kscience.kmath.nd.BufferedRingOpsND
import space.kscience.kmath.operations.BigInt.Companion.BASE import space.kscience.kmath.operations.BigInt.Companion.BASE
import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBuffer
import kotlin.math.log2 import kotlin.math.log2
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -528,19 +527,11 @@ public fun String.parseBigInteger(): BigInt? {
public val BigInt.algebra: BigIntField get() = BigIntField public val BigInt.algebra: BigIntField get() = BigIntField
@Deprecated("Use BigInt::buffer")
public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> =
boxing(size, initializer)
public inline fun BigInt.Companion.buffer(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> = public inline fun BigInt.Companion.buffer(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> =
Buffer.boxing(size, initializer) Buffer.boxing(size, initializer)
@Deprecated("Use BigInt::mutableBuffer") public inline fun BigInt.Companion.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> =
public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer<BigInt> =
boxing(size, initializer)
public inline fun BigInt.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> =
Buffer.boxing(size, initializer) Buffer.boxing(size, initializer)
public val BigIntField.nd: BufferedRingOpsND<BigInt, BigIntField> public val BigIntField.nd: BufferedRingOpsND<BigInt, BigIntField>
get() = BufferedRingOpsND(BufferRingOps(BigIntField, BigInt::buffer)) get() = BufferedRingOpsND(BufferRingOps(BigIntField))

View File

@ -7,8 +7,6 @@ package space.kscience.kmath.operations
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.ShortBuffer
public interface WithSize { public interface WithSize {
public val size: Int public val size: Int
@ -19,11 +17,11 @@ public interface WithSize {
*/ */
public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> { public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
public val elementAlgebra: A public val elementAlgebra: A
public val bufferFactory: BufferFactory<T> public val elementBufferFactory: BufferFactory<T> get() = elementAlgebra.bufferFactory
public fun buffer(size: Int, vararg elements: T): Buffer<T> { public fun buffer(size: Int, vararg elements: T): Buffer<T> {
require(elements.size == size) { "Expected $size elements but found ${elements.size}" } require(elements.size == size) { "Expected $size elements but found ${elements.size}" }
return bufferFactory(size) { elements[it] } return elementBufferFactory(size) { elements[it] }
} }
//TODO move to multi-receiver inline extension //TODO move to multi-receiver inline extension
@ -36,13 +34,13 @@ public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
override fun unaryOperationFunction(operation: String): (arg: Buffer<T>) -> Buffer<T> { override fun unaryOperationFunction(operation: String): (arg: Buffer<T>) -> Buffer<T> {
val operationFunction = elementAlgebra.unaryOperationFunction(operation) val operationFunction = elementAlgebra.unaryOperationFunction(operation)
return { arg -> bufferFactory(arg.size) { operationFunction(arg[it]) } } return { arg -> elementBufferFactory(arg.size) { operationFunction(arg[it]) } }
} }
override fun binaryOperationFunction(operation: String): (left: Buffer<T>, right: Buffer<T>) -> Buffer<T> { override fun binaryOperationFunction(operation: String): (left: Buffer<T>, right: Buffer<T>) -> Buffer<T> {
val operationFunction = elementAlgebra.binaryOperationFunction(operation) val operationFunction = elementAlgebra.binaryOperationFunction(operation)
return { left, right -> return { left, right ->
bufferFactory(left.size) { operationFunction(left[it], right[it]) } elementBufferFactory(left.size) { operationFunction(left[it], right[it]) }
} }
} }
} }
@ -53,7 +51,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> = elementBufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) }
/** /**
* Inline map * Inline map
@ -61,7 +59,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> = elementBufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) }
/** /**
* Inline zip * Inline zip
@ -72,15 +70,15 @@ private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.zipInline(
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 elementBufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) }
} }
public fun <T> BufferAlgebra<T, *>.buffer(size: Int, initializer: (Int) -> T): Buffer<T> { public fun <T> BufferAlgebra<T, *>.buffer(size: Int, initializer: (Int) -> T): Buffer<T> {
return bufferFactory(size, initializer) return elementBufferFactory(size, initializer)
} }
public fun <T, A> A.buffer(initializer: (Int) -> T): Buffer<T> where A : BufferAlgebra<T, *>, A : WithSize { public fun <T, A> A.buffer(initializer: (Int) -> T): Buffer<T> where A : BufferAlgebra<T, *>, A : WithSize {
return bufferFactory(size, initializer) return elementBufferFactory(size, initializer)
} }
public fun <T, A : TrigonometricOperations<T>> BufferAlgebra<T, A>.sin(arg: Buffer<T>): Buffer<T> = public fun <T, A : TrigonometricOperations<T>> BufferAlgebra<T, A>.sin(arg: Buffer<T>): Buffer<T> =
@ -131,7 +129,6 @@ public fun <T, A : PowerOperations<T>> BufferAlgebra<T, A>.pow(arg: Buffer<T>, p
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>,
) : 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 }
@ -146,15 +143,13 @@ public open class BufferRingOps<T, A : Ring<T>>(
} }
public val ShortRing.bufferAlgebra: BufferRingOps<Short, ShortRing> public val ShortRing.bufferAlgebra: BufferRingOps<Short, ShortRing>
get() = BufferRingOps(ShortRing, ::ShortBuffer) get() = BufferRingOps(ShortRing)
public open class BufferFieldOps<T, A : Field<T>>( public open class BufferFieldOps<T, A : Field<T>>(
elementAlgebra: A, elementAlgebra: A,
bufferFactory: BufferFactory<T>, ) : BufferRingOps<T, A>(elementAlgebra), 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 }
@ -167,30 +162,26 @@ 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>,
override val size: Int, override val size: Int,
) : BufferFieldOps<T, A>(elementAlgebra, bufferFactory), Field<Buffer<T>>, WithSize { ) : BufferFieldOps<T, A>(elementAlgebra), Field<Buffer<T>>, WithSize {
override val zero: Buffer<T> = bufferFactory(size) { elementAlgebra.zero } override val zero: Buffer<T> = elementAlgebra.bufferFactory(size) { elementAlgebra.zero }
override val one: Buffer<T> = bufferFactory(size) { elementAlgebra.one } override val one: Buffer<T> = elementAlgebra.bufferFactory(size) { elementAlgebra.one }
} }
/** /**
* Generate full buffer field from given buffer operations * Generate full buffer field from given buffer operations
*/ */
public fun <T, A : Field<T>> BufferFieldOps<T, A>.withSize(size: Int): BufferField<T, A> = public fun <T, A : Field<T>> BufferFieldOps<T, A>.withSize(size: Int): BufferField<T, A> =
BufferField(elementAlgebra, bufferFactory, size) BufferField(elementAlgebra, size)
//Double buffer specialization //Double buffer specialization
public fun BufferField<Double, *>.buffer(vararg elements: Number): Buffer<Double> { public fun BufferField<Double, *>.buffer(vararg elements: Number): Buffer<Double> {
require(elements.size == size) { "Expected $size elements but found ${elements.size}" } require(elements.size == size) { "Expected $size elements but found ${elements.size}" }
return bufferFactory(size) { elements[it].toDouble() } return elementBufferFactory(size) { elements[it].toDouble() }
} }
public fun <T, A : Field<T>> A.bufferAlgebra(bufferFactory: BufferFactory<T>): BufferFieldOps<T, A> = public val <T, A : Field<T>> A.bufferAlgebra: BufferFieldOps<T, A>
BufferFieldOps(this, bufferFactory) get() = BufferFieldOps(this)
public val DoubleField.bufferAlgebra: BufferFieldOps<Double, DoubleField>
get() = BufferFieldOps(DoubleField, ::DoubleBuffer)

View File

@ -7,8 +7,8 @@ package space.kscience.kmath.operations
import space.kscience.kmath.linear.Point import space.kscience.kmath.linear.Point
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferFactory
import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.MutableBufferFactory
import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.asBuffer
import kotlin.math.* import kotlin.math.*
@ -19,7 +19,7 @@ public abstract class DoubleBufferOps : BufferAlgebra<Double, DoubleField>, Exte
Norm<Buffer<Double>, Double> { Norm<Buffer<Double>, Double> {
override val elementAlgebra: DoubleField get() = DoubleField override val elementAlgebra: DoubleField get() = DoubleField
override val bufferFactory: BufferFactory<Double> get() = BufferFactory(::DoubleBuffer) override val elementBufferFactory: MutableBufferFactory<Double> get() = elementAlgebra.bufferFactory
override fun Buffer<Double>.map(block: DoubleField.(Double) -> Double): DoubleBuffer = override fun Buffer<Double>.map(block: DoubleField.(Double) -> Double): DoubleBuffer =
mapInline { DoubleField.block(it) } mapInline { DoubleField.block(it) }

View File

@ -88,7 +88,7 @@ public inline fun <T, R> Buffer<T>.mapIndexed(
*/ */
public inline fun <T, reified R : Any> Buffer<T>.mapIndexed( public inline fun <T, reified R : Any> Buffer<T>.mapIndexed(
crossinline block: (index: Int, value: T) -> R, crossinline block: (index: Int, value: T) -> R,
): Buffer<R> = BufferFactory<R>(Buffer.Companion::auto).invoke(size) { block(it, get(it)) } ): Buffer<R> = Buffer.auto(size) { block(it, get(it)) }
/** /**
* Fold given buffer according to [operation] * Fold given buffer according to [operation]
@ -105,7 +105,7 @@ public inline fun <T, R> Buffer<T>.fold(initial: R, operation: (acc: R, T) -> R)
@UnstableKMathAPI @UnstableKMathAPI
public inline fun <T1, T2 : Any, reified R : Any> Buffer<T1>.zip( public inline fun <T1, T2 : Any, reified R : Any> Buffer<T1>.zip(
other: Buffer<T2>, other: Buffer<T2>,
bufferFactory: BufferFactory<R> = BufferFactory(Buffer.Companion::auto), bufferFactory: BufferFactory<R> = BufferFactory.auto(),
crossinline transform: (T1, T2) -> R, crossinline transform: (T1, T2) -> R,
): Buffer<R> { ): Buffer<R> {
require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" } require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" }

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.operations package space.kscience.kmath.operations
import space.kscience.kmath.structures.*
import kotlin.math.pow as kpow import kotlin.math.pow as kpow
/** /**
@ -65,6 +66,8 @@ public interface ExtendedField<T> : ExtendedFieldOps<T>, Field<T>, PowerOperatio
*/ */
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public object DoubleField : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> { public object DoubleField : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> {
override val bufferFactory: MutableBufferFactory<Double> = MutableBufferFactory(::DoubleBuffer)
override inline val zero: Double get() = 0.0 override inline val zero: Double get() = 0.0
override inline val one: Double get() = 1.0 override inline val one: Double get() = 1.0
@ -123,6 +126,8 @@ public val Double.Companion.algebra: DoubleField get() = DoubleField
*/ */
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public object FloatField : ExtendedField<Float>, Norm<Float, Float> { public object FloatField : ExtendedField<Float>, Norm<Float, Float> {
override val bufferFactory: MutableBufferFactory<Float> = MutableBufferFactory(::FloatBuffer)
override inline val zero: Float get() = 0.0f override inline val zero: Float get() = 0.0f
override inline val one: Float get() = 1.0f override inline val one: Float get() = 1.0f
@ -177,11 +182,10 @@ public val Float.Companion.algebra: FloatField get() = FloatField
*/ */
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public object IntRing : Ring<Int>, Norm<Int, Int>, NumericAlgebra<Int> { public object IntRing : Ring<Int>, Norm<Int, Int>, NumericAlgebra<Int> {
override inline val zero: Int override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory(::IntBuffer)
get() = 0
override inline val one: Int override inline val zero: Int get() = 0
get() = 1 override inline val one: Int get() = 1
override fun number(value: Number): Int = value.toInt() override fun number(value: Number): Int = value.toInt()
override inline fun add(left: Int, right: Int): Int = left + right override inline fun add(left: Int, right: Int): Int = left + right
@ -201,11 +205,10 @@ public val Int.Companion.algebra: IntRing get() = IntRing
*/ */
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public object ShortRing : Ring<Short>, Norm<Short, Short>, NumericAlgebra<Short> { public object ShortRing : Ring<Short>, Norm<Short, Short>, NumericAlgebra<Short> {
override inline val zero: Short override val bufferFactory: MutableBufferFactory<Short> = MutableBufferFactory(::ShortBuffer)
get() = 0
override inline val one: Short override inline val zero: Short get() = 0
get() = 1 override inline val one: Short get() = 1
override fun number(value: Number): Short = value.toShort() override fun number(value: Number): Short = value.toShort()
override inline fun add(left: Short, right: Short): Short = (left + right).toShort() override inline fun add(left: Short, right: Short): Short = (left + right).toShort()
@ -225,11 +228,10 @@ public val Short.Companion.algebra: ShortRing get() = ShortRing
*/ */
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public object ByteRing : Ring<Byte>, Norm<Byte, Byte>, NumericAlgebra<Byte> { public object ByteRing : Ring<Byte>, Norm<Byte, Byte>, NumericAlgebra<Byte> {
override inline val zero: Byte override val bufferFactory: MutableBufferFactory<Byte> = MutableBufferFactory(::ByteBuffer)
get() = 0
override inline val one: Byte override inline val zero: Byte get() = 0
get() = 1 override inline val one: Byte get() = 1
override fun number(value: Number): Byte = value.toByte() override fun number(value: Number): Byte = value.toByte()
override inline fun add(left: Byte, right: Byte): Byte = (left + right).toByte() override inline fun add(left: Byte, right: Byte): Byte = (left + right).toByte()
@ -249,11 +251,10 @@ public val Byte.Companion.algebra: ByteRing get() = ByteRing
*/ */
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public object LongRing : Ring<Long>, Norm<Long, Long>, NumericAlgebra<Long> { public object LongRing : Ring<Long>, Norm<Long, Long>, NumericAlgebra<Long> {
override inline val zero: Long override val bufferFactory: MutableBufferFactory<Long> = MutableBufferFactory(::LongBuffer)
get() = 0L
override inline val one: Long override inline val zero: Long get() = 0L
get() = 1L override inline val one: Long get() = 1L
override fun number(value: Number): Long = value.toLong() override fun number(value: Number): Long = value.toLong()
override inline fun add(left: Long, right: Long): Long = left + right override inline fun add(left: Long, right: Long): Long = left + right

View File

@ -16,6 +16,14 @@ import kotlin.reflect.KClass
*/ */
public fun interface BufferFactory<T> { public fun interface BufferFactory<T> {
public operator fun invoke(size: Int, builder: (Int) -> T): Buffer<T> public operator fun invoke(size: Int, builder: (Int) -> T): Buffer<T>
public companion object{
public inline fun <reified T : Any> auto(): BufferFactory<T> =
BufferFactory(Buffer.Companion::auto)
public fun <T> boxing(): BufferFactory<T> =
BufferFactory(Buffer.Companion::boxing)
}
} }
/** /**
@ -23,8 +31,16 @@ public fun interface BufferFactory<T> {
* *
* @param T the type of buffer. * @param T the type of buffer.
*/ */
public fun interface MutableBufferFactory<T>: BufferFactory<T>{ public fun interface MutableBufferFactory<T> : BufferFactory<T> {
override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T> override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T>
public companion object {
public inline fun <reified T : Any> auto(): MutableBufferFactory<T> =
MutableBufferFactory(MutableBuffer.Companion::auto)
public fun <T> boxing(): MutableBufferFactory<T> =
MutableBufferFactory(MutableBuffer.Companion::boxing)
}
} }
/** /**

View File

@ -0,0 +1,57 @@
/*
* 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.structures
import kotlin.jvm.JvmInline
/**
* Specialized [MutableBuffer] implementation over [ByteArray].
*
* @property array the underlying array.
*/
@JvmInline
public value class ByteBuffer(public val array: ByteArray) : MutableBuffer<Byte> {
override val size: Int get() = array.size
override operator fun get(index: Int): Byte = array[index]
override operator fun set(index: Int, value: Byte) {
array[index] = value
}
override operator fun iterator(): ByteIterator = array.iterator()
override fun copy(): MutableBuffer<Byte> = ByteBuffer(array.copyOf())
}
/**
* Creates a new [ByteBuffer] with the specified [size], where each element is calculated by calling the specified
* [init] function.
*
* The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for a buffer element given its index.
*/
public inline fun ByteBuffer(size: Int, init: (Int) -> Byte): ByteBuffer = ByteBuffer(ByteArray(size) { init(it) })
/**
* Returns a new [ByteBuffer] of given elements.
*/
public fun ByteBuffer(vararg bytes: Byte): ByteBuffer = ByteBuffer(bytes)
/**
* Returns a new [ByteArray] containing all the elements of this [Buffer].
*/
public fun Buffer<Byte>.toByteArray(): ByteArray = when (this) {
is ByteBuffer -> array.copyOf()
else -> ByteArray(size, ::get)
}
/**
* Returns [ByteBuffer] over this array.
*
* @receiver the array.
* @return the new buffer.
*/
public fun ByteArray.asBuffer(): ByteBuffer = ByteBuffer(this)

View File

@ -22,7 +22,7 @@ internal inline fun diff(
block: DSField<Double, DoubleField>.() -> Unit, block: DSField<Double, DoubleField>.() -> Unit,
) { ) {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
DSField(DoubleField, ::DoubleBuffer, order, mapOf(*parameters)).block() DSField(DoubleField, order, mapOf(*parameters), ::DoubleBuffer).block()
} }
internal class DSTest { internal class DSTest {

View File

@ -21,14 +21,14 @@ public typealias HyperSquareBin<V> = DomainBin<Double, HyperSquareDomain, V>
/** /**
* Multivariate histogram space for hyper-square real-field bins. * Multivariate histogram space for hyper-square real-field bins.
* @param bufferFactory is an optional parameter used to optimize buffer production. * @param valueBufferFactory is an optional parameter used to optimize buffer production.
*/ */
public class UniformHistogramGroupND<V : Any, A : Field<V>>( public class UniformHistogramGroupND<V : Any, A : Field<V>>(
override val valueAlgebraND: FieldOpsND<V, A>, override val valueAlgebraND: FieldOpsND<V, A>,
private val lower: Buffer<Double>, private val lower: Buffer<Double>,
private val upper: Buffer<Double>, private val upper: Buffer<Double>,
private val binNums: IntArray = IntArray(lower.size) { 20 }, private val binNums: IntArray = IntArray(lower.size) { 20 },
private val bufferFactory: BufferFactory<V> = BufferFactory(Buffer.Companion::boxing), private val valueBufferFactory: BufferFactory<V> = valueAlgebraND.elementAlgebra.bufferFactory,
) : HistogramGroupND<Double, HyperSquareDomain, V> { ) : HistogramGroupND<Double, HyperSquareDomain, V> {
init { init {
@ -94,7 +94,7 @@ public class UniformHistogramGroupND<V : Any, A : Field<V>>(
} }
} }
hBuilder.apply(builder) hBuilder.apply(builder)
val values: BufferND<V> = ndCounter.mapToBuffer(bufferFactory) { it.value } val values: BufferND<V> = ndCounter.mapToBuffer(valueBufferFactory) { it.value }
return HistogramND(this, values) return HistogramND(this, values)
} }
@ -114,12 +114,12 @@ public class UniformHistogramGroupND<V : Any, A : Field<V>>(
public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges( public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
valueAlgebraND: FieldOpsND<V, A>, valueAlgebraND: FieldOpsND<V, A>,
vararg ranges: ClosedFloatingPointRange<Double>, vararg ranges: ClosedFloatingPointRange<Double>,
bufferFactory: BufferFactory<V> = BufferFactory(Buffer.Companion::boxing), bufferFactory: BufferFactory<V> = valueAlgebraND.elementAlgebra.bufferFactory,
): UniformHistogramGroupND<V, A> = UniformHistogramGroupND( ): UniformHistogramGroupND<V, A> = UniformHistogramGroupND(
valueAlgebraND, valueAlgebraND,
ranges.map(ClosedFloatingPointRange<Double>::start).asBuffer(), ranges.map(ClosedFloatingPointRange<Double>::start).asBuffer(),
ranges.map(ClosedFloatingPointRange<Double>::endInclusive).asBuffer(), ranges.map(ClosedFloatingPointRange<Double>::endInclusive).asBuffer(),
bufferFactory = bufferFactory valueBufferFactory = bufferFactory
) )
public fun Histogram.Companion.uniformDoubleNDFromRanges( public fun Histogram.Companion.uniformDoubleNDFromRanges(
@ -140,7 +140,7 @@ public fun Histogram.Companion.uniformDoubleNDFromRanges(
public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges( public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
valueAlgebraND: FieldOpsND<V, A>, valueAlgebraND: FieldOpsND<V, A>,
vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>, vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>,
bufferFactory: BufferFactory<V> = BufferFactory(Buffer.Companion::boxing), bufferFactory: BufferFactory<V> = valueAlgebraND.elementAlgebra.bufferFactory,
): UniformHistogramGroupND<V, A> = UniformHistogramGroupND( ): UniformHistogramGroupND<V, A> = UniformHistogramGroupND(
valueAlgebraND, valueAlgebraND,
ListBuffer( ListBuffer(
@ -154,7 +154,7 @@ public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
.map(ClosedFloatingPointRange<Double>::endInclusive) .map(ClosedFloatingPointRange<Double>::endInclusive)
), ),
ranges.map(Pair<ClosedFloatingPointRange<Double>, Int>::second).toIntArray(), ranges.map(Pair<ClosedFloatingPointRange<Double>, Int>::second).toIntArray(),
bufferFactory = bufferFactory valueBufferFactory = bufferFactory
) )
public fun Histogram.Companion.uniformDoubleNDFromRanges( public fun Histogram.Companion.uniformDoubleNDFromRanges(

View File

@ -35,7 +35,7 @@ public fun interface Sampler<out T : Any> {
public fun <T : Any> Sampler<T>.sampleBuffer( public fun <T : Any> Sampler<T>.sampleBuffer(
generator: RandomGenerator, generator: RandomGenerator,
size: Int, size: Int,
bufferFactory: BufferFactory<T> = BufferFactory(Buffer.Companion::boxing), bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
): Chain<Buffer<T>> { ): Chain<Buffer<T>> {
require(size > 1) require(size > 1)
//creating temporary storage once //creating temporary storage once