diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c2e987f0..2163afe94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -201,7 +201,7 @@ - Full autodiff refactoring based on `Symbol` - `kmath-prob` renamed to `kmath-stat` - Grid generators moved to `kmath-for-real` -- Use `Point` instead of specialized type in `kmath-for-real` +- Use `Point` instead of specialized type in `kmath-for-real` - Optimized dot product for buffer matrices moved to `kmath-for-real` - EjmlMatrix context is an object - Matrix LUP `inverse` renamed to `inverseWithLup` diff --git a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index 29d4cde79..6a525dd0a 100644 --- a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -14,6 +14,7 @@ import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Float64 import kotlin.math.sin import kotlin.random.Random import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression @@ -67,7 +68,7 @@ class ExpressionsInterpretersBenchmark { blackhole.consume(sum) } - private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { + private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { val random = Random(0) var sum = 0.0 val m = HashMap() @@ -99,7 +100,7 @@ class ExpressionsInterpretersBenchmark { private val wasm = node.wasmCompileToExpression(Float64Field) private val estree = node.estreeCompileToExpression(Float64Field) - private val raw = Expression { args -> + private val raw = Expression { args -> val x = args.getValue(x) x * 2.0 + 2.0 / x - 16.0 / sin(x) } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index 45b3916dc..1c5ac71e3 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -15,6 +15,7 @@ import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Float64 import kotlin.math.sin import kotlin.random.Random @@ -83,7 +84,7 @@ internal class ExpressionsInterpretersBenchmark { blackhole.consume(sum) } - private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { + private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { val random = Random(0) var sum = 0.0 val m = HashMap() @@ -114,9 +115,9 @@ internal class ExpressionsInterpretersBenchmark { private val asmPrimitive = node.compileToExpression(Float64Field) private val xIdx = asmPrimitive.indexer.indexOf(x) - private val asmGeneric = node.compileToExpression(Float64Field as Algebra) + private val asmGeneric = node.compileToExpression(Float64Field as Algebra) - private val raw = Expression { args -> + private val raw = Expression { args -> val x = args[x]!! x * 2.0 + 2.0 / x - 16.0 / sin(x) } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt index 77ca03099..06089ef2e 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -17,6 +17,7 @@ import space.kscience.kmath.UnsafeKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.nd4j.nd4j import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.one import space.kscience.kmath.tensors.core.tensorAlgebra @@ -37,28 +38,28 @@ internal class NDFieldBenchmark { @Benchmark fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) { - var res: StructureND = one(shape) + var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @Benchmark fun boxingFieldAdd(blackhole: Blackhole) = with(genericField) { - var res: StructureND = one(shape) + var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @Benchmark fun multikAdd(blackhole: Blackhole) = with(multikAlgebra) { - var res: StructureND = one(shape) + var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @Benchmark fun viktorAdd(blackhole: Blackhole) = with(viktorField) { - var res: StructureND = one(shape) + var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -87,7 +88,7 @@ internal class NDFieldBenchmark { // @Benchmark // fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) { -// var res: StructureND = one(dim, dim) +// var res: StructureND = one(dim, dim) // repeat(n) { res += 1.0 } // blackhole.consume(res) // } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index bd5c2006a..21ba472b6 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -15,6 +15,7 @@ import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd.one import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.viktor.ViktorFieldND @State(Scope.Benchmark) @@ -23,7 +24,7 @@ internal class ViktorBenchmark { @Benchmark fun doubleFieldAddition(blackhole: Blackhole) { with(doubleField) { - var res: StructureND = one(shape) + var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } diff --git a/docs/nd-structure.md b/docs/nd-structure.md index 8f2e504db..771cd6048 100644 --- a/docs/nd-structure.md +++ b/docs/nd-structure.md @@ -31,7 +31,7 @@ The code to run this looks like: ```kotlin specializedField.run { - var res: NDBuffer = one + var res: NDBuffer = one repeat(n) { res += 1.0 } @@ -103,7 +103,7 @@ The boxing field produced by ```kotlin genericField.run { - var res: NDBuffer = one + var res: NDBuffer = one repeat(n) { res += 1.0 } diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt index 07bacc45d..d3f6b19c4 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt @@ -14,11 +14,12 @@ import space.kscience.kmath.integration.gaussIntegrator import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.structures.Float64 import kotlin.math.pow fun main() { //Define a function - val function: Function1D = { x -> 3 * x.pow(2) + 2 * x + 1 } + val function: Function1D = { x -> 3 * x.pow(2) + 2 * x + 1 } //get the result of the integration val result = Float64Field.gaussIntegrator.integrate(0.0..10.0, function = function) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt index c2e33afd4..9307e97e2 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.structures.Float64 import space.kscience.plotly.Plotly import space.kscience.plotly.UnstablePlotlyAPI import space.kscience.plotly.makeFile @@ -23,7 +24,7 @@ fun main() { x to sin(x) } - val polynomial: PiecewisePolynomial = SplineInterpolator(Float64Field).interpolatePolynomials(data) + val polynomial: PiecewisePolynomial = SplineInterpolator(Float64Field).interpolatePolynomials(data) val function = polynomial.asFunction(Float64Field, 0.0) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt index 29a40498b..6470ee528 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt @@ -10,6 +10,7 @@ import space.kscience.kmath.interpolation.splineInterpolator import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.real.map import space.kscience.kmath.real.step +import space.kscience.kmath.structures.Float64 import space.kscience.plotly.Plotly import space.kscience.plotly.UnstablePlotlyAPI import space.kscience.plotly.makeFile @@ -18,7 +19,7 @@ import space.kscience.plotly.scatter @OptIn(UnstablePlotlyAPI::class) fun main() { - val function: Function1D = { x -> + val function: Function1D = { x -> if (x in 30.0..50.0) { 1.0 } else { @@ -28,7 +29,7 @@ fun main() { val xs = 0.0..100.0 step 0.5 val ys = xs.map(function) - val polynomial: PiecewisePolynomial = Float64Field.splineInterpolator.interpolatePolynomials(xs, ys) + val polynomial: PiecewisePolynomial = Float64Field.splineInterpolator.interpolatePolynomials(xs, ys) val polyFunction = polynomial.asFunction(Float64Field, 0.0) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt index 0680f42b0..bf9e31c40 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.structureND import space.kscience.kmath.nd.withNdAlgebra import space.kscience.kmath.operations.algebra +import space.kscience.kmath.structures.Float64 import kotlin.math.pow fun main(): Unit = Double.algebra.withNdAlgebra(2, 2) { @@ -22,7 +23,7 @@ fun main(): Unit = Double.algebra.withNdAlgebra(2, 2) { } //Define a function in a nd space - val function: (Double) -> StructureND = { x: Double -> 3 * x.pow(2) + 2 * diagonal(x) + 1 } + val function: (Double) -> StructureND = { x: Double -> 3 * x.pow(2) + 2 * diagonal(x) + 1 } //get the result of the integration val result = gaussIntegrator.integrate(0.0..10.0, function = function) diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt index 6ebd1d221..1d79a2dfd 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt @@ -6,18 +6,19 @@ package space.kscience.kmath.linear import space.kscience.kmath.real.* +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer fun main() { val x0 = DoubleVector(0.0, 0.0, 0.0) val sigma = DoubleVector(1.0, 1.0, 1.0) - val gaussian: (Point) -> Double = { x -> + val gaussian: (Point) -> Double = { x -> require(x.size == x0.size) kotlin.math.exp(-((x - x0) / sigma).square().sum()) } - fun ((Point) -> Double).grad(x: Point): Point { + fun ((Point) -> Double).grad(x: Point): Point { require(x.size == x0.size) return Float64Buffer(x.size) { i -> val h = sigma[i] / 5 diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt index 7af026759..6c87491eb 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.nd.Float64BufferND import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.nd.mutableStructureND import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.viktor.viktorAlgebra import kotlin.collections.component1 import kotlin.collections.component2 @@ -20,7 +21,7 @@ fun main() { if (i == j) 2.0 else 0.0 } - val cmMatrix: Structure2D = CMLinearSpace.matrix(2, 2)(0.0, 1.0, 0.0, 3.0) + val cmMatrix: Structure2D = CMLinearSpace.matrix(2, 2)(0.0, 1.0, 0.0, 3.0) val res: Float64BufferND = Float64Field.ndAlgebra { exp(viktorStructure) + 2.0 * cmMatrix diff --git a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt b/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt index e6d3ef56b..0f475f74e 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt @@ -14,6 +14,7 @@ import space.kscience.kmath.operations.toList import space.kscience.kmath.stat.KMComparisonResult import space.kscience.kmath.stat.ksComparisonStatistic import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.slice import space.kscience.plotly.* import kotlin.math.PI @@ -24,7 +25,7 @@ fun Double.Companion.seriesAlgebra() = Double.algebra.bufferAlgebra.seriesAlgebr fun main() = with(Double.seriesAlgebra()) { - fun Plot.plotSeries(name: String, buffer: Buffer) { + fun Plot.plotSeries(name: String, buffer: Buffer) { scatter { this.name = name x.numbers = buffer.labels @@ -37,10 +38,10 @@ fun main() = with(Double.seriesAlgebra()) { val s2 = s1.slice(20..50).moveTo(40) - val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 + val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 val s4 = s3.map { ln(it) } - val kmTest: KMComparisonResult = ksComparisonStatistic(s1, s2) + val kmTest: KMComparisonResult = ksComparisonStatistic(s1, s2) Plotly.page { h1 { +"This is my plot" } diff --git a/examples/src/main/kotlin/space/kscience/kmath/series/seriesBuilder.kt b/examples/src/main/kotlin/space/kscience/kmath/series/seriesBuilder.kt index 9dfb0fdc9..43e90b53a 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/series/seriesBuilder.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/series/seriesBuilder.kt @@ -6,10 +6,7 @@ package space.kscience.kmath.series -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.Float64Buffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.toDoubleArray +import space.kscience.kmath.structures.* import space.kscience.plotly.* import space.kscience.plotly.models.Scatter import space.kscience.plotly.models.ScatterMode @@ -22,7 +19,7 @@ fun main(): Unit = with(Double.seriesAlgebra()) { val arrayOfRandoms = DoubleArray(20) { random.nextDouble() } val series1: Float64Buffer = arrayOfRandoms.asBuffer() - val series2: Series = series1.moveBy(3) + val series2: Series = series1.moveBy(3) val res = series2 - series1 @@ -30,7 +27,7 @@ fun main(): Unit = with(Double.seriesAlgebra()) { println(res) - fun Plot.series(name: String, buffer: Buffer, block: Scatter.() -> Unit = {}) { + fun Plot.series(name: String, buffer: Buffer, block: Scatter.() -> Unit = {}) { scatter { this.name = name x.numbers = buffer.offsetIndices diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt index 19b763113..89a1cdc28 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt @@ -37,7 +37,7 @@ private suspend fun runKMathChained(): Duration { } private fun runCMDirect(): Duration { - val rng = RandomSource.create(RandomSource.MT, 123L) + val rng = RandomSource.MT.create(123L) val sampler = CMGaussianSampler.of( BoxMullerNormalizedGaussianSampler.of(rng), diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt index 2f8e9d959..e9a988b35 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt @@ -10,13 +10,14 @@ import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.combineWithState import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.structures.Float64 private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0) /** * Averaging. */ -private fun Chain.mean(): Chain = combineWithState(AveragingChainState(), { it.copy() }) { chain -> +private fun Chain.mean(): Chain = combineWithState(AveragingChainState(), { it.copy() }) { chain -> val next = chain.next() num++ value += next diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt index 9b48e44a0..50b3ece1f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt @@ -26,7 +26,7 @@ fun main() { val realTime = measureTimeMillis { realField { - var res: StructureND = one + var res: StructureND = one repeat(n) { res += 1.0 } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt index 9ec8719ad..2c65c2287 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -45,35 +45,35 @@ fun main() { measureAndPrint("Boxing addition") { genericField { - var res: StructureND = one(shape) + var res: StructureND = one(shape) repeat(n) { res += 1.0 } } } measureAndPrint("Specialized addition") { doubleField { - var res: StructureND = one(shape) + var res: StructureND = one(shape) repeat(n) { res += 1.0 } } } measureAndPrint("Nd4j specialized addition") { nd4jField { - var res: StructureND = one(shape) + var res: StructureND = one(shape) repeat(n) { res += 1.0 } } } measureAndPrint("Viktor addition") { viktorField { - var res: StructureND = one + var res: StructureND = one repeat(n) { res += 1.0 } } } measureAndPrint("Parallel stream addition") { parallelField { - var res: StructureND = one + var res: StructureND = one repeat(n) { res += 1.0 } } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt index 1171231ab..2835a9bc9 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -19,21 +19,21 @@ import java.util.stream.IntStream * execution. */ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND, - NumbersAddOps>, - ExtendedField> { + NumbersAddOps>, + ExtendedField> { private val strides = ColumnStrides(shape) override val elementAlgebra: Float64Field get() = Float64Field - override val zero: BufferND by lazy { structureND(shape) { zero } } - override val one: BufferND by lazy { structureND(shape) { one } } + override val zero: BufferND by lazy { structureND(shape) { zero } } + override val one: BufferND by lazy { structureND(shape) { one } } - override fun number(value: Number): BufferND { + override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions return structureND(shape) { d } } @OptIn(PerformancePitfall::class) - private val StructureND.buffer: Float64Buffer + private val StructureND.buffer: Float64Buffer get() = when { shape != this@StreamDoubleFieldND.shape -> throw ShapeMismatchException( this@StreamDoubleFieldND.shape, @@ -44,7 +44,7 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND Float64Buffer(strides.linearSize) { offset -> get(strides.index(offset)) } } - override fun structureND(shape: ShapeND, initializer: Float64Field.(IntArray) -> Double): BufferND { + override fun structureND(shape: ShapeND, initializer: Float64Field.(IntArray) -> Double): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> val index = strides.index(offset) Float64Field.initializer(index) @@ -56,7 +56,7 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND Double, - ): MutableBufferND { + ): MutableBufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> val index = strides.index(offset) DoubleField.initializer(index) @@ -66,17 +66,17 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND.map( + override fun StructureND.map( transform: Float64Field.(Double) -> Double, - ): BufferND { + ): BufferND { val array = Arrays.stream(buffer.array).parallel().map { Float64Field.transform(it) }.toArray() return BufferND(strides, array.asBuffer()) } @OptIn(PerformancePitfall::class) - override fun StructureND.mapIndexed( + override fun StructureND.mapIndexed( transform: Float64Field.(index: IntArray, Double) -> Double, - ): BufferND { + ): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> Float64Field.transform( strides.index(offset), @@ -89,39 +89,39 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND, - right: StructureND, + left: StructureND, + right: StructureND, transform: Float64Field.(Double, Double) -> Double, - ): BufferND { + ): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> Float64Field.transform(left.buffer.array[offset], right.buffer.array[offset]) }.toArray() return BufferND(strides, array.asBuffer()) } - override fun StructureND.unaryMinus(): StructureND = map { -it } + override fun StructureND.unaryMinus(): StructureND = map { -it } - override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } + override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } - override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } + override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } - override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } + override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } + override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } + override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } + override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } + override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } + override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } + override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } + override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } - override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } + override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } + override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } + override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } + override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } + override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } + override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } } fun Float64Field.ndStreaming(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(ShapeND(shape)) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/mutableNd.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/mutableNd.kt index 0b0a4cac1..fdabfcdb1 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/mutableNd.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/mutableNd.kt @@ -11,7 +11,7 @@ import space.kscience.kmath.operations.algebra @OptIn(PerformancePitfall::class) fun main(): Unit = with(Double.algebra.ndAlgebra) { - val structure: MutableStructure2D = mutableStructureND(ShapeND(2, 2)) { (i, j) -> + val structure: MutableStructure2D = mutableStructureND(ShapeND(2, 2)) { (i, j) -> i.toDouble() + j.toDouble() }.as2D() diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamLm.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamLm.kt index dca7325ce..b90b6895f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamLm.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamLm.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.component1 +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.tensors.LevenbergMarquardt.StartDataLm import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.zeros import space.kscience.kmath.tensors.core.DoubleTensorAlgebra @@ -20,9 +21,9 @@ import space.kscience.kmath.tensors.core.levenbergMarquardt import kotlin.random.Random fun streamLm( - lm_func: (MutableStructure2D, MutableStructure2D, Int) -> (MutableStructure2D), + lm_func: (MutableStructure2D, MutableStructure2D, Int) -> (MutableStructure2D), startData: StartDataLm, launchFrequencyInMs: Long, numberOfLaunches: Int, -): Flow> = flow { +): Flow> = flow { var example_number = startData.example_number var p_init = startData.p_init @@ -64,7 +65,7 @@ fun streamLm( } } -fun generateNewYDat(y_dat: MutableStructure2D, delta: Double): MutableStructure2D { +fun generateNewYDat(y_dat: MutableStructure2D, delta: Double): MutableStructure2D { val n = y_dat.shape.component1() val y_dat_new = zeros(ShapeND(intArrayOf(n, 1))).as2D() for (i in 0 until n) { diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/functionsToOptimize.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/functionsToOptimize.kt index 9a4b613b2..9f25a2bc5 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/functionsToOptimize.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/functionsToOptimize.kt @@ -9,6 +9,7 @@ import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.component1 +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.div import space.kscience.kmath.tensors.core.DoubleTensorAlgebra @@ -19,24 +20,24 @@ import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.times import space.kscience.kmath.tensors.core.asDoubleTensor public data class StartDataLm( - var lm_matx_y_dat: MutableStructure2D, + var lm_matx_y_dat: MutableStructure2D, var example_number: Int, - var p_init: MutableStructure2D, - var t: MutableStructure2D, - var y_dat: MutableStructure2D, + var p_init: MutableStructure2D, + var t: MutableStructure2D, + var y_dat: MutableStructure2D, var weight: Double, - var dp: MutableStructure2D, - var p_min: MutableStructure2D, - var p_max: MutableStructure2D, - var consts: MutableStructure2D, + var dp: MutableStructure2D, + var p_min: MutableStructure2D, + var p_max: MutableStructure2D, + var consts: MutableStructure2D, var opts: DoubleArray, ) fun funcEasyForLm( - t: MutableStructure2D, - p: MutableStructure2D, + t: MutableStructure2D, + p: MutableStructure2D, exampleNumber: Int, -): MutableStructure2D { +): MutableStructure2D { val m = t.shape.component1() var y_hat = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(m, 1))) @@ -59,10 +60,10 @@ fun funcEasyForLm( } fun funcMiddleForLm( - t: MutableStructure2D, - p: MutableStructure2D, + t: MutableStructure2D, + p: MutableStructure2D, exampleNumber: Int, -): MutableStructure2D { +): MutableStructure2D { val m = t.shape.component1() var y_hat = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(m, 1))) @@ -79,10 +80,10 @@ fun funcMiddleForLm( } fun funcDifficultForLm( - t: MutableStructure2D, - p: MutableStructure2D, + t: MutableStructure2D, + p: MutableStructure2D, exampleNumber: Int, -): MutableStructure2D { +): MutableStructure2D { val m = t.shape.component1() var y_hat = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(m, 1))) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt index f8bf65ad7..bc1a493f0 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt @@ -10,12 +10,13 @@ import org.jetbrains.kotlinx.multik.api.ndarray import org.jetbrains.kotlinx.multik.default.DefaultEngine import space.kscience.kmath.multik.MultikDoubleAlgebra import space.kscience.kmath.nd.one +import space.kscience.kmath.structures.Float64 val multikAlgebra = MultikDoubleAlgebra(DefaultEngine()) fun main(): Unit = with(multikAlgebra) { - val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType().wrap() + val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType().wrap() val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)).wrap() one(a.shape) - a + b * 3.0 } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt index 74fd4b56c..dfced7f14 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt @@ -9,6 +9,7 @@ import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Int32Ring import space.kscience.kmath.operations.Int8Ring import space.kscience.kmath.operations.pi +import space.kscience.kmath.structures.Float64 import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.fail @@ -41,7 +42,7 @@ internal class TestFolding { @Test fun foldSymbol() = assertEquals( Float64Field.pi, - ("pi".parseMath().evaluateConstants(Float64Field) as? TypedMst.Constant ?: fail()).value, + ("pi".parseMath().evaluateConstants(Float64Field) as? TypedMst.Constant ?: fail()).value, ) @Test diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt index ee2346b13..59239cf24 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -10,12 +10,13 @@ import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Int32Ring +import space.kscience.kmath.structures.Float64 internal interface CompilerTestContext { fun MST.compileToExpression(algebra: Int32Ring): Expression fun MST.compile(algebra: Int32Ring, arguments: Map): Int fun MST.compile(algebra: Int32Ring, vararg arguments: Pair): Int = compile(algebra, mapOf(*arguments)) - fun MST.compileToExpression(algebra: Float64Field): Expression + fun MST.compileToExpression(algebra: Float64Field): Expression fun MST.compile(algebra: Float64Field, arguments: Map): Double fun MST.compile(algebra: Float64Field, vararg arguments: Pair): Double = diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt index 18ef35c4b..5a12ccb8f 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.expressions.* import space.kscience.kmath.internal.binaryen.* import space.kscience.kmath.internal.webassembly.Instance import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.internal.binaryen.Module as BinaryenModule import space.kscience.kmath.internal.webassembly.Module as WasmModule @@ -85,13 +86,13 @@ internal sealed class WasmBuilder>( } @UnstableKMathAPI -internal class DoubleWasmBuilder(target: TypedMst) : +internal class DoubleWasmBuilder(target: TypedMst) : WasmBuilder(f64, Float64Field, target) { override val instance by lazy { object : DoubleExpression { override val indexer = SimpleSymbolIndexer(keys) - override fun invoke(arguments: DoubleArray) = spreader(executable, arguments).unsafeCast() + override fun invoke(arguments: DoubleArray) = spreader(executable, arguments).unsafeCast() } } @@ -99,7 +100,7 @@ internal class DoubleWasmBuilder(target: TypedMst) : override fun visitNumber(number: Number) = ctx.f64.const(number.toDouble()) - override fun visitUnary(node: TypedMst.Unary): ExpressionRef = when (node.operation) { + override fun visitUnary(node: TypedMst.Unary): ExpressionRef = when (node.operation) { GroupOps.MINUS_OPERATION -> ctx.f64.neg(visit(node.value)) GroupOps.PLUS_OPERATION -> visit(node.value) PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(node.value)) @@ -120,7 +121,7 @@ internal class DoubleWasmBuilder(target: TypedMst) : else -> super.visitUnary(node) } - override fun visitBinary(mst: TypedMst.Binary): ExpressionRef = when (mst.operation) { + override fun visitBinary(mst: TypedMst.Binary): ExpressionRef = when (mst.operation) { GroupOps.PLUS_OPERATION -> ctx.f64.add(visit(mst.left), visit(mst.right)) GroupOps.MINUS_OPERATION -> ctx.f64.sub(visit(mst.left), visit(mst.right)) RingOps.TIMES_OPERATION -> ctx.f64.mul(visit(mst.left), visit(mst.right)) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt index ceb1ad69d..26e6a2486 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt @@ -13,6 +13,7 @@ import space.kscience.kmath.ast.evaluateConstants import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Int32Ring +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.wasm.internal.DoubleWasmBuilder import space.kscience.kmath.wasm.internal.IntWasmBuilder @@ -58,7 +59,7 @@ public fun MST.compile(algebra: Int32Ring, vararg arguments: Pair): * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: Float64Field): Expression { +public fun MST.compileToExpression(algebra: Float64Field): Expression { val typed = evaluateConstants(algebra) return if (typed is TypedMst.Constant) object : DoubleExpression { diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt index c747adc0c..dab84e94f 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -13,6 +13,7 @@ import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Int32Ring +import space.kscience.kmath.structures.Float64 import kotlin.contracts.InvocationKind import kotlin.contracts.contract import space.kscience.kmath.estree.compile as estreeCompile @@ -24,7 +25,7 @@ import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression private object WasmCompilerTestContext : CompilerTestContext { override fun MST.compileToExpression(algebra: Int32Ring): Expression = wasmCompileToExpression(algebra) override fun MST.compile(algebra: Int32Ring, arguments: Map): Int = wasmCompile(algebra, arguments) - override fun MST.compileToExpression(algebra: Float64Field): Expression = wasmCompileToExpression(algebra) + override fun MST.compileToExpression(algebra: Float64Field): Expression = wasmCompileToExpression(algebra) override fun MST.compile(algebra: Float64Field, arguments: Map): Double = wasmCompile(algebra, arguments) @@ -33,7 +34,7 @@ private object WasmCompilerTestContext : CompilerTestContext { private object ESTreeCompilerTestContext : CompilerTestContext { override fun MST.compileToExpression(algebra: Int32Ring): Expression = estreeCompileToExpression(algebra) override fun MST.compile(algebra: Int32Ring, arguments: Map): Int = estreeCompile(algebra, arguments) - override fun MST.compileToExpression(algebra: Float64Field): Expression = estreeCompileToExpression(algebra) + override fun MST.compileToExpression(algebra: Float64Field): Expression = estreeCompileToExpression(algebra) override fun MST.compile(algebra: Float64Field, arguments: Map): Double = estreeCompile(algebra, arguments) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt index 3f003bb09..ed0f361af 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt @@ -15,6 +15,7 @@ import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Float64 import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType import java.nio.file.Paths @@ -381,7 +382,7 @@ internal sealed class PrimitiveAsmBuilder>( } @UnstableKMathAPI -internal class DoubleAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder( +internal class DoubleAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder( Float64Field, java.lang.Double::class.java, java.lang.Double.TYPE, @@ -410,7 +411,7 @@ internal class DoubleAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder< false, ) - override fun visitUnary(node: TypedMst.Unary) { + override fun visitUnary(node: TypedMst.Unary) { super.visitUnary(node) when (node.operation) { @@ -435,7 +436,7 @@ internal class DoubleAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder< } } - override fun visitBinary(node: TypedMst.Binary) { + override fun visitBinary(node: TypedMst.Binary) { super.visitBinary(node) when (node.operation) { diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt index b48a8fdba..2c800f4ef 100644 --- a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Int32Ring +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.asm.compile as asmCompile import space.kscience.kmath.asm.compileToExpression as asmCompileToExpression @@ -22,18 +23,18 @@ private object GenericAsmCompilerTestContext : CompilerTestContext { override fun MST.compile(algebra: Int32Ring, arguments: Map): Int = asmCompile(algebra as Algebra, arguments) - override fun MST.compileToExpression(algebra: Float64Field): Expression = - asmCompileToExpression(algebra as Algebra) + override fun MST.compileToExpression(algebra: Float64Field): Expression = + asmCompileToExpression(algebra as Algebra) override fun MST.compile(algebra: Float64Field, arguments: Map): Double = - asmCompile(algebra as Algebra, arguments) + asmCompile(algebra as Algebra, arguments) } @OptIn(UnstableKMathAPI::class) private object PrimitiveAsmCompilerTestContext : CompilerTestContext { override fun MST.compileToExpression(algebra: Int32Ring): Expression = asmCompileToExpression(algebra) override fun MST.compile(algebra: Int32Ring, arguments: Map): Int = asmCompile(algebra, arguments) - override fun MST.compileToExpression(algebra: Float64Field): Expression = asmCompileToExpression(algebra) + override fun MST.compileToExpression(algebra: Float64Field): Expression = asmCompileToExpression(algebra) override fun MST.compile(algebra: Float64Field, arguments: Map): Double = asmCompile(algebra, arguments) diff --git a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt index 855de14a0..65e01e2d5 100644 --- a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt +++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt @@ -14,6 +14,7 @@ import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBufferFactory /** @@ -132,9 +133,9 @@ public object CmDsProcessor : AutoDiffProcessor DerivativeStructure, -) : DifferentiableExpression { +) : DifferentiableExpression { - override val type: SafeType get() = DoubleField.type + override val type: SafeType get() = DoubleField.type override operator fun invoke(arguments: Map): Double = CmDsField(0, arguments).function().value @@ -142,7 +143,7 @@ public class CmDsExpression( /** * Get the derivative expression with given orders */ - override fun derivativeOrNull(symbols: List): Expression = Expression(type) { arguments -> + override fun derivativeOrNull(symbols: List): Expression = Expression(type) { arguments -> with(CmDsField(symbols.size, arguments)) { function().derivative(symbols) } } } diff --git a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt index b4680bace..9791539f9 100644 --- a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt +++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.commons.integration import org.apache.commons.math3.analysis.integration.gauss.GaussIntegrator import org.apache.commons.math3.analysis.integration.gauss.GaussIntegratorFactory import space.kscience.kmath.integration.* +import space.kscience.kmath.structures.Float64 /** * A simple one-pass integrator based on Gauss rule @@ -14,9 +15,9 @@ import space.kscience.kmath.integration.* public class CMGaussRuleIntegrator( private val numpoints: Int, private var type: GaussRule = GaussRule.LEGENDRE, -) : UnivariateIntegrator { +) : UnivariateIntegrator { - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val range = integrand[IntegrationRange] ?: error("Integration range is not provided") val integrator: GaussIntegrator = getIntegrator(range) @@ -28,7 +29,7 @@ public class CMGaussRuleIntegrator( } } - private fun getIntegrator(range: ClosedRange): GaussIntegrator { + private fun getIntegrator(range: ClosedRange): GaussIntegrator { return when (type) { GaussRule.LEGENDRE -> factory.legendre( numpoints, @@ -77,7 +78,7 @@ public class CMGaussRuleIntegrator( private val factory: GaussIntegratorFactory = GaussIntegratorFactory() public fun integrate( - range: ClosedRange, + range: ClosedRange, numPoints: Int = 100, type: GaussRule = GaussRule.LEGENDRE, function: (Double) -> Double, diff --git a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt index 83880287e..e37eed06d 100644 --- a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt +++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt @@ -10,6 +10,7 @@ import org.apache.commons.math3.analysis.integration.SimpsonIntegrator import space.kscience.attributes.Attributes import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.integration.* +import space.kscience.kmath.structures.Float64 import org.apache.commons.math3.analysis.integration.UnivariateIntegrator as CMUnivariateIntegrator /** @@ -17,10 +18,10 @@ import org.apache.commons.math3.analysis.integration.UnivariateIntegrator as CMU */ public class CMIntegrator( private val defaultMaxCalls: Int = 200, - public val integratorBuilder: (Integrand) -> CMUnivariateIntegrator, -) : UnivariateIntegrator { + public val integratorBuilder: (Integrand) -> CMUnivariateIntegrator, +) : UnivariateIntegrator { - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val integrator = integratorBuilder(integrand) val maxCalls = integrand[IntegrandMaxCalls] ?: defaultMaxCalls val remainingCalls = maxCalls - integrand.calls diff --git a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt index 1fe923cbb..d7470be56 100644 --- a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt +++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt @@ -12,6 +12,7 @@ import space.kscience.attributes.SafeType import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.* import space.kscience.kmath.linear.CholeskyDecomposition +import space.kscience.kmath.linear.EigenDecomposition import space.kscience.kmath.linear.QRDecomposition import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.nd.StructureAttribute @@ -22,7 +23,7 @@ import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.IntBuffer import space.kscience.kmath.structures.asBuffer -public class CMMatrix(public val origin: RealMatrix) : Matrix { +public class CMMatrix(public val origin: RealMatrix) : Matrix { override val rowNum: Int get() = origin.rowDimension override val colNum: Int get() = origin.columnDimension @@ -31,12 +32,12 @@ public class CMMatrix(public val origin: RealMatrix) : Matrix { } @JvmInline -public value class CMVector(public val origin: RealVector) : Point { +public value class CMVector(public val origin: RealVector) : Point { override val size: Int get() = origin.dimension override operator fun get(index: Int): Double = origin.getEntry(index) - override operator fun iterator(): Iterator = origin.toArray().iterator() + override operator fun iterator(): Iterator = origin.toArray().iterator() override fun toString(): String = Buffer.toString(this) } @@ -46,7 +47,7 @@ public fun RealVector.toPoint(): CMVector = CMVector(this) public object CMLinearSpace : LinearSpace { override val elementAlgebra: Float64Field get() = Float64Field - override val type: SafeType get() = DoubleField.type + override val type: SafeType get() = DoubleField.type override fun buildMatrix( rows: Int, @@ -58,7 +59,7 @@ public object CMLinearSpace : LinearSpace { } @OptIn(UnstableKMathAPI::class) - public fun Matrix.toCM(): CMMatrix = when (val matrix = origin) { + public fun Matrix.toCM(): CMMatrix = when (val matrix = origin) { is CMMatrix -> matrix else -> { //TODO add feature analysis @@ -67,7 +68,7 @@ public object CMLinearSpace : LinearSpace { } } - public fun Point.toCM(): CMVector = if (this is CMVector) this else { + public fun Point.toCM(): CMVector = if (this is CMVector) this else { val array = DoubleArray(size) { this[it] } ArrayRealVector(array).wrap() } @@ -75,40 +76,40 @@ public object CMLinearSpace : LinearSpace { internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this) internal fun RealVector.wrap(): CMVector = CMVector(this) - override fun buildVector(size: Int, initializer: Float64Field.(Int) -> Double): Point = + override fun buildVector(size: Int, initializer: Float64Field.(Int) -> Double): Point = ArrayRealVector(DoubleArray(size) { Float64Field.initializer(it) }).wrap() - override fun Matrix.plus(other: Matrix): CMMatrix = + override fun Matrix.plus(other: Matrix): CMMatrix = toCM().origin.add(other.toCM().origin).wrap() - override fun Point.plus(other: Point): CMVector = + override fun Point.plus(other: Point): CMVector = toCM().origin.add(other.toCM().origin).wrap() - override fun Point.minus(other: Point): CMVector = + override fun Point.minus(other: Point): CMVector = toCM().origin.subtract(other.toCM().origin).wrap() - override fun Matrix.dot(other: Matrix): CMMatrix = + override fun Matrix.dot(other: Matrix): CMMatrix = toCM().origin.multiply(other.toCM().origin).wrap() - override fun Matrix.dot(vector: Point): CMVector = + override fun Matrix.dot(vector: Point): CMVector = toCM().origin.preMultiply(vector.toCM().origin).wrap() - override operator fun Matrix.minus(other: Matrix): CMMatrix = + override operator fun Matrix.minus(other: Matrix): CMMatrix = toCM().origin.subtract(other.toCM().origin).wrap() - override operator fun Matrix.times(value: Double): CMMatrix = + override operator fun Matrix.times(value: Double): CMMatrix = toCM().origin.scalarMultiply(value).wrap() - override fun Double.times(m: Matrix): CMMatrix = + override fun Double.times(m: Matrix): CMMatrix = m * this - override fun Point.times(value: Double): CMVector = + override fun Point.times(value: Double): CMVector = toCM().origin.mapMultiply(value).wrap() - override fun Double.times(v: Point): CMVector = + override fun Double.times(v: Point): CMVector = v * this - override fun > computeAttribute(structure: Structure2D, attribute: A): V? { + override fun > computeAttribute(structure: Structure2D, attribute: A): V? { val origin = structure.toCM().origin @@ -125,7 +126,7 @@ public object CMLinearSpace : LinearSpace { Cholesky -> object : CholeskyDecomposition { val cmCholesky by lazy { org.apache.commons.math3.linear.CholeskyDecomposition(origin) } - override val l: Matrix get() = cmCholesky.l.wrap() + override val l: Matrix get() = cmCholesky.l.wrap() } QR -> object : QRDecomposition { @@ -144,6 +145,13 @@ public object CMLinearSpace : LinearSpace { } + EIG -> object : EigenDecomposition { + val cmEigen by lazy { org.apache.commons.math3.linear.EigenDecomposition(origin) } + + override val v: Matrix get() = cmEigen.v.wrap() + override val d: Matrix get() = cmEigen.d.wrap() + } + else -> null } @Suppress("UNCHECKED_CAST") diff --git a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt index 0c15d1016..ec12de1f2 100644 --- a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt +++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt @@ -9,6 +9,7 @@ import org.apache.commons.math3.linear.* import space.kscience.kmath.linear.LinearSolver import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.Point +import space.kscience.kmath.structures.Float64 public enum class CMDecomposition { LUP, @@ -19,7 +20,7 @@ public enum class CMDecomposition { } private fun CMLinearSpace.solver( - a: Matrix, + a: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP, ): DecompositionSolver = when (decomposition) { CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver @@ -30,31 +31,31 @@ private fun CMLinearSpace.solver( } public fun CMLinearSpace.solve( - a: Matrix, - b: Matrix, + a: Matrix, + b: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP, ): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap() public fun CMLinearSpace.solve( - a: Matrix, - b: Point, + a: Matrix, + b: Point, decomposition: CMDecomposition = CMDecomposition.LUP, ): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint() public fun CMLinearSpace.inverse( - a: Matrix, + a: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP, ): CMMatrix = solver(a, decomposition).inverse.wrap() -public fun CMLinearSpace.solver(decomposition: CMDecomposition): LinearSolver = object : LinearSolver { - override fun solve(a: Matrix, b: Matrix): Matrix = +public fun CMLinearSpace.solver(decomposition: CMDecomposition): LinearSolver = object : LinearSolver { + override fun solve(a: Matrix, b: Matrix): Matrix = solver(a, decomposition).solve(b.toCM().origin).wrap() - override fun solve(a: Matrix, b: Point): Point = + override fun solve(a: Matrix, b: Point): Point = solver(a, decomposition).solve(b.toCM().origin).toPoint() - override fun inverse(matrix: Matrix): Matrix = solver(matrix, decomposition).inverse.wrap() + override fun inverse(matrix: Matrix): Matrix = solver(matrix, decomposition).inverse.wrap() } -public fun CMLinearSpace.lupSolver(): LinearSolver = solver((CMDecomposition.LUP)) \ No newline at end of file +public fun CMLinearSpace.lupSolver(): LinearSolver = solver((CMDecomposition.LUP)) \ No newline at end of file diff --git a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt index 4030e630f..db4b3b733 100644 --- a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt +++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt @@ -22,6 +22,7 @@ import space.kscience.kmath.expressions.SymbolIndexer import space.kscience.kmath.expressions.derivative import space.kscience.kmath.expressions.withSymbols import space.kscience.kmath.optimization.* +import space.kscience.kmath.structures.Float64 import kotlin.collections.set import kotlin.reflect.KClass @@ -33,7 +34,7 @@ public object CMOptimizerEngine : OptimizationAttribute<() -> MultivariateOptimi /** * Specify a Commons-maths optimization engine */ -public fun AttributesBuilder>.cmEngine(optimizerBuilder: () -> MultivariateOptimizer) { +public fun AttributesBuilder>.cmEngine(optimizerBuilder: () -> MultivariateOptimizer) { set(CMOptimizerEngine, optimizerBuilder) } @@ -42,18 +43,18 @@ public object CMOptimizerData : SetAttribute OptimizationDat /** * Specify Commons-maths optimization data. */ -public fun AttributesBuilder>.cmOptimizationData(data: SymbolIndexer.() -> OptimizationData) { +public fun AttributesBuilder>.cmOptimizationData(data: SymbolIndexer.() -> OptimizationData) { CMOptimizerData add data } -public fun AttributesBuilder>.simplexSteps(vararg steps: Pair) { +public fun AttributesBuilder>.simplexSteps(vararg steps: Pair) { //TODO use convergence checker from features cmEngine { SimplexOptimizer(CMOptimizer.defaultConvergenceChecker) } cmOptimizationData { NelderMeadSimplex(mapOf(*steps).toDoubleArray()) } } @OptIn(UnstableKMathAPI::class) -public object CMOptimizer : Optimizer> { +public object CMOptimizer : Optimizer> { public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 @@ -67,12 +68,12 @@ public object CMOptimizer : Optimizer> { override suspend fun optimize( - problem: FunctionOptimization, - ): FunctionOptimization { + problem: FunctionOptimization, + ): FunctionOptimization { val startPoint = problem.startPoint val parameters = problem.attributes[OptimizationParameters] - ?: problem.attributes[OptimizationStartPoint()]?.keys + ?: problem.attributes[OptimizationStartPoint()]?.keys ?: startPoint.keys diff --git a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/transform/Transformations.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/transform/Transformations.kt index 838ab95d5..a274e518a 100644 --- a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/transform/Transformations.kt +++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/transform/Transformations.kt @@ -77,7 +77,7 @@ public fun Flow>.fft( } @JvmName("realFFT") -public fun Flow>.fft( +public fun Flow>.fft( normalization: DftNormalization = DftNormalization.STANDARD, direction: TransformType = TransformType.FORWARD, ): Flow> { @@ -89,7 +89,7 @@ public fun Flow>.fft( * Process a continuous flow of real numbers in FFT splitting it in chunks of [bufferSize]. */ @JvmName("realFFT") -public fun Flow.fft( +public fun Flow.fft( bufferSize: Int = Int.MAX_VALUE, normalization: DftNormalization = DftNormalization.STANDARD, direction: TransformType = TransformType.FORWARD, @@ -99,4 +99,4 @@ public fun Flow.fft( * Map a complex flow into real flow by taking real part of each number */ @FlowPreview -public fun Flow.real(): Flow = map { it.re } +public fun Flow.real(): Flow = map { it.re } diff --git a/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt b/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt index 8b314cf1a..2fe7b85e7 100644 --- a/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt +++ b/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt @@ -18,6 +18,7 @@ import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.optimization.* import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.stat.chiSquaredExpression +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.asBuffer import kotlin.test.Test @@ -70,7 +71,7 @@ internal class OptimizeTest { bindSymbol(a) * arg.pow(2) + bindSymbol(b) * arg + cWithDefault } - val result: FunctionOptimization = chi2.optimizeWith( + val result: FunctionOptimization = chi2.optimizeWith( CMOptimizer, mapOf(a to 1.5, b to 0.9, c to 1.0), ) { diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt index 6a6171975..a8f83d7ed 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.memory.* import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableBufferFactory import kotlin.math.* @@ -28,7 +29,7 @@ public class Quaternion( public val x: Double, public val y: Double, public val z: Double, -) : Buffer { +) : Buffer { init { require(!w.isNaN()) { "w-component of quaternion is not-a-number" } require(!x.isNaN()) { "x-component of quaternion is not-a-number" } @@ -51,7 +52,7 @@ public class Quaternion( else -> error("Index $index out of bounds [0,3]") } - override fun iterator(): Iterator = listOf(w, x, y, z).iterator() + override fun iterator(): Iterator = listOf(w, x, y, z).iterator() override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt index 79f446f6d..62d97f7b7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.domains import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point +import space.kscience.kmath.structures.Float64 @UnstableKMathAPI public abstract class Domain1D>(public val range: ClosedRange) : Domain { @@ -22,8 +23,8 @@ public abstract class Domain1D>(public val range: ClosedRange< @UnstableKMathAPI public class DoubleDomain1D( - @Suppress("CanBeParameter") public val doubleRange: ClosedFloatingPointRange, -) : Domain1D(doubleRange), Float64Domain { + @Suppress("CanBeParameter") public val doubleRange: ClosedFloatingPointRange, +) : Domain1D(doubleRange), Float64Domain { override fun getLowerBound(num: Int): Double { require(num == 0) return range.start @@ -55,5 +56,5 @@ public class DoubleDomain1D( } @UnstableKMathAPI -public val Domain1D.center: Double +public val Domain1D.center: Double get() = (range.endInclusive + range.start) / 2 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Float64Domain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Float64Domain.kt index a522381e1..ee5c1cff6 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Float64Domain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Float64Domain.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.domains import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.structures.Float64 /** * n-dimensional volume @@ -12,7 +13,7 @@ import space.kscience.kmath.UnstableKMathAPI * @author Alexander Nozik */ @UnstableKMathAPI -public interface Float64Domain : Domain { +public interface Float64Domain : Domain { /** * Global lower edge * @param num axis number diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt index 16dae5699..95e9fea19 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.domains import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.indices @@ -15,7 +16,7 @@ import space.kscience.kmath.structures.indices * and a [Buffer] of upper boundaries. Upper should be greater or equals than lower. */ @UnstableKMathAPI -public class HyperSquareDomain(public val lower: Buffer, public val upper: Buffer) : Float64Domain { +public class HyperSquareDomain(public val lower: Buffer, public val upper: Buffer) : Float64Domain { init { require(lower.size == upper.size) { "Domain borders size mismatch. Lower borders size is ${lower.size}, but upper borders size is ${upper.size}." @@ -29,7 +30,7 @@ public class HyperSquareDomain(public val lower: Buffer, public val uppe public val center: Float64Buffer get() = Float64Buffer(dimension) { (lower[it] + upper[it]) / 2.0 } - override operator fun contains(point: Point): Boolean = point.indices.all { i -> + override operator fun contains(point: Point): Boolean = point.indices.all { i -> point[i] in lower[i]..upper[i] } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt index f651dcde3..535606a29 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt @@ -6,10 +6,11 @@ package space.kscience.kmath.domains import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point +import space.kscience.kmath.structures.Float64 @UnstableKMathAPI public class UnconstrainedDomain(override val dimension: Int) : Float64Domain { - override operator fun contains(point: Point): Boolean = true + override operator fun contains(point: Point): Boolean = true override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt index f2e134963..1cc3b766b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt @@ -13,6 +13,7 @@ import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing import space.kscience.kmath.operations.LongRing +import space.kscience.kmath.structures.Float64 import kotlin.jvm.JvmName import kotlin.properties.ReadOnlyProperty @@ -47,9 +48,9 @@ public inline fun Expression(noinline block: (Map) -> T): * Specialization of [Expression] for [Double] allowing better performance because of using array. */ @UnstableKMathAPI -public interface DoubleExpression : Expression { +public interface DoubleExpression : Expression { - override val type: SafeType get() = DoubleField.type + override val type: SafeType get() = DoubleField.type /** * The indexer of this expression's arguments that should be used to build array for [invoke]. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 8ec69c6de..5b6b1083e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBufferFactory import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -197,5 +198,5 @@ public inline fun > A.expressionInExtendedField( ): Expression = FunctionalExpressionExtendedField(this).block() public inline fun Float64Field.expression( - block: FunctionalExpressionExtendedField.() -> Expression, -): Expression = FunctionalExpressionExtendedField(this).block() + block: FunctionalExpressionExtendedField.() -> Expression, +): Expression = FunctionalExpressionExtendedField(this).block() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/EigenDecomposition.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/EigenDecomposition.kt new file mode 100644 index 000000000..4675509bd --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/EigenDecomposition.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2018-2024 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.linear + +import space.kscience.attributes.PolymorphicAttribute +import space.kscience.attributes.safeTypeOf + +public interface EigenDecomposition { + /** + * Eigenvector matrix. + */ + public val v: Matrix + + /** + * A diagonal matrix of eigenvalues. Must have [IsDiagonal] + */ + public val d: Matrix +} + +public class EigenDecompositionAttribute : + PolymorphicAttribute>(safeTypeOf()), + MatrixAttribute> + +public val MatrixScope.EIG: EigenDecompositionAttribute + get() = EigenDecompositionAttribute() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt index 561cb5fd4..1b0e08f5c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt @@ -6,12 +6,19 @@ package space.kscience.kmath.linear import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.Floa64FieldOpsND +import space.kscience.kmath.nd.ShapeND +import space.kscience.kmath.nd.as2D +import space.kscience.kmath.nd.asND import space.kscience.kmath.operations.Float64BufferOps import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.map public object Float64LinearSpace : LinearSpace { @@ -21,36 +28,36 @@ public object Float64LinearSpace : LinearSpace { rows: Int, columns: Int, initializer: Float64Field.(i: Int, j: Int) -> Double, - ): Matrix = Floa64FieldOpsND.structureND(ShapeND(rows, columns)) { (i, j) -> + ): Matrix = Floa64FieldOpsND.structureND(ShapeND(rows, columns)) { (i, j) -> Float64Field.initializer(i, j) }.as2D() override fun buildVector(size: Int, initializer: Float64Field.(Int) -> Double): Float64Buffer = Float64Buffer(size) { Float64Field.initializer(it) } - override fun Matrix.unaryMinus(): Matrix = Floa64FieldOpsND { + override fun Matrix.unaryMinus(): Matrix = Floa64FieldOpsND { asND().map { -it }.as2D() } - override fun Matrix.plus(other: Matrix): Matrix = Floa64FieldOpsND { + override fun Matrix.plus(other: Matrix): Matrix = Floa64FieldOpsND { require(shape == other.shape) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } asND().plus(other.asND()).as2D() } - override fun Matrix.minus(other: Matrix): Matrix = Floa64FieldOpsND { + override fun Matrix.minus(other: Matrix): Matrix = Floa64FieldOpsND { require(shape == other.shape) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } asND().minus(other.asND()).as2D() } // Create a continuous in-memory representation of this vector for better memory layout handling - private fun Buffer.linearize() = if (this is Float64Buffer) { + private fun Buffer.linearize() = if (this is Float64Buffer) { this.array } else { DoubleArray(size) { get(it) } } @OptIn(PerformancePitfall::class) - override fun Matrix.dot(other: Matrix): Matrix { + override fun Matrix.dot(other: Matrix): Matrix { require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } val rows = this@dot.rows.map { it.linearize() } val columns = other.columns.map { it.linearize() } @@ -67,7 +74,7 @@ public object Float64LinearSpace : LinearSpace { } @OptIn(PerformancePitfall::class) - override fun Matrix.dot(vector: Point): Float64Buffer { + override fun Matrix.dot(vector: Point): Float64Buffer { require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } val rows = this@dot.rows.map { it.linearize() } val indices = 0 until this.colNum @@ -82,27 +89,27 @@ public object Float64LinearSpace : LinearSpace { } - override fun Matrix.times(value: Double): Matrix = Floa64FieldOpsND { + override fun Matrix.times(value: Double): Matrix = Floa64FieldOpsND { asND().map { it * value }.as2D() } - public override fun Point.plus(other: Point): Float64Buffer = Float64BufferOps.run { + public override fun Point.plus(other: Point): Float64Buffer = Float64BufferOps.run { this@plus + other } - public override fun Point.minus(other: Point): Float64Buffer = Float64BufferOps.run { + public override fun Point.minus(other: Point): Float64Buffer = Float64BufferOps.run { this@minus - other } - public override fun Point.times(value: Double): Float64Buffer = Float64BufferOps.run { + public override fun Point.times(value: Double): Float64Buffer = Float64BufferOps.run { scale(this@times, value) } - public operator fun Point.div(value: Double): Float64Buffer = Float64BufferOps.run { + public operator fun Point.div(value: Double): Float64Buffer = Float64BufferOps.run { scale(this@div, 1.0 / value) } - public override fun Double.times(v: Point): Float64Buffer = v * this + public override fun Double.times(v: Point): Float64Buffer = v * this } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt index 03859ba83..f9ebcc452 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt @@ -163,9 +163,9 @@ public fun > Field.lup( public fun Field.lup( - matrix: Matrix, + matrix: Matrix, singularityThreshold: Double = 1e-11, -): GenericLupDecomposition = lup(matrix) { it < singularityThreshold } +): GenericLupDecomposition = lup(matrix) { it < singularityThreshold } private fun Field.solve( lup: LupDecomposition, @@ -235,5 +235,5 @@ public fun > LinearSpace>.lupSolver( override fun inverse(matrix: Matrix): Matrix = solve(matrix, one(matrix.rowNum, matrix.colNum)) } -public fun LinearSpace.lupSolver(singularityThreshold: Double = 1e-11): LinearSolver = +public fun LinearSpace.lupSolver(singularityThreshold: Double = 1e-11): LinearSolver = lupSolver { it < singularityThreshold } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt index 60f71b943..761478f9b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.misc import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import kotlin.jvm.JvmName /** @@ -47,7 +48,7 @@ public fun Iterable.cumulativeSum(ring: Ring): Iterable = ring { cumulative(zero) { element: T, sum: T -> sum + element } } @JvmName("cumulativeSumOfDouble") -public fun Iterable.cumulativeSum(): Iterable = cumulative(0.0) { element, sum -> sum + element } +public fun Iterable.cumulativeSum(): Iterable = cumulative(0.0) { element, sum -> sum + element } @JvmName("cumulativeSumOfInt") public fun Iterable.cumulativeSum(): Iterable = cumulative(0) { element, sum -> sum + element } @@ -59,7 +60,7 @@ public fun Sequence.cumulativeSum(ring: Ring): Sequence = ring { cumulative(zero) { element: T, sum: T -> sum + element } } @JvmName("cumulativeSumOfDouble") -public fun Sequence.cumulativeSum(): Sequence = cumulative(0.0) { element, sum -> sum + element } +public fun Sequence.cumulativeSum(): Sequence = cumulative(0.0) { element, sum -> sum + element } @JvmName("cumulativeSumOfInt") public fun Sequence.cumulativeSum(): Sequence = cumulative(0) { element, sum -> sum + element } @@ -71,7 +72,7 @@ public fun List.cumulativeSum(group: Ring): List = group { cumulative(zero) { element: T, sum: T -> sum + element } } @JvmName("cumulativeSumOfDouble") -public fun List.cumulativeSum(): List = cumulative(0.0) { element, sum -> sum + element } +public fun List.cumulativeSum(): List = cumulative(0.0) { element, sum -> sum + element } @JvmName("cumulativeSumOfInt") public fun List.cumulativeSum(): List = cumulative(0) { element, sum -> sum + element } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Float64FieldND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Float64FieldND.kt index 4bb853af8..62e0f39e0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Float64FieldND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Float64FieldND.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.nd import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -20,7 +21,7 @@ import kotlin.math.pow as kpow public class Float64BufferND( indexes: ShapeIndexer, override val buffer: Float64Buffer, -) : MutableBufferND(indexes, buffer), MutableStructureNDOfDouble { +) : MutableBufferND(indexes, buffer), MutableStructureNDOfDouble { override fun getDouble(index: IntArray): Double = buffer[indices.offset(index)] @@ -30,11 +31,11 @@ public class Float64BufferND( } -public sealed class Floa64FieldOpsND : BufferedFieldOpsND(Float64Field.bufferAlgebra), - ScaleOperations>, ExtendedFieldOps> { +public sealed class Floa64FieldOpsND : BufferedFieldOpsND(Float64Field.bufferAlgebra), + ScaleOperations>, ExtendedFieldOps> { @OptIn(PerformancePitfall::class) - override fun StructureND.toBufferND(): Float64BufferND = when (this) { + override fun StructureND.toBufferND(): Float64BufferND = when (this) { is Float64BufferND -> this else -> { val indexer = indexerBuilder(shape) @@ -64,16 +65,16 @@ public sealed class Floa64FieldOpsND : BufferedFieldOpsND( } @OptIn(PerformancePitfall::class) - override fun StructureND.map(transform: Float64Field.(Double) -> Double): BufferND = + override fun StructureND.map(transform: Float64Field.(Double) -> Double): BufferND = mapInline(toBufferND()) { Float64Field.transform(it) } @OptIn(PerformancePitfall::class) override fun zip( - left: StructureND, - right: StructureND, + left: StructureND, + right: StructureND, transform: Float64Field.(Double, Double) -> Double, - ): BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> Float64Field.transform(l, r) } + ): BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> Float64Field.transform(l, r) } override fun mutableStructureND(shape: ShapeND, initializer: Float64Field.(IntArray) -> Double): Float64BufferND { val indexer = indexerBuilder(shape) @@ -85,102 +86,102 @@ public sealed class Floa64FieldOpsND : BufferedFieldOpsND( ) } - override fun add(left: StructureND, right: StructureND): Float64BufferND = + override fun add(left: StructureND, right: StructureND): Float64BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l + r } - override fun multiply(left: StructureND, right: StructureND): Float64BufferND = + override fun multiply(left: StructureND, right: StructureND): Float64BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l * r } - override fun StructureND.unaryMinus(): Float64BufferND = mapInline(toBufferND()) { -it } + override fun StructureND.unaryMinus(): Float64BufferND = mapInline(toBufferND()) { -it } - override fun StructureND.div(arg: StructureND): Float64BufferND = + override fun StructureND.div(arg: StructureND): Float64BufferND = zipInline(toBufferND(), arg.toBufferND()) { l, r -> l / r } - override fun divide(left: StructureND, right: StructureND): Float64BufferND = + override fun divide(left: StructureND, right: StructureND): Float64BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l: Double, r: Double -> l / r } - override fun StructureND.div(arg: Double): Float64BufferND = + override fun StructureND.div(arg: Double): Float64BufferND = mapInline(toBufferND()) { it / arg } - override fun Double.div(arg: StructureND): Float64BufferND = + override fun Double.div(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { this / it } - override fun StructureND.unaryPlus(): Float64BufferND = toBufferND() + override fun StructureND.unaryPlus(): Float64BufferND = toBufferND() - override fun StructureND.plus(arg: StructureND): Float64BufferND = + override fun StructureND.plus(arg: StructureND): Float64BufferND = zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l + r } - override fun StructureND.minus(arg: StructureND): Float64BufferND = + override fun StructureND.minus(arg: StructureND): Float64BufferND = zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l - r } - override fun StructureND.times(arg: StructureND): Float64BufferND = + override fun StructureND.times(arg: StructureND): Float64BufferND = zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l * r } - override fun StructureND.times(k: Number): Float64BufferND = + override fun StructureND.times(k: Number): Float64BufferND = mapInline(toBufferND()) { it * k.toDouble() } - override fun StructureND.div(k: Number): Float64BufferND = + override fun StructureND.div(k: Number): Float64BufferND = mapInline(toBufferND()) { it / k.toDouble() } - override fun Number.times(arg: StructureND): Float64BufferND = arg * this + override fun Number.times(arg: StructureND): Float64BufferND = arg * this - override fun StructureND.plus(arg: Double): Float64BufferND = mapInline(toBufferND()) { it + arg } + override fun StructureND.plus(arg: Double): Float64BufferND = mapInline(toBufferND()) { it + arg } - override fun StructureND.minus(arg: Double): StructureND = mapInline(toBufferND()) { it - arg } + override fun StructureND.minus(arg: Double): StructureND = mapInline(toBufferND()) { it - arg } - override fun Double.plus(arg: StructureND): StructureND = arg + this + override fun Double.plus(arg: StructureND): StructureND = arg + this - override fun Double.minus(arg: StructureND): StructureND = mapInline(arg.toBufferND()) { this - it } + override fun Double.minus(arg: StructureND): StructureND = mapInline(arg.toBufferND()) { this - it } - override fun scale(a: StructureND, value: Double): Float64BufferND = + override fun scale(a: StructureND, value: Double): Float64BufferND = mapInline(a.toBufferND()) { it * value } - override fun exp(arg: StructureND): Float64BufferND = + override fun exp(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.exp(it) } - override fun ln(arg: StructureND): Float64BufferND = + override fun ln(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.ln(it) } - override fun sin(arg: StructureND): Float64BufferND = + override fun sin(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.sin(it) } - override fun cos(arg: StructureND): Float64BufferND = + override fun cos(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.cos(it) } - override fun tan(arg: StructureND): Float64BufferND = + override fun tan(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.tan(it) } - override fun asin(arg: StructureND): Float64BufferND = + override fun asin(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.asin(it) } - override fun acos(arg: StructureND): Float64BufferND = + override fun acos(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.acos(it) } - override fun atan(arg: StructureND): Float64BufferND = + override fun atan(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.atan(it) } - override fun sinh(arg: StructureND): Float64BufferND = + override fun sinh(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.sinh(it) } - override fun cosh(arg: StructureND): Float64BufferND = + override fun cosh(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.cosh(it) } - override fun tanh(arg: StructureND): Float64BufferND = + override fun tanh(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.tanh(it) } - override fun asinh(arg: StructureND): Float64BufferND = + override fun asinh(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.asinh(it) } - override fun acosh(arg: StructureND): Float64BufferND = + override fun acosh(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.acosh(it) } - override fun atanh(arg: StructureND): Float64BufferND = + override fun atanh(arg: StructureND): Float64BufferND = mapInline(arg.toBufferND()) { kotlin.math.atanh(it) } override fun power( - arg: StructureND, + arg: StructureND, pow: Number, - ): StructureND = if (pow is Int) { + ): StructureND = if (pow is Int) { mapInline(arg.toBufferND()) { it.pow(pow) } } else { mapInline(arg.toBufferND()) { it.pow(pow.toDouble()) } @@ -191,18 +192,18 @@ public sealed class Floa64FieldOpsND : BufferedFieldOpsND( @OptIn(UnstableKMathAPI::class) public class Float64FieldND(override val shape: ShapeND) : - Floa64FieldOpsND(), FieldND, NumbersAddOps>, - ExtendedField> { + Floa64FieldOpsND(), FieldND, NumbersAddOps>, + ExtendedField> { - override fun power(arg: StructureND, pow: UInt): Float64BufferND = mapInline(arg.toBufferND()) { + override fun power(arg: StructureND, pow: UInt): Float64BufferND = mapInline(arg.toBufferND()) { it.kpow(pow.toInt()) } - override fun power(arg: StructureND, pow: Int): Float64BufferND = mapInline(arg.toBufferND()) { + override fun power(arg: StructureND, pow: Int): Float64BufferND = mapInline(arg.toBufferND()) { it.kpow(pow) } - override fun power(arg: StructureND, pow: Number): Float64BufferND = if (pow.isInteger()) { + override fun power(arg: StructureND, pow: Number): Float64BufferND = if (pow.isInteger()) { power(arg, pow.toInt()) } else { val dpow = pow.toDouble() @@ -212,17 +213,17 @@ public class Float64FieldND(override val shape: ShapeND) : } } - override fun sinh(arg: StructureND): Float64BufferND = super.sinh(arg) + override fun sinh(arg: StructureND): Float64BufferND = super.sinh(arg) - override fun cosh(arg: StructureND): Float64BufferND = super.cosh(arg) + override fun cosh(arg: StructureND): Float64BufferND = super.cosh(arg) - override fun tanh(arg: StructureND): Float64BufferND = super.tan(arg) + override fun tanh(arg: StructureND): Float64BufferND = super.tan(arg) - override fun asinh(arg: StructureND): Float64BufferND = super.asinh(arg) + override fun asinh(arg: StructureND): Float64BufferND = super.asinh(arg) - override fun acosh(arg: StructureND): Float64BufferND = super.acosh(arg) + override fun acosh(arg: StructureND): Float64BufferND = super.acosh(arg) - override fun atanh(arg: StructureND): Float64BufferND = super.atanh(arg) + override fun atanh(arg: StructureND): Float64BufferND = super.atanh(arg) override fun number(value: Number): Float64BufferND { val d = value.toDouble() // minimize conversions diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index 5c1021147..be2856c3b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -14,6 +14,7 @@ import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import kotlin.math.abs public interface StructureAttribute : Attribute @@ -76,8 +77,8 @@ public interface StructureND : AttributeContainer, WithShape { @PerformancePitfall public fun contentEquals( - st1: StructureND, - st2: StructureND, + st1: StructureND, + st2: StructureND, tolerance: Double = 1e-11, ): Boolean { if (st1 === st2) return true @@ -210,7 +211,7 @@ public fun > LinearSpace>.contentEquals( @PerformancePitfall public operator fun StructureND.get(vararg index: Int): T = get(index) -public operator fun StructureND.get(vararg index: Int): Double = getDouble(index) +public operator fun StructureND.get(vararg index: Int): Double = getDouble(index) public operator fun StructureND.get(vararg index: Int): Int = getInt(index) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt index a7e0b0053..3765707a8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.nd import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.structures.Float64 public open class VirtualStructureND( override val shape: ShapeND, @@ -24,7 +25,7 @@ public open class VirtualStructureND( public class VirtualDoubleStructureND( shape: ShapeND, producer: (IntArray) -> Double, -) : VirtualStructureND(shape, producer) +) : VirtualStructureND(shape, producer) @UnstableKMathAPI public class VirtualIntStructureND( diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt index 4831b4138..e9b104746 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt @@ -6,8 +6,9 @@ package space.kscience.kmath.nd import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.structures.Float64 -public interface StructureNDOfDouble : StructureND { +public interface StructureNDOfDouble : StructureND { /** * Guaranteed non-blocking access to content @@ -19,10 +20,10 @@ public interface StructureNDOfDouble : StructureND { * Optimized method to access primitive without boxing if possible */ @OptIn(PerformancePitfall::class) -public fun StructureND.getDouble(index: IntArray): Double = +public fun StructureND.getDouble(index: IntArray): Double = if (this is StructureNDOfDouble) getDouble(index) else get(index) -public interface MutableStructureNDOfDouble : StructureNDOfDouble, MutableStructureND { +public interface MutableStructureNDOfDouble : StructureNDOfDouble, MutableStructureND { /** * Guaranteed non-blocking access to content @@ -31,7 +32,7 @@ public interface MutableStructureNDOfDouble : StructureNDOfDouble, MutableStruct } @OptIn(PerformancePitfall::class) -public fun MutableStructureND.getDouble(index: IntArray): Double = +public fun MutableStructureND.getDouble(index: IntArray): Double = if (this is StructureNDOfDouble) getDouble(index) else get(index) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt index 6c260db9f..a55b63cf4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.operations import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableBufferFactory @@ -182,7 +183,7 @@ public fun > BufferFieldOps.withSize(size: Int): BufferFie //Double buffer specialization -public fun BufferField.buffer(vararg elements: Number): Buffer { +public fun BufferField.buffer(vararg elements: Number): Buffer { require(elements.size == size) { "Expected $size elements but found ${elements.size}" } return elementBufferFactory(size) { elements[it].toDouble() } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferField.kt index 1c4bda18f..8ddb5d445 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferField.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.operations import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer /** @@ -13,23 +14,23 @@ import space.kscience.kmath.structures.Float64Buffer * * @property size the size of buffers to operate on. */ -public class Float64BufferField(public val size: Int) : ExtendedField>, Float64BufferOps() { - override val zero: Buffer by lazy { Float64Buffer(size) { 0.0 } } - override val one: Buffer by lazy { Float64Buffer(size) { 1.0 } } +public class Float64BufferField(public val size: Int) : ExtendedField>, Float64BufferOps() { + override val zero: Buffer by lazy { Float64Buffer(size) { 0.0 } } + override val one: Buffer by lazy { Float64Buffer(size) { 1.0 } } - override fun sinh(arg: Buffer): Float64Buffer = super.sinh(arg) + override fun sinh(arg: Buffer): Float64Buffer = super.sinh(arg) - override fun cosh(arg: Buffer): Float64Buffer = super.cosh(arg) + override fun cosh(arg: Buffer): Float64Buffer = super.cosh(arg) - override fun tanh(arg: Buffer): Float64Buffer = super.tanh(arg) + override fun tanh(arg: Buffer): Float64Buffer = super.tanh(arg) - override fun asinh(arg: Buffer): Float64Buffer = super.asinh(arg) + override fun asinh(arg: Buffer): Float64Buffer = super.asinh(arg) - override fun acosh(arg: Buffer): Float64Buffer = super.acosh(arg) + override fun acosh(arg: Buffer): Float64Buffer = super.acosh(arg) - override fun atanh(arg: Buffer): Float64Buffer = super.atanh(arg) + override fun atanh(arg: Buffer): Float64Buffer = super.atanh(arg) - override fun power(arg: Buffer, pow: Number): Float64Buffer = if (pow.isInteger()) { + override fun power(arg: Buffer, pow: Number): Float64Buffer = if (pow.isInteger()) { arg.map { it.pow(pow.toInt()) } } else { arg.map { @@ -38,6 +39,6 @@ public class Float64BufferField(public val size: Int) : ExtendedField) -> Buffer = + override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = super.unaryOperationFunction(operation) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferOps.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferOps.kt index ca4eacb8a..dfa542d83 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferOps.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferOps.kt @@ -14,43 +14,43 @@ import kotlin.math.sqrt /** * [ExtendedFieldOps] over [Float64Buffer]. */ -public abstract class Float64BufferOps : BufferAlgebra, ExtendedFieldOps>, - Norm, Double> { +public abstract class Float64BufferOps : BufferAlgebra, ExtendedFieldOps>, + Norm, Double> { override val elementAlgebra: Float64Field get() = Float64Field - override val elementBufferFactory: MutableBufferFactory get() = elementAlgebra.bufferFactory + override val elementBufferFactory: MutableBufferFactory get() = elementAlgebra.bufferFactory @Suppress("OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) - final override inline fun Buffer.map(block: Float64Field.(Double) -> Double): Float64Buffer = + final override inline fun Buffer.map(block: Float64Field.(Double) -> Double): Float64Buffer = DoubleArray(size) { Float64Field.block(getDouble(it)) }.asBuffer() @OptIn(UnstableKMathAPI::class) @Suppress("OVERRIDE_BY_INLINE") - final override inline fun Buffer.mapIndexed(block: Float64Field.(index: Int, arg: Double) -> Double): Float64Buffer = + final override inline fun Buffer.mapIndexed(block: Float64Field.(index: Int, arg: Double) -> Double): Float64Buffer = Float64Buffer(size) { Float64Field.block(it, getDouble(it)) } @OptIn(UnstableKMathAPI::class) @Suppress("OVERRIDE_BY_INLINE") - final override inline fun Buffer.zip( - other: Buffer, + final override inline fun Buffer.zip( + other: Buffer, block: Float64Field.(left: Double, right: Double) -> Double, ): Float64Buffer { require(size == other.size) { "Incompatible buffer sizes. left: ${size}, right: ${other.size}" } return Float64Buffer(size) { Float64Field.block(getDouble(it), other.getDouble(it)) } } - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = + override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = super.unaryOperationFunction(operation) - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = + override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = super.binaryOperationFunction(operation) - override fun Buffer.unaryMinus(): Float64Buffer = map { -it } + override fun Buffer.unaryMinus(): Float64Buffer = map { -it } - override fun add(left: Buffer, right: Buffer): Float64Buffer { + override fun add(left: Buffer, right: Buffer): Float64Buffer { require(right.size == left.size) { "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " } @@ -62,9 +62,9 @@ public abstract class Float64BufferOps : BufferAlgebra, Ex } else Float64Buffer(DoubleArray(left.size) { left[it] + right[it] }) } - override fun Buffer.plus(arg: Buffer): Float64Buffer = add(this, arg) + override fun Buffer.plus(arg: Buffer): Float64Buffer = add(this, arg) - override fun Buffer.minus(arg: Buffer): Float64Buffer { + override fun Buffer.minus(arg: Buffer): Float64Buffer { require(arg.size == this.size) { "The size of the first buffer ${this.size} should be the same as for second one: ${arg.size} " } @@ -77,7 +77,7 @@ public abstract class Float64BufferOps : BufferAlgebra, Ex } // -// override fun multiply(a: Buffer, k: Number): RealBuffer { +// override fun multiply(a: Buffer, k: Number): RealBuffer { // val kValue = k.toDouble() // // return if (a is RealBuffer) { @@ -86,7 +86,7 @@ public abstract class Float64BufferOps : BufferAlgebra, Ex // } else RealBuffer(DoubleArray(a.size) { a[it] * kValue }) // } // -// override fun divide(a: Buffer, k: Number): RealBuffer { +// override fun divide(a: Buffer, k: Number): RealBuffer { // val kValue = k.toDouble() // // return if (a is RealBuffer) { @@ -96,7 +96,7 @@ public abstract class Float64BufferOps : BufferAlgebra, Ex // } @UnstableKMathAPI - override fun multiply(left: Buffer, right: Buffer): Float64Buffer { + override fun multiply(left: Buffer, right: Buffer): Float64Buffer { require(right.size == left.size) { "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " } @@ -108,7 +108,7 @@ public abstract class Float64BufferOps : BufferAlgebra, Ex } else Float64Buffer(DoubleArray(left.size) { left[it] * right[it] }) } - override fun divide(left: Buffer, right: Buffer): Float64Buffer { + override fun divide(left: Buffer, right: Buffer): Float64Buffer { require(right.size == left.size) { "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " } @@ -120,39 +120,39 @@ public abstract class Float64BufferOps : BufferAlgebra, Ex } else Float64Buffer(DoubleArray(left.size) { left[it] / right[it] }) } - override fun sin(arg: Buffer): Float64Buffer = arg.map { sin(it) } + override fun sin(arg: Buffer): Float64Buffer = arg.map { sin(it) } - override fun cos(arg: Buffer): Float64Buffer = arg.map { cos(it) } + override fun cos(arg: Buffer): Float64Buffer = arg.map { cos(it) } - override fun tan(arg: Buffer): Float64Buffer = arg.map { tan(it) } + override fun tan(arg: Buffer): Float64Buffer = arg.map { tan(it) } - override fun asin(arg: Buffer): Float64Buffer = arg.map { asin(it) } + override fun asin(arg: Buffer): Float64Buffer = arg.map { asin(it) } - override fun acos(arg: Buffer): Float64Buffer = arg.map { acos(it) } + override fun acos(arg: Buffer): Float64Buffer = arg.map { acos(it) } - override fun atan(arg: Buffer): Float64Buffer = arg.map { atan(it) } + override fun atan(arg: Buffer): Float64Buffer = arg.map { atan(it) } - override fun sinh(arg: Buffer): Float64Buffer = arg.map { sinh(it) } + override fun sinh(arg: Buffer): Float64Buffer = arg.map { sinh(it) } - override fun cosh(arg: Buffer): Float64Buffer = arg.map { cosh(it) } + override fun cosh(arg: Buffer): Float64Buffer = arg.map { cosh(it) } - override fun tanh(arg: Buffer): Float64Buffer = arg.map { tanh(it) } + override fun tanh(arg: Buffer): Float64Buffer = arg.map { tanh(it) } - override fun asinh(arg: Buffer): Float64Buffer = arg.map { asinh(it) } + override fun asinh(arg: Buffer): Float64Buffer = arg.map { asinh(it) } - override fun acosh(arg: Buffer): Float64Buffer = arg.map { acosh(it) } + override fun acosh(arg: Buffer): Float64Buffer = arg.map { acosh(it) } - override fun atanh(arg: Buffer): Float64Buffer = arg.map { atanh(it) } + override fun atanh(arg: Buffer): Float64Buffer = arg.map { atanh(it) } - override fun exp(arg: Buffer): Float64Buffer = arg.map { exp(it) } + override fun exp(arg: Buffer): Float64Buffer = arg.map { exp(it) } - override fun ln(arg: Buffer): Float64Buffer = arg.map { ln(it) } + override fun ln(arg: Buffer): Float64Buffer = arg.map { ln(it) } - override fun norm(arg: Buffer): Double = Float64L2Norm.norm(arg) + override fun norm(arg: Buffer): Double = Float64L2Norm.norm(arg) - override fun scale(a: Buffer, value: Double): Float64Buffer = a.map { it * value } + override fun scale(a: Buffer, value: Double): Float64Buffer = a.map { it * value } - override fun power(arg: Buffer, pow: Number): Buffer = if (pow is Int) { + override fun power(arg: Buffer, pow: Number): Buffer = if (pow is Int) { arg.map { it.pow(pow) } } else { arg.map { it.pow(pow.toDouble()) } @@ -161,11 +161,11 @@ public abstract class Float64BufferOps : BufferAlgebra, Ex public companion object : Float64BufferOps() } -public object Float64L2Norm : Norm, Double> { - override fun norm(arg: Point): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) +public object Float64L2Norm : Norm, Double> { + override fun norm(arg: Point): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) } -public fun Float64BufferOps.sum(buffer: Buffer): Double = buffer.reduce(Double::plus) +public fun Float64BufferOps.sum(buffer: Buffer): Double = buffer.reduce(Double::plus) /** * Sum of elements using given [conversion] @@ -173,7 +173,7 @@ public fun Float64BufferOps.sum(buffer: Buffer): Double = buffer.reduce( public inline fun Float64BufferOps.sumOf(buffer: Buffer, conversion: (T) -> Double): Double = buffer.fold(0.0) { acc, value -> acc + conversion(value) } -public fun Float64BufferOps.average(buffer: Buffer): Double = sum(buffer) / buffer.size +public fun Float64BufferOps.average(buffer: Buffer): Double = sum(buffer) / buffer.size /** * Average of elements using given [conversion] @@ -181,14 +181,14 @@ public fun Float64BufferOps.average(buffer: Buffer): Double = sum(buffer public inline fun Float64BufferOps.averageOf(buffer: Buffer, conversion: (T) -> Double): Double = sumOf(buffer, conversion) / buffer.size -public fun Float64BufferOps.dispersion(buffer: Buffer): Double { +public fun Float64BufferOps.dispersion(buffer: Buffer): Double { val av = average(buffer) return buffer.fold(0.0) { acc, value -> acc + (value - av).pow(2) } / buffer.size } -public fun Float64BufferOps.std(buffer: Buffer): Double = sqrt(dispersion(buffer)) +public fun Float64BufferOps.std(buffer: Buffer): Double = sqrt(dispersion(buffer)) -public fun Float64BufferOps.covariance(x: Buffer, y: Buffer): Double { +public fun Float64BufferOps.covariance(x: Buffer, y: Buffer): Double { require(x.size == y.size) { "Expected buffers of the same size, but x.size == ${x.size} and y.size == ${y.size}" } val xMean = average(x) val yMean = average(y) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 96a080afd..9799c5428 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -4,6 +4,7 @@ */ package space.kscience.kmath.operations +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBufferFactory import kotlin.math.pow as kpow @@ -66,8 +67,8 @@ public interface ExtendedField : ExtendedFieldOps, Field, NumericAlgebr * A field for [Double] without boxing. Does not produce an appropriate field element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER") -public object Float64Field : ExtendedField, Norm, ScaleOperations { - override val bufferFactory: MutableBufferFactory = MutableBufferFactory() +public object Float64Field : ExtendedField, Norm, ScaleOperations { + override val bufferFactory: MutableBufferFactory = MutableBufferFactory() override val zero: Double get() = 0.0 override val one: Double get() = 1.0 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index 7fc06c43e..73454ca2d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -115,7 +115,7 @@ public fun Buffer( size: Int, initializer: (Int) -> T, ): Buffer = when (type.kType) { - typeOf() -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer + typeOf() -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer typeOf() -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer typeOf() -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer typeOf() -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer @@ -134,7 +134,7 @@ public inline fun Buffer(size: Int, initializer: (Int) -> T): Buffer //code duplication here because we want to inline initializers val type = safeTypeOf() return when (type.kType) { - typeOf() -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer + typeOf() -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer typeOf() -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer typeOf() -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer typeOf() -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float64Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float64Buffer.kt index 38b737fd5..beeccbdcf 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float64Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float64Buffer.kt @@ -14,7 +14,7 @@ import kotlin.jvm.JvmInline * @property array the underlying array. */ @JvmInline -public value class Float64Buffer(public val array: DoubleArray) : PrimitiveBuffer { +public value class Float64Buffer(public val array: DoubleArray) : PrimitiveBuffer { override val size: Int get() = array.size @@ -54,7 +54,7 @@ public fun Float64Buffer(vararg doubles: Double): Float64Buffer = Float64Buffer( /** * Returns a new [DoubleArray] containing all the elements of this [Buffer]. */ -public fun Buffer.toDoubleArray(): DoubleArray = when (this) { +public fun Buffer.toDoubleArray(): DoubleArray = when (this) { is Float64Buffer -> array else -> DoubleArray(size, ::get) } @@ -62,7 +62,7 @@ public fun Buffer.toDoubleArray(): DoubleArray = when (this) { /** * Represent this buffer as [Float64Buffer]. Does not guarantee that changes in the original buffer are reflected on this buffer. */ -public fun Buffer.toFloat64Buffer(): Float64Buffer = when (this) { +public fun Buffer.toFloat64Buffer(): Float64Buffer = when (this) { is Float64Buffer -> this else -> DoubleArray(size, ::get).asBuffer() } @@ -79,5 +79,5 @@ public fun DoubleArray.asBuffer(): Float64Buffer = Float64Buffer(this) public fun interface Float64BufferTransform : BufferTransform { public fun transform(arg: Float64Buffer): Float64Buffer - override fun transform(arg: Buffer): Float64Buffer = arg.toFloat64Buffer() + override fun transform(arg: Buffer): Float64Buffer = arg.toFloat64Buffer() } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt index eeee5faad..a32cba214 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt @@ -99,7 +99,7 @@ public inline fun MutableBuffer( typeOf() -> MutableBuffer.int(size) { initializer(it) as Int32 } as MutableBuffer typeOf() -> MutableBuffer.long(size) { initializer(it) as Int64 } as MutableBuffer typeOf() -> MutableBuffer.float(size) { initializer(it) as Float } as MutableBuffer - typeOf() -> MutableBuffer.double(size) { initializer(it) as Double } as MutableBuffer + typeOf() -> MutableBuffer.double(size) { initializer(it) as Double } as MutableBuffer //TODO add unsigned types else -> MutableListBuffer(MutableList(size, initializer)) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt index 6035811b9..a590a1cf8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt @@ -11,7 +11,7 @@ import space.kscience.kmath.UnstableKMathAPI * Non-boxing access to primitive [Double] */ @UnstableKMathAPI -public fun Buffer.getDouble(index: Int): Double = if (this is BufferView) { +public fun Buffer.getDouble(index: Int): Double = if (this is BufferView) { val originIndex = originIndex(index) if (originIndex >= 0) { origin.getDouble(originIndex) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt index ca2e31d7d..efd993f85 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.structures.Float64 import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFails @@ -37,7 +38,7 @@ class ExpressionFieldTest { @Test fun valueExpression() { - val expressionBuilder: FunctionalExpressionField.() -> Expression = { + val expressionBuilder: FunctionalExpressionField.() -> Expression = { val x by binding x * x + 2 * x + one } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt index dcfb16042..529ecbf73 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.asBuffer import kotlin.math.E import kotlin.math.PI @@ -21,18 +22,18 @@ internal class SimpleAutoDiffTest { fun dx( xBinding: Pair, - body: SimpleAutoDiffField.(x: AutoDiffValue) -> AutoDiffValue, - ): DerivationResult = Float64Field.simpleAutoDiff(xBinding) { body(bindSymbol(xBinding.first)) } + body: SimpleAutoDiffField.(x: AutoDiffValue) -> AutoDiffValue, + ): DerivationResult = Float64Field.simpleAutoDiff(xBinding) { body(bindSymbol(xBinding.first)) } fun dxy( xBinding: Pair, yBinding: Pair, - body: SimpleAutoDiffField.(x: AutoDiffValue, y: AutoDiffValue) -> AutoDiffValue, - ): DerivationResult = Float64Field.simpleAutoDiff(xBinding, yBinding) { + body: SimpleAutoDiffField.(x: AutoDiffValue, y: AutoDiffValue) -> AutoDiffValue, + ): DerivationResult = Float64Field.simpleAutoDiff(xBinding, yBinding) { body(bindSymbol(xBinding.first), bindSymbol(yBinding.first)) } - fun diff(block: SimpleAutoDiffField.() -> AutoDiffValue): SimpleAutoDiffExpression { + fun diff(block: SimpleAutoDiffField.() -> AutoDiffValue): SimpleAutoDiffExpression { return SimpleAutoDiffExpression(Float64Field, block) } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt index 30b8aaffb..3489e92a4 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt @@ -10,6 +10,7 @@ import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.algebra +import space.kscience.kmath.structures.Float64 import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -38,7 +39,7 @@ class MatrixTest { @Test fun testMatrixExtension() = Double.algebra.linearSpace.run { - val transitionMatrix: Matrix = VirtualMatrix(6, 6) { row, col -> + val transitionMatrix: Matrix = VirtualMatrix(6, 6) { row, col -> when { col == 0 -> .50 row + 1 == col -> .50 @@ -47,7 +48,7 @@ class MatrixTest { } } - infix fun Matrix.pow(power: Int): Matrix { + infix fun Matrix.pow(power: Int): Matrix { var res = this repeat(power - 1) { res = res dot this@pow diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt index 088b0fd9f..1a4c04bde 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.operations.Float64BufferOps import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.asBuffer import java.util.stream.IntStream @@ -25,7 +26,7 @@ public object Float64ParallelLinearSpace : LinearSpace { rows: Int, columns: Int, initializer: Float64Field.(i: Int, j: Int) -> Double, - ): Matrix { + ): Matrix { val shape = ShapeND(rows, columns) val indexer = BufferAlgebraND.defaultIndexerBuilder(shape) @@ -43,29 +44,29 @@ public object Float64ParallelLinearSpace : LinearSpace { override fun buildVector(size: Int, initializer: Float64Field.(Int) -> Double): Float64Buffer = IntStream.range(0, size).parallel().mapToDouble { Float64Field.initializer(it) }.toArray().asBuffer() - override fun Matrix.unaryMinus(): Matrix = Floa64FieldOpsND { + override fun Matrix.unaryMinus(): Matrix = Floa64FieldOpsND { asND().map { -it }.as2D() } - override fun Matrix.plus(other: Matrix): Matrix = Floa64FieldOpsND { + override fun Matrix.plus(other: Matrix): Matrix = Floa64FieldOpsND { require(shape == other.shape) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } asND().plus(other.asND()).as2D() } - override fun Matrix.minus(other: Matrix): Matrix = Floa64FieldOpsND { + override fun Matrix.minus(other: Matrix): Matrix = Floa64FieldOpsND { require(shape == other.shape) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } asND().minus(other.asND()).as2D() } // Create a continuous in-memory representation of this vector for better memory layout handling - private fun Buffer.linearize() = if (this is Float64Buffer) { + private fun Buffer.linearize() = if (this is Float64Buffer) { this.array } else { DoubleArray(size) { get(it) } } @OptIn(PerformancePitfall::class) - override fun Matrix.dot(other: Matrix): Matrix { + override fun Matrix.dot(other: Matrix): Matrix { require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } val rows = this@dot.rows.map { it.linearize() } val columns = other.columns.map { it.linearize() } @@ -82,7 +83,7 @@ public object Float64ParallelLinearSpace : LinearSpace { } @OptIn(PerformancePitfall::class) - override fun Matrix.dot(vector: Point): Float64Buffer { + override fun Matrix.dot(vector: Point): Float64Buffer { require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } val rows = this@dot.rows.map { it.linearize() } val indices = 0 until this.colNum @@ -97,27 +98,27 @@ public object Float64ParallelLinearSpace : LinearSpace { } - override fun Matrix.times(value: Double): Matrix = Floa64FieldOpsND { + override fun Matrix.times(value: Double): Matrix = Floa64FieldOpsND { asND().map { it * value }.as2D() } - public override fun Point.plus(other: Point): Float64Buffer = Float64BufferOps.run { + public override fun Point.plus(other: Point): Float64Buffer = Float64BufferOps.run { this@plus + other } - public override fun Point.minus(other: Point): Float64Buffer = Float64BufferOps.run { + public override fun Point.minus(other: Point): Float64Buffer = Float64BufferOps.run { this@minus - other } - public override fun Point.times(value: Double): Float64Buffer = Float64BufferOps.run { + public override fun Point.times(value: Double): Float64Buffer = Float64BufferOps.run { scale(this@times, value) } - public operator fun Point.div(value: Double): Float64Buffer = Float64BufferOps.run { + public operator fun Point.div(value: Double): Float64Buffer = Float64BufferOps.run { scale(this@div, 1.0 / value) } - public override fun Double.times(v: Point): Float64Buffer = v * this + public override fun Double.times(v: Point): Float64Buffer = v * this } diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/structures/parallelMutableBuffer.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/structures/parallelMutableBuffer.kt index d19f50dba..376f090c7 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/structures/parallelMutableBuffer.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/structures/parallelMutableBuffer.kt @@ -30,7 +30,7 @@ public fun MutableBuffer.Companion.parallel( .asBuffer() as MutableBuffer typeOf() -> Float32Buffer(size) { initializer(it) as Float } as MutableBuffer - typeOf() -> IntStream.range(0, size).parallel().mapToDouble { initializer(it) as Float64 }.toArray() + typeOf() -> IntStream.range(0, size).parallel().mapToDouble { initializer(it) as Float64 }.toArray() .asBuffer() as MutableBuffer //TODO add unsigned types else -> IntStream.range(0, size).parallel().mapToObj { initializer(it) }.collect(Collectors.toList()) diff --git a/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt b/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt index 2abc36c8e..19a37c9fb 100644 --- a/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt +++ b/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt @@ -9,6 +9,7 @@ import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.structures.Float64 import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -37,7 +38,7 @@ class ParallelMatrixTest { @Test fun testMatrixExtension() = Float64Field.linearSpace.parallel { - val transitionMatrix: Matrix = VirtualMatrix(6, 6) { row, col -> + val transitionMatrix: Matrix = VirtualMatrix(6, 6) { row, col -> when { col == 0 -> .50 row + 1 == col -> .50 @@ -46,7 +47,7 @@ class ParallelMatrixTest { } } - infix fun Matrix.pow(power: Int): Matrix { + infix fun Matrix.pow(power: Int): Matrix { var res = this repeat(power - 1) { res = res dot this@pow diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt index b3e1b59b7..b3ac31e91 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt @@ -5,12 +5,13 @@ package space.kscience.kmath.chains +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer /** * Chunked, specialized chain for double values, which supports blocking [nextBlocking] operation */ -public interface BlockingDoubleChain : BlockingBufferChain { +public interface BlockingDoubleChain : BlockingBufferChain { /** * Returns an [DoubleArray] chunk of [size] values of [next]. diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt index 12665c8a5..3d6116595 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt @@ -17,6 +17,7 @@ import space.kscience.kmath.chains.BlockingDoubleChain import space.kscience.kmath.operations.Group import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer /** @@ -56,7 +57,7 @@ public fun Flow.chunked(bufferSize: Int, bufferFactory: BufferFactory) /** * Specialized flow chunker for real buffer */ -public fun Flow.chunked(bufferSize: Int): Flow = flow { +public fun Flow.chunked(bufferSize: Int): Flow = flow { require(bufferSize > 0) { "Resulting chunk size must be more than zero" } if (this@chunked is BlockingDoubleChain) { diff --git a/kmath-ejml/build.gradle.kts b/kmath-ejml/build.gradle.kts index 50416eaf3..de0399244 100644 --- a/kmath-ejml/build.gradle.kts +++ b/kmath-ejml/build.gradle.kts @@ -5,8 +5,9 @@ plugins { val ejmlVerision = "0.43.1" dependencies { - api("org.ejml:ejml-all:$ejmlVerision") api(projects.kmathCore) + api(projects.kmathComplex) + api("org.ejml:ejml-all:$ejmlVerision") } readme { diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt index d5bd8ccb7..fe522844d 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt @@ -6,9 +6,13 @@ package space.kscience.kmath.ejml import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.linear.* -import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.linear.Inverted +import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.linear.Point +import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.operations.Ring +import space.kscience.kmath.structures.Float64 /** * [LinearSpace] implementation specialized for a certain EJML type. @@ -38,6 +42,6 @@ public abstract class EjmlLinearSpace, out M : org.ejml public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector @UnstableKMathAPI - public fun EjmlMatrix.inverted(): Matrix = - computeAttribute(this, Float64Field.linearSpace.Inverted)!! + public fun Structure2D.inverted(): Matrix = + computeAttribute(this, Inverted()) ?: error("Can't invert matrix") } diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/implementations.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/implementations.kt index df4941c52..d84eeb589 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/implementations.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/implementations.kt @@ -12,6 +12,8 @@ import org.ejml.dense.row.CommonOps_DDRM import org.ejml.dense.row.CommonOps_FDRM import org.ejml.dense.row.factory.DecompositionFactory_DDRM import org.ejml.dense.row.factory.DecompositionFactory_FDRM +import org.ejml.interfaces.decomposition.EigenDecomposition_F32 +import org.ejml.interfaces.decomposition.EigenDecomposition_F64 import org.ejml.sparse.FillReducing import org.ejml.sparse.csc.CommonOps_DSCC import org.ejml.sparse.csc.CommonOps_FSCC @@ -19,6 +21,7 @@ import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC import space.kscience.attributes.SafeType import space.kscience.attributes.safeTypeOf +import space.kscience.kmath.complex.Complex import space.kscience.kmath.linear.* import space.kscience.kmath.linear.Matrix import space.kscience.kmath.nd.Structure2D @@ -27,9 +30,15 @@ import space.kscience.kmath.operations.Float32Field import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Float32 +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.IntBuffer import space.kscience.kmath.structures.asBuffer +/** + * Copy EJML [Complex_F64] into KMath [Complex] + */ +public fun Complex_F64.toKMathComplex(): Complex = Complex(real, imaginary) + /** * [EjmlVector] specialization for [Double]. */ @@ -79,16 +88,16 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace get() = safeTypeOf() + override val type: SafeType get() = safeTypeOf() @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlDoubleMatrix = when { + override fun Matrix.toEjml(): EjmlDoubleMatrix = when { this is EjmlDoubleMatrix<*> && origin is DMatrixRMaj -> this as EjmlDoubleMatrix else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } } @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlDoubleVector = when { + override fun Point.toEjml(): EjmlDoubleVector = when { this is EjmlDoubleVector<*> && origin is DMatrixRMaj -> this as EjmlDoubleVector else -> EjmlDoubleVector(DMatrixRMaj(size, 1).also { (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } @@ -115,21 +124,21 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace T.wrapMatrix() = EjmlDoubleMatrix(this) private fun T.wrapVector() = EjmlDoubleVector(this) - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { + override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.mult(toEjml().origin, other.toEjml().origin, out) return out.wrapMatrix() } - override fun Matrix.dot(vector: Point): EjmlDoubleVector { + override fun Matrix.dot(vector: Point): EjmlDoubleVector { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.mult(toEjml().origin, vector.toEjml().origin, out) return out.wrapVector() } - override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { + override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.add( @@ -143,19 +152,19 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace.times(value: Double): EjmlDoubleMatrix { + override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { val res = DMatrixRMaj(1, 1) CommonOps_DDRM.scale(value, toEjml().origin, res) return res.wrapMatrix() } - override fun Point.unaryMinus(): EjmlDoubleVector { + override fun Point.unaryMinus(): EjmlDoubleVector { val res = DMatrixRMaj(1, 1) CommonOps_DDRM.changeSign(toEjml().origin, res) return res.wrapVector() } - override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { + override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.add( @@ -169,7 +178,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace.plus(other: Point): EjmlDoubleVector { + override fun Point.plus(other: Point): EjmlDoubleVector { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.add( @@ -183,7 +192,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace.minus(other: Point): EjmlDoubleVector { + override fun Point.minus(other: Point): EjmlDoubleVector { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.add( @@ -197,18 +206,18 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace): EjmlDoubleMatrix = m * this + override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - override fun Point.times(value: Double): EjmlDoubleVector { + override fun Point.times(value: Double): EjmlDoubleVector { val res = DMatrixRMaj(1, 1) CommonOps_DDRM.scale(value, toEjml().origin, res) return res.wrapVector() } - override fun Double.times(v: Point): EjmlDoubleVector = v * this + override fun Double.times(v: Point): EjmlDoubleVector = v * this - override fun > computeAttribute(structure: Structure2D, attribute: A): V? { - val origin = structure.toEjml().origin + override fun > computeAttribute(structure: Structure2D, attribute: A): V? { + val origin: DMatrixRMaj = structure.toEjml().origin val raw: Any? = when (attribute) { Inverted -> { @@ -218,28 +227,28 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace CommonOps_DDRM.det(origin) - SVD -> object : SingularValueDecomposition { + SVD -> object : SingularValueDecomposition { val ejmlSvd by lazy { DecompositionFactory_DDRM .svd(origin.numRows, origin.numCols, true, true, false) .apply { decompose(origin.copy()) } } - override val u: Matrix get() = ejmlSvd.getU(null, false).wrapMatrix() + override val u: Matrix get() = ejmlSvd.getU(null, false).wrapMatrix() - override val s: Matrix get() = ejmlSvd.getW(null).wrapMatrix() - override val v: Matrix get() = ejmlSvd.getV(null, false).wrapMatrix() - override val singularValues: Point get() = ejmlSvd.singularValues.asBuffer() + override val s: Matrix get() = ejmlSvd.getW(null).wrapMatrix() + override val v: Matrix get() = ejmlSvd.getV(null, false).wrapMatrix() + override val singularValues: Point get() = ejmlSvd.singularValues.asBuffer() } - QR -> object : QRDecomposition { + QR -> object : QRDecomposition { val ejmlQr by lazy { DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } } - override val q: Matrix get() = ejmlQr.getQ(null, false).wrapMatrix() - override val r: Matrix get() = ejmlQr.getR(null, false).wrapMatrix() + override val q: Matrix get() = ejmlQr.getQ(null, false).wrapMatrix() + override val r: Matrix get() = ejmlQr.getR(null, false).wrapMatrix() } - Cholesky -> object : CholeskyDecomposition { - override val l: Matrix by lazy { + Cholesky -> object : CholeskyDecomposition { + override val l: Matrix by lazy { val cholesky = DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } @@ -247,20 +256,49 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace object : LupDecomposition { + LUP -> object : LupDecomposition { private val lup by lazy { DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } } - override val l: Matrix + override val l: Matrix get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular) - - override val u: Matrix + override val u: Matrix get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular) + override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer() } + EIG -> { + check(origin.numCols == origin.numRows) { "Eigenvalue decomposition requires symmetric matrix" } + object : EigenDecomposition { + val cmEigen: EigenDecomposition_F64 by lazy { + DecompositionFactory_DDRM.eig(origin.numRows, true).apply { decompose(origin) } + } + + override val v: Matrix by lazy { + val eigenvectors = List(origin.numRows) { cmEigen.getEigenVector(it) } + buildMatrix(origin.numRows, origin.numCols) { row, column -> + eigenvectors[row][column] + } + } + + override val d: Matrix by lazy { + val eigenvalues = List(origin.numRows) { cmEigen.getEigenvalue(it) } + + buildMatrix(origin.numRows, origin.numCols) { row, column -> + when (row) { + column -> eigenvalues[row].real + column - 1 -> eigenvalues[row].imaginary + column + 1 -> -eigenvalues[row].imaginary + else -> 0.0 + } + } + } + } + } + else -> null } @@ -275,7 +313,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace, b: Matrix): EjmlDoubleMatrix { + public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { val res = DMatrixRMaj(1, 1) CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) return res.wrapMatrix() @@ -288,7 +326,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace, b: Point): EjmlDoubleVector { + public fun solve(a: Matrix, b: Point): EjmlDoubleVector { val res = DMatrixRMaj(1, 1) CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) return EjmlDoubleVector(res) @@ -488,6 +526,35 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace { + check(origin.numCols == origin.numRows) { "Eigenvalue decomposition requires symmetric matrix" } + object : EigenDecomposition { + val cmEigen: EigenDecomposition_F32 by lazy { + DecompositionFactory_FDRM.eig(origin.numRows, true).apply { decompose(origin) } + } + + override val v by lazy { + val eigenvectors: List = List(origin.numRows) { cmEigen.getEigenVector(it) } + buildMatrix(origin.numRows, origin.numCols) { row, column -> + eigenvectors[row][column] + } + } + + override val d: Matrix by lazy { + val eigenvalues = List(origin.numRows) { cmEigen.getEigenvalue(it) } + + buildMatrix(origin.numRows, origin.numCols) { row, column -> + when (row) { + column -> eigenvalues[row].real + column - 1 -> eigenvalues[row].imaginary + column + 1 -> -eigenvalues[row].imaginary + else -> 0f + } + } + } + } + } + else -> null } @@ -533,16 +600,16 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace get() = safeTypeOf() + override val type: SafeType get() = safeTypeOf() @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlDoubleMatrix = when { + override fun Matrix.toEjml(): EjmlDoubleMatrix = when { this is EjmlDoubleMatrix<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleMatrix else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } } @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlDoubleVector = when { + override fun Point.toEjml(): EjmlDoubleVector = when { this is EjmlDoubleVector<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleVector else -> EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } @@ -569,21 +636,21 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace T.wrapMatrix() = EjmlDoubleMatrix(this) private fun T.wrapVector() = EjmlDoubleVector(this) - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { + override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.mult(toEjml().origin, other.toEjml().origin, out) return out.wrapMatrix() } - override fun Matrix.dot(vector: Point): EjmlDoubleVector { + override fun Matrix.dot(vector: Point): EjmlDoubleVector { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.mult(toEjml().origin, vector.toEjml().origin, out) return out.wrapVector() } - override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { + override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.add( @@ -599,19 +666,19 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace.times(value: Double): EjmlDoubleMatrix { + override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { val res = DMatrixSparseCSC(1, 1) CommonOps_DSCC.scale(value, toEjml().origin, res) return res.wrapMatrix() } - override fun Point.unaryMinus(): EjmlDoubleVector { + override fun Point.unaryMinus(): EjmlDoubleVector { val res = DMatrixSparseCSC(1, 1) CommonOps_DSCC.changeSign(toEjml().origin, res) return res.wrapVector() } - override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { + override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.add( @@ -627,7 +694,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace.plus(other: Point): EjmlDoubleVector { + override fun Point.plus(other: Point): EjmlDoubleVector { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.add( @@ -643,7 +710,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace.minus(other: Point): EjmlDoubleVector { + override fun Point.minus(other: Point): EjmlDoubleVector { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.add( @@ -659,17 +726,17 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace): EjmlDoubleMatrix = m * this + override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - override fun Point.times(value: Double): EjmlDoubleVector { + override fun Point.times(value: Double): EjmlDoubleVector { val res = DMatrixSparseCSC(1, 1) CommonOps_DSCC.scale(value, toEjml().origin, res) return res.wrapVector() } - override fun Double.times(v: Point): EjmlDoubleVector = v * this + override fun Double.times(v: Point): EjmlDoubleVector = v * this - override fun > computeAttribute(structure: Structure2D, attribute: A): V? { + override fun > computeAttribute(structure: Structure2D, attribute: A): V? { val origin = structure.toEjml().origin val raw: Any? = when (attribute) { @@ -681,16 +748,16 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace CommonOps_DSCC.det(origin) - QR -> object : QRDecomposition { + QR -> object : QRDecomposition { val ejmlQr by lazy { DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } } - override val q: Matrix get() = ejmlQr.getQ(null, false).wrapMatrix() - override val r: Matrix get() = ejmlQr.getR(null, false).wrapMatrix() + override val q: Matrix get() = ejmlQr.getQ(null, false).wrapMatrix() + override val r: Matrix get() = ejmlQr.getR(null, false).wrapMatrix() } - Cholesky -> object : CholeskyDecomposition { - override val l: Matrix by lazy { + Cholesky -> object : CholeskyDecomposition { + override val l: Matrix by lazy { val cholesky = DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) } @@ -698,16 +765,16 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace object : LupDecomposition { + LUP -> object : LupDecomposition { private val lup by lazy { DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } } - override val l: Matrix + override val l: Matrix get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular) - override val u: Matrix + override val u: Matrix get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular) override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer() } @@ -726,7 +793,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace, b: Matrix): EjmlDoubleMatrix { + public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { val res = DMatrixSparseCSC(1, 1) CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) return res.wrapMatrix() @@ -739,7 +806,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace, b: Point): EjmlDoubleVector { + public fun solve(a: Matrix, b: Point): EjmlDoubleVector { val res = DMatrixSparseCSC(1, 1) CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) return EjmlDoubleVector(res) diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt index 8b1b28e7d..dda42d42c 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt @@ -17,6 +17,7 @@ import space.kscience.kmath.linear.* import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.toArray import space.kscience.kmath.operations.algebra +import space.kscience.kmath.structures.Float64 import kotlin.random.Random import kotlin.random.asJavaRandom import kotlin.test.* @@ -63,7 +64,7 @@ internal class EjmlMatrixTest { val w = EjmlDoubleMatrix(m) val det: Double = w.getOrComputeAttribute(Determinant) ?: fail() assertEquals(CommonOps_DDRM.det(m), det) - val lup: LupDecomposition = w.getOrComputeAttribute(LUP) ?: fail() + val lup: LupDecomposition = w.getOrComputeAttribute(LUP) ?: fail() val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols) .also { it.decompose(m.copy()) } @@ -104,4 +105,11 @@ internal class EjmlMatrixTest { assertTrue { StructureND.contentEquals(one(dim, dim), res, 1e-3) } } + + @Test + fun eigenValueDecomposition() = EjmlLinearSpaceDDRM { + val matrix = EjmlDoubleMatrix(randomMatrix) + val eigen = matrix.getOrComputeAttribute(EIG) ?: fail() + assertMatrixEquals(matrix, eigen.v dot eigen.d dot eigen.v.transposed()) + } } diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt index 493a299c0..7d13f82da 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt @@ -9,12 +9,13 @@ import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point import space.kscience.kmath.operations.Float64L2Norm import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBuffer.Companion.double import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.indices import kotlin.math.pow -public typealias DoubleVector = Point +public typealias DoubleVector = Point public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer() @@ -41,7 +42,7 @@ public operator fun DoubleVector.plus(number: Number): DoubleVector = map { it + public operator fun Number.plus(vector: DoubleVector): DoubleVector = vector + this -public operator fun DoubleVector.unaryMinus(): Buffer = map { -it } +public operator fun DoubleVector.unaryMinus(): Buffer = map { -it } public operator fun DoubleVector.minus(other: DoubleVector): DoubleVector { require(size == other.size) { "Vector size $size expected but ${other.size} found" } diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt index 208c82c6d..39933076a 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt @@ -15,6 +15,7 @@ import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.asIterable import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import kotlin.math.pow @@ -30,7 +31,7 @@ import kotlin.math.pow * Functions that help create a real (Double) matrix */ -public typealias RealMatrix = Matrix +public typealias RealMatrix = Matrix public fun realMatrix(rowNum: Int, colNum: Int, initializer: Float64Field.(i: Int, j: Int) -> Double): RealMatrix = Double.algebra.linearSpace.buildMatrix(rowNum, colNum, initializer) @@ -114,7 +115,7 @@ public operator fun RealMatrix.minus(other: RealMatrix): RealMatrix = * Operations on columns */ -public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) -> Double): RealMatrix = +public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) -> Double): RealMatrix = Double.algebra.linearSpace.buildMatrix(rowNum, colNum + 1) { row, col -> if (col < colNum) get(row, col) diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt index e9fdfb506..d69333b0e 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt @@ -8,11 +8,12 @@ package space.kscience.kmath.real import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.operations.algebra +import space.kscience.kmath.structures.Float64 /** * Optimized dot product for real matrices */ -public infix fun Matrix.dot(other: Matrix): Matrix = Double.algebra.linearSpace.run { +public infix fun Matrix.dot(other: Matrix): Matrix = Double.algebra.linearSpace.run { this@dot dot other } \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt index 3a25739c3..282c19f42 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt @@ -7,16 +7,17 @@ package space.kscience.kmath.real import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import kotlin.math.floor -public val ClosedFloatingPointRange.length: Double get() = endInclusive - start +public val ClosedFloatingPointRange.length: Double get() = endInclusive - start /** * Create a Buffer-based grid with equally distributed [numberOfPoints] points. The range could be increasing or decreasing. * If range has a zero size, then the buffer consisting of [numberOfPoints] equal values is returned. */ -public fun Buffer.Companion.fromRange(range: ClosedFloatingPointRange, numberOfPoints: Int): Float64Buffer { +public fun Buffer.Companion.fromRange(range: ClosedFloatingPointRange, numberOfPoints: Int): Float64Buffer { require(numberOfPoints >= 2) { "Number of points in grid must be more than 1" } val normalizedRange = when { range.endInclusive > range.start -> range @@ -31,7 +32,7 @@ public fun Buffer.Companion.fromRange(range: ClosedFloatingPointRange, n * Create a Buffer-based grid with equally distributed points with a fixed [step]. The range could be increasing or decreasing. * If the step is larger than the range size, single point is returned. */ -public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange, step: Double): Float64Buffer { +public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange, step: Double): Float64Buffer { require(step > 0) { "The grid step must be positive" } val normalizedRange = when { range.endInclusive > range.start -> range @@ -51,4 +52,4 @@ public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange.step(step: Double): Float64Buffer = Buffer.withFixedStep(this, step) \ No newline at end of file +public infix fun ClosedFloatingPointRange.step(step: Double): Float64Buffer = Buffer.withFixedStep(this, step) \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt index 223cdd25d..7fac74f64 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt @@ -7,12 +7,13 @@ package space.kscience.kmath.real import space.kscience.kmath.nd.BufferND import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer /** * Map one [BufferND] using function without indices. */ -public inline fun BufferND.mapInline(crossinline transform: Float64Field.(Double) -> Double): BufferND { +public inline fun BufferND.mapInline(crossinline transform: Float64Field.(Double) -> Double): BufferND { val array = DoubleArray(indices.linearSize) { offset -> Float64Field.transform(buffer[offset]) } return BufferND(indices, Float64Buffer(array)) } @@ -20,7 +21,7 @@ public inline fun BufferND.mapInline(crossinline transform: Float64Field /** * Element by element application of any operation on elements to the whole array. Just like in numpy. */ -public operator fun Function1.invoke(elementND: BufferND): BufferND = +public operator fun Function1.invoke(elementND: BufferND): BufferND = elementND.mapInline { this@invoke(it) } /* plus and minus */ @@ -28,9 +29,9 @@ public operator fun Function1.invoke(elementND: BufferND /** * Summation operation for [BufferND] and single element */ -public operator fun BufferND.plus(arg: Double): BufferND = mapInline { it + arg } +public operator fun BufferND.plus(arg: Double): BufferND = mapInline { it + arg } /** * Subtraction operation between [BufferND] and single element */ -public operator fun BufferND.minus(arg: Double): BufferND = mapInline { it - arg } \ No newline at end of file +public operator fun BufferND.minus(arg: Double): BufferND = mapInline { it - arg } \ No newline at end of file diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt index f54ec6290..69ed9574d 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt @@ -170,7 +170,7 @@ internal class DoubleMatrixTest { assertEquals(matrix1.average(), 1.375) } -// fun printMatrix(m: Matrix) { +// fun printMatrix(m: Matrix) { // for (row in 0 until m.shape[0]) { // for (col in 0 until m.shape[1]) { // print(m[row, col]) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index e85f698c4..094ab5b6f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Float64 import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.math.max @@ -31,7 +32,7 @@ public inline fun A.polynomialSpace(block: PolynomialSpace.() -> /** * Evaluates value of [this] Double polynomial on provided Double argument. */ -public fun Polynomial.value(arg: Double): Double = +public fun Polynomial.value(arg: Double): Double = coefficients.reduceIndexedOrNull { index, acc, c -> acc + c * arg.pow(index) } ?: .0 diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt index 666379c7a..7aa1b601a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt @@ -8,6 +8,7 @@ import space.kscience.attributes.AttributesBuilder import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.indices @@ -27,7 +28,7 @@ public class GaussIntegrator( public val algebra: Field, ) : UnivariateIntegrator { - private fun buildRule(integrand: UnivariateIntegrand): Pair, Buffer> { + private fun buildRule(integrand: UnivariateIntegrand): Pair, Buffer> { val factory = integrand[GaussIntegratorRuleFactory] ?: GaussLegendreRuleFactory val predefinedRanges = integrand[UnivariateIntegrandRanges] if (predefinedRanges == null || predefinedRanges.ranges.isEmpty()) { @@ -89,7 +90,7 @@ public val Field.gaussIntegrator: GaussIntegrator get() = GaussI */ @UnstableKMathAPI public inline fun GaussIntegrator.integrate( - range: ClosedRange, + range: ClosedRange, order: Int = 10, intervals: Int = 10, noinline attributesBuilder: AttributesBuilder>.() -> Unit = {}, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt index 60777bfdb..cf067f602 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt @@ -8,16 +8,17 @@ package space.kscience.kmath.integration import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.mapToBuffer import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.asBuffer import kotlin.math.ulp import kotlin.native.concurrent.ThreadLocal public interface GaussIntegratorRuleFactory { - public fun build(numPoints: Int): Pair, Buffer> + public fun build(numPoints: Int): Pair, Buffer> public companion object : IntegrandAttribute { - public fun double(numPoints: Int, range: ClosedRange): Pair, Buffer> = + public fun double(numPoints: Int, range: ClosedRange): Pair, Buffer> = GaussLegendreRuleFactory.build(numPoints, range) } } @@ -28,9 +29,9 @@ public interface GaussIntegratorRuleFactory { */ public fun GaussIntegratorRuleFactory.build( numPoints: Int, - range: ClosedRange, -): Pair, Buffer> { - val normalized: Pair, Buffer> = build(numPoints) + range: ClosedRange, +): Pair, Buffer> { + val normalized: Pair, Buffer> = build(numPoints) val length = range.endInclusive - range.start val points = normalized.first.mapToBuffer(Float64Field.bufferFactory) { @@ -55,13 +56,13 @@ public fun GaussIntegratorRuleFactory.build( @ThreadLocal public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { - private val cache = HashMap, Buffer>>() + private val cache = HashMap, Buffer>>() - private fun getOrBuildRule(numPoints: Int): Pair, Buffer> = + private fun getOrBuildRule(numPoints: Int): Pair, Buffer> = cache.getOrPut(numPoints) { buildRule(numPoints) } - private fun buildRule(numPoints: Int): Pair, Buffer> { + private fun buildRule(numPoints: Int): Pair, Buffer> { if (numPoints == 1) { // Break recursion. return Pair( @@ -73,7 +74,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { // Get previous rule. // If it has not been computed, yet it will trigger a recursive call // to this method. - val previousPoints: Buffer = getOrBuildRule(numPoints - 1).first + val previousPoints: Buffer = getOrBuildRule(numPoints - 1).first // Compute next rule. val points = DoubleArray(numPoints) @@ -162,7 +163,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { return Pair(points.asBuffer(), weights.asBuffer()) } - override fun build(numPoints: Int): Pair, Buffer> = getOrBuildRule(numPoints) + override fun build(numPoints: Int): Pair, Buffer> = getOrBuildRule(numPoints) override fun toString(): String = "GaussLegendreRule" } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt index babc86c54..cbf694e41 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.integration import space.kscience.attributes.* +import space.kscience.kmath.structures.Float64 public interface IntegrandAttribute : Attribute @@ -44,9 +45,9 @@ public inline val Integrand.valueOrNull: T? get() = attribu */ public inline val Integrand.value: T get() = valueOrNull ?: error("No value in the integrand") -public object IntegrandRelativeAccuracy : IntegrandAttribute +public object IntegrandRelativeAccuracy : IntegrandAttribute -public object IntegrandAbsoluteAccuracy : IntegrandAttribute +public object IntegrandAbsoluteAccuracy : IntegrandAttribute public object IntegrandCallsPerformed : IntegrandAttribute diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt index 60e53c54a..ac589e160 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt @@ -10,6 +10,7 @@ import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.sum +import space.kscience.kmath.structures.Float64 /** * Use double pass Simpson rule integration with a fixed number of points. @@ -24,7 +25,7 @@ public class SimpsonIntegrator( ) : UnivariateIntegrator { private fun integrateRange( - integrand: UnivariateIntegrand, range: ClosedRange, numPoints: Int, + integrand: UnivariateIntegrand, range: ClosedRange, numPoints: Int, ): T = algebra { val h: Double = (range.endInclusive - range.start) / (numPoints - 1) val values: List = List(numPoints) { i -> @@ -75,9 +76,9 @@ public val Field.simpsonIntegrator: SimpsonIntegrator get() = Si * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses * the maximum number of points. By default, uses 10 points. */ -public object DoubleSimpsonIntegrator : UnivariateIntegrator { +public object DoubleSimpsonIntegrator : UnivariateIntegrator { private fun integrateRange( - integrand: UnivariateIntegrand, range: ClosedRange, numPoints: Int, + integrand: UnivariateIntegrand, range: ClosedRange, numPoints: Int, ): Double { val h: Double = (range.endInclusive - range.start) / (numPoints - 1) val values = DoubleArray(numPoints) { i -> @@ -96,7 +97,7 @@ public object DoubleSimpsonIntegrator : UnivariateIntegrator { return res } - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val ranges = integrand[UnivariateIntegrandRanges] return if (ranges != null) { val res = ranges.ranges.sumOf { integrateRange(integrand, it.first, it.second) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index 24149959b..5faeed011 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -14,6 +14,7 @@ import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.MutableBufferFactory @@ -59,7 +60,7 @@ public class SplineIntegrator>( val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) - val nodes: Buffer = integrand[UnivariateIntegrationNodes] ?: run { + val nodes: Buffer = integrand[UnivariateIntegrationNodes] ?: run { val numPoints = integrand[IntegrandMaxCalls] ?: 100 val step = (range.endInclusive - range.start) / (numPoints - 1) Float64Buffer(numPoints) { i -> range.start + i * step } @@ -85,12 +86,12 @@ public class SplineIntegrator>( * uses the maximum number of points. By default, uses 10 points. */ @UnstableKMathAPI -public object DoubleSplineIntegrator : UnivariateIntegrator { - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { +public object DoubleSplineIntegrator : UnivariateIntegrator { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val range = integrand[IntegrationRange] ?: 0.0..1.0 - val interpolator: PolynomialInterpolator = SplineInterpolator(Float64Field, Float64Field.bufferFactory) + val interpolator: PolynomialInterpolator = SplineInterpolator(Float64Field, Float64Field.bufferFactory) - val nodes: Buffer = integrand[UnivariateIntegrationNodes] ?: run { + val nodes: Buffer = integrand[UnivariateIntegrationNodes] ?: run { val numPoints = integrand[IntegrandMaxCalls] ?: 100 val step = (range.endInclusive - range.start) / (numPoints - 1) Float64Buffer(numPoints) { i -> range.start + i * step } @@ -108,5 +109,5 @@ public object DoubleSplineIntegrator : UnivariateIntegrator { @Suppress("unused") @UnstableKMathAPI -public inline val Float64Field.splineIntegrator: UnivariateIntegrator +public inline val Float64Field.splineIntegrator: UnivariateIntegrator get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt index e5d220f0f..72b678e2a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.integration import space.kscience.attributes.* import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer public class UnivariateIntegrand( @@ -36,15 +37,15 @@ public inline fun UnivariateIntegrand( public typealias UnivariateIntegrator = Integrator> -public object IntegrationRange : IntegrandAttribute> +public object IntegrationRange : IntegrandAttribute> /** * Set of univariate integration ranges. First components correspond to the ranges themselves, second components to * the number of integration nodes per range. */ -public class UnivariateIntegrandRanges(public val ranges: List, Int>>) { - public constructor(vararg pairs: Pair, Int>) : this(pairs.toList()) +public class UnivariateIntegrandRanges(public val ranges: List, Int>>) { + public constructor(vararg pairs: Pair, Int>) : this(pairs.toList()) override fun toString(): String { val rangesString = ranges.joinToString(separator = ",") { (range, points) -> @@ -56,7 +57,7 @@ public class UnivariateIntegrandRanges(public val ranges: List } -public object UnivariateIntegrationNodes : IntegrandAttribute> +public object UnivariateIntegrationNodes : IntegrandAttribute> public fun AttributesBuilder>.integrationNodes(vararg nodes: Double) { UnivariateIntegrationNodes(Float64Buffer(nodes)) @@ -78,7 +79,7 @@ public inline fun UnivariateIntegrator.integrate( */ @UnstableKMathAPI public inline fun UnivariateIntegrator.integrate( - range: ClosedRange, + range: ClosedRange, noinline attributeBuilder: AttributesBuilder>.() -> Unit = {}, noinline function: (Double) -> T, ): UnivariateIntegrand { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt index 2b58f0b05..381c75b65 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBufferFactory /** @@ -78,5 +79,5 @@ public fun > Field.splineInterpolator( bufferFactory: MutableBufferFactory, ): SplineInterpolator = SplineInterpolator(this, bufferFactory) -public val Float64Field.splineInterpolator: SplineInterpolator +public val Float64Field.splineInterpolator: SplineInterpolator get() = SplineInterpolator(this, bufferFactory) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt index c62d2c8bc..bb5ddf9c6 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt @@ -19,7 +19,7 @@ internal class LinearInterpolatorTest { 3.0 to 4.0 ) - //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) + //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) val function = Float64Field.linearInterpolator.interpolate(data) assertEquals(null, function(-1.0)) assertEquals(0.5, function(0.5)) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt index 8869a1f45..52efc5db6 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -19,7 +19,7 @@ internal class SplineInterpolatorTest { x to sin(x) } - //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) + //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) val function = Float64Field.splineInterpolator.interpolate(data, Double.NaN) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt index ca9a37dcb..702a050e2 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt @@ -25,7 +25,7 @@ public val Circle2D<*>.circumference: Double get() = radius * 2 * PI public data class Float64Circle2D( @Serializable(Float64Space2D.VectorSerializer::class) override val center: Float64Vector2D, override val radius: Float64, -) : Circle2D +) : Circle2D public fun Circle2D(center: Vector2D, radius: Double): Float64Circle2D = Float64Circle2D( center as? Float64Vector2D ?: Float64Vector2D(center.x, center.y), diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt index fa07190bb..03b6602ea 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt @@ -113,7 +113,7 @@ public object Float64Space3D : GeometrySpace, Double> { /** * Vector product with the right basis */ - public infix fun Vector3D.cross(other: Vector3D): Vector3D = vectorProduct(this, other) + public infix fun Vector3D.cross(other: Vector3D): Vector3D = vectorProduct(this, other) public val xAxis: Float64Vector3D = vector(1.0, 0.0, 0.0) public val yAxis: Float64Vector3D = vector(0.0, 1.0, 0.0) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt index cebad79a2..78fe01733 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt @@ -90,7 +90,7 @@ public fun Float64Space3D.rotate( /** * Rotate a [Float64] vector in 3D space with a rotation matrix */ -public fun Float64Space3D.rotate(vector: Float64Vector3D, matrix: Matrix): Vector3D { +public fun Float64Space3D.rotate(vector: Float64Vector3D, matrix: Matrix): Vector3D { require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" } return with(linearSpace) { (matrix dot vector).asVector3D() } } @@ -101,7 +101,7 @@ public fun Float64Space3D.rotate(vector: Float64Vector3D, matrix: Matrix @OptIn(UnstableKMathAPI::class) public fun Quaternion.toRotationMatrix( linearSpace: LinearSpace = Float64Field.linearSpace, -): Matrix { +): Matrix { val s = QuaternionAlgebra.norm(this).pow(-2) return linearSpace.matrix(3, 3)( 1.0 - 2 * s * (y * y + z * z), 2 * s * (x * y - z * w), 2 * s * (x * z + y * w), @@ -115,7 +115,7 @@ public fun Quaternion.toRotationMatrix( * * taken from https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ */ -public fun Quaternion.Companion.fromRotationMatrix(matrix: Matrix): Quaternion { +public fun Quaternion.Companion.fromRotationMatrix(matrix: Matrix): Quaternion { require(matrix.colNum == 3 && matrix.rowNum == 3) { "Rotation matrix should be 3x3 but is ${matrix.rowNum}x${matrix.colNum}" } val trace = matrix[0, 0] + matrix[1, 1] + matrix[2, 2] @@ -256,7 +256,7 @@ public fun Quaternion.Companion.fromEuler( * Based on https://github.com/mrdoob/three.js/blob/master/src/math/Euler.js */ public fun AngleVector.Companion.fromRotationMatrix( - matrix: Matrix, + matrix: Matrix, rotationOrder: RotationOrder, gimbaldLockThreshold: Double = 0.9999999, ): AngleVector = when (rotationOrder) { diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt index 22b58d260..6deff6bc8 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt @@ -9,15 +9,15 @@ import space.kscience.kmath.structures.Float64 import kotlin.math.abs import kotlin.test.assertEquals -fun ClosedRange.generateList(step: Double): List = generateSequence(start) { previous -> +fun ClosedRange.generateList(step: Double): List = generateSequence(start) { previous -> if (previous == Double.POSITIVE_INFINITY) return@generateSequence null val next = previous + step if (next > endInclusive) null else next }.toList() fun grid( - xRange: ClosedRange, - yRange: ClosedRange, + xRange: ClosedRange, + yRange: ClosedRange, step: Double, ): List> { val xs = xRange.generateList(step) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt index a931b957d..b99f0bf75 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt @@ -9,6 +9,7 @@ import kotlinx.atomicfu.atomic import kotlinx.atomicfu.getAndUpdate import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Group +import space.kscience.kmath.structures.Float64 /** * Common representation for atomic counters @@ -18,7 +19,7 @@ public interface Counter { public val value: T public companion object { - public fun ofDouble(): ObjectCounter = ObjectCounter(Float64Field) + public fun ofDouble(): ObjectCounter = ObjectCounter(Float64Field) public fun of(group: Group): ObjectCounter = ObjectCounter(group) } } diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt index 75f18a5a4..833ea6eb5 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.domains.center import space.kscience.kmath.linear.Point import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 /** @@ -49,7 +50,7 @@ public interface Histogram1DBuilder : HistogramBuilder.fill(items: Iterable): Unit = +public fun Histogram1DBuilder.fill(items: Iterable): Unit = items.forEach(this::putValue) @UnstableKMathAPI diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt index 770fd70a0..d1863edb2 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBufferFactory import kotlin.math.floor @@ -137,7 +138,7 @@ public fun Histogram.Companion.uniform1D( @UnstableKMathAPI public fun UniformHistogram1DGroup.produce( - buffer: Buffer, + buffer: Buffer, ): UniformHistogram1D = produce { fill(buffer) } /** diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt index 4a53ea1a0..a6d817a67 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt @@ -24,8 +24,8 @@ public typealias HyperSquareBin = DomainBin */ public class UniformHistogramGroupND>( override val valueAlgebraND: FieldOpsND, - private val lower: Buffer, - private val upper: Buffer, + private val lower: Buffer, + private val upper: Buffer, private val binNums: IntArray = IntArray(lower.size) { 20 }, private val valueBufferFactory: BufferFactory = valueAlgebraND.elementAlgebra.bufferFactory, ) : HistogramGroupND { @@ -54,7 +54,7 @@ public class UniformHistogramGroupND>( else -> floor((value - lower[axis]) / binSize[axis]).toInt() } - override fun getIndexOrNull(point: Buffer): IntArray = IntArray(dimension) { + override fun getIndexOrNull(point: Buffer): IntArray = IntArray(dimension) { getIndex(it, point[it]) } @@ -93,7 +93,7 @@ public class UniformHistogramGroupND>( val hBuilder = object : HistogramBuilder { override val defaultValue: V get() = valueAlgebraND.elementAlgebra.one - override fun putValue(point: Point, value: V) = with(valueAlgebraND.elementAlgebra) { + override fun putValue(point: Point, value: V) = with(valueAlgebraND.elementAlgebra) { val index = getIndexOrNull(point) ndCounter[index].add(value) } @@ -120,17 +120,17 @@ public class UniformHistogramGroupND>( */ public fun > Histogram.Companion.uniformNDFromRanges( valueAlgebraND: FieldOpsND, - vararg ranges: ClosedFloatingPointRange, + vararg ranges: ClosedFloatingPointRange, bufferFactory: BufferFactory = valueAlgebraND.elementAlgebra.bufferFactory, ): UniformHistogramGroupND = UniformHistogramGroupND( valueAlgebraND, - ranges.map(ClosedFloatingPointRange::start).asBuffer(), - ranges.map(ClosedFloatingPointRange::endInclusive).asBuffer(), + ranges.map(ClosedFloatingPointRange::start).asBuffer(), + ranges.map(ClosedFloatingPointRange::endInclusive).asBuffer(), valueBufferFactory = bufferFactory ) public fun Histogram.Companion.uniformDoubleNDFromRanges( - vararg ranges: ClosedFloatingPointRange, + vararg ranges: ClosedFloatingPointRange, ): UniformHistogramGroupND = uniformNDFromRanges(Floa64FieldOpsND, *ranges) @@ -145,22 +145,22 @@ public fun Histogram.Companion.uniformDoubleNDFromRanges( */ public fun > Histogram.Companion.uniformNDFromRanges( valueAlgebraND: FieldOpsND, - vararg ranges: Pair, Int>, + vararg ranges: Pair, Int>, bufferFactory: BufferFactory = valueAlgebraND.elementAlgebra.bufferFactory, ): UniformHistogramGroupND = UniformHistogramGroupND( valueAlgebraND, ranges - .map(Pair, Int>::first) - .map(ClosedFloatingPointRange::start) + .map(Pair, Int>::first) + .map(ClosedFloatingPointRange::start) .asBuffer(), ranges - .map(Pair, Int>::first) - .map(ClosedFloatingPointRange::endInclusive) + .map(Pair, Int>::first) + .map(ClosedFloatingPointRange::endInclusive) .asBuffer(), - ranges.map(Pair, Int>::second).toIntArray(), + ranges.map(Pair, Int>::second).toIntArray(), valueBufferFactory = bufferFactory ) public fun Histogram.Companion.uniformDoubleNDFromRanges( - vararg ranges: Pair, Int>, + vararg ranges: Pair, Int>, ): UniformHistogramGroupND = uniformNDFromRanges(Floa64FieldOpsND, *ranges) \ No newline at end of file diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt index c8be4f846..dfe44fe05 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt @@ -17,7 +17,7 @@ import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.structures.* import java.util.* -private fun > TreeMap.getBin(value: Double): B? { +private fun > TreeMap.getBin(value: Double): B? { // check ceiling entry and return it if it is what needed val ceil = ceilingEntry(value)?.value if (ceil != null && value in ceil) return ceil @@ -53,7 +53,7 @@ public class TreeHistogramGroup( override val bufferFactory: MutableBufferFactory> = MutableBufferFactory() internal inner class DomainCounter(val domain: DoubleDomain1D, val counter: Counter = Counter.of(valueAlgebra)) : - ClosedRange by domain.range + ClosedRange by domain.range @PublishedApi internal inner class TreeHistogramBuilder : Histogram1DBuilder { @@ -153,7 +153,7 @@ public class TreeHistogramGroup( */ public fun Histogram.Companion.custom1D( valueAlgebra: A, - borders: Buffer, + borders: Buffer, ): TreeHistogramGroup where A : Ring, A : ScaleOperations { val sorted = borders.sorted() diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt index 1b7bbf3ed..87eef4331 100644 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt @@ -8,15 +8,16 @@ package space.kscience.kmath.jafama import net.jafama.FastMath import net.jafama.StrictFastMath import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBufferFactory /** * A field for [Double] (using FastMath) without boxing. Does not produce appropriate field element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object JafamaDoubleField : ExtendedField, Norm, ScaleOperations { +public object JafamaDoubleField : ExtendedField, Norm, ScaleOperations { - override val bufferFactory: MutableBufferFactory get() = DoubleField.bufferFactory + override val bufferFactory: MutableBufferFactory get() = DoubleField.bufferFactory override inline val zero: Double get() = 0.0 override inline val one: Double get() = 1.0 @@ -68,9 +69,9 @@ public object JafamaDoubleField : ExtendedField, Norm, S * A field for [Double] (using StrictMath) without boxing. Does not produce appropriate field element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object StrictJafamaDoubleField : ExtendedField, Norm, ScaleOperations { +public object StrictJafamaDoubleField : ExtendedField, Norm, ScaleOperations { - override val bufferFactory: MutableBufferFactory get() = DoubleField.bufferFactory + override val bufferFactory: MutableBufferFactory get() = DoubleField.bufferFactory override inline val zero: Double get() = 0.0 override inline val one: Double get() = 1.0 diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt index 6a8749946..eae53c12c 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt @@ -14,56 +14,57 @@ import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.ExponentialOperations import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.TrigonometricOperations +import space.kscience.kmath.structures.Float64 public class MultikDoubleAlgebra( multikEngine: Engine, ) : MultikDivisionTensorAlgebra(multikEngine), - TrigonometricOperations>, ExponentialOperations> { + TrigonometricOperations>, ExponentialOperations> { override val elementAlgebra: Float64Field get() = Float64Field override val dataType: DataType get() = DataType.DoubleDataType - override fun sin(arg: StructureND): MultikTensor = + override fun sin(arg: StructureND): MultikTensor = multikMath.mathEx.sin(arg.asMultik().array).wrap() - override fun cos(arg: StructureND): MultikTensor = + override fun cos(arg: StructureND): MultikTensor = multikMath.mathEx.cos(arg.asMultik().array).wrap() - override fun tan(arg: StructureND): MultikTensor = sin(arg) / cos(arg) + override fun tan(arg: StructureND): MultikTensor = sin(arg) / cos(arg) @PerformancePitfall - override fun asin(arg: StructureND): MultikTensor = arg.map { asin(it) } + override fun asin(arg: StructureND): MultikTensor = arg.map { asin(it) } @PerformancePitfall - override fun acos(arg: StructureND): MultikTensor = arg.map { acos(it) } + override fun acos(arg: StructureND): MultikTensor = arg.map { acos(it) } @PerformancePitfall - override fun atan(arg: StructureND): MultikTensor = arg.map { atan(it) } + override fun atan(arg: StructureND): MultikTensor = arg.map { atan(it) } - override fun exp(arg: StructureND): MultikTensor = + override fun exp(arg: StructureND): MultikTensor = multikMath.mathEx.exp(arg.asMultik().array).wrap() - override fun ln(arg: StructureND): MultikTensor = multikMath.mathEx.log(arg.asMultik().array).wrap() + override fun ln(arg: StructureND): MultikTensor = multikMath.mathEx.log(arg.asMultik().array).wrap() - override fun sinh(arg: StructureND): MultikTensor = (exp(arg) - exp(-arg)) / 2.0 + override fun sinh(arg: StructureND): MultikTensor = (exp(arg) - exp(-arg)) / 2.0 - override fun cosh(arg: StructureND): MultikTensor = (exp(arg) + exp(-arg)) / 2.0 + override fun cosh(arg: StructureND): MultikTensor = (exp(arg) + exp(-arg)) / 2.0 - override fun tanh(arg: StructureND): MultikTensor { + override fun tanh(arg: StructureND): MultikTensor { val expPlus = exp(arg) val expMinus = exp(-arg) return (expPlus - expMinus) / (expPlus + expMinus) } @PerformancePitfall - override fun asinh(arg: StructureND): MultikTensor = arg.map { asinh(it) } + override fun asinh(arg: StructureND): MultikTensor = arg.map { asinh(it) } @PerformancePitfall - override fun acosh(arg: StructureND): MultikTensor = arg.map { acosh(it) } + override fun acosh(arg: StructureND): MultikTensor = arg.map { acosh(it) } @PerformancePitfall - override fun atanh(arg: StructureND): MultikTensor = arg.map { atanh(it) } + override fun atanh(arg: StructureND): MultikTensor = arg.map { atanh(it) } - override fun scalar(value: Double): MultikTensor = Multik.ndarrayOf(value).wrap() + override fun scalar(value: Double): MultikTensor = Multik.ndarrayOf(value).wrap() } //public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt index 51f59f731..01a182034 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt @@ -15,6 +15,7 @@ import space.kscience.kmath.UnsafeKMathAPI import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Float64 /** * Represents [AlgebraND] over [Nd4jArrayAlgebra]. @@ -193,31 +194,31 @@ public sealed interface Nd4jArrayExtendedFieldOps> : public open class DoubleNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps { override val elementAlgebra: Float64Field get() = Float64Field - override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class) - override val StructureND.ndArray: INDArray + override val StructureND.ndArray: INDArray get() = when (this) { - is Nd4jArrayStructure -> ndArray + is Nd4jArrayStructure -> ndArray else -> Nd4j.zeros(*shape.asArray()).also { elements().forEach { (idx, value) -> it.putScalar(idx, value) } } } - override fun scale(a: StructureND, value: Double): Nd4jArrayStructure = a.ndArray.mul(value).wrap() + override fun scale(a: StructureND, value: Double): Nd4jArrayStructure = a.ndArray.mul(value).wrap() - override operator fun StructureND.div(arg: Double): Nd4jArrayStructure = ndArray.div(arg).wrap() + override operator fun StructureND.div(arg: Double): Nd4jArrayStructure = ndArray.div(arg).wrap() - override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure = ndArray.add(arg).wrap() + override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure = ndArray.add(arg).wrap() - override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure = ndArray.sub(arg).wrap() + override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure = ndArray.sub(arg).wrap() - override operator fun StructureND.times(arg: Double): Nd4jArrayStructure = ndArray.mul(arg).wrap() + override operator fun StructureND.times(arg: Double): Nd4jArrayStructure = ndArray.mul(arg).wrap() - override operator fun Double.div(arg: StructureND): Nd4jArrayStructure = + override operator fun Double.div(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rdiv(this).wrap() - override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure = + override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() public companion object : DoubleNd4jArrayFieldOps() diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt index 0a2305e71..cf5d8988b 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.nd4j import org.nd4j.linalg.api.ndarray.INDArray import org.nd4j.linalg.api.shape.Shape +import space.kscience.kmath.structures.Float64 private class Nd4jArrayIndicesIterator(private val iterateOver: INDArray) : Iterator { private var i: Int = 0 @@ -42,7 +43,7 @@ private sealed class Nd4jArrayIteratorBase(protected val iterateOver: IND } } -private class Nd4jArrayDoubleIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase(iterateOver) { +private class Nd4jArrayDoubleIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase(iterateOver) { override fun getSingle(indices: LongArray): Double = iterateOver.getDouble(*indices) } diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt index ac4ef68d2..b8c04faa0 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.nd4j import org.nd4j.linalg.api.ndarray.INDArray import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* +import space.kscience.kmath.structures.Float64 /** * Represents a [StructureND] wrapping an [INDArray] object. @@ -48,7 +49,7 @@ public data class Nd4jArrayIntStructure(override val ndArray: INDArray) : Nd4jAr */ public fun INDArray.asIntStructure(): Nd4jArrayIntStructure = Nd4jArrayIntStructure(this) -public data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4jArrayStructure(), +public data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4jArrayStructure(), StructureNDOfDouble { override fun elementsIterator(): Iterator> = ndArray.realIterator() @@ -64,7 +65,7 @@ public data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4 /** * Wraps this [INDArray] to [Nd4jArrayStructure]. */ -public fun INDArray.asDoubleStructure(): Nd4jArrayStructure = Nd4jArrayDoubleStructure(this) +public fun INDArray.asDoubleStructure(): Nd4jArrayStructure = Nd4jArrayDoubleStructure(this) public data class Nd4jArrayFloatStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt index 954984a69..af69c8c44 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt @@ -14,9 +14,13 @@ import org.nd4j.linalg.factory.ops.NDBase import org.nd4j.linalg.ops.transforms.Transforms import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.UnsafeKMathAPI -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.ColumnStrides +import space.kscience.kmath.nd.ShapeND +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.asArray import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra @@ -177,13 +181,13 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra override val elementAlgebra: Float64Field get() = Float64Field - override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() @OptIn(UnsafeKMathAPI::class) override fun mutableStructureND( shape: ShapeND, initializer: Float64Field.(IntArray) -> Double, - ): Nd4jArrayStructure { + ): Nd4jArrayStructure { val array: INDArray = Nd4j.zeros(*shape.asArray()) val indices = ColumnStrides(shape) indices.asSequence().forEach { index -> @@ -194,29 +198,29 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class) - override val StructureND.ndArray: INDArray + override val StructureND.ndArray: INDArray get() = when (this) { - is Nd4jArrayStructure -> ndArray + is Nd4jArrayStructure -> ndArray else -> Nd4j.zeros(*shape.asArray()).also { elements().forEach { (idx, value) -> it.putScalar(idx, value) } } } - override fun StructureND.valueOrNull(): Double? = + override fun StructureND.valueOrNull(): Double? = if (shape == ShapeND(1)) ndArray.getDouble(0) else null // TODO rewrite override fun diagonalEmbedding( - diagonalEntries: StructureND, + diagonalEntries: StructureND, offset: Int, dim1: Int, dim2: Int, - ): Tensor = DoubleTensorAlgebra.diagonalEmbedding(diagonalEntries, offset, dim1, dim2) + ): Tensor = DoubleTensorAlgebra.diagonalEmbedding(diagonalEntries, offset, dim1, dim2) - override fun StructureND.sum(): Double = ndArray.sumNumber().toDouble() - override fun StructureND.min(): Double = ndArray.minNumber().toDouble() - override fun StructureND.max(): Double = ndArray.maxNumber().toDouble() - override fun mean(structureND: StructureND): Double = structureND.ndArray.meanNumber().toDouble() - override fun std(structureND: StructureND): Double = structureND.ndArray.stdNumber().toDouble() - override fun variance(structureND: StructureND): Double = structureND.ndArray.varNumber().toDouble() + override fun StructureND.sum(): Double = ndArray.sumNumber().toDouble() + override fun StructureND.min(): Double = ndArray.minNumber().toDouble() + override fun StructureND.max(): Double = ndArray.maxNumber().toDouble() + override fun mean(structureND: StructureND): Double = structureND.ndArray.meanNumber().toDouble() + override fun std(structureND: StructureND): Double = structureND.ndArray.stdNumber().toDouble() + override fun variance(structureND: StructureND): Double = structureND.ndArray.varNumber().toDouble() } diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt index 07fa97efb..25f1ec72e 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.misc.log import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64L2Norm import space.kscience.kmath.operations.algebra +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import kotlin.math.abs @@ -27,7 +28,7 @@ public object QowRuns : OptimizationAttribute public object QowOptimizer : Optimizer { private val linearSpace: LinearSpace = Double.algebra.linearSpace - private val solver: LinearSolver = linearSpace.lupSolver() + private val solver: LinearSolver = linearSpace.lupSolver() @OptIn(UnstableKMathAPI::class) private class QoWeight( @@ -47,7 +48,7 @@ public object QowOptimizer : Optimizer { /** * Derivatives of the spectrum over parameters. First index in the point number, second one - index of parameter */ - val derivs: Matrix by lazy { + val derivs: Matrix by lazy { linearSpace.buildMatrix(problem.data.size, symbols.size) { d, s -> problem.distance(d).derivative(symbols[s]).invoke(allParameters) } @@ -56,14 +57,14 @@ public object QowOptimizer : Optimizer { /** * Array of dispersions in each point */ - val dispersion: Point by lazy { + val dispersion: Point by lazy { Float64Buffer(problem.data.size) { d -> 1.0 / problem.weight(d).invoke(allParameters) } } - val prior: DifferentiableExpression? - get() = problem.attributes[OptimizationPrior()]?.withDefaultArgs(allParameters) + val prior: DifferentiableExpression? + get() = problem.attributes[OptimizationPrior()]?.withDefaultArgs(allParameters) override fun toString(): String = freeParameters.toString() } @@ -86,7 +87,7 @@ public object QowOptimizer : Optimizer { * * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 */ - private fun QoWeight.covarF(): Matrix = + private fun QoWeight.covarF(): Matrix = linearSpace.matrix(size, size).symmetric { s1, s2 -> (0 until data.size).sumOf { d -> derivs[d, s1] * derivs[d, s2] / dispersion[d] } } @@ -95,7 +96,7 @@ public object QowOptimizer : Optimizer { * Experimental covariance Eq (22) from * http://arxiv.org/abs/physics/0604127 */ - private fun QoWeight.covarFExp(theta: Map): Matrix = + private fun QoWeight.covarFExp(theta: Map): Matrix = with(linearSpace) { /* * Важно! Если не делать предварителього вычисления этих производных, то @@ -116,7 +117,7 @@ public object QowOptimizer : Optimizer { */ private fun QoWeight.getEqDerivValues( theta: Map = freeParameters, - ): Matrix = with(linearSpace) { + ): Matrix = with(linearSpace) { //Derivative of k Eq over l parameter val sderiv = buildMatrix(data.size, size) { d, s -> distanceDerivative(symbols[s], d, theta) @@ -141,7 +142,7 @@ public object QowOptimizer : Optimizer { /** * Quasi optimal weights equations values */ - private fun QoWeight.getEqValues(theta: Map): Point { + private fun QoWeight.getEqValues(theta: Map): Point { val distances = Float64Buffer(data.size) { d -> distance(d, theta) } return Float64Buffer(size) { s -> val base = (0 until data.size).sumOf { d -> distances[d] * derivs[d, s] / dispersion[d] } @@ -155,7 +156,7 @@ public object QowOptimizer : Optimizer { private fun QoWeight.newtonianStep( theta: Map, - eqValues: Point, + eqValues: Point, ): QoWeight = linearSpace { val start = theta.toPoint() val invJacob = solver.inverse(getEqDerivValues(theta)) @@ -224,7 +225,7 @@ public object QowOptimizer : Optimizer { return QoWeight(problem, par) } - private fun QoWeight.covariance(): NamedMatrix { + private fun QoWeight.covariance(): NamedMatrix { val logger = problem.attributes[OptimizationLog] logger?.log { diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt index 44b7d17bd..d27783926 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -16,26 +16,27 @@ import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.bindSymbol +import space.kscience.kmath.structures.Float64 import kotlin.math.pow /** * Specify the way to compute distance from point to the curve as DifferentiableExpression */ public interface PointToCurveDistance { - public fun distance(problem: XYFit, index: Int): DifferentiableExpression + public fun distance(problem: XYFit, index: Int): DifferentiableExpression public companion object : OptimizationAttribute { public val byY: PointToCurveDistance = object : PointToCurveDistance { - override fun distance(problem: XYFit, index: Int): DifferentiableExpression { + override fun distance(problem: XYFit, index: Int): DifferentiableExpression { val x = problem.data.x[index] val y = problem.data.y[index] - return object : DifferentiableExpression { - override val type: SafeType get() = DoubleField.type + return object : DifferentiableExpression { + override val type: SafeType get() = DoubleField.type override fun derivativeOrNull( symbols: List, - ): Expression? = problem.model.derivativeOrNull(symbols)?.let { derivExpression -> + ): Expression? = problem.model.derivativeOrNull(symbols)?.let { derivExpression -> Expression(DoubleField.type) { arguments -> derivExpression.invoke(arguments + (Symbol.x to x)) } @@ -56,19 +57,19 @@ public interface PointToCurveDistance { * By default, uses Dispersion^-1 */ public interface PointWeight { - public fun weight(problem: XYFit, index: Int): DifferentiableExpression + public fun weight(problem: XYFit, index: Int): DifferentiableExpression public companion object : OptimizationAttribute { public fun bySigma(sigmaSymbol: Symbol): PointWeight = object : PointWeight { - override fun weight(problem: XYFit, index: Int): DifferentiableExpression = - object : DifferentiableExpression { - override val type: SafeType get() = DoubleField.type + override fun weight(problem: XYFit, index: Int): DifferentiableExpression = + object : DifferentiableExpression { + override val type: SafeType get() = DoubleField.type override fun invoke(arguments: Map): Double { return problem.data[sigmaSymbol]?.get(index)?.pow(-2) ?: 1.0 } - override fun derivativeOrNull(symbols: List): Expression = + override fun derivativeOrNull(symbols: List): Expression = Expression(DoubleField.type) { 0.0 } } @@ -85,24 +86,24 @@ public interface PointWeight { */ public class XYFit( public val data: XYColumnarData, - public val model: DifferentiableExpression, + public val model: DifferentiableExpression, override val attributes: Attributes, internal val pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, internal val pointWeight: PointWeight = PointWeight.byYSigma, public val xSymbol: Symbol = Symbol.x, -) : OptimizationProblem { +) : OptimizationProblem { - override val type: SafeType get() = Float64Field.type + override val type: SafeType get() = Float64Field.type - public fun distance(index: Int): DifferentiableExpression = pointToCurveDistance.distance(this, index) + public fun distance(index: Int): DifferentiableExpression = pointToCurveDistance.distance(this, index) - public fun weight(index: Int): DifferentiableExpression = pointWeight.weight(this, index) + public fun weight(index: Int): DifferentiableExpression = pointWeight.weight(this, index) } public fun XYOptimization( data: XYColumnarData, - model: DifferentiableExpression, + model: DifferentiableExpression, builder: AttributesBuilder.() -> Unit, ): XYFit = XYFit(data, model, Attributes(builder)) @@ -112,7 +113,7 @@ public fun XYFit.withAttributes( public suspend fun XYColumnarData.fitWith( optimizer: Optimizer, - modelExpression: DifferentiableExpression, + modelExpression: DifferentiableExpression, startingPoint: Map, attributes: Attributes = Attributes.EMPTY, xSymbol: Symbol = Symbol.x, @@ -149,7 +150,7 @@ public suspend fun XYColumnarData.fitWith( pointWeight: PointWeight = PointWeight.byYSigma, model: A.(I) -> I, ): XYFit where A : ExtendedField, A : ExpressionAlgebra { - val modelExpression: DifferentiableExpression = processor.differentiate { + val modelExpression: DifferentiableExpression = processor.differentiate { val x = bindSymbol(xSymbol) model(x) } diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt index a3ccbfab4..ef346278d 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt @@ -15,6 +15,7 @@ import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.derivative import space.kscience.kmath.operations.Float64Field +import space.kscience.kmath.structures.Float64 import kotlin.math.PI import kotlin.math.ln import kotlin.math.pow @@ -24,10 +25,10 @@ import kotlin.math.sqrt private val oneOver2Pi = 1.0 / sqrt(2 * PI) @UnstableKMathAPI -internal fun XYFit.logLikelihood(): DifferentiableExpression = object : DifferentiableExpression { - override val type: SafeType get() = Float64Field.type +internal fun XYFit.logLikelihood(): DifferentiableExpression = object : DifferentiableExpression { + override val type: SafeType get() = Float64Field.type - override fun derivativeOrNull(symbols: List): Expression = Expression(type) { arguments -> + override fun derivativeOrNull(symbols: List): Expression = Expression(type) { arguments -> data.indices.sumOf { index -> val d = distance(index)(arguments) val weight = weight(index)(arguments) @@ -57,7 +58,7 @@ internal fun XYFit.logLikelihood(): DifferentiableExpression = object : * possible weight dependency on the model and parameters. */ @UnstableKMathAPI -public suspend fun Optimizer>.maximumLogLikelihood(problem: XYFit): XYFit { +public suspend fun Optimizer>.maximumLogLikelihood(problem: XYFit): XYFit { val functionOptimization = FunctionOptimization(problem.logLikelihood(), problem.attributes) val result = optimize( functionOptimization.withAttributes { @@ -68,8 +69,8 @@ public suspend fun Optimizer>.maximumLogLik } @UnstableKMathAPI -public suspend fun Optimizer>.maximumLogLikelihood( +public suspend fun Optimizer>.maximumLogLikelihood( data: XYColumnarData, - model: DifferentiableExpression, + model: DifferentiableExpression, builder: AttributesBuilder.() -> Unit, ): XYFit = maximumLogLikelihood(XYOptimization(data, model, builder)) diff --git a/kmath-optimization/src/commonMain/tmp/QowFit.kt b/kmath-optimization/src/commonMain/tmp/QowFit.kt index 493ef8d12..1b204d9b3 100644 --- a/kmath-optimization/src/commonMain/tmp/QowFit.kt +++ b/kmath-optimization/src/commonMain/tmp/QowFit.kt @@ -27,28 +27,28 @@ private typealias ParamSet = Map public class QowFit( override val symbols: List, private val space: LinearSpace, - private val solver: LinearSolver, -) : XYOptimization, SymbolIndexer { + private val solver: LinearSolver, +) : XYOptimization, SymbolIndexer { private var logger: FitLogger? = null private var startingPoint: Map = TODO() - private var covariance: Matrix? = TODO() - private val prior: DifferentiableExpression>? = TODO() + private var covariance: Matrix? = TODO() + private val prior: DifferentiableExpression>? = TODO() private var data: XYErrorColumnarData = TODO() - private var model: DifferentiableExpression> = TODO() + private var model: DifferentiableExpression> = TODO() private val features = HashSet() - override fun update(result: OptimizationResult) { + override fun update(result: OptimizationResult) { TODO("Not yet implemented") } - override val algebra: Field + override val algebra: Field get() = TODO("Not yet implemented") override fun data( - dataSet: ColumnarData, + dataSet: ColumnarData, xSymbol: Symbol, ySymbol: Symbol, xErrSymbol: Symbol?, @@ -82,14 +82,14 @@ public class QowFit( */ private fun getDispersion(i: Int, parameters: Map): Double = data.yErr[i].pow(2) - private fun getCovariance(weight: QoWeight): Matrix = solver.inverse(getEqDerivValues(weight)) + private fun getCovariance(weight: QoWeight): Matrix = solver.inverse(getEqDerivValues(weight)) /** * Теоретическая ковариация весовых функций. * * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 */ - private fun covarF(weight: QoWeight): Matrix = space.buildSymmetricMatrix(symbols.size) { k, l -> + private fun covarF(weight: QoWeight): Matrix = space.buildSymmetricMatrix(symbols.size) { k, l -> (0 until data.size).sumOf { i -> weight.derivs[k, i] * weight.derivs[l, i] / weight.dispersion[i] } } @@ -103,7 +103,7 @@ public class QowFit( * @param weight * @return */ - private fun covarFExp(weight: QoWeight, theta: Map): Matrix = space.run { + private fun covarFExp(weight: QoWeight, theta: Map): Matrix = space.run { /* * Важно! Если не делать предварителього вычисления этих производных, то * количество вызывов функции будет dim^2 вместо dim Первый индекс - @@ -129,7 +129,7 @@ public class QowFit( */ private fun getEqDerivValues( weight: QoWeight, theta: Map = weight.theta, - ): Matrix = space.run { + ): Matrix = space.run { val fitDim = symbols.size //Возвращает производную k-того Eq по l-тому параметру val res = Array(fitDim) { DoubleArray(fitDim) } @@ -162,7 +162,7 @@ public class QowFit( * @param weight * @return */ - private fun getEqValues(weight: QoWeight, theta: Map = weight.theta): Point { + private fun getEqValues(weight: QoWeight, theta: Map = weight.theta): Point { val distances = DoubleBuffer(data.size) { i -> distance(i, theta) } return DoubleBuffer(symbols.size) { k -> @@ -190,7 +190,7 @@ public class QowFit( /** * Derivatives of the spectrum over parameters. First index in the point number, second one - index of parameter */ - val derivs: Matrix by lazy { + val derivs: Matrix by lazy { space.buildMatrix(data.size, symbols.size) { i, k -> distanceDerivative(symbols[k], i, theta) } @@ -199,7 +199,7 @@ public class QowFit( /** * Array of dispersions in each point */ - val dispersion: Point by lazy { + val dispersion: Point by lazy { DoubleBuffer(data.size) { i -> getDispersion(i, theta) } } @@ -208,7 +208,7 @@ public class QowFit( private fun newtonianStep( weight: QoWeight, par: Map, - eqvalues: Point, + eqvalues: Point, ): Map = space.run { val start = par.toPoint() val invJacob = solver.inverse(getEqDerivValues(weight, par)) @@ -318,7 +318,7 @@ public class QowFit( /** * generateErrors. */ - private fun generateErrors(): Matrix { + private fun generateErrors(): Matrix { logger?.log { """ Starting errors estimation using quasioptimal weights method. The starting weight is: @@ -340,7 +340,7 @@ public class QowFit( } - override suspend fun optimize(): OptimizationResult { + override suspend fun optimize(): OptimizationResult { val curWeight = QoWeight(startingPoint) logger?.log { """ diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt index 8b2f8786e..145b278fe 100644 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt +++ b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt @@ -33,7 +33,7 @@ class MnUserParameterState { private var theGCCValid = false private var theGlobalCC: MnGlobalCorrelationCoeff? = null private var theIntCovariance: MnUserCovariance - private var theIntParameters: MutableList + private var theIntParameters: MutableList private var theNFcn = 0 private var theParameters: MnUserParameters private var theValid: Boolean @@ -43,7 +43,7 @@ class MnUserParameterState { theCovarianceValid = false theParameters = MnUserParameters() theCovariance = MnUserCovariance() - theIntParameters = java.util.ArrayList() + theIntParameters = java.util.ArrayList() theIntCovariance = MnUserCovariance() } @@ -57,7 +57,7 @@ class MnUserParameterState { theParameters = other.theParameters.copy() theCovariance = other.theCovariance theGlobalCC = other.theGlobalCC - theIntParameters = java.util.ArrayList(other.theIntParameters) + theIntParameters = java.util.ArrayList(other.theIntParameters) theIntCovariance = other.theIntCovariance.copy() } @@ -71,7 +71,7 @@ class MnUserParameterState { theParameters = MnUserParameters(par, err) theCovariance = MnUserCovariance() theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.size) + theIntParameters = java.util.ArrayList(par.size) for (i in par.indices) { theIntParameters.add(par[i]) } @@ -108,7 +108,7 @@ class MnUserParameterState { theCovarianceValid = true theCovariance = MnUserCovariance(cov, nrow) theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.size) + theIntParameters = java.util.ArrayList(par.size) theIntCovariance = MnUserCovariance(cov, nrow) val err = DoubleArray(par.size) for (i in par.indices) { @@ -125,7 +125,7 @@ class MnUserParameterState { theCovarianceValid = true theCovariance = cov theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.size) + theIntParameters = java.util.ArrayList(par.size) theIntCovariance = cov.copy() require(!(theCovariance.nrow() !== variableParameters())) { "Bad covariance size" } val err = DoubleArray(par.size) @@ -143,7 +143,7 @@ class MnUserParameterState { theParameters = par theCovariance = cov theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList() + theIntParameters = java.util.ArrayList() theIntCovariance = cov.copy() theIntCovariance.scale(0.5) val i = 0 @@ -175,7 +175,7 @@ class MnUserParameterState { theParameters = MnUserParameters() theCovariance = MnUserCovariance() theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList() + theIntParameters = java.util.ArrayList() theIntCovariance = MnUserCovariance() for (ipar in trafo.parameters()) { if (ipar.isConst()) { @@ -442,7 +442,7 @@ class MnUserParameterState { * Minuit internal representation * @return */ - fun intParameters(): List { + fun intParameters(): List { return theIntParameters } diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt index ca17611b1..9209ae1c3 100644 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt +++ b/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt @@ -27,7 +27,7 @@ import org.apache.commons.math3.linear.ArrayRealVector */ class MnUserTransformation { private val nameMap: MutableMap = HashMap() - private var theCache: MutableList + private var theCache: MutableList private var theExtOfInt: MutableList private var theParameters: MutableList private var thePrecision: MnMachinePrecision @@ -36,7 +36,7 @@ class MnUserTransformation { thePrecision = MnMachinePrecision() theParameters = java.util.ArrayList() theExtOfInt = java.util.ArrayList() - theCache = java.util.ArrayList(0) + theCache = java.util.ArrayList(0) } private constructor(other: MnUserTransformation) { @@ -46,14 +46,14 @@ class MnUserTransformation { theParameters.add(par.copy()) } theExtOfInt = java.util.ArrayList(other.theExtOfInt) - theCache = java.util.ArrayList(other.theCache) + theCache = java.util.ArrayList(other.theCache) } constructor(par: DoubleArray, err: DoubleArray) { thePrecision = MnMachinePrecision() theParameters = java.util.ArrayList(par.size) theExtOfInt = java.util.ArrayList(par.size) - theCache = java.util.ArrayList(par.size) + theCache = java.util.ArrayList(par.size) for (i in par.indices) { add("p$i", par[i], err[i]) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt index 89f1dd8d7..2d30e8b6c 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.samplers.InternalGamma import space.kscience.kmath.samplers.NormalizedGaussianSampler import space.kscience.kmath.samplers.ZigguratNormalizedGaussianSampler +import space.kscience.kmath.structures.Float64 import kotlin.math.* @@ -30,7 +31,7 @@ internal object InternalErf { /** * Implements [Distribution1D] for the normal (gaussian) distribution. */ -public class NormalDistribution(public val sampler: GaussianSampler) : Distribution1D { +public class NormalDistribution(public val sampler: GaussianSampler) : Distribution1D { override fun probability(arg: Double): Double { val x1 = (arg - sampler.mean) / sampler.standardDeviation diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt index d0f13398c..7458c4965 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt @@ -8,13 +8,14 @@ package space.kscience.kmath.distributions import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.SimpleChain import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.structures.Float64 -public class UniformDistribution(public val range: ClosedFloatingPointRange) : Distribution1D { +public class UniformDistribution(public val range: ClosedFloatingPointRange) : Distribution1D { private val length: Double = range.endInclusive - range.start override fun probability(arg: Double): Double = if (arg in range) 1.0 / length else 0.0 - override fun sample(generator: RandomGenerator): Chain = + override fun sample(generator: RandomGenerator): Chain = SimpleChain { range.start + generator.nextDouble() * length } override fun cumulative(arg: Double): Double = when { @@ -24,5 +25,5 @@ public class UniformDistribution(public val range: ClosedFloatingPointRange): UniformDistribution = +public fun Distribution.Companion.uniform(range: ClosedFloatingPointRange): UniformDistribution = UniformDistribution(range) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt index 0276cd654..232d17166 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.stat.Sampler +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import kotlin.math.ln import kotlin.math.pow @@ -18,7 +19,7 @@ import kotlin.math.pow * Based on Commons RNG implementation. * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/AhrensDieterExponentialSampler.html]. */ -public class AhrensDieterExponentialSampler(public val mean: Double) : Sampler { +public class AhrensDieterExponentialSampler(public val mean: Double) : Sampler { init { require(mean > 0) { "mean is not strictly positive: $mean" } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt index 05163387d..7a5333dc2 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt @@ -10,6 +10,7 @@ import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.random.chain import space.kscience.kmath.stat.Sampler import space.kscience.kmath.stat.next +import space.kscience.kmath.structures.Float64 import kotlin.math.* /** @@ -26,14 +27,14 @@ import kotlin.math.* public class AhrensDieterMarsagliaTsangGammaSampler private constructor( alpha: Double, theta: Double, -) : Sampler { +) : Sampler { private val delegate: BaseGammaSampler = if (alpha < 1) AhrensDieterGammaSampler(alpha, theta) else MarsagliaTsangGammaSampler(alpha, theta) private abstract class BaseGammaSampler internal constructor( protected val alpha: Double, protected val theta: Double, - ) : Sampler { + ) : Sampler { init { require(alpha > 0) { "alpha is not strictly positive: $alpha" } require(theta > 0) { "theta is not strictly positive: $theta" } @@ -47,7 +48,7 @@ public class AhrensDieterMarsagliaTsangGammaSampler private constructor( private val oneOverAlpha: Double = 1.0 / alpha private val bGSOptim: Double = 1.0 + alpha / E - override fun sample(generator: RandomGenerator): Chain = generator.chain { + override fun sample(generator: RandomGenerator): Chain = generator.chain { var x: Double // [1]: p. 228, Algorithm GS. @@ -90,7 +91,7 @@ public class AhrensDieterMarsagliaTsangGammaSampler private constructor( cOptim = ONE_THIRD / sqrt(dOptim) } - override fun sample(generator: RandomGenerator): Chain = generator.chain { + override fun sample(generator: RandomGenerator): Chain = generator.chain { var v: Double while (true) { @@ -113,13 +114,13 @@ public class AhrensDieterMarsagliaTsangGammaSampler private constructor( } } - override fun sample(generator: RandomGenerator): Chain = delegate.sample(generator) + override fun sample(generator: RandomGenerator): Chain = delegate.sample(generator) override fun toString(): String = delegate.toString() public companion object { public fun of( alpha: Double, theta: Double, - ): Sampler = AhrensDieterMarsagliaTsangGammaSampler(alpha, theta) + ): Sampler = AhrensDieterMarsagliaTsangGammaSampler(alpha, theta) } } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MetropolisHastingsSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MetropolisHastingsSampler.kt index a6bba910b..7dcf1dc06 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MetropolisHastingsSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MetropolisHastingsSampler.kt @@ -57,7 +57,7 @@ public class MetropolisHastingsSampler( startPoint: Float64, stepSampler: Sampler, targetPdf: suspend (Float64) -> Float64, - ): MetropolisHastingsSampler = MetropolisHastingsSampler( + ): MetropolisHastingsSampler = MetropolisHastingsSampler( algebra = Float64.algebra, startPoint = {startPoint}, stepSampler = stepSampler, @@ -71,6 +71,6 @@ public class MetropolisHastingsSampler( startPoint: Float64, stepSigma: Float64, targetPdf: suspend (Float64) -> Float64, - ): MetropolisHastingsSampler = univariate(startPoint, GaussianSampler(0.0, stepSigma), targetPdf) + ): MetropolisHastingsSampler = univariate(startPoint, GaussianSampler(0.0, stepSigma), targetPdf) } } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt index 81d1edb47..b3f18e605 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt @@ -8,8 +8,9 @@ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.stat.Sampler +import space.kscience.kmath.structures.Float64 -public interface BlockingDoubleSampler : Sampler { +public interface BlockingDoubleSampler : Sampler { override fun sample(generator: RandomGenerator): BlockingDoubleChain } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt index 9bc1a6bc2..b53a1d923 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.chains.combine import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory +import space.kscience.kmath.structures.Float64 import kotlin.jvm.JvmName /** @@ -66,7 +67,7 @@ public inline fun Sampler.sampleBuffer(generator: RandomGen /** * Samples a [Buffer] of values from this [Sampler]. */ -public suspend fun Sampler.nextBuffer(generator: RandomGenerator, size: Int): Buffer = +public suspend fun Sampler.nextBuffer(generator: RandomGenerator, size: Int): Buffer = sampleBuffer(generator, size).first() //TODO add `context(RandomGenerator) Sampler.nextBuffer \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt index 337b13020..1abd50f47 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.series import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.operations.Float64Field.pow import space.kscience.kmath.operations.fold +import space.kscience.kmath.structures.Float64 import kotlin.math.absoluteValue @@ -31,7 +32,7 @@ public data class VarianceRatioTestResult( * @author https://github.com/mrFendel */ public fun SeriesAlgebra.varianceRatioTest( - series: Series, + series: Series, shift: Int, homoscedastic: Boolean = true, ): VarianceRatioTestResult { diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt index 846e95b18..031bb3298 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.stat import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.indices /** @@ -42,7 +43,7 @@ public class Mean( } public companion object { - public fun evaluate(buffer: Buffer): Double = Float64Field.mean.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Double = Float64Field.mean.evaluateBlocking(buffer) public fun evaluate(buffer: Buffer): Int = Int32Ring.mean.evaluateBlocking(buffer) public fun evaluate(buffer: Buffer): Long = Int64Ring.mean.evaluateBlocking(buffer) } @@ -50,7 +51,7 @@ public class Mean( //TODO replace with optimized version which respects overflow -public val Float64Field.mean: Mean get() = Mean(Float64Field) +public val Float64Field.mean: Mean get() = Mean(Float64Field) public val Int32Ring.mean: Mean get() = Mean(Int32Field) public val Int64Ring.mean: Mean get() = Mean(Int64Field) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt index f0328839f..fd829bffe 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.stat import space.kscience.kmath.misc.sortedWith import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 /** * Non-composable median @@ -27,12 +28,12 @@ public class Median(private val field: Field, private val comparator: Comp public companion object { - public fun evaluate(buffer: Buffer): Double = Float64Field.mean.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Double = Float64Field.mean.evaluateBlocking(buffer) public fun evaluate(buffer: Buffer): Int = Int32Ring.mean.evaluateBlocking(buffer) public fun evaluate(buffer: Buffer): Long = Int64Ring.mean.evaluateBlocking(buffer) } } -public val Float64Field.median: Median get() = Median(Float64Field) { a, b -> a.compareTo(b) } +public val Float64Field.median: Median get() = Median(Float64Field) { a, b -> a.compareTo(b) } public val Int32Ring.median: Median get() = Median(Int32Field) { a, b -> a.compareTo(b) } public val Int64Ring.median: Median get() = Median(Int64Field) { a, b -> a.compareTo(b) } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt index c42f149f2..19ca518e5 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.expressions.ExpressionAlgebra import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.asIterable import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.indices import kotlin.jvm.JvmName @@ -48,11 +49,11 @@ public fun , I : Any, A> AutoDiffProcessor.chiSquared } public fun AutoDiffProcessor.chiSquaredExpression( - x: Buffer, - y: Buffer, - yErr: Buffer, + x: Buffer, + y: Buffer, + yErr: Buffer, model: A.(I) -> I, -): DifferentiableExpression where A : ExtendedField, A : ExpressionAlgebra { +): DifferentiableExpression where A : ExtendedField, A : ExpressionAlgebra { require(yErr.asIterable().all { it > 0.0 }) { "All errors must be strictly positive" } return chiSquaredExpression(x, y, yErr, model) } \ No newline at end of file diff --git a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt index 461edcaf5..275160b06 100644 --- a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt +++ b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.series import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.bufferAlgebra import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.slice import kotlin.math.PI import kotlin.test.Test @@ -21,7 +22,7 @@ class TestSeries { val s2 = s1.slice(20..50).moveTo(40) - val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 + val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 assertEquals(s3.getByOffset(40), s1.getByOffset(40) + s1.getByOffset(20)) } diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt index 516a3a2ce..ff7b9a190 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -20,13 +20,14 @@ import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.FieldOps import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.PowerOperations +import space.kscience.kmath.structures.Float64 public class DoubleTensorFlowOutput( graph: Graph, output: Output, ) : TensorFlowOutput(graph, output) { - override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TFloat64 + override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TFloat64 } internal fun ShapeND.toLongArray(): LongArray = LongArray(size) { get(it).toLong() } @@ -34,14 +35,14 @@ internal fun ShapeND.toLongArray(): LongArray = LongArray(size) { get(it).toLong public class DoubleTensorFlowAlgebra internal constructor( graph: Graph, ) : TensorFlowAlgebra(graph), FieldOps>, PowerOperations> { + Float64Field>(graph), FieldOps>, PowerOperations> { override val elementAlgebra: Float64Field get() = Float64Field override fun mutableStructureND( shape: ShapeND, initializer: Float64Field.(IntArray) -> Double, - ): MutableStructureND { + ): MutableStructureND { val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> ColumnStrides(shape).forEach { index -> array.setDouble(elementAlgebra.initializer(index), *index.toLongArray()) @@ -50,7 +51,7 @@ public class DoubleTensorFlowAlgebra internal constructor( return DoubleTensorFlowOutput(graph, ops.constant(res).asOutput()) } - override fun StructureND.asTensorFlow(): TensorFlowOutput = + override fun StructureND.asTensorFlow(): TensorFlowOutput = if (this is TensorFlowOutput && output.type() == TFloat64::class.java) { @Suppress("UNCHECKED_CAST") this as TensorFlowOutput @@ -69,13 +70,13 @@ public class DoubleTensorFlowAlgebra internal constructor( override fun const(value: Double): Constant = ops.constant(value) override fun divide( - left: StructureND, - right: StructureND, + left: StructureND, + right: StructureND, ): TensorFlowOutput = left.operate(right) { l, r -> ops.math.div(l, r) } - override fun power(arg: StructureND, pow: Number): TensorFlowOutput = + override fun power(arg: StructureND, pow: Number): TensorFlowOutput = arg.operate { ops.math.pow(it, const(pow.toDouble())) } } @@ -86,8 +87,8 @@ public class DoubleTensorFlowAlgebra internal constructor( */ @UnstableKMathAPI public fun Float64Field.produceWithTF( - block: DoubleTensorFlowAlgebra.() -> StructureND, -): StructureND = Graph().use { graph -> + block: DoubleTensorFlowAlgebra.() -> StructureND, +): StructureND = Graph().use { graph -> val scope = DoubleTensorFlowAlgebra(graph) scope.export(scope.block()) } @@ -99,8 +100,8 @@ public fun Float64Field.produceWithTF( */ @OptIn(UnstableKMathAPI::class) public fun Float64Field.produceMapWithTF( - block: DoubleTensorFlowAlgebra.() -> Map>, -): Map> = Graph().use { graph -> + block: DoubleTensorFlowAlgebra.() -> Map>, +): Map> = Graph().use { graph -> val scope = DoubleTensorFlowAlgebra(graph) scope.block().mapValues { scope.export(it.value) } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index f9f0ed832..09a3265f3 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.tensors.api import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Field +import space.kscience.kmath.structures.Float64 /** * Common linear algebra operations. Operates on [Tensor]. @@ -110,5 +111,5 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input1` and the `input2`. * @return the square matrix x which is the solution of the equation. */ - public fun solve(a: MutableStructure2D, b: MutableStructure2D): MutableStructure2D + public fun solve(a: MutableStructure2D, b: MutableStructure2D): MutableStructure2D } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index d02a9f99e..801a24529 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.internal.broadcastTensors @@ -18,7 +19,7 @@ import space.kscience.kmath.tensors.core.internal.broadcastTo */ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - override fun StructureND.plus(arg: StructureND): DoubleTensor { + override fun StructureND.plus(arg: StructureND): DoubleTensor { val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] @@ -28,14 +29,14 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.plusAssign(arg: StructureND) { + override fun Tensor.plusAssign(arg: StructureND) { val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) for (i in 0 until asDoubleTensor().indices.linearSize) { asDoubleTensor().source[i] += newOther.source[i] } } - override fun StructureND.minus(arg: StructureND): DoubleTensor { + override fun StructureND.minus(arg: StructureND): DoubleTensor { val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] @@ -45,14 +46,14 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.minusAssign(arg: StructureND) { + override fun Tensor.minusAssign(arg: StructureND) { val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) for (i in 0 until indices.linearSize) { asDoubleTensor().source[i] -= newOther.source[i] } } - override fun StructureND.times(arg: StructureND): DoubleTensor { + override fun StructureND.times(arg: StructureND): DoubleTensor { val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] @@ -62,14 +63,14 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.timesAssign(arg: StructureND) { + override fun Tensor.timesAssign(arg: StructureND) { val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) for (i in 0 until indices.linearSize) { asDoubleTensor().source[+i] *= newOther.source[i] } } - override fun StructureND.div(arg: StructureND): DoubleTensor { + override fun StructureND.div(arg: StructureND): DoubleTensor { val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] @@ -79,7 +80,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.divAssign(arg: StructureND) { + override fun Tensor.divAssign(arg: StructureND) { val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) for (i in 0 until indices.linearSize) { asDoubleTensor().source[i] /= newOther.source[i] diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt index b3c2eb1b4..132a1f1e6 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt @@ -16,7 +16,7 @@ public class OffsetDoubleBuffer( override val origin: Float64Buffer, private val offset: Int, override val size: Int, -) : MutableBuffer, BufferView { +) : MutableBuffer, BufferView { init { require(offset >= 0) { "Offset must be non-negative" } @@ -36,7 +36,7 @@ public class OffsetDoubleBuffer( */ public fun copy(): Float64Buffer = origin.array.copyOfRange(offset, offset + size).asBuffer() - override fun iterator(): Iterator = iterator { + override fun iterator(): Iterator = iterator { for (i in indices) { yield(get(i)) } @@ -86,7 +86,7 @@ public inline fun OffsetDoubleBuffer.mapInPlace(operation: (Double) -> Double) { public open class DoubleTensor( shape: ShapeND, final override val source: OffsetDoubleBuffer, -) : BufferedTensor(shape), MutableStructureNDOfDouble { +) : BufferedTensor(shape), MutableStructureNDOfDouble { init { require(linearSize == source.size) { "Source buffer size must be equal tensor size" } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt index 05f1b2f20..aefd87bf0 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt @@ -8,10 +8,11 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.MutableStructure1D import space.kscience.kmath.nd.ShapeND +import space.kscience.kmath.structures.Float64 public class DoubleTensor1D( source: OffsetDoubleBuffer, -) : DoubleTensor(ShapeND(source.size), source), MutableStructure1D { +) : DoubleTensor(ShapeND(source.size), source), MutableStructure1D { @PerformancePitfall override fun get(index: IntArray): Double = super.get(index) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt index 013dfe791..bee8832ea 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt @@ -9,6 +9,7 @@ import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.linearSize +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.PermutedMutableBuffer import space.kscience.kmath.structures.permute @@ -16,7 +17,7 @@ public class DoubleTensor2D( override val rowNum: Int, override val colNum: Int, source: OffsetDoubleBuffer, -) : DoubleTensor(ShapeND(rowNum, colNum), source), MutableStructure2D { +) : DoubleTensor(ShapeND(rowNum, colNum), source), MutableStructure2D { override fun get(i: Int, j: Int): Double = source[i * colNum + j] @@ -35,7 +36,7 @@ public class DoubleTensor2D( @OptIn(PerformancePitfall::class) - override val columns: List> + override val columns: List> get() = List(colNum) { j -> val indices = IntArray(rowNum) { i -> j + i * colNum } source.permute(indices) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index d9e107d86..7bf0dcb8b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -44,7 +44,7 @@ public open class DoubleTensorAlgebra : * @return the resulting tensor after applying the function. */ @Suppress("OVERRIDE_BY_INLINE") - final override inline fun StructureND.map(transform: Float64Field.(Double) -> Double): DoubleTensor { + final override inline fun StructureND.map(transform: Float64Field.(Double) -> Double): DoubleTensor { val tensor = asDoubleTensor() //TODO remove additional copy val array = Float64Buffer(tensor.source.size) { Float64Field.transform(tensor.source[it]) } @@ -54,7 +54,7 @@ public open class DoubleTensorAlgebra : ) } - public inline fun Tensor.mapInPlace(operation: (Double) -> Double) { + public inline fun Tensor.mapInPlace(operation: (Double) -> Double) { if (this is DoubleTensor) { source.mapInPlace(operation) } else { @@ -62,20 +62,20 @@ public open class DoubleTensorAlgebra : } } - public inline fun Tensor.mapIndexedInPlace(operation: Float64Field.(IntArray, Double) -> Double) { + public inline fun Tensor.mapIndexedInPlace(operation: Float64Field.(IntArray, Double) -> Double) { indices.forEach { set(it, Float64Field.operation(it, get(it))) } } @Suppress("OVERRIDE_BY_INLINE") - final override inline fun StructureND.mapIndexed(transform: Float64Field.(index: IntArray, Double) -> Double): DoubleTensor { + final override inline fun StructureND.mapIndexed(transform: Float64Field.(index: IntArray, Double) -> Double): DoubleTensor { return copyToTensor().apply { mapIndexedInPlace(transform) } } @Suppress("OVERRIDE_BY_INLINE") final override inline fun zip( - left: StructureND, - right: StructureND, + left: StructureND, + right: StructureND, transform: Float64Field.(Double, Double) -> Double, ): DoubleTensor { checkShapesCompatible(left, right) @@ -89,19 +89,19 @@ public open class DoubleTensorAlgebra : } - public inline fun StructureND.reduceElements(transform: (Float64Buffer) -> Double): Double = + public inline fun StructureND.reduceElements(transform: (Float64Buffer) -> Double): Double = transform(asDoubleTensor().source.copy()) //TODO Add read-only DoubleBuffer wrapper. To avoid protective copy - override fun StructureND.valueOrNull(): Double? { + override fun StructureND.valueOrNull(): Double? { val dt = asDoubleTensor() return if (dt.shape == ShapeND(1)) dt.source[0] else null } - override fun StructureND.value(): Double = valueOrNull() + override fun StructureND.value(): Double = valueOrNull() ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") - public fun fromBuffer(shape: ShapeND, buffer: Buffer): DoubleTensor { + public fun fromBuffer(shape: ShapeND, buffer: Buffer): DoubleTensor { checkNotEmptyShape(shape) check(buffer.size > 0) { "Illegal empty buffer provided" } check(buffer.size == shape.linearSize) { @@ -133,7 +133,7 @@ public open class DoubleTensorAlgebra : RowStrides(shape).asSequence().map { Float64Field.initializer(it) }.toMutableList().toDoubleArray() ) - override fun Tensor.getTensor(i: Int): DoubleTensor { + override fun Tensor.getTensor(i: Int): DoubleTensor { val dt = asDoubleTensor() val lastShape = shape.last(shape.size - 1) val newShape: ShapeND = if (lastShape.isNotEmpty()) lastShape else ShapeND(1) @@ -214,71 +214,71 @@ public open class DoubleTensorAlgebra : return res } - override fun Double.plus(arg: StructureND): DoubleTensor = arg.map { this@plus + it } + override fun Double.plus(arg: StructureND): DoubleTensor = arg.map { this@plus + it } - override fun StructureND.plus(arg: Double): DoubleTensor = map { it + arg } + override fun StructureND.plus(arg: Double): DoubleTensor = map { it + arg } - override fun StructureND.plus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l + r } + override fun StructureND.plus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l + r } - override fun Tensor.plusAssign(value: Double) { + override fun Tensor.plusAssign(value: Double) { mapInPlace { it + value } } - override fun Tensor.plusAssign(arg: StructureND) { + override fun Tensor.plusAssign(arg: StructureND) { checkShapesCompatible(asDoubleTensor(), arg.asDoubleTensor()) mapIndexedInPlace { index, value -> value + arg[index] } } - override fun Double.minus(arg: StructureND): DoubleTensor = arg.map { this@minus - it } + override fun Double.minus(arg: StructureND): DoubleTensor = arg.map { this@minus - it } - override fun StructureND.minus(arg: Double): DoubleTensor = map { it - arg } + override fun StructureND.minus(arg: Double): DoubleTensor = map { it - arg } - override fun StructureND.minus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l - r } + override fun StructureND.minus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l - r } - override fun Tensor.minusAssign(value: Double) { + override fun Tensor.minusAssign(value: Double) { mapInPlace { it - value } } - override fun Tensor.minusAssign(arg: StructureND) { + override fun Tensor.minusAssign(arg: StructureND) { checkShapesCompatible(this, arg) mapIndexedInPlace { index, value -> value - arg.getDouble(index) } } - override fun Double.times(arg: StructureND): DoubleTensor = arg.map { this@times * it } + override fun Double.times(arg: StructureND): DoubleTensor = arg.map { this@times * it } - override fun StructureND.times(arg: Double): DoubleTensor = arg * asDoubleTensor() + override fun StructureND.times(arg: Double): DoubleTensor = arg * asDoubleTensor() - override fun StructureND.times(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l * r } + override fun StructureND.times(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l * r } - override fun Tensor.timesAssign(value: Double) { + override fun Tensor.timesAssign(value: Double) { mapInPlace { it * value } } - override fun Tensor.timesAssign(arg: StructureND) { + override fun Tensor.timesAssign(arg: StructureND) { checkShapesCompatible(this, arg) mapIndexedInPlace { index, value -> value * arg[index] } } - override fun Double.div(arg: StructureND): DoubleTensor = arg.map { this@div / it } + override fun Double.div(arg: StructureND): DoubleTensor = arg.map { this@div / it } - override fun StructureND.div(arg: Double): DoubleTensor = map { it / arg } + override fun StructureND.div(arg: Double): DoubleTensor = map { it / arg } - override fun StructureND.div(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l / r } + override fun StructureND.div(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l / r } - override fun Tensor.divAssign(value: Double) { + override fun Tensor.divAssign(value: Double) { mapInPlace { it / value } } - override fun Tensor.divAssign(arg: StructureND) { + override fun Tensor.divAssign(arg: StructureND) { checkShapesCompatible(asDoubleTensor(), arg) mapIndexedInPlace { index, value -> value / arg[index] } } - override fun StructureND.unaryMinus(): DoubleTensor = map { -it } + override fun StructureND.unaryMinus(): DoubleTensor = map { -it } - override fun StructureND.transposed(i: Int, j: Int): Tensor { + override fun StructureND.transposed(i: Int, j: Int): Tensor { val actualI = if (i >= 0) i else shape.size + i val actualJ = if (j >= 0) j else shape.size + j return asDoubleTensor().permute( @@ -315,12 +315,12 @@ public open class DoubleTensorAlgebra : // return resTensor } - override fun Tensor.view(shape: ShapeND): DoubleTensor { + override fun Tensor.view(shape: ShapeND): DoubleTensor { checkView(asDoubleTensor(), shape) return DoubleTensor(shape, asDoubleTensor().source) } - override fun Tensor.viewAs(other: StructureND): DoubleTensor = + override fun Tensor.viewAs(other: StructureND): DoubleTensor = view(other.shape) /** @@ -352,7 +352,7 @@ public open class DoubleTensorAlgebra : * @param other tensor to be multiplied. * @return a mathematical product of two tensors. */ - public infix fun StructureND.matmul(other: StructureND): DoubleTensor { + public infix fun StructureND.matmul(other: StructureND): DoubleTensor { if (shape.size == 1 && other.shape.size == 1) { return DoubleTensor(ShapeND(1), Float64Buffer(times(other).sum())) } @@ -412,13 +412,13 @@ public open class DoubleTensorAlgebra : } } - override fun StructureND.dot(other: StructureND): DoubleTensor { + override fun StructureND.dot(other: StructureND): DoubleTensor { return if (dimension in 0..2 && other.dimension in 0..2) this.matmul(other) else error("Only vectors and matrices are allowed in non-broadcasting dot operation") } override fun diagonalEmbedding( - diagonalEntries: StructureND, + diagonalEntries: StructureND, offset: Int, dim1: Int, dim2: Int, @@ -476,7 +476,7 @@ public open class DoubleTensorAlgebra : * @param epsilon permissible error when comparing two Double values. * @return true if two tensors have the same shape and elements, false otherwise. */ - public fun Tensor.eq(other: Tensor, epsilon: Double): Boolean = + public fun Tensor.eq(other: Tensor, epsilon: Double): Boolean = asDoubleTensor().eq(other) { x, y -> abs(x - y) < epsilon } /** @@ -486,10 +486,10 @@ public open class DoubleTensorAlgebra : * @param other the tensor to compare with `input` tensor. * @return true if two tensors have the same shape and elements, false otherwise. */ - public infix fun Tensor.eq(other: Tensor): Boolean = eq(other, 1e-5) + public infix fun Tensor.eq(other: Tensor): Boolean = eq(other, 1e-5) - private fun Tensor.eq( - other: Tensor, + private fun Tensor.eq( + other: Tensor, eqFunction: (Double, Double) -> Boolean, ): Boolean { //TODO optimize tensor conversion @@ -512,10 +512,10 @@ public open class DoubleTensorAlgebra : * @param indices the [IntArray] of 1-dimensional indices * @return tensor with rows corresponding to row by [indices] */ - public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { getTensor(it) }) + public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { getTensor(it) }) - private inline fun StructureND.foldDimToDouble( + private inline fun StructureND.foldDimToDouble( dim: Int, keepDim: Boolean, foldFunction: (DoubleArray) -> Double, @@ -543,7 +543,7 @@ public open class DoubleTensorAlgebra : return resTensor } - private inline fun StructureND.foldDimToInt( + private inline fun StructureND.foldDimToInt( dim: Int, keepDim: Boolean, foldFunction: (DoubleArray) -> Int, @@ -571,46 +571,46 @@ public open class DoubleTensorAlgebra : } - override fun StructureND.sum(): Double = reduceElements { it.array.sum() } + override fun StructureND.sum(): Double = reduceElements { it.array.sum() } - override fun StructureND.sum(dim: Int, keepDim: Boolean): DoubleTensor = + override fun StructureND.sum(dim: Int, keepDim: Boolean): DoubleTensor = foldDimToDouble(dim, keepDim) { x -> x.sum() } - override fun StructureND.min(): Double = reduceElements { it.array.min() } + override fun StructureND.min(): Double = reduceElements { it.array.min() } - override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = + override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = foldDimToDouble(dim, keepDim) { x -> x.minOrNull()!! } - override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = foldDimToInt(dim, keepDim) { x -> + override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = foldDimToInt(dim, keepDim) { x -> x.withIndex().minBy { it.value }.index } - override fun StructureND.max(): Double = reduceElements { it.array.max() } + override fun StructureND.max(): Double = reduceElements { it.array.max() } - override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = + override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = foldDimToDouble(dim, keepDim) { x -> x.maxOrNull()!! } - override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = + override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = foldDimToInt(dim, keepDim) { x -> x.withIndex().maxBy { it.value }.index } - override fun mean(structureND: StructureND): Double = structureND.sum() / structureND.indices.linearSize + override fun mean(structureND: StructureND): Double = structureND.sum() / structureND.indices.linearSize - override fun mean(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = + override fun mean(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = structureND.foldDimToDouble(dim, keepDim) { arr -> check(dim < structureND.dimension) { "Dimension $dim out of range ${structureND.dimension}" } arr.sum() / structureND.shape[dim] } - override fun std(structureND: StructureND): Double = structureND.reduceElements { arr -> + override fun std(structureND: StructureND): Double = structureND.reduceElements { arr -> val mean = arr.array.sum() / structureND.indices.linearSize sqrt(arr.array.sumOf { (it - mean) * (it - mean) } / (structureND.indices.linearSize - 1)) } - override fun std(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = + override fun std(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = structureND.foldDimToDouble( dim, keepDim @@ -620,13 +620,13 @@ public open class DoubleTensorAlgebra : sqrt(arr.sumOf { (it - mean) * (it - mean) } / (structureND.shape[dim] - 1)) } - override fun variance(structureND: StructureND): Double = structureND.reduceElements { arr -> + override fun variance(structureND: StructureND): Double = structureND.reduceElements { arr -> val linearSize = structureND.indices.linearSize val mean = arr.array.sum() / linearSize arr.array.sumOf { (it - mean) * (it - mean) } / (linearSize - 1) } - override fun variance(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = + override fun variance(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = structureND.foldDimToDouble( dim, keepDim @@ -637,56 +637,56 @@ public open class DoubleTensorAlgebra : } - override fun exp(arg: StructureND): DoubleTensor = arg.map { this.exp(it) } + override fun exp(arg: StructureND): DoubleTensor = arg.map { this.exp(it) } - override fun ln(arg: StructureND): DoubleTensor = arg.map { this.ln(it) } + override fun ln(arg: StructureND): DoubleTensor = arg.map { this.ln(it) } - override fun sqrt(arg: StructureND): DoubleTensor = arg.map { this.sqrt(it) } + override fun sqrt(arg: StructureND): DoubleTensor = arg.map { this.sqrt(it) } - override fun cos(arg: StructureND): DoubleTensor = arg.map { this.cos(it) } + override fun cos(arg: StructureND): DoubleTensor = arg.map { this.cos(it) } - override fun acos(arg: StructureND): DoubleTensor = arg.map { this.acos(it) } + override fun acos(arg: StructureND): DoubleTensor = arg.map { this.acos(it) } - override fun cosh(arg: StructureND): DoubleTensor = arg.map { this.cosh(it) } + override fun cosh(arg: StructureND): DoubleTensor = arg.map { this.cosh(it) } - override fun acosh(arg: StructureND): DoubleTensor = arg.map { this.acosh(it) } + override fun acosh(arg: StructureND): DoubleTensor = arg.map { this.acosh(it) } - override fun sin(arg: StructureND): DoubleTensor = arg.map { this.sin(it) } + override fun sin(arg: StructureND): DoubleTensor = arg.map { this.sin(it) } - override fun asin(arg: StructureND): DoubleTensor = arg.map { this.asin(it) } + override fun asin(arg: StructureND): DoubleTensor = arg.map { this.asin(it) } - override fun sinh(arg: StructureND): DoubleTensor = arg.map { this.sinh(it) } + override fun sinh(arg: StructureND): DoubleTensor = arg.map { this.sinh(it) } - override fun asinh(arg: StructureND): DoubleTensor = arg.map { this.asinh(it) } + override fun asinh(arg: StructureND): DoubleTensor = arg.map { this.asinh(it) } - override fun tan(arg: StructureND): DoubleTensor = arg.map { this.tan(it) } + override fun tan(arg: StructureND): DoubleTensor = arg.map { this.tan(it) } - override fun atan(arg: StructureND): DoubleTensor = arg.map { this.atan(it) } + override fun atan(arg: StructureND): DoubleTensor = arg.map { this.atan(it) } - override fun tanh(arg: StructureND): DoubleTensor = arg.map { this.tanh(it) } + override fun tanh(arg: StructureND): DoubleTensor = arg.map { this.tanh(it) } - override fun atanh(arg: StructureND): DoubleTensor = arg.map { this.atanh(it) } + override fun atanh(arg: StructureND): DoubleTensor = arg.map { this.atanh(it) } - override fun power(arg: StructureND, pow: Number): StructureND = if (pow is Int) { + override fun power(arg: StructureND, pow: Number): StructureND = if (pow is Int) { arg.map { it.pow(pow) } } else { arg.map { it.pow(pow.toDouble()) } } - override fun ceil(arg: StructureND): DoubleTensor = arg.map { ceil(it) } + override fun ceil(arg: StructureND): DoubleTensor = arg.map { ceil(it) } - override fun floor(structureND: StructureND): DoubleTensor = structureND.map { floor(it) } + override fun floor(structureND: StructureND): DoubleTensor = structureND.map { floor(it) } - override fun StructureND.inv(): DoubleTensor = invLU(this, 1e-9) + override fun StructureND.inv(): DoubleTensor = invLU(this, 1e-9) - override fun StructureND.det(): DoubleTensor = detLU(this, 1e-9) + override fun StructureND.det(): DoubleTensor = detLU(this, 1e-9) - override fun lu(structureND: StructureND): Triple = + override fun lu(structureND: StructureND): Triple = lu(structureND, 1e-9) - override fun cholesky(structureND: StructureND): DoubleTensor = cholesky(structureND, 1e-6) + override fun cholesky(structureND: StructureND): DoubleTensor = cholesky(structureND, 1e-6) - override fun qr(structureND: StructureND): Pair { + override fun qr(structureND: StructureND): Pair { checkSquareMatrix(structureND.shape) val qTensor = zeroesLike(structureND) val rTensor = zeroesLike(structureND) @@ -705,14 +705,14 @@ public open class DoubleTensorAlgebra : } override fun svd( - structureND: StructureND, - ): Triple, StructureND, StructureND> = + structureND: StructureND, + ): Triple, StructureND, StructureND> = svdGolubKahan(structureND = structureND, epsilon = 1e-10) - override fun symEig(structureND: StructureND): Pair = + override fun symEig(structureND: StructureND): Pair = symEigJacobi(structureND = structureND, maxIteration = 50, epsilon = 1e-15) - override fun solve(a: MutableStructure2D, b: MutableStructure2D): MutableStructure2D { + override fun solve(a: MutableStructure2D, b: MutableStructure2D): MutableStructure2D { val aSvd = DoubleTensorAlgebra.svd(a) val s = BroadcastDoubleTensorAlgebra.diagonalEmbedding(aSvd.second.map { 1.0 / it }) val aInverse = aSvd.third.dot(s).dot(aSvd.first.transposed()) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/LevenbergMarquardtAlgorithm.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/LevenbergMarquardtAlgorithm.kt index b2106200e..60a7229e6 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/LevenbergMarquardtAlgorithm.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/LevenbergMarquardtAlgorithm.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* +import space.kscience.kmath.structures.Float64 import kotlin.math.abs import kotlin.math.max import kotlin.math.min @@ -49,7 +50,7 @@ public data class LMResultInfo( var funcCalls: Int, var resultChiSq: Double, var resultLambda: Double, - var resultParameters: MutableStructure2D, + var resultParameters: MutableStructure2D, var typeOfConvergence: TypeOfConvergence, ) @@ -82,14 +83,14 @@ public data class LMResultInfo( * exampleNumber: a parameter for a function with which you can choose its behavior. */ public data class LMInput( - var func: (MutableStructure2D, MutableStructure2D, Int) -> (MutableStructure2D), - var startParameters: MutableStructure2D, - var independentVariables: MutableStructure2D, - var realValues: MutableStructure2D, + var func: (MutableStructure2D, MutableStructure2D, Int) -> (MutableStructure2D), + var startParameters: MutableStructure2D, + var independentVariables: MutableStructure2D, + var realValues: MutableStructure2D, var weight: Double, - var pDelta: MutableStructure2D, - var minParameters: MutableStructure2D, - var maxParameters: MutableStructure2D, + var pDelta: MutableStructure2D, + var minParameters: MutableStructure2D, + var maxParameters: MutableStructure2D, var maxIterations: Int, var epsilons: DoubleArray, var lambdas: DoubleArray, @@ -408,7 +409,7 @@ private data class LMSettings( ) /* matrix -> column of all elements */ -private fun makeColumn(tensor: MutableStructure2D): MutableStructure2D { +private fun makeColumn(tensor: MutableStructure2D): MutableStructure2D { val shape = intArrayOf(tensor.shape.component1() * tensor.shape.component2(), 1) val buffer = DoubleArray(tensor.shape.component1() * tensor.shape.component2()) for (i in 0 until tensor.shape.component1()) { @@ -420,11 +421,11 @@ private fun makeColumn(tensor: MutableStructure2D): MutableStructure2D): Int { +private fun length(column: MutableStructure2D): Int { return column.shape.component1() } -private fun MutableStructure2D.abs() { +private fun MutableStructure2D.abs() { for (i in 0 until this.shape[0]) { for (j in 0 until this.shape[1]) { this[i, j] = abs(this[i, j]) @@ -432,7 +433,7 @@ private fun MutableStructure2D.abs() { } } -private fun abs(input: MutableStructure2D): MutableStructure2D { +private fun abs(input: MutableStructure2D): MutableStructure2D { val tensor = BroadcastDoubleTensorAlgebra.ones( ShapeND( intArrayOf( @@ -449,7 +450,7 @@ private fun abs(input: MutableStructure2D): MutableStructure2D { return tensor } -private fun makeColumnFromDiagonal(input: MutableStructure2D): MutableStructure2D { +private fun makeColumnFromDiagonal(input: MutableStructure2D): MutableStructure2D { val tensor = BroadcastDoubleTensorAlgebra.ones(ShapeND(intArrayOf(input.shape.component1(), 1))).as2D() for (i in 0 until tensor.shape.component1()) { tensor[i, 0] = input[i, i] @@ -457,7 +458,7 @@ private fun makeColumnFromDiagonal(input: MutableStructure2D): MutableSt return tensor } -private fun makeMatrixWithDiagonal(column: MutableStructure2D): MutableStructure2D { +private fun makeMatrixWithDiagonal(column: MutableStructure2D): MutableStructure2D { val size = column.shape.component1() val tensor = BroadcastDoubleTensorAlgebra.zeros(ShapeND(intArrayOf(size, size))).as2D() for (i in 0 until size) { @@ -466,15 +467,15 @@ private fun makeMatrixWithDiagonal(column: MutableStructure2D): MutableS return tensor } -private fun lmEye(size: Int): MutableStructure2D { +private fun lmEye(size: Int): MutableStructure2D { val column = BroadcastDoubleTensorAlgebra.ones(ShapeND(intArrayOf(size, 1))).as2D() return makeMatrixWithDiagonal(column) } private fun largestElementComparison( - a: MutableStructure2D, - b: MutableStructure2D, -): MutableStructure2D { + a: MutableStructure2D, + b: MutableStructure2D, +): MutableStructure2D { val aSizeX = a.shape.component1() val aSizeY = a.shape.component2() val bSizeX = b.shape.component1() @@ -496,9 +497,9 @@ private fun largestElementComparison( } private fun smallestElementComparison( - a: MutableStructure2D, - b: MutableStructure2D, -): MutableStructure2D { + a: MutableStructure2D, + b: MutableStructure2D, +): MutableStructure2D { val aSizeX = a.shape.component1() val aSizeY = a.shape.component2() val bSizeX = b.shape.component1() @@ -520,10 +521,10 @@ private fun smallestElementComparison( } private fun getZeroIndices( - column: MutableStructure2D, + column: MutableStructure2D, epsilon: Double = 0.000001, -): MutableStructure2D? { - var idx = emptyArray() +): MutableStructure2D? { + var idx = emptyArray() for (i in 0 until column.shape.component1()) { if (abs(column[i, 0]) > epsilon) { idx += (i + 1.0) @@ -536,26 +537,26 @@ private fun getZeroIndices( } private fun evaluateFunction( - func: (MutableStructure2D, MutableStructure2D, Int) -> MutableStructure2D, - t: MutableStructure2D, p: MutableStructure2D, exampleNumber: Int, + func: (MutableStructure2D, MutableStructure2D, Int) -> MutableStructure2D, + t: MutableStructure2D, p: MutableStructure2D, exampleNumber: Int, ) - : MutableStructure2D { + : MutableStructure2D { return func(t, p, exampleNumber) } private fun lmMatx( - func: (MutableStructure2D, MutableStructure2D, Int) -> MutableStructure2D, - t: MutableStructure2D, - pOld: MutableStructure2D, - yOld: MutableStructure2D, + func: (MutableStructure2D, MutableStructure2D, Int) -> MutableStructure2D, + t: MutableStructure2D, + pOld: MutableStructure2D, + yOld: MutableStructure2D, dX2: Int, - JInput: MutableStructure2D, - p: MutableStructure2D, - yDat: MutableStructure2D, - weight: MutableStructure2D, - dp: MutableStructure2D, + JInput: MutableStructure2D, + p: MutableStructure2D, + yDat: MutableStructure2D, + weight: MutableStructure2D, + dp: MutableStructure2D, settings: LMSettings, -): Array> = with(DoubleTensorAlgebra) { +): Array> = with(DoubleTensorAlgebra) { // default: dp = 0.001 val Npar = length(p) // number of parameters @@ -581,9 +582,9 @@ private fun lmMatx( } private fun lmBroydenJ( - pOld: MutableStructure2D, yOld: MutableStructure2D, JInput: MutableStructure2D, - p: MutableStructure2D, y: MutableStructure2D, -): MutableStructure2D = with(DoubleTensorAlgebra) { + pOld: MutableStructure2D, yOld: MutableStructure2D, JInput: MutableStructure2D, + p: MutableStructure2D, y: MutableStructure2D, +): MutableStructure2D = with(DoubleTensorAlgebra) { var J = JInput.copyToTensor() val h = p.minus(pOld) @@ -595,13 +596,13 @@ private fun lmBroydenJ( @OptIn(PerformancePitfall::class) private fun lmFdJ( - func: (MutableStructure2D, MutableStructure2D, exampleNumber: Int) -> MutableStructure2D, - t: MutableStructure2D, - p: MutableStructure2D, - y: MutableStructure2D, - dp: MutableStructure2D, + func: (MutableStructure2D, MutableStructure2D, exampleNumber: Int) -> MutableStructure2D, + t: MutableStructure2D, + p: MutableStructure2D, + y: MutableStructure2D, + dp: MutableStructure2D, settings: LMSettings, -): MutableStructure2D = with(DoubleTensorAlgebra) { +): MutableStructure2D = with(DoubleTensorAlgebra) { // default: dp = 0.001 * ones(1,n) val m = length(y) // number of data points diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt index 736f9c33d..f526a8c98 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.linearSize +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensorAlgebra @@ -54,7 +55,7 @@ internal fun checkSquareMatrix(shape: ShapeND) { } internal fun DoubleTensorAlgebra.checkSymmetric( - tensor: Tensor, epsilon: Double = 1e-6, + tensor: Tensor, epsilon: Double = 1e-6, ) = check(tensor.eq(tensor.transposed(), epsilon)) { "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt index 4750dbea2..3e41a19c6 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.* +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.indices @@ -19,10 +20,10 @@ import kotlin.math.max import kotlin.math.sqrt -internal fun MutableStructure2D.jacobiHelper( +internal fun MutableStructure2D.jacobiHelper( maxIteration: Int, epsilon: Double, -): Pair> { +): Pair> { val n = rowNum val A_ = copyToTensor() val V = eye(n) @@ -35,7 +36,7 @@ internal fun MutableStructure2D.jacobiHelper( return source[i * shape[0] + j] } - operator fun BufferedTensor.set(i: Int, j: Int, value: Double) { + operator fun BufferedTensor.set(i: Int, j: Int, value: Double) { source[i * shape[0] + j] = value } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index 239d1dd18..eaf64c8a2 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -7,10 +7,7 @@ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.* import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Float64Buffer -import space.kscience.kmath.structures.Int32Buffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.indices +import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.core.* import kotlin.math.abs import kotlin.math.max @@ -18,9 +15,9 @@ import kotlin.math.min import kotlin.math.sqrt internal fun dotTo( - a: BufferedTensor, - b: BufferedTensor, - res: BufferedTensor, + a: BufferedTensor, + b: BufferedTensor, + res: BufferedTensor, l: Int, m: Int, n: Int, ) { val aBuffer = a.source @@ -39,7 +36,7 @@ internal fun dotTo( } internal fun luHelper( - lu: MutableStructure2D, + lu: MutableStructure2D, pivots: MutableStructure1D, epsilon: Double, ): Boolean { @@ -102,7 +99,7 @@ internal fun StructureND.setUpPivots(): IntTensor { } internal fun DoubleTensorAlgebra.computeLU( - tensor: StructureND, + tensor: StructureND, epsilon: Double, ): Pair? { @@ -118,7 +115,7 @@ internal fun DoubleTensorAlgebra.computeLU( } internal fun pivInit( - p: MutableStructure2D, + p: MutableStructure2D, pivot: MutableStructure1D, n: Int, ) { @@ -128,9 +125,9 @@ internal fun pivInit( } internal fun luPivotHelper( - l: MutableStructure2D, - u: MutableStructure2D, - lu: MutableStructure2D, + l: MutableStructure2D, + u: MutableStructure2D, + lu: MutableStructure2D, n: Int, ) { for (i in 0 until n) { @@ -149,8 +146,8 @@ internal fun luPivotHelper( } internal fun choleskyHelper( - a: MutableStructure2D, - l: MutableStructure2D, + a: MutableStructure2D, + l: MutableStructure2D, n: Int, ) { for (i in 0 until n) { @@ -169,7 +166,7 @@ internal fun choleskyHelper( } } -internal fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructure1D): Double { +internal fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructure1D): Double { if (lu[0, 0] == 0.0) { return 0.0 } @@ -179,9 +176,9 @@ internal fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructur } internal fun luMatrixInv( - lu: MutableStructure2D, + lu: MutableStructure2D, pivots: MutableStructure1D, - invMatrix: MutableStructure2D, + invMatrix: MutableStructure2D, ) { val m = lu.shape[0] @@ -208,7 +205,7 @@ internal fun luMatrixInv( internal fun DoubleTensorAlgebra.qrHelper( matrix: DoubleTensor, q: DoubleTensor, - r: MutableStructure2D, + r: MutableStructure2D, ) { checkSquareMatrix(matrix.shape) val n = matrix.shape[0] @@ -261,7 +258,7 @@ internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10) internal fun DoubleTensorAlgebra.svdHelper( matrix: DoubleTensor, - USV: Triple, BufferedTensor, BufferedTensor>, + USV: Triple, BufferedTensor, BufferedTensor>, m: Int, n: Int, epsilon: Double, ) { val res = ArrayList>(0) @@ -310,9 +307,9 @@ internal fun DoubleTensorAlgebra.svdHelper( } } -internal fun MutableStructure2D.svdGolubKahanHelper( - u: MutableStructure2D, w: BufferedTensor, - v: MutableStructure2D, iterations: Int, epsilon: Double, +internal fun MutableStructure2D.svdGolubKahanHelper( + u: MutableStructure2D, w: BufferedTensor, + v: MutableStructure2D, iterations: Int, epsilon: Double, ) { fun pythag(a: Double, b: Double): Double { val at: Double = abs(a) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt index bd95cee5f..1eb25477b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.nd.* import space.kscience.kmath.operations.covariance import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.internal.* @@ -44,12 +45,12 @@ public fun DoubleTensorAlgebra.randomNormalLike(structure: WithShape, seed: Long * @param tensors the [List] of tensors with same shapes to concatenate * @return tensor with concatenation result */ -public fun stack(tensors: List>): DoubleTensor { +public fun stack(tensors: List>): DoubleTensor { check(tensors.isNotEmpty()) { "List must have at least 1 element" } val shape = tensors[0].shape check(tensors.all { it.shape == shape }) { "Tensors must have same shapes" } val resShape = ShapeND(tensors.size) + shape -// val resBuffer: List = tensors.flatMap { +// val resBuffer: List = tensors.flatMap { // it.asDoubleTensor().source.array.drop(it.asDoubleTensor().bufferStart) // .take(it.asDoubleTensor().linearSize) // } @@ -67,7 +68,7 @@ public fun stack(tensors: List>): DoubleTensor { * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. */ public fun DoubleTensorAlgebra.luFactor( - structureND: StructureND, + structureND: StructureND, epsilon: Double = 1e-9, ): Pair = computeLU(structureND, epsilon) @@ -86,7 +87,7 @@ public fun DoubleTensorAlgebra.luFactor( * @return triple of `P`, `L` and `U` tensors */ public fun DoubleTensorAlgebra.luPivot( - luTensor: StructureND, + luTensor: StructureND, pivotsTensor: Tensor, ): Triple { checkSquareMatrix(luTensor.shape) @@ -130,7 +131,7 @@ public fun DoubleTensorAlgebra.luPivot( * @return triple of `P`, `L` and `U` tensors. */ public fun DoubleTensorAlgebra.lu( - structureND: StructureND, + structureND: StructureND, epsilon: Double = 1e-9, ): Triple { val (lu, pivots) = luFactor(structureND, epsilon) @@ -151,7 +152,7 @@ public fun DoubleTensorAlgebra.lu( * Used when checking the positive definiteness of the input matrix or matrices. * @return a pair of `Q` and `R` tensors. */ -public fun DoubleTensorAlgebra.cholesky(structureND: StructureND, epsilon: Double = 1e-6): DoubleTensor { +public fun DoubleTensorAlgebra.cholesky(structureND: StructureND, epsilon: Double = 1e-6): DoubleTensor { checkSquareMatrix(structureND.shape) checkPositiveDefinite(structureND.asDoubleTensor(), epsilon) @@ -179,9 +180,9 @@ public fun DoubleTensorAlgebra.cholesky(structureND: StructureND, epsilo * @return a triple `Triple(U, S, V)`. */ public fun DoubleTensorAlgebra.svd( - structureND: StructureND, + structureND: StructureND, epsilon: Double, -): Triple, StructureND, StructureND> { +): Triple, StructureND, StructureND> { val size = structureND.dimension val commonShape = structureND.shape.slice(0 until size - 2) val (n, m) = structureND.shape.slice(size - 2 until size) @@ -213,7 +214,7 @@ public fun DoubleTensorAlgebra.svd( } public fun DoubleTensorAlgebra.svdGolubKahan( - structureND: StructureND, + structureND: StructureND, iterations: Int = 30, epsilon: Double = 1e-10, ): Triple { val size = structureND.dimension @@ -253,13 +254,13 @@ public fun DoubleTensorAlgebra.svdGolubKahan( * @return a pair `eigenvalues to eigenvectors`. */ public fun DoubleTensorAlgebra.symEigSvd( - structureND: StructureND, + structureND: StructureND, epsilon: Double, -): Pair> { +): Pair> { //TODO optimize conversion checkSymmetric(structureND.asDoubleTensor(), epsilon) - fun MutableStructure2D.cleanSym(n: Int) { + fun MutableStructure2D.cleanSym(n: Int) { for (i in 0 until n) { for (j in 0 until n) { if (i == j) { @@ -284,7 +285,7 @@ public fun DoubleTensorAlgebra.symEigSvd( } public fun DoubleTensorAlgebra.symEigJacobi( - structureND: StructureND, + structureND: StructureND, maxIteration: Int, epsilon: Double, ): Pair { @@ -326,7 +327,7 @@ public fun DoubleTensorAlgebra.symEigJacobi( * with zero. * @return the determinant. */ -public fun DoubleTensorAlgebra.detLU(structureND: StructureND, epsilon: Double = 1e-9): DoubleTensor { +public fun DoubleTensorAlgebra.detLU(structureND: StructureND, epsilon: Double = 1e-9): DoubleTensor { checkSquareMatrix(structureND.shape) //TODO check for unnecessary copies val luTensor = structureND.copyToTensor() @@ -362,7 +363,7 @@ public fun DoubleTensorAlgebra.detLU(structureND: StructureND, epsilon: * @param epsilon error in the LU algorithm—permissible error when comparing the determinant of a matrix with zero * @return the multiplicative inverse of a matrix. */ -public fun DoubleTensorAlgebra.invLU(structureND: StructureND, epsilon: Double = 1e-9): DoubleTensor { +public fun DoubleTensorAlgebra.invLU(structureND: StructureND, epsilon: Double = 1e-9): DoubleTensor { val (luTensor, pivotsTensor) = luFactor(structureND, epsilon) val invTensor = zeroesLike(luTensor) @@ -384,7 +385,7 @@ public fun DoubleTensorAlgebra.invLU(structureND: StructureND, epsilon: * @param vectors the [List] of 1-dimensional tensors with same shape * @return `M`. */ -public fun DoubleTensorAlgebra.covariance(vectors: List>): DoubleTensor { +public fun DoubleTensorAlgebra.covariance(vectors: List>): DoubleTensor { check(vectors.isNotEmpty()) { "List must have at least 1 element" } val n = vectors.size val m = vectors[0].size diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt index 6490ecdb9..07891cd5b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.nd.* +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.tensors.api.Tensor @@ -14,7 +15,7 @@ import space.kscience.kmath.tensors.api.Tensor /** * Create a mutable copy of given [StructureND]. */ -public fun StructureND.copyToTensor(): DoubleTensor = if (this is DoubleTensor) { +public fun StructureND.copyToTensor(): DoubleTensor = if (this is DoubleTensor) { DoubleTensor(shape, source.copy()) } else if (this is Float64BufferND && indices is RowStrides) { DoubleTensor(shape, buffer.array.copyOf().asBuffer()) @@ -43,7 +44,7 @@ public fun StructureND.toDoubleTensor(): DoubleTensor { /** * Transforms [StructureND] of [Double] to [DoubleTensor]. Zero copy if possible, but is not guaranteed */ -public fun StructureND.asDoubleTensor(): DoubleTensor = if (this is DoubleTensor) { +public fun StructureND.asDoubleTensor(): DoubleTensor = if (this is DoubleTensor) { this } else if (this is Float64BufferND && indices is RowStrides) { DoubleTensor(shape, buffer) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 92d997468..25db17f4f 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.toDoubleArray import space.kscience.kmath.tensors.core.internal.matrixSequence @@ -68,7 +69,7 @@ internal class TestDoubleTensor { val doubleArray = Float64Buffer(1.0, 2.0, 3.0) // create ND buffers, no data is copied - val ndArray: MutableBufferND = Float64BufferND(ColumnStrides(ShapeND(3)), doubleArray) + val ndArray: MutableBufferND = Float64BufferND(ColumnStrides(ShapeND(3)), doubleArray) // map to tensors val tensorArray = ndArray.asDoubleTensor() // Data is copied because of strides change. diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt index 38c51d66e..245db5c2a 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.indices import kotlin.jvm.JvmName @@ -20,5 +21,5 @@ public fun OffsetDoubleBuffer.contentEquals(vararg doubles: Double): Boolean = i public infix fun OffsetDoubleBuffer.contentEquals(otherArray: DoubleArray): Boolean = contentEquals(*otherArray) @JvmName("contentEqualsBuffer") -public infix fun OffsetDoubleBuffer.contentEquals(otherBuffer: Buffer): Boolean = +public infix fun OffsetDoubleBuffer.contentEquals(otherBuffer: Buffer): Boolean = indices.all { get(it) == otherBuffer[it] } \ No newline at end of file diff --git a/kmath-tensors/src/jvmTest/kotlin/space/kscience/kmath/tensors/core/TestLmAlgorithm.kt b/kmath-tensors/src/jvmTest/kotlin/space/kscience/kmath/tensors/core/TestLmAlgorithm.kt index 6c072d52b..a6176dcf6 100644 --- a/kmath-tensors/src/jvmTest/kotlin/space/kscience/kmath/tensors/core/TestLmAlgorithm.kt +++ b/kmath-tensors/src/jvmTest/kotlin/space/kscience/kmath/tensors/core/TestLmAlgorithm.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.Float64Buffer import kotlin.test.Test import kotlin.test.assertEquals @@ -16,10 +17,10 @@ import kotlin.test.assertEquals class TestLmAlgorithm { companion object { fun funcEasyForLm( - t: MutableStructure2D, - p: MutableStructure2D, + t: MutableStructure2D, + p: MutableStructure2D, exampleNumber: Int, - ): MutableStructure2D = with(DoubleTensorAlgebra) { + ): MutableStructure2D = with(DoubleTensorAlgebra) { val m = t.shape.component1() val yHat = when (exampleNumber) { 1 -> exp((t * (-1.0 / p[1, 0]))) * p[0, 0] + (t * p[2, 0]) * exp((t * (-1.0 / p[3, 0]))) @@ -42,10 +43,10 @@ class TestLmAlgorithm { } fun funcMiddleForLm( - t: MutableStructure2D, - p: MutableStructure2D, + t: MutableStructure2D, + p: MutableStructure2D, exampleNumber: Int, - ): MutableStructure2D = with(DoubleTensorAlgebra) { + ): MutableStructure2D = with(DoubleTensorAlgebra) { val m = t.shape.component1() var yHat = zeros(ShapeND(intArrayOf(m, 1))) @@ -62,10 +63,10 @@ class TestLmAlgorithm { } fun funcDifficultForLm( - t: MutableStructure2D, - p: MutableStructure2D, + t: MutableStructure2D, + p: MutableStructure2D, exampleNumber: Int, - ): MutableStructure2D = with(DoubleTensorAlgebra) { + ): MutableStructure2D = with(DoubleTensorAlgebra) { val m = t.shape.component1() var yHat = zeros(ShapeND(intArrayOf(m, 1))) diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt index 89b51f269..86099226a 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt @@ -7,11 +7,12 @@ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64FlatArray import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.MutableBuffer @Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") @JvmInline -public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { +public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { override val size: Int get() = flatArray.length @@ -22,7 +23,7 @@ public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuf flatArray[index] = value } - override operator fun iterator(): Iterator = flatArray.data.iterator() + override operator fun iterator(): Iterator = flatArray.data.iterator() override fun toString(): String = Buffer.toString(this) } diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt index 61ef00c6f..22ef49db2 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt @@ -16,14 +16,15 @@ import space.kscience.kmath.operations.ExtendedFieldOps import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.PowerOperations +import space.kscience.kmath.structures.Float64 @OptIn(PerformancePitfall::class) public open class ViktorFieldOpsND : FieldOpsND, - ExtendedFieldOps>, - PowerOperations> { + ExtendedFieldOps>, + PowerOperations> { - public val StructureND.f64Buffer: F64Array + public val StructureND.f64Buffer: F64Array get() = when (this) { is ViktorStructureND -> this.f64Buffer else -> mutableStructureND(shape) { this@f64Buffer[it] }.f64Buffer @@ -39,11 +40,11 @@ public open class ViktorFieldOpsND : } }.asStructure() - override fun StructureND.unaryMinus(): StructureND = -1 * this + override fun StructureND.unaryMinus(): StructureND = -1 * this @OptIn(UnsafeKMathAPI::class) @PerformancePitfall - override fun StructureND.map(transform: Float64Field.(Double) -> Double): ViktorStructureND = + override fun StructureND.map(transform: Float64Field.(Double) -> Double): ViktorStructureND = F64Array(*shape.asArray()).apply { ColumnStrides(ShapeND(shape)).asSequence().forEach { index -> set(value = Float64Field.transform(this@map[index]), indices = index) @@ -52,7 +53,7 @@ public open class ViktorFieldOpsND : @OptIn(UnsafeKMathAPI::class) @PerformancePitfall - override fun StructureND.mapIndexed( + override fun StructureND.mapIndexed( transform: Float64Field.(index: IntArray, Double) -> Double, ): ViktorStructureND = F64Array(*shape.asArray()).apply { ColumnStrides(ShapeND(shape)).asSequence().forEach { index -> @@ -63,8 +64,8 @@ public open class ViktorFieldOpsND : @OptIn(UnsafeKMathAPI::class) @PerformancePitfall override fun zip( - left: StructureND, - right: StructureND, + left: StructureND, + right: StructureND, transform: Float64Field.(Double, Double) -> Double, ): ViktorStructureND { require(left.shape == right.shape) @@ -75,46 +76,46 @@ public open class ViktorFieldOpsND : }.asStructure() } - override fun add(left: StructureND, right: StructureND): ViktorStructureND = + override fun add(left: StructureND, right: StructureND): ViktorStructureND = (left.f64Buffer + right.f64Buffer).asStructure() - override fun scale(a: StructureND, value: Double): ViktorStructureND = + override fun scale(a: StructureND, value: Double): ViktorStructureND = (a.f64Buffer * value).asStructure() - override fun StructureND.plus(arg: StructureND): ViktorStructureND = + override fun StructureND.plus(arg: StructureND): ViktorStructureND = (f64Buffer + arg.f64Buffer).asStructure() - override fun StructureND.minus(arg: StructureND): ViktorStructureND = + override fun StructureND.minus(arg: StructureND): ViktorStructureND = (f64Buffer - arg.f64Buffer).asStructure() - override fun StructureND.times(k: Number): ViktorStructureND = + override fun StructureND.times(k: Number): ViktorStructureND = (f64Buffer * k.toDouble()).asStructure() - override fun StructureND.plus(arg: Double): ViktorStructureND = + override fun StructureND.plus(arg: Double): ViktorStructureND = (f64Buffer.plus(arg)).asStructure() - override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } - override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } - override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } - override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } - override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } - override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } + override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } + override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } + override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } + override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } + override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } + override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } - override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } + override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } - override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() + override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() - override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() + override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() - override fun sinh(arg: StructureND): ViktorStructureND = arg.map { sinh(it) } + override fun sinh(arg: StructureND): ViktorStructureND = arg.map { sinh(it) } - override fun cosh(arg: StructureND): ViktorStructureND = arg.map { cosh(it) } + override fun cosh(arg: StructureND): ViktorStructureND = arg.map { cosh(it) } - override fun asinh(arg: StructureND): ViktorStructureND = arg.map { asinh(it) } + override fun asinh(arg: StructureND): ViktorStructureND = arg.map { asinh(it) } - override fun acosh(arg: StructureND): ViktorStructureND = arg.map { acosh(it) } + override fun acosh(arg: StructureND): ViktorStructureND = arg.map { acosh(it) } - override fun atanh(arg: StructureND): ViktorStructureND = arg.map { atanh(it) } + override fun atanh(arg: StructureND): ViktorStructureND = arg.map { atanh(it) } public companion object : ViktorFieldOpsND() } @@ -124,7 +125,7 @@ public val Float64Field.viktorAlgebra: ViktorFieldOpsND get() = ViktorFieldOpsND @OptIn(UnstableKMathAPI::class) public open class ViktorFieldND( private val shapeAsArray: IntArray, -) : ViktorFieldOpsND(), FieldND, NumbersAddOps> { +) : ViktorFieldOpsND(), FieldND, NumbersAddOps> { override val shape: ShapeND = ShapeND(shapeAsArray) diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt index 328a0ab01..5a9e80fe6 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt @@ -10,9 +10,10 @@ import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.nd.MutableStructureND import space.kscience.kmath.nd.ShapeND +import space.kscience.kmath.structures.Float64 @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructureND { +public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructureND { override val shape: ShapeND get() = ShapeND(f64Buffer.shape) @OptIn(PerformancePitfall::class) diff --git a/test-utils/src/commonMain/kotlin/asserts.kt b/test-utils/src/commonMain/kotlin/asserts.kt index 54c6301b6..f4716f9f6 100644 --- a/test-utils/src/commonMain/kotlin/asserts.kt +++ b/test-utils/src/commonMain/kotlin/asserts.kt @@ -6,11 +6,12 @@ package space.kscience.kmath.testutils import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.Float64 import space.kscience.kmath.structures.indices import kotlin.test.assertEquals import kotlin.test.fail -public fun assertBufferEquals(expected: Buffer, result: Buffer, tolerance: Double = 1e-4) { +public fun assertBufferEquals(expected: Buffer, result: Buffer, tolerance: Double = 1e-4) { if (expected.size != result.size) { fail("Expected size is ${expected.size}, but the result size is ${result.size}") }