Compare commits

...

17 Commits

Author SHA1 Message Date
46eacbb750 0.4 WIP 2023-11-03 09:56:19 +03:00
ea887b8c72 0.4 WIP 2023-11-01 08:55:47 +03:00
544b8610e1 Merge branch 'dev' into dev-0.4
# Conflicts:
#	buildSrc/settings.gradle.kts
#	gradle.properties
#	gradle/wrapper/gradle-wrapper.properties
#	kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt
#	kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float32Space2D.kt
#	kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float64Space2D.kt
#	kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/quaternionOperations.kt
2023-10-31 14:18:50 +03:00
a84f1e1500 Merge branch 'kotlin/1.9.20' into dev 2023-10-31 14:05:37 +03:00
328d45444c 1.9.20 finalization 2023-10-31 14:05:17 +03:00
1765f8cf8c Remove asPolynomial 2023-10-25 10:28:39 +03:00
bfb556b013 remove webpack and node version fixture 2023-10-03 19:33:39 +03:00
5129f29084 update geometry 2023-09-22 09:53:44 +03:00
56933ecff3 1.9.20-Beta2 2023-09-22 09:04:39 +03:00
12a02320ec Merge branch 'dev' into kotlin/1.9.20
# Conflicts:
#	build.gradle.kts
2023-09-22 08:33:40 +03:00
7a4e9e70f9 add some quaternion operations 2023-09-22 08:21:14 +03:00
23c0758ba6 Kotlin 1.9.20 2023-09-13 13:25:54 +03:00
dd3d38490a [WIP] refactor features to attributes 2023-09-13 09:00:56 +03:00
a001c74025 1.9.0-RC 2023-06-22 08:49:51 +03:00
1f6b7abf46 wasm test version 2023-06-07 15:16:58 +03:00
c940645e2e fix simja version 2023-06-06 17:43:38 +03:00
65c6962544 Update build tools 2023-05-26 16:46:18 +03:00
84 changed files with 665 additions and 389 deletions

View File

@ -3,10 +3,11 @@
## Unreleased
### Added
- Integer division algebras
- Float32 geometries
- New Attributes-kt module that could be used as stand-alone. It declares type-safe attributes containers.
- Explicit `mutableStructureND` builders for mutable structures
- Explicit `SafeType` for algebras and buffers.
- Integer division algebras.
- Float32 geometries.
- New Attributes-kt module that could be used as stand-alone. It declares. type-safe attributes containers.
- Explicit `mutableStructureND` builders for mutable structures.
### Changed
- Default naming for algebra and buffers now uses IntXX/FloatXX notation instead of Java types.
@ -19,6 +20,7 @@
### Deprecated
### Removed
- `asPolynomial` function due to scope pollution
### Fixed
- Median statistics

View File

@ -7,8 +7,10 @@ package space.kscience.attributes
/**
* A safe builder for [Attributes]
*
* @param O type marker of an owner object, for which these attributes are made
*/
public class AttributesBuilder internal constructor(private val map: MutableMap<Attribute<*>, Any>) {
public class TypedAttributesBuilder<in O> internal constructor(private val map: MutableMap<Attribute<*>, Any>) {
public constructor() : this(mutableMapOf())
@ -47,6 +49,8 @@ public class AttributesBuilder internal constructor(private val map: MutableMap<
public fun build(): Attributes = Attributes(map)
}
public typealias AttributesBuilder = TypedAttributesBuilder<Any?>
public fun AttributesBuilder(
attributes: Attributes,
): AttributesBuilder = AttributesBuilder(attributes.content.toMutableMap())

View File

@ -16,7 +16,7 @@ import kotlin.reflect.typeOf
* @param kType raw [KType]
*/
@JvmInline
public value class SafeType<T> @PublishedApi internal constructor(public val kType: KType)
public value class SafeType<out T> @PublishedApi internal constructor(public val kType: KType)
public inline fun <reified T> safeTypeOf(): SafeType<T> = SafeType(typeOf<T>())

View File

@ -1,4 +1,3 @@
import space.kscience.gradle.isInDevelopment
import space.kscience.gradle.useApache2Licence
import space.kscience.gradle.useSPCTeam
@ -64,17 +63,10 @@ ksciencePublish {
useApache2Licence()
useSPCTeam()
}
github("kmath", "SciProgCentre")
space(
if (isInDevelopment) {
"https://maven.pkg.jetbrains.space/spc/p/sci/dev"
} else {
"https://maven.pkg.jetbrains.space/spc/p/sci/maven"
}
)
repository("spc","https://maven.sciprog.center/kscience")
sonatype("https://oss.sonatype.org")
}
apiValidation.nonPublicMarkers.add("space.kscience.kmath.UnstableKMathAPI")
val multikVersion by extra("0.2.0")
val multikVersion by extra("0.2.2")

View File

@ -17,7 +17,7 @@ val benchmarksVersion = spclibs.versions.kotlinx.benchmark.get()
dependencies {
api("space.kscience:gradle-tools:$toolsVersion")
//plugins form benchmarks
api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.4.7")
api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.4.9")
//api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
//to be used inside build-script only
//implementation(spclibs.kotlinx.serialization.json)

View File

@ -1,4 +1,13 @@
rootProject.name = "buildSrc"
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
}
dependencyResolutionManagement {
val projectProperties = java.util.Properties()

View File

@ -54,9 +54,9 @@ fun Project.addBenchmarkProperties() {
p.extensions.findByType(KScienceReadmeExtension::class.java)?.run {
benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg ->
property("benchmark${cfg.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }}") {
val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}")
val launches = benchmarksProject.layout.buildDirectory.dir("reports/benchmarks/${cfg.name}").get()
val resDirectory = launches.listFiles()?.maxByOrNull {
val resDirectory = launches.files().maxByOrNull {
LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant()
}

View File

@ -6,9 +6,12 @@ kotlin.code.style=official
kotlin.mpp.stability.nowarn=true
kotlin.native.ignoreDisabledTargets=true
toolsVersion=0.14.9-kotlin-1.8.20
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx4096m
org.gradle.parallel=true
org.gradle.workers.max=4
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx4096m
toolsVersion=0.15.0-kotlin-1.9.20
#kotlin.experimental.tryK2=true
#kscience.wasm.disabled=true

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -31,7 +31,7 @@ kscience{
kotlin {
js {
nodejs {
testTask {
testTask{
useMocha().timeout = "0"
}
}

View File

@ -17,7 +17,7 @@ internal class TestFeatures {
fun printNumeric() {
val num = object : Number() {
override fun toByte(): Byte = throw UnsupportedOperationException()
override fun toChar(): Char = throw UnsupportedOperationException()
// override fun toChar(): Char = throw UnsupportedOperationException()
override fun toDouble(): Double = throw UnsupportedOperationException()
override fun toFloat(): Float = throw UnsupportedOperationException()
override fun toInt(): Int = throw UnsupportedOperationException()

View File

@ -8,9 +8,8 @@
"OVERRIDING_FINAL_MEMBER",
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
"CONFLICTING_OVERLOADS",
"NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING",
"PropertyName",
"ClassName",
"ClassName", "ENUM_CLASS_IN_EXTERNAL_DECLARATION_WARNING",
)
@file:JsModule("binaryen")

View File

@ -1,17 +1,20 @@
plugins {
id("space.kscience.gradle.jvm")
id("space.kscience.gradle.mpp")
}
description = "Commons math binding for kmath"
dependencies {
api(project(":kmath-core"))
api(project(":kmath-complex"))
api(project(":kmath-coroutines"))
api(project(":kmath-optimization"))
api(project(":kmath-stat"))
api(project(":kmath-functions"))
kscience {
jvm()
jvmMain {
api(projects.kmathCore)
api(projects.kmathComplex)
api(projects.kmathCoroutines)
api(projects.kmathOptimization)
api(projects.kmathStat)
api(projects.kmathFunctions)
api("org.apache.commons:commons-math3:3.6.1")
}
}
readme {

View File

@ -22,7 +22,7 @@ public class CMGaussRuleIntegrator(
val integrator: GaussIntegrator = getIntegrator(range)
//TODO check performance
val res: Double = integrator.integrate(integrand.function)
return integrand.modify {
return integrand.withAttributes {
IntegrandValue(res)
IntegrandCallsPerformed(integrand.calls + numpoints)
}

View File

@ -26,7 +26,7 @@ public class CMIntegrator(
val range = integrand[IntegrationRange] ?: error("Integration range is not provided")
val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive)
return integrand.modify {
return integrand.withAttributes {
value(res)
IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy)
IntegrandRelativeAccuracy(integrator.relativeAccuracy)

View File

@ -6,7 +6,6 @@ kscience {
jvm()
js()
native()
wasm()
dependencies {

View File

@ -10,6 +10,7 @@ import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.nd.Structure2D
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.VirtualBuffer
import kotlin.math.max
/**
@ -33,7 +34,10 @@ public interface XYColumnarData<out T, out X : T, out Y : T> : ColumnarData<T> {
else -> null
}
public companion object{
public companion object {
/**
* Create data form two buffers (zero-copy)
*/
@UnstableKMathAPI
public fun <T, X : T, Y : T> of(x: Buffer<X>, y: Buffer<Y>): XYColumnarData<T, X, Y> {
require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" }
@ -43,6 +47,26 @@ public interface XYColumnarData<out T, out X : T, out Y : T> : ColumnarData<T> {
override val y: Buffer<Y> = y
}
}
/**
* Create two-column data from a list of row-objects (zero-copy)
*/
@UnstableKMathAPI
public inline fun <I, T, reified X : T, reified Y : T> ofList(
list: List<I>,
noinline xConverter: (I) -> X,
noinline yConverter: (I) -> Y,
): XYColumnarData<T, X, Y> = object : XYColumnarData<T, X, Y> {
override val size: Int get() = list.size
override val x: Buffer<X> = VirtualBuffer(list.size) {
xConverter(list[it])
}
override val y: Buffer<Y> = VirtualBuffer(list.size) {
yConverter(list[it])
}
}
}
}
@ -56,9 +80,10 @@ public fun <T> ColumnarData<T>.asXYData(
ySymbol: Symbol,
): XYColumnarData<T, T, T> = object : XYColumnarData<T, T, T> {
init {
requireNotNull(this@asXYData[xSymbol]){"The column with name $xSymbol is not present in $this"}
requireNotNull(this@asXYData[ySymbol]){"The column with name $ySymbol is not present in $this"}
requireNotNull(this@asXYData[xSymbol]) { "The column with name $xSymbol is not present in $this" }
requireNotNull(this@asXYData[ySymbol]) { "The column with name $ySymbol is not present in $this" }
}
override val size: Int get() = this@asXYData.size
override val x: Buffer<T> get() = this@asXYData[xSymbol]!!
override val y: Buffer<T> get() = this@asXYData[ySymbol]!!

View File

@ -13,8 +13,6 @@ import space.kscience.kmath.structures.MutableBufferFactory
import space.kscience.kmath.structures.asBuffer
import kotlin.math.max
import kotlin.math.min
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* Class representing both the value and the differentials of a function.
@ -84,6 +82,8 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
bindings: Map<Symbol, T>,
) : ExpressionAlgebra<T, DS<T, A>>, SymbolIndexer {
override val bufferFactory: MutableBufferFactory<DS<T, A>> = MutableBufferFactory()
/**
* Get the compiler for number of free parameters and order.
*

View File

@ -6,6 +6,7 @@
package space.kscience.kmath.expressions
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
@ -17,6 +18,8 @@ import kotlin.contracts.contract
public abstract class FunctionalExpressionAlgebra<T, out A : Algebra<T>>(
public val algebra: A,
) : ExpressionAlgebra<T, Expression<T>> {
override val bufferFactory: MutableBufferFactory<Expression<T>> = MutableBufferFactory<Expression<T>>()
/**
* Builds an Expression of constant expression that does not depend on arguments.
*/
@ -49,6 +52,7 @@ public abstract class FunctionalExpressionAlgebra<T, out A : Algebra<T>>(
public open class FunctionalExpressionGroup<T, out A : Group<T>>(
algebra: A,
) : FunctionalExpressionAlgebra<T, A>(algebra), Group<Expression<T>> {
override val zero: Expression<T> get() = const(algebra.zero)
override fun Expression<T>.unaryMinus(): Expression<T> =

View File

@ -7,11 +7,14 @@ package space.kscience.kmath.expressions
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.MutableBufferFactory
/**
* [Algebra] over [MST] nodes.
*/
public object MstNumericAlgebra : NumericAlgebra<MST> {
override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
override fun number(value: Number): MST.Numeric = MST.Numeric(value)
override fun bindSymbolOrNull(value: String): Symbol = StringSymbol(value)
override fun bindSymbol(value: String): Symbol = bindSymbolOrNull(value)
@ -27,6 +30,9 @@ public object MstNumericAlgebra : NumericAlgebra<MST> {
* [Group] over [MST] nodes.
*/
public object MstGroup : Group<MST>, NumericAlgebra<MST>, ScaleOperations<MST> {
override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
override val zero: MST.Numeric = number(0.0)
override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value)
@ -57,7 +63,11 @@ public object MstGroup : Group<MST>, NumericAlgebra<MST>, ScaleOperations<MST> {
@Suppress("OVERRIDE_BY_INLINE")
@OptIn(UnstableKMathAPI::class)
public object MstRing : Ring<MST>, NumbersAddOps<MST>, ScaleOperations<MST> {
override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
override inline val zero: MST.Numeric get() = MstGroup.zero
override val one: MST.Numeric = number(1.0)
override fun number(value: Number): MST.Numeric = MstGroup.number(value)
@ -87,7 +97,11 @@ public object MstRing : Ring<MST>, NumbersAddOps<MST>, ScaleOperations<MST> {
@Suppress("OVERRIDE_BY_INLINE")
@OptIn(UnstableKMathAPI::class)
public object MstField : Field<MST>, NumbersAddOps<MST>, ScaleOperations<MST> {
override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
override inline val zero: MST.Numeric get() = MstRing.zero
override inline val one: MST.Numeric get() = MstRing.one
override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value)
@ -117,7 +131,11 @@ public object MstField : Field<MST>, NumbersAddOps<MST>, ScaleOperations<MST> {
*/
@Suppress("OVERRIDE_BY_INLINE")
public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
override inline val zero: MST.Numeric get() = MstField.zero
override inline val one: MST.Numeric get() = MstField.one
override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value)
@ -164,6 +182,9 @@ public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
*/
@UnstableKMathAPI
public object MstLogicAlgebra : LogicAlgebra<MST> {
override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
override fun bindSymbolOrNull(value: String): MST = super.bindSymbolOrNull(value) ?: StringSymbol(value)
override fun const(boolean: Boolean): Symbol = if (boolean) {

View File

@ -5,9 +5,11 @@
package space.kscience.kmath.expressions
import space.kscience.attributes.SafeType
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.linear.Point
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.MutableBufferFactory
import space.kscience.kmath.structures.asBuffer
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
@ -30,9 +32,10 @@ public open class AutoDiffValue<out T>(public val value: T)
*/
public class DerivationResult<T : Any>(
public val value: T,
override val type: SafeType<T>,
private val derivativeValues: Map<String, T>,
public val context: Field<T>,
) {
) : WithType<T> {
/**
* Returns derivative of [variable] or returns [Ring.zero] in [context].
*/
@ -49,19 +52,23 @@ public class DerivationResult<T : Any>(
*/
public fun <T : Any> DerivationResult<T>.grad(vararg variables: Symbol): Point<T> {
check(variables.isNotEmpty()) { "Variable order is not provided for gradient construction" }
return variables.map(::derivative).asBuffer()
return variables.map(::derivative).asBuffer(type)
}
/**
* Represents field in context of which functions can be derived.
* Represents field. Function derivatives could be computed in this field
*/
@OptIn(UnstableKMathAPI::class)
public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
public val context: F,
public val algebra: F,
bindings: Map<Symbol, T>,
) : Field<AutoDiffValue<T>>, ExpressionAlgebra<T, AutoDiffValue<T>>, NumbersAddOps<AutoDiffValue<T>> {
override val zero: AutoDiffValue<T> get() = const(context.zero)
override val one: AutoDiffValue<T> get() = const(context.one)
override val bufferFactory: MutableBufferFactory<AutoDiffValue<T>> = MutableBufferFactory<AutoDiffValue<T>>()
override val zero: AutoDiffValue<T> get() = const(algebra.zero)
override val one: AutoDiffValue<T> get() = const(algebra.one)
// this stack contains pairs of blocks and values to apply them to
private var stack: Array<Any?> = arrayOfNulls<Any?>(8)
@ -69,7 +76,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
private val derivatives: MutableMap<AutoDiffValue<T>, T> = hashMapOf()
private val bindings: Map<String, AutoDiffVariableWithDerivative<T>> = bindings.entries.associate {
it.key.identity to AutoDiffVariableWithDerivative(it.key.identity, it.value, context.zero)
it.key.identity to AutoDiffVariableWithDerivative(it.key.identity, it.value, algebra.zero)
}
/**
@ -92,7 +99,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
override fun bindSymbolOrNull(value: String): AutoDiffValue<T>? = bindings[value]
private fun getDerivative(variable: AutoDiffValue<T>): T =
(variable as? AutoDiffVariableWithDerivative)?.d ?: derivatives[variable] ?: context.zero
(variable as? AutoDiffVariableWithDerivative)?.d ?: derivatives[variable] ?: algebra.zero
private fun setDerivative(variable: AutoDiffValue<T>, value: T) {
if (variable is AutoDiffVariableWithDerivative) variable.d = value else derivatives[variable] = value
@ -103,7 +110,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
while (sp > 0) {
val value = stack[--sp]
val block = stack[--sp] as F.(Any?) -> Unit
context.block(value)
algebra.block(value)
}
}
@ -130,7 +137,6 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
* }
* ```
*/
@Suppress("UNCHECKED_CAST")
public fun <R> derive(value: R, block: F.(R) -> Unit): R {
// save block to stack for backward pass
if (sp >= stack.size) stack = stack.copyOf(stack.size * 2)
@ -142,9 +148,9 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
internal fun differentiate(function: SimpleAutoDiffField<T, F>.() -> AutoDiffValue<T>): DerivationResult<T> {
val result = function()
result.d = context.one // computing derivative w.r.t result
result.d = algebra.one // computing derivative w.r.t result
runBackwardPass()
return DerivationResult(result.value, bindings.mapValues { it.value.d }, context)
return DerivationResult(result.value, algebra.type, bindings.mapValues { it.value.d }, algebra)
}
// // Overloads for Double constants
@ -194,7 +200,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
public inline fun <T : Any, F : Field<T>> SimpleAutoDiffField<T, F>.const(block: F.() -> T): AutoDiffValue<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return const(context.block())
return const(algebra.block())
}

View File

@ -10,10 +10,9 @@ import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.BufferRingOps
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.WithType
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* Alias for [Structure2D] with more familiar name.
@ -34,7 +33,7 @@ public typealias Point<T> = Buffer<T>
* A marker interface for algebras that operate on matrices
* @param T type of matrix element
*/
public interface MatrixOperations<T>
public interface MatrixOperations<T> : WithType<T>
/**
* Basic operations on matrices and vectors.
@ -45,6 +44,8 @@ public interface MatrixOperations<T>
public interface LinearSpace<T, out A : Ring<T>> : MatrixOperations<T> {
public val elementAlgebra: A
override val type: SafeType<T> get() = elementAlgebra.type
/**
* Produces a matrix with this context and given dimensions.
*/
@ -212,4 +213,4 @@ public fun <T : Any> Matrix<T>.asVector(): Point<T> =
* @receiver a buffer.
* @return the new matrix.
*/
public fun <T : Any> Point<T>.asMatrix(): VirtualMatrix<T> = VirtualMatrix(size, 1) { i, _ -> get(i) }
public fun <T : Any> Point<T>.asMatrix(): VirtualMatrix<T> = VirtualMatrix(type, size, 1) { i, _ -> get(i) }

View File

@ -22,11 +22,27 @@ import space.kscience.kmath.structures.*
* @param l The lower triangular matrix in this decomposition. It may have [LowerTriangular].
* @param u The upper triangular matrix in this decomposition. It may have [UpperTriangular].
*/
public data class LupDecomposition<T>(
public class LupDecomposition<T>(
public val linearSpace: LinearSpace<T, Ring<T>>,
public val l: Matrix<T>,
public val u: Matrix<T>,
public val pivot: IntBuffer,
)
) {
public val elementAlgebra: Ring<T> get() = linearSpace.elementAlgebra
public val pivotMatrix: VirtualMatrix<T>
get() = VirtualMatrix(linearSpace.type, l.rowNum, l.colNum) { row, column ->
if (column == pivot[row]) elementAlgebra.one else elementAlgebra.zero
}
public val <T> LupDecomposition<T>.determinant by lazy {
elementAlgebra { (0 until l.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } }
}
}
public class LupDecompositionAttribute<T>(type: SafeType<LupDecomposition<T>>) :
@ -168,7 +184,7 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
for (row in col + 1 until m) lu[row, col] /= luDiag
}
val l: MatrixWrapper<T> = VirtualMatrix(rowNum, colNum) { i, j ->
val l: MatrixWrapper<T> = VirtualMatrix(type, rowNum, colNum) { i, j ->
when {
j < i -> lu[i, j]
j == i -> one
@ -176,7 +192,7 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
}
}.withAttribute(LowerTriangular)
val u = VirtualMatrix(rowNum, colNum) { i, j ->
val u = VirtualMatrix(type, rowNum, colNum) { i, j ->
if (j >= i) lu[i, j] else zero
}.withAttribute(UpperTriangular)
//
@ -184,7 +200,7 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
// if (j == pivot[i]) one else zero
// }.withAttribute(Determinant, if (even) one else -one)
return LupDecomposition(l, u, pivot.asBuffer())
return LupDecomposition(this@lup, l, u, pivot.asBuffer())
}
}
}

View File

@ -6,16 +6,21 @@
package space.kscience.kmath.linear
import space.kscience.attributes.FlagAttribute
import space.kscience.attributes.SafeType
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.WithType
import space.kscience.kmath.structures.BufferAccessor2D
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableBufferFactory
public class MatrixBuilder<T : Any, out A : Ring<T>>(
public val linearSpace: LinearSpace<T, A>,
public val rows: Int,
public val columns: Int,
) {
) : WithType<T> {
override val type: SafeType<T> get() = linearSpace.type
public operator fun invoke(vararg elements: T): Matrix<T> {
require(rows * columns == elements.size) { "The number of elements ${elements.size} is not equal $rows * $columns" }
return linearSpace.buildMatrix(rows, columns) { i, j -> elements[i * columns + j] }
@ -61,7 +66,7 @@ public fun <T : Any, A : Ring<T>> MatrixBuilder<T, A>.symmetric(
builder: (i: Int, j: Int) -> T,
): Matrix<T> {
require(columns == rows) { "In order to build symmetric matrix, number of rows $rows should be equal to number of columns $columns" }
return with(BufferAccessor2D<T?>(rows, rows, MutableBuffer.Companion::boxing)) {
return with(BufferAccessor2D<T?>(rows, rows, MutableBufferFactory(type))) {
val cache = factory(rows * rows) { null }
linearSpace.buildMatrix(rows, rows) { i, j ->
val cached = cache[i, j]

View File

@ -39,7 +39,7 @@ public fun <T : Any, A : Attribute<T>> Matrix<T>.withAttribute(
attribute: A,
attrValue: T,
): MatrixWrapper<T> = if (this is MatrixWrapper) {
MatrixWrapper(origin, attributes.withAttribute(attribute,attrValue))
MatrixWrapper(origin, attributes.withAttribute(attribute, attrValue))
} else {
MatrixWrapper(this, Attributes(attribute, attrValue))
}
@ -68,7 +68,7 @@ public fun <T : Any> Matrix<T>.modifyAttributes(modifier: (Attributes) -> Attrib
public fun <T : Any> LinearSpace<T, Ring<T>>.one(
rows: Int,
columns: Int,
): MatrixWrapper<T> = VirtualMatrix(rows, columns) { i, j ->
): MatrixWrapper<T> = VirtualMatrix(type, rows, columns) { i, j ->
if (i == j) elementAlgebra.one else elementAlgebra.zero
}.withAttribute(IsUnit)
@ -79,6 +79,6 @@ public fun <T : Any> LinearSpace<T, Ring<T>>.one(
public fun <T : Any> LinearSpace<T, Ring<T>>.zero(
rows: Int,
columns: Int,
): MatrixWrapper<T> = VirtualMatrix(rows, columns) { _, _ ->
): MatrixWrapper<T> = VirtualMatrix(type, rows, columns) { _, _ ->
elementAlgebra.zero
}.withAttribute(IsZero)

View File

@ -6,10 +6,14 @@
package space.kscience.kmath.linear
import space.kscience.attributes.Attributes
import space.kscience.attributes.SafeType
public class TransposedMatrix<T>(public val origin: Matrix<T>) : Matrix<T> {
override val type: SafeType<T> get() = origin.type
override val rowNum: Int get() = origin.colNum
override val colNum: Int get() = origin.rowNum
override fun get(i: Int, j: Int): T = origin[j, i]

View File

@ -6,6 +6,7 @@
package space.kscience.kmath.linear
import space.kscience.attributes.Attributes
import space.kscience.attributes.SafeType
import space.kscience.kmath.nd.ShapeND
@ -14,7 +15,8 @@ import space.kscience.kmath.nd.ShapeND
*
* @property generator the function that provides elements.
*/
public class VirtualMatrix<out T : Any>(
public class VirtualMatrix<out T>(
override val type: SafeType<T>,
override val rowNum: Int,
override val colNum: Int,
override val attributes: Attributes = Attributes.EMPTY,
@ -29,4 +31,4 @@ public class VirtualMatrix<out T : Any>(
public fun <T : Any> MatrixBuilder<T, *>.virtual(
attributes: Attributes = Attributes.EMPTY,
generator: (i: Int, j: Int) -> T,
): VirtualMatrix<T> = VirtualMatrix(rows, columns, attributes, generator)
): VirtualMatrix<T> = VirtualMatrix(type, rows, columns, attributes, generator)

View File

@ -3,13 +3,11 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:OptIn(UnstableKMathAPI::class)
@file:Suppress("UnusedReceiverParameter")
package space.kscience.kmath.linear
import space.kscience.attributes.*
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.StructureAttribute
/**
@ -51,9 +49,11 @@ public val <T> MatrixOperations<T>.Inverted: Inverted<T> get() = Inverted(safeTy
*
* @param T the type of matrices' items.
*/
public class Determinant<T> : MatrixAttribute<T>
public class Determinant<T>(type: SafeType<T>) :
PolymorphicAttribute<T>(type),
MatrixAttribute<T>
public val <T> MatrixOperations<T>.Determinant: Determinant<T> get() = Determinant()
public val <T> MatrixOperations<T>.Determinant: Determinant<T> get() = Determinant(type)
/**
* Matrices with this feature are lower triangular ones.

View File

@ -4,6 +4,8 @@
*/
@file:OptIn(UnstableKMathAPI::class)
package space.kscience.kmath.misc
import space.kscience.kmath.UnstableKMathAPI
@ -22,10 +24,9 @@ public fun <V : Comparable<V>> Buffer<V>.indicesSorted(): IntArray = permSortInd
/**
* Create a zero-copy virtual buffer that contains the same elements but in ascending order
*/
@OptIn(UnstableKMathAPI::class)
public fun <V : Comparable<V>> Buffer<V>.sorted(): Buffer<V> {
val permutations = indicesSorted()
return VirtualBuffer(size) { this[permutations[it]] }
return VirtualBuffer(type, size) { this[permutations[it]] }
}
@UnstableKMathAPI
@ -35,30 +36,27 @@ public fun <V : Comparable<V>> Buffer<V>.indicesSortedDescending(): IntArray =
/**
* Create a zero-copy virtual buffer that contains the same elements but in descending order
*/
@OptIn(UnstableKMathAPI::class)
public fun <V : Comparable<V>> Buffer<V>.sortedDescending(): Buffer<V> {
val permutations = indicesSortedDescending()
return VirtualBuffer(size) { this[permutations[it]] }
return VirtualBuffer(type, size) { this[permutations[it]] }
}
@UnstableKMathAPI
public fun <V, C : Comparable<C>> Buffer<V>.indicesSortedBy(selector: (V) -> C): IntArray =
permSortIndicesWith(compareBy { selector(get(it)) })
@OptIn(UnstableKMathAPI::class)
public fun <V, C : Comparable<C>> Buffer<V>.sortedBy(selector: (V) -> C): Buffer<V> {
val permutations = indicesSortedBy(selector)
return VirtualBuffer(size) { this[permutations[it]] }
return VirtualBuffer(type, size) { this[permutations[it]] }
}
@UnstableKMathAPI
public fun <V, C : Comparable<C>> Buffer<V>.indicesSortedByDescending(selector: (V) -> C): IntArray =
permSortIndicesWith(compareByDescending { selector(get(it)) })
@OptIn(UnstableKMathAPI::class)
public fun <V, C : Comparable<C>> Buffer<V>.sortedByDescending(selector: (V) -> C): Buffer<V> {
val permutations = indicesSortedByDescending(selector)
return VirtualBuffer(size) { this[permutations[it]] }
return VirtualBuffer(type, size) { this[permutations[it]] }
}
@UnstableKMathAPI
@ -68,10 +66,9 @@ public fun <V> Buffer<V>.indicesSortedWith(comparator: Comparator<V>): IntArray
/**
* Create virtual zero-copy buffer with elements sorted by [comparator]
*/
@OptIn(UnstableKMathAPI::class)
public fun <V> Buffer<V>.sortedWith(comparator: Comparator<V>): Buffer<V> {
val permutations = indicesSortedWith(comparator)
return VirtualBuffer(size) { this[permutations[it]] }
return VirtualBuffer(type,size) { this[permutations[it]] }
}
private fun <V> Buffer<V>.permSortIndicesWith(comparator: Comparator<Int>): IntArray {

View File

@ -8,7 +8,7 @@ package space.kscience.kmath.nd
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.*
import kotlin.reflect.KClass
import space.kscience.kmath.structures.MutableBufferFactory
/**
* The base interface for all ND-algebra implementations.
@ -91,6 +91,8 @@ public interface AlgebraND<T, out C : Algebra<T>> : Algebra<StructureND<T>> {
* @param A the type of group over structure elements.
*/
public interface GroupOpsND<T, out A : GroupOps<T>> : GroupOps<StructureND<T>>, AlgebraND<T, A> {
override val bufferFactory: MutableBufferFactory<StructureND<T>> get() = MutableBufferFactory<StructureND<T>>()
/**
* Element-wise addition.
*

View File

@ -7,6 +7,8 @@
package space.kscience.kmath.nd
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.*
@ -105,6 +107,9 @@ public open class BufferedGroupNDOps<T, out A : Group<T>>(
override val bufferAlgebra: BufferAlgebra<T, A>,
override val indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
) : GroupOpsND<T, A>, BufferAlgebraND<T, A> {
override val type: SafeType<StructureND<T>> get() = safeTypeOf<StructureND<T>>()
override fun StructureND<T>.unaryMinus(): StructureND<T> = map { -it }
}

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.nd
import space.kscience.attributes.SafeType
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferFactory
@ -23,6 +24,8 @@ public open class BufferND<out T>(
public open val buffer: Buffer<T>,
) : StructureND<T> {
override val type: SafeType<T> get() = buffer.type
@PerformancePitfall
override operator fun get(index: IntArray): T = buffer[indices.offset(index)]
@ -36,7 +39,7 @@ public open class BufferND<out T>(
*/
public inline fun <reified T> BufferND(
shape: ShapeND,
bufferFactory: BufferFactory<T> = BufferFactory.auto<T>(),
bufferFactory: BufferFactory<T> = BufferFactory<T>(),
crossinline initializer: (IntArray) -> T,
): BufferND<T> {
val strides = Strides(shape)
@ -84,10 +87,10 @@ public open class MutableBufferND<T>(
/**
* Create a generic [BufferND] using provided [initializer]
*/
public fun <T> MutableBufferND(
public inline fun <reified T> MutableBufferND(
shape: ShapeND,
bufferFactory: MutableBufferFactory<T> = MutableBufferFactory.boxing(),
initializer: (IntArray) -> T,
bufferFactory: MutableBufferFactory<T> = MutableBufferFactory(),
crossinline initializer: (IntArray) -> T,
): MutableBufferND<T> {
val strides = Strides(shape)
return MutableBufferND(strides, bufferFactory(strides.linearSize) { initializer(strides.index(it)) })

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.nd
import space.kscience.attributes.SafeType
import space.kscience.kmath.PerformancePitfall
@ -13,6 +14,8 @@ public class PermutedStructureND<T>(
public val permutation: (IntArray) -> IntArray,
) : StructureND<T> {
override val type: SafeType<T> get() = origin.type
override val shape: ShapeND
get() = origin.shape
@ -32,6 +35,7 @@ public class PermutedMutableStructureND<T>(
public val permutation: (IntArray) -> IntArray,
) : MutableStructureND<T> {
override val type: SafeType<T> get() = origin.type
@OptIn(PerformancePitfall::class)
override fun set(index: IntArray, value: T) {

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.nd
import space.kscience.attributes.SafeType
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.operations.asSequence
import space.kscience.kmath.structures.Buffer
@ -46,6 +47,9 @@ public interface MutableStructure1D<T> : Structure1D<T>, MutableStructureND<T>,
*/
@JvmInline
private value class Structure1DWrapper<out T>(val structure: StructureND<T>) : Structure1D<T> {
override val type: SafeType<T> get() = structure.type
override val shape: ShapeND get() = structure.shape
override val size: Int get() = structure.shape[0]
@ -60,6 +64,9 @@ private value class Structure1DWrapper<out T>(val structure: StructureND<T>) : S
* A 1D wrapper for a mutable nd-structure
*/
private class MutableStructure1DWrapper<T>(val structure: MutableStructureND<T>) : MutableStructure1D<T> {
override val type: SafeType<T> get() = structure.type
override val shape: ShapeND get() = structure.shape
override val size: Int get() = structure.shape[0]
@ -79,7 +86,7 @@ private class MutableStructure1DWrapper<T>(val structure: MutableStructureND<T>)
.elements()
.map(Pair<IntArray, T>::second)
.toMutableList()
.asMutableBuffer()
.asMutableBuffer(type)
override fun toString(): String = Buffer.toString(this)
}
@ -90,6 +97,9 @@ private class MutableStructure1DWrapper<T>(val structure: MutableStructureND<T>)
*/
@JvmInline
private value class Buffer1DWrapper<out T>(val buffer: Buffer<T>) : Structure1D<T> {
override val type: SafeType<T> get() = buffer.type
override val shape: ShapeND get() = ShapeND(buffer.size)
override val size: Int get() = buffer.size
@ -102,6 +112,9 @@ private value class Buffer1DWrapper<out T>(val buffer: Buffer<T>) : Structure1D<
}
internal class MutableBuffer1DWrapper<T>(val buffer: MutableBuffer<T>) : MutableStructure1D<T> {
override val type: SafeType<T> get() = buffer.type
override val shape: ShapeND get() = ShapeND(buffer.size)
override val size: Int get() = buffer.size

View File

@ -6,13 +6,12 @@
package space.kscience.kmath.nd
import space.kscience.attributes.Attributes
import space.kscience.attributes.SafeType
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableListBuffer
import space.kscience.kmath.structures.VirtualBuffer
import kotlin.jvm.JvmInline
import kotlin.reflect.KClass
/**
* A structure that is guaranteed to be two-dimensional.
@ -33,18 +32,18 @@ public interface Structure2D<out T> : StructureND<T> {
override val shape: ShapeND get() = ShapeND(rowNum, colNum)
/**
* The buffer of rows of this structure. It gets elements from the structure dynamically.
* The buffer of rows for this structure. It gets elements from the structure dynamically.
*/
@PerformancePitfall
public val rows: List<Buffer<T>>
get() = List(rowNum) { i -> VirtualBuffer(colNum) { j -> get(i, j) } }
get() = List(rowNum) { i -> VirtualBuffer(type, colNum) { j -> get(i, j) } }
/**
* The buffer of columns of this structure. It gets elements from the structure dynamically.
* The buffer of columns for this structure. It gets elements from the structure dynamically.
*/
@PerformancePitfall
public val columns: List<Buffer<T>>
get() = List(colNum) { j -> VirtualBuffer(rowNum) { i -> get(i, j) } }
get() = List(colNum) { j -> VirtualBuffer(type, rowNum) { i -> get(i, j) } }
/**
* Retrieves an element from the structure by two indices.
@ -88,14 +87,14 @@ public interface MutableStructure2D<T> : Structure2D<T>, MutableStructureND<T> {
*/
@PerformancePitfall
override val rows: List<MutableBuffer<T>>
get() = List(rowNum) { i -> MutableListBuffer(colNum) { j -> get(i, j) } }
get() = List(rowNum) { i -> MutableBuffer(type, colNum) { j -> get(i, j) } }
/**
* The buffer of columns of this structure. It gets elements from the structure dynamically.
* The buffer of columns for this structure. It gets elements from the structure dynamically.
*/
@PerformancePitfall
override val columns: List<MutableBuffer<T>>
get() = List(colNum) { j -> MutableListBuffer(rowNum) { i -> get(i, j) } }
get() = List(colNum) { j -> MutableBuffer(type, rowNum) { i -> get(i, j) } }
}
/**
@ -103,6 +102,9 @@ public interface MutableStructure2D<T> : Structure2D<T>, MutableStructureND<T> {
*/
@JvmInline
private value class Structure2DWrapper<out T>(val structure: StructureND<T>) : Structure2D<T> {
override val type: SafeType<T> get() = structure.type
override val shape: ShapeND get() = structure.shape
override val rowNum: Int get() = shape[0]
@ -122,6 +124,9 @@ private value class Structure2DWrapper<out T>(val structure: StructureND<T>) : S
* A 2D wrapper for a mutable nd-structure
*/
private class MutableStructure2DWrapper<T>(val structure: MutableStructureND<T>) : MutableStructure2D<T> {
override val type: SafeType<T> get() = structure.type
override val shape: ShapeND get() = structure.shape
override val rowNum: Int get() = shape[0]

View File

@ -12,6 +12,7 @@ import space.kscience.attributes.SafeType
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.linear.LinearSpace
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.WithType
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer
import kotlin.jvm.JvmName
@ -28,9 +29,9 @@ public interface StructureAttribute<T> : Attribute<T>
*
* @param T the type of items.
*/
public interface StructureND<out T> : AttributeContainer, WithShape {
public interface StructureND<out T> : AttributeContainer, WithShape, WithType<T> {
/**
* The shape of structure i.e., non-empty sequence of non-negative integers that specify sizes of dimensions of
* The shape of structure i.e., non-empty sequence of non-negative integers that specify sizes of dimensions for
* this structure.
*/
override val shape: ShapeND
@ -117,56 +118,60 @@ public interface StructureND<out T> : AttributeContainer, WithShape {
return "$className(shape=${structure.shape}, buffer=$bufferRepr)"
}
/**
}
}
/**
* Creates a NDStructure with explicit buffer factory.
*
* Strides should be reused if possible.
*/
public fun <T> buffered(
public fun <T> BufferND(
type: SafeType<T>,
strides: Strides,
initializer: (IntArray) -> T,
): BufferND<T> = BufferND(strides, Buffer.boxing(strides.linearSize) { i -> initializer(strides.index(i)) })
): BufferND<T> = BufferND(strides, Buffer(type, strides.linearSize) { i -> initializer(strides.index(i)) })
public fun <T> buffered(
public fun <T> BufferND(
type: SafeType<T>,
shape: ShapeND,
initializer: (IntArray) -> T,
): BufferND<T> = buffered(ColumnStrides(shape), initializer)
): BufferND<T> = BufferND(type, ColumnStrides(shape), initializer)
/**
/**
* Inline create NDStructure with non-boxing buffer implementation if it is possible
*/
public inline fun <reified T : Any> auto(
public inline fun <reified T : Any> BufferND(
strides: Strides,
crossinline initializer: (IntArray) -> T,
): BufferND<T> = BufferND(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) })
): BufferND<T> = BufferND(strides, Buffer(strides.linearSize) { i -> initializer(strides.index(i)) })
public inline fun <T : Any> auto(
public inline fun <T : Any> BufferND(
type: SafeType<T>,
strides: Strides,
crossinline initializer: (IntArray) -> T,
): BufferND<T> = BufferND(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) })
): BufferND<T> = BufferND(strides, Buffer(type, strides.linearSize) { i -> initializer(strides.index(i)) })
public inline fun <reified T : Any> auto(
public inline fun <reified T : Any> BufferND(
shape: ShapeND,
crossinline initializer: (IntArray) -> T,
): BufferND<T> = auto(ColumnStrides(shape), initializer)
): BufferND<T> = BufferND(ColumnStrides(shape), initializer)
@JvmName("autoVarArg")
public inline fun <reified T : Any> auto(
@JvmName("autoVarArg")
public inline fun <reified T : Any> BufferND(
vararg shape: Int,
crossinline initializer: (IntArray) -> T,
): BufferND<T> =
auto(ColumnStrides(ShapeND(shape)), initializer)
): BufferND<T> = BufferND(ColumnStrides(ShapeND(shape)), initializer)
public inline fun <T : Any> auto(
public inline fun <T : Any> BufferND(
type: SafeType<T>,
vararg shape: Int,
crossinline initializer: (IntArray) -> T,
): BufferND<T> = auto(type, ColumnStrides(ShapeND(shape)), initializer)
}
}
): BufferND<T> = BufferND(type, ColumnStrides(ShapeND(shape)), initializer)
/**
* Indicates whether some [StructureND] is equal to another one.

View File

@ -5,10 +5,13 @@
package space.kscience.kmath.nd
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.UnstableKMathAPI
public open class VirtualStructureND<T>(
override val type: SafeType<T>,
override val shape: ShapeND,
public val producer: (IntArray) -> T,
) : StructureND<T> {
@ -24,10 +27,10 @@ public open class VirtualStructureND<T>(
public class VirtualDoubleStructureND(
shape: ShapeND,
producer: (IntArray) -> Double,
) : VirtualStructureND<Double>(shape, producer)
) : VirtualStructureND<Double>(safeTypeOf(), shape, producer)
@UnstableKMathAPI
public class VirtualIntStructureND(
shape: ShapeND,
producer: (IntArray) -> Int,
) : VirtualStructureND<Int>(shape, producer)
) : VirtualStructureND<Int>(safeTypeOf(), shape, producer)

View File

@ -10,7 +10,7 @@ import space.kscience.kmath.PerformancePitfall
@OptIn(PerformancePitfall::class)
public fun <T> StructureND<T>.roll(axis: Int, step: Int = 1): StructureND<T> {
require(axis in shape.indices) { "Axis $axis is outside of shape dimensions: [0, ${shape.size})" }
return VirtualStructureND(shape) { index ->
return VirtualStructureND(type, shape) { index ->
val newIndex: IntArray = IntArray(index.size) { indexAxis ->
if (indexAxis == axis) {
(index[indexAxis] + step).mod(shape[indexAxis])
@ -26,7 +26,7 @@ public fun <T> StructureND<T>.roll(axis: Int, step: Int = 1): StructureND<T> {
public fun <T> StructureND<T>.roll(pair: Pair<Int, Int>, vararg others: Pair<Int, Int>): StructureND<T> {
val axisMap: Map<Int, Int> = mapOf(pair, *others)
require(axisMap.keys.all { it in shape.indices }) { "Some of axes ${axisMap.keys} is outside of shape dimensions: [0, ${shape.size})" }
return VirtualStructureND(shape) { index ->
return VirtualStructureND(type, shape) { index ->
val newIndex: IntArray = IntArray(index.size) { indexAxis ->
val offset = axisMap[indexAxis] ?: 0
(index[indexAxis] + offset).mod(shape[indexAxis])

View File

@ -5,22 +5,32 @@
package space.kscience.kmath.operations
import space.kscience.attributes.SafeType
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.operations.Ring.Companion.optimizedPower
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.reflect.KType
/**
* An interface containing [type] for dynamic type checking.
*/
public interface WithType<out T> {
public val type: SafeType<T>
}
/**
* Represents an algebraic structure.
*
* @param T the type of element which Algebra operates on.
*/
public interface Algebra<T> {
public interface Algebra<T> : WithType<T> {
/**
* Provide a factory for buffers, associated with this [Algebra]
*/
public val bufferFactory: MutableBufferFactory<T> get() = MutableBufferFactory.boxing()
public val bufferFactory: MutableBufferFactory<T>
override val type: SafeType<T> get() = bufferFactory.type
/**
* Wraps a raw string to [T] object. This method is designed for three purposes:
@ -265,7 +275,7 @@ public interface Ring<T> : Group<T>, RingOps<T> {
*/
public fun power(arg: T, pow: UInt): T = optimizedPower(arg, pow)
public companion object{
public companion object {
/**
* Raises [arg] to the non-negative integer power [exponent].
*
@ -348,7 +358,7 @@ public interface Field<T> : Ring<T>, FieldOps<T>, ScaleOperations<T>, NumericAlg
public fun power(arg: T, pow: Int): T = optimizedPower(arg, pow)
public companion object{
public companion object {
/**
* Raises [arg] to the integer power [exponent].
*
@ -361,7 +371,11 @@ public interface Field<T> : Ring<T>, FieldOps<T>, ScaleOperations<T>, NumericAlg
* @author Iaroslav Postovalov, Evgeniy Zhelenskiy
*/
private fun <T> Field<T>.optimizedPower(arg: T, exponent: Int): T = when {
exponent < 0 -> one / (this as Ring<T>).optimizedPower(arg, if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt())
exponent < 0 -> one / (this as Ring<T>).optimizedPower(
arg,
if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt()
)
else -> (this as Ring<T>).optimizedPower(arg, exponent.toUInt())
}
}

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.operations
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.BufferedRingOpsND
import space.kscience.kmath.operations.BigInt.Companion.BASE
@ -26,6 +28,9 @@ private typealias TBase = ULong
*/
@OptIn(UnstableKMathAPI::class)
public object BigIntField : Field<BigInt>, NumbersAddOps<BigInt>, ScaleOperations<BigInt> {
override val type: SafeType<BigInt> = safeTypeOf()
override val zero: BigInt = BigInt.ZERO
override val one: BigInt = BigInt.ONE
@ -528,10 +533,10 @@ public fun String.parseBigInteger(): BigInt? {
public val BigInt.algebra: BigIntField get() = BigIntField
public inline fun BigInt.Companion.buffer(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> =
Buffer.boxing(size, initializer)
Buffer(size, initializer)
public inline fun BigInt.Companion.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> =
Buffer.boxing(size, initializer)
Buffer(size, initializer)
public val BigIntField.nd: BufferedRingOpsND<BigInt, BigIntField>
get() = BufferedRingOpsND(BufferRingOps(BigIntField))

View File

@ -5,10 +5,11 @@
package space.kscience.kmath.operations
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.reflect.KType
public interface WithSize {
public val size: Int
@ -20,6 +21,8 @@ public interface WithSize {
public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
public val elementAlgebra: A
override val type: SafeType<Buffer<T>> get() = safeTypeOf<Buffer<T>>()
public val elementBufferFactory: MutableBufferFactory<T> get() = elementAlgebra.bufferFactory
public fun buffer(size: Int, vararg elements: T): Buffer<T> {

View File

@ -5,9 +5,10 @@
package space.kscience.kmath.operations
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.symbol
/**
* An algebra for generic boolean logic
@ -61,8 +62,8 @@ public interface LogicAlgebra<T : Any> : Algebra<T> {
public companion object {
public val TRUE: Symbol by symbol
public val FALSE: Symbol by symbol
public val TRUE: Symbol = Symbol("TRUE")//by symbol
public val FALSE: Symbol = Symbol("FALSE")// by symbol
}
}
@ -73,6 +74,8 @@ public interface LogicAlgebra<T : Any> : Algebra<T> {
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object BooleanAlgebra : LogicAlgebra<Boolean> {
override val type: SafeType<Boolean> get() = safeTypeOf()
override fun const(boolean: Boolean): Boolean = boolean
override fun Boolean.not(): Boolean = !this

View File

@ -8,7 +8,10 @@ package space.kscience.kmath.operations
import space.kscience.kmath.operations.Int16Field.div
import space.kscience.kmath.operations.Int32Field.div
import space.kscience.kmath.operations.Int64Field.div
import space.kscience.kmath.structures.*
import space.kscience.kmath.structures.Int16
import space.kscience.kmath.structures.Int32
import space.kscience.kmath.structures.Int64
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.roundToInt
import kotlin.math.roundToLong
@ -22,7 +25,7 @@ import kotlin.math.roundToLong
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object Int16Field : Field<Int16>, Norm<Int16, Int16>, NumericAlgebra<Int16> {
override val bufferFactory: MutableBufferFactory<Int16> = MutableBufferFactory(::Int16Buffer)
override val bufferFactory: MutableBufferFactory<Int16> = MutableBufferFactory<Int16>()
override val zero: Int16 get() = 0
override val one: Int16 get() = 1
@ -45,7 +48,8 @@ public object Int16Field : Field<Int16>, Norm<Int16, Int16>, NumericAlgebra<Int1
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object Int32Field : Field<Int32>, Norm<Int32, Int32>, NumericAlgebra<Int32> {
override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory(::Int32Buffer)
override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory()
override val zero: Int get() = 0
override val one: Int get() = 1
@ -68,7 +72,7 @@ public object Int32Field : Field<Int32>, Norm<Int32, Int32>, NumericAlgebra<Int3
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object Int64Field : Field<Int64>, Norm<Int64, Int64>, NumericAlgebra<Int64> {
override val bufferFactory: MutableBufferFactory<Int64> = MutableBufferFactory(::Int64Buffer)
override val bufferFactory: MutableBufferFactory<Int64> = MutableBufferFactory()
override val zero: Int64 get() = 0L
override val one: Int64 get() = 1L

View File

@ -67,7 +67,7 @@ public interface ExtendedField<T> : ExtendedFieldOps<T>, Field<T>, NumericAlgebr
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object Float64Field : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> {
override val bufferFactory: MutableBufferFactory<Double> = MutableBufferFactory(::Float64Buffer)
override val bufferFactory: MutableBufferFactory<Double> = MutableBufferFactory()
override val zero: Double get() = 0.0
override val one: Double get() = 1.0

View File

@ -8,8 +8,8 @@ package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.operations.WithSize
import space.kscience.kmath.operations.WithType
import space.kscience.kmath.operations.asSequence
import kotlin.jvm.JvmInline
import kotlin.reflect.typeOf
/**
@ -17,35 +17,46 @@ import kotlin.reflect.typeOf
*
* @param T the type of buffer.
*/
public fun interface BufferFactory<T> {
public interface BufferFactory<T> : WithType<T> {
public operator fun invoke(size: Int, builder: (Int) -> T): Buffer<T>
public companion object{
public inline fun <reified T> auto(): BufferFactory<T> =
BufferFactory(Buffer.Companion::auto)
public fun <T> boxing(): BufferFactory<T> =
BufferFactory(Buffer.Companion::boxing)
}
}
/**
* Create a [BufferFactory] for given [type], using primitive storage if possible
*/
public fun <T> BufferFactory(type: SafeType<T>): BufferFactory<T> = object : BufferFactory<T> {
override val type: SafeType<T> = type
override fun invoke(size: Int, builder: (Int) -> T): Buffer<T> = Buffer(type, size, builder)
}
/**
* Create [BufferFactory] using the reified type
*/
public inline fun <reified T> BufferFactory(): BufferFactory<T> = BufferFactory(safeTypeOf())
/**
* Function that produces [MutableBuffer] from its size and function that supplies values.
*
* @param T the type of buffer.
*/
public fun interface MutableBufferFactory<T> : BufferFactory<T> {
public interface MutableBufferFactory<T> : BufferFactory<T> {
override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T>
public companion object {
public inline fun <reified T : Any> auto(): MutableBufferFactory<T> =
MutableBufferFactory(MutableBuffer.Companion::auto)
public fun <T> boxing(): MutableBufferFactory<T> =
MutableBufferFactory(MutableBuffer.Companion::boxing)
}
}
/**
* Create a [MutableBufferFactory] for given [type], using primitive storage if possible
*/
public fun <T> MutableBufferFactory(type: SafeType<T>): MutableBufferFactory<T> = object : MutableBufferFactory<T> {
override val type: SafeType<T> = type
override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T> = MutableBuffer(type, size, builder)
}
/**
* Create [BufferFactory] using the reified type
*/
public inline fun <reified T> MutableBufferFactory(): MutableBufferFactory<T> = MutableBufferFactory(safeTypeOf())
/**
* A generic read-only random-access structure for both primitives and objects.
*
@ -53,14 +64,14 @@ public fun interface MutableBufferFactory<T> : BufferFactory<T> {
*
* @param T the type of elements contained in the buffer.
*/
public interface Buffer<out T> : WithSize {
public interface Buffer<out T> : WithSize, WithType<T> {
/**
* The size of this buffer.
*/
override val size: Int
/**
* Gets element at given index.
* Gets an element at given index.
*/
public operator fun get(index: Int): T
@ -87,41 +98,48 @@ public interface Buffer<out T> : WithSize {
return true
}
/**
* Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the
* specified [initializer] function.
*/
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> =
List(size, initializer).asBuffer()
/**
* Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([Int32Buffer],
* [Float64Buffer], etc.), [ListBuffer] is returned otherwise.
*
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/
@Suppress("UNCHECKED_CAST")
public inline fun <T> auto(type: SafeType<T>, size: Int, initializer: (Int) -> T): Buffer<T> =
when (type.kType) {
typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer<T>
typeOf<Short>() -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
typeOf<Int>() -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
typeOf<Long>() -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
else -> boxing(size, initializer)
}
}
/**
/**
* Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([Int32Buffer],
* [Float64Buffer], etc.), [ListBuffer] is returned otherwise.
*
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/
public inline fun <reified T> auto(size: Int, initializer: (Int) -> T): Buffer<T> =
auto(safeTypeOf<T>(), size, initializer)
@Suppress("UNCHECKED_CAST")
public inline fun <reified T> Buffer(size: Int, initializer: (Int) -> T): Buffer<T> {
val type = safeTypeOf<T>()
return when (type.kType) {
typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer<T>
typeOf<Short>() -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
typeOf<Int>() -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
typeOf<Long>() -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
else -> List(size, initializer).asBuffer(type)
}
}
/**
* Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([Int32Buffer],
* [Float64Buffer], etc.), [ListBuffer] is returned otherwise.
*
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/
@Suppress("UNCHECKED_CAST")
public fun <T> Buffer(
type: SafeType<T>,
size: Int,
initializer: (Int) -> T,
): Buffer<T> = when (type.kType) {
typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer<T>
typeOf<Short>() -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
typeOf<Int>() -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
typeOf<Long>() -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
else -> List(size, initializer).asBuffer(type)
}
/**
* Returns an [IntRange] of the valid indices for this [Buffer].
*/
@ -144,28 +162,17 @@ public fun <T> Buffer<T>.last(): T {
return get(size - 1)
}
/**
* Immutable wrapper for [MutableBuffer].
*
* @param T the type of elements contained in the buffer.
* @property buffer The underlying buffer.
*/
@JvmInline
public value class ReadOnlyBuffer<T>(public val buffer: MutableBuffer<T>) : Buffer<T> {
override val size: Int get() = buffer.size
override operator fun get(index: Int): T = buffer[index]
override operator fun iterator(): Iterator<T> = buffer.iterator()
}
/**
* A buffer with content calculated on-demand. The calculated content is not stored, so it is recalculated on each call.
* Useful when one needs single element from the buffer.
* Useful when one needs a single element from the buffer.
*
* @param T the type of elements provided by the buffer.
*/
public class VirtualBuffer<out T>(override val size: Int, private val generator: (Int) -> T) : Buffer<T> {
public class VirtualBuffer<out T>(
override val type: SafeType<T>,
override val size: Int,
private val generator: (Int) -> T,
) : Buffer<T> {
override operator fun get(index: Int): T {
if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index")
return generator(index)
@ -177,6 +184,9 @@ public class VirtualBuffer<out T>(override val size: Int, private val generator:
}
/**
* Convert this buffer to read-only buffer.
* Inline builder for [VirtualBuffer]
*/
public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this
public inline fun <reified T> VirtualBuffer(
size: Int,
noinline generator: (Int) -> T,
): VirtualBuffer<T> = VirtualBuffer(safeTypeOf(), size, generator)

View File

@ -5,7 +5,13 @@
package space.kscience.kmath.structures
import space.kscience.kmath.nd.*
import space.kscience.attributes.SafeType
import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.Structure2D
import space.kscience.kmath.nd.as2D
import kotlin.collections.component1
import kotlin.collections.component2
/**
* A context that allows to operate on a [MutableBuffer] as on 2d array
@ -27,11 +33,13 @@ internal class BufferAccessor2D<T>(
fun create(mat: Structure2D<T>): MutableBuffer<T> = create { i, j -> mat[i, j] }
//TODO optimize wrapper
fun MutableBuffer<T>.toStructure2D(): Structure2D<T> = StructureND.buffered(
ColumnStrides(ShapeND(rowNum, colNum))
fun MutableBuffer<T>.toStructure2D(): Structure2D<T> = BufferND(
type, ShapeND(rowNum, colNum)
) { (i, j) -> get(i, j) }.as2D()
inner class Row(val buffer: MutableBuffer<T>, val rowIndex: Int) : MutableBuffer<T> {
override val type: SafeType<T> get() = buffer.type
override val size: Int get() = colNum
override operator fun get(index: Int): T = buffer[rowIndex, index]

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import kotlin.experimental.and
/**
@ -57,6 +59,9 @@ public class FlaggedDoubleBuffer(
public val values: DoubleArray,
public val flags: ByteArray
) : FlaggedBuffer<Double?>, Buffer<Double?> {
override val type: SafeType<Double?> = safeTypeOf()
init {
require(values.size == flags.size) { "Values and flags must have the same dimensions" }
}

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import kotlin.jvm.JvmInline
/**
@ -15,6 +17,9 @@ import kotlin.jvm.JvmInline
*/
@JvmInline
public value class Float32Buffer(public val array: FloatArray) : PrimitiveBuffer<Float> {
override val type: SafeType<Float32> get() = safeTypeOf<Float32>()
override val size: Int get() = array.size
override operator fun get(index: Int): Float = array[index]

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.operations.BufferTransform
import kotlin.jvm.JvmInline
@ -15,6 +17,9 @@ import kotlin.jvm.JvmInline
*/
@JvmInline
public value class Float64Buffer(public val array: DoubleArray) : PrimitiveBuffer<Double> {
override val type: SafeType<Double> get() = safeTypeOf()
override val size: Int get() = array.size
override operator fun get(index: Int): Double = array[index]

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import kotlin.jvm.JvmInline
/**
@ -14,6 +16,8 @@ import kotlin.jvm.JvmInline
*/
@JvmInline
public value class Int16Buffer(public val array: ShortArray) : MutableBuffer<Short> {
override val type: SafeType<Short> get() = safeTypeOf()
override val size: Int get() = array.size
override operator fun get(index: Int): Short = array[index]

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import kotlin.jvm.JvmInline
/**
@ -14,6 +16,9 @@ import kotlin.jvm.JvmInline
*/
@JvmInline
public value class Int32Buffer(public val array: IntArray) : PrimitiveBuffer<Int> {
override val type: SafeType<Int> get() = safeTypeOf()
override val size: Int get() = array.size
override operator fun get(index: Int): Int = array[index]

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import kotlin.jvm.JvmInline
/**
@ -14,6 +16,9 @@ import kotlin.jvm.JvmInline
*/
@JvmInline
public value class Int64Buffer(public val array: LongArray) : PrimitiveBuffer<Long> {
override val type: SafeType<Long> get() = safeTypeOf()
override val size: Int get() = array.size
override operator fun get(index: Int): Long = array[index]

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import kotlin.jvm.JvmInline
/**
@ -14,6 +16,9 @@ import kotlin.jvm.JvmInline
*/
@JvmInline
public value class Int8Buffer(public val array: ByteArray) : MutableBuffer<Byte> {
override val type: SafeType<Byte> get() = safeTypeOf()
override val size: Int get() = array.size
override operator fun get(index: Int): Byte = array[index]

View File

@ -5,7 +5,8 @@
package space.kscience.kmath.structures
import kotlin.jvm.JvmInline
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
/**
* [Buffer] implementation over [List].
@ -13,9 +14,7 @@ import kotlin.jvm.JvmInline
* @param T the type of elements contained in the buffer.
* @property list The underlying list.
*/
public class ListBuffer<T>(public val list: List<T>) : Buffer<T> {
public constructor(size: Int, initializer: (Int) -> T) : this(List(size, initializer))
public class ListBuffer<T>(override val type: SafeType<T>, public val list: List<T>) : Buffer<T> {
override val size: Int get() = list.size
@ -29,7 +28,12 @@ public class ListBuffer<T>(public val list: List<T>) : Buffer<T> {
/**
* Returns an [ListBuffer] that wraps the original list.
*/
public fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this)
public fun <T> List<T>.asBuffer(type: SafeType<T>): ListBuffer<T> = ListBuffer(type, this)
/**
* Returns an [ListBuffer] that wraps the original list.
*/
public inline fun <reified T> List<T>.asBuffer(): ListBuffer<T> = asBuffer(safeTypeOf())
/**
* [MutableBuffer] implementation over [MutableList].
@ -37,10 +41,7 @@ public fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this)
* @param T the type of elements contained in the buffer.
* @property list The underlying list.
*/
@JvmInline
public value class MutableListBuffer<T>(public val list: MutableList<T>) : MutableBuffer<T> {
public constructor(size: Int, initializer: (Int) -> T) : this(MutableList(size, initializer))
public class MutableListBuffer<T>(override val type: SafeType<T>, public val list: MutableList<T>) : MutableBuffer<T> {
override val size: Int get() = list.size
@ -51,10 +52,24 @@ public value class MutableListBuffer<T>(public val list: MutableList<T>) : Mutab
}
override operator fun iterator(): Iterator<T> = list.iterator()
override fun copy(): MutableBuffer<T> = MutableListBuffer(ArrayList(list))
override fun copy(): MutableBuffer<T> = MutableListBuffer(type, ArrayList(list))
override fun toString(): String = Buffer.toString(this)
}
/**
* Returns an [MutableListBuffer] that wraps the original list.
*/
public fun <T> MutableList<T>.asMutableBuffer(): MutableListBuffer<T> = MutableListBuffer(this)
public fun <T> MutableList<T>.asMutableBuffer(type: SafeType<T>): MutableListBuffer<T> = MutableListBuffer(
type,
this
)
/**
* Returns an [MutableListBuffer] that wraps the original list.
*/
public inline fun <reified T> MutableList<T>.asMutableBuffer(): MutableListBuffer<T> = MutableListBuffer(
safeTypeOf(),
this
)

View File

@ -61,41 +61,35 @@ public interface MutableBuffer<T> : Buffer<T> {
*/
public inline fun float(size: Int, initializer: (Int) -> Float): Float32Buffer =
Float32Buffer(size, initializer)
}
}
/**
* Create a boxing mutable buffer of given type
*/
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
MutableListBuffer(MutableList(size, initializer))
/**
/**
* Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used
* ([Int32Buffer], [Float64Buffer], etc.), [ListBuffer] is returned otherwise.
*
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/
@Suppress("UNCHECKED_CAST")
public inline fun <T> auto(type: SafeType<T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
@Suppress("UNCHECKED_CAST")
public inline fun <T> MutableBuffer(type: SafeType<T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
when (type.kType) {
typeOf<Double>() -> double(size) { initializer(it) as Double } as MutableBuffer<T>
typeOf<Short>() -> short(size) { initializer(it) as Short } as MutableBuffer<T>
typeOf<Int>() -> int(size) { initializer(it) as Int } as MutableBuffer<T>
typeOf<Float>() -> float(size) { initializer(it) as Float } as MutableBuffer<T>
typeOf<Long>() -> long(size) { initializer(it) as Long } as MutableBuffer<T>
else -> boxing(size, initializer)
typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as MutableBuffer<T>
typeOf<Short>() -> MutableBuffer.short(size) { initializer(it) as Short } as MutableBuffer<T>
typeOf<Int>() -> MutableBuffer.int(size) { initializer(it) as Int } as MutableBuffer<T>
typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as MutableBuffer<T>
typeOf<Long>() -> MutableBuffer.long(size) { initializer(it) as Long } as MutableBuffer<T>
else -> MutableListBuffer(type, MutableList(size, initializer))
}
/**
/**
* Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
* ([Int32Buffer], [Float64Buffer], etc.), [ListBuffer] is returned otherwise.
*
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/
public inline fun <reified T> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
auto(safeTypeOf<T>(), size, initializer)
}
}
public inline fun <reified T> MutableBuffer(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
MutableBuffer(safeTypeOf<T>(), size, initializer)
public sealed interface PrimitiveBuffer<T> : MutableBuffer<T>

View File

@ -40,7 +40,7 @@ class DoubleLUSolverTest {
//Check determinant
assertEquals(7.0, lup.determinant)
assertMatrixEquals(lup.p dot matrix, lup.l dot lup.u)
assertMatrixEquals(lup.pivotMatrix dot matrix, lup.l dot lup.u)
}
@Test

View File

@ -65,9 +65,7 @@ public class RingBuffer<T>(
}
}
@Suppress("NOTHING_TO_INLINE")
private inline fun Int.forward(n: Int): Int = (this + n) % (buffer.size)
private fun Int.forward(n: Int): Int = (this + n) % (buffer.size)
override fun toString(): String = Buffer.toString(this)

View File

@ -4,7 +4,7 @@
*/
package space.kscience.kmath.integration
import space.kscience.attributes.AttributesBuilder
import space.kscience.attributes.TypedAttributesBuilder
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.Field
import space.kscience.kmath.structures.Buffer
@ -54,10 +54,10 @@ public class GaussIntegrator<T : Any>(
}
}
override fun process(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> = with(algebra) {
override fun integrate(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> = with(algebra) {
val f = integrand.function
val (points, weights) = buildRule(integrand)
var res = zero
var res: T = zero
var c = zero
for (i in points.indices) {
val x = points[i]
@ -67,8 +67,8 @@ public class GaussIntegrator<T : Any>(
c = t - res - y
res = t
}
return integrand.modify {
value(res)
return integrand.withAttributes {
IntegrandValue(res)
IntegrandCallsPerformed(integrand.calls + points.size)
}
}
@ -88,12 +88,12 @@ public val <T : Any> Field<T>.gaussIntegrator: GaussIntegrator<T> get() = GaussI
* Integrate using [intervals] segments with Gauss-Legendre rule of [order] order.
*/
@UnstableKMathAPI
public fun <T : Any> GaussIntegrator<T>.integrate(
public inline fun <reified T : Any> GaussIntegrator<T>.integrate(
range: ClosedRange<Double>,
order: Int = 10,
intervals: Int = 10,
attributesBuilder: AttributesBuilder.() -> Unit,
function: (Double) -> T,
attributesBuilder: TypedAttributesBuilder<UnivariateIntegrand<T>>.() -> Unit,
noinline function: (Double) -> T,
): UnivariateIntegrand<T> {
require(range.endInclusive > range.start) { "The range upper bound should be higher than lower bound" }
require(order > 1) { "The order of polynomial must be more than 1" }
@ -102,8 +102,8 @@ public fun <T : Any> GaussIntegrator<T>.integrate(
val ranges = UnivariateIntegrandRanges(
(0 until intervals).map { i -> (range.start + rangeSize * i)..(range.start + rangeSize * (i + 1)) to order }
)
return process(
UnivariateIntegrand(
return integrate(
UnivariateIntegrand<T>(
attributeBuilder = {
IntegrationRange(range)
GaussIntegratorRuleFactory(GaussLegendreRuleFactory)

View File

@ -5,10 +5,7 @@
package space.kscience.kmath.integration
import space.kscience.attributes.Attribute
import space.kscience.attributes.AttributeContainer
import space.kscience.attributes.AttributesBuilder
import space.kscience.attributes.SafeType
import space.kscience.attributes.*
public interface IntegrandAttribute<T> : Attribute<T>
@ -16,9 +13,10 @@ public interface Integrand<T> : AttributeContainer {
public val type: SafeType<T>
public fun modify(block: AttributesBuilder.() -> Unit): Integrand<T>
public fun <A : Any> withAttribute(attribute: Attribute<A>, value: A): Integrand<T>
/**
* Create a copy of this integrand with a new set of attributes
*/
public fun withAttributes(attributes: Attributes): Integrand<T>
public companion object
}
@ -32,7 +30,7 @@ public sealed class IntegrandValue<T> private constructor(): IntegrandAttribute<
}
}
public fun <T> AttributesBuilder.value(value: T) {
public fun <T> TypedAttributesBuilder<Integrand<T>>.value(value: T) {
IntegrandValue.forType<T>().invoke(value)
}

View File

@ -8,9 +8,9 @@ package space.kscience.kmath.integration
/**
* A general interface for all integrators.
*/
public interface Integrator<I : Integrand> {
public interface Integrator<T, I : Integrand<T>> {
/**
* Runs one integration pass and return a new [Integrand] with a new set of features.
*/
public fun process(integrand: I): I
public fun integrate(integrand: I): I
}

View File

@ -14,14 +14,21 @@ public class MultivariateIntegrand<T>(
public val function: (Point<T>) -> T,
) : Integrand<T> {
override fun modify(block: AttributesBuilder.() -> Unit): MultivariateIntegrand<T> =
MultivariateIntegrand(type, attributes.modify(block), function)
override fun withAttributes(attributes: Attributes): MultivariateIntegrand<T> =
MultivariateIntegrand(type, attributes, function)
override fun <A : Any> withAttribute(attribute: Attribute<A>, value: A): MultivariateIntegrand<T> =
MultivariateIntegrand(type, attributes.withAttribute(attribute, value), function)
}
public fun <T, A : Any> MultivariateIntegrand<T>.withAttribute(
attribute: Attribute<A>,
value: A,
): MultivariateIntegrand<T> = withAttributes(attributes.withAttribute(attribute, value))
public fun <T> MultivariateIntegrand<T>.withAttributes(
block: TypedAttributesBuilder<MultivariateIntegrand<T>>.() -> Unit,
): MultivariateIntegrand<T> = withAttributes(attributes.modify(block))
public inline fun <reified T : Any> MultivariateIntegrand(
attributeBuilder: AttributesBuilder.() -> Unit,
attributeBuilder: TypedAttributesBuilder<MultivariateIntegrand<T>>.() -> Unit,
noinline function: (Point<T>) -> T,
): MultivariateIntegrand<T> = MultivariateIntegrand(safeTypeOf<T>(), Attributes(attributeBuilder), function)

View File

@ -44,12 +44,12 @@ public class SimpsonIntegrator<T : Any>(
return res
}
override fun process(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> {
override fun integrate(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> {
val ranges = integrand[UnivariateIntegrandRanges]
return if (ranges != null) {
val res = algebra.sum(ranges.ranges.map { integrateRange(integrand, it.first, it.second) })
integrand.modify {
value(res)
integrand.withAttributes {
IntegrandValue(res)
IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second })
}
} else {
@ -57,8 +57,8 @@ public class SimpsonIntegrator<T : Any>(
require(numPoints >= 4) { "Simpson integrator requires at least 4 nodes" }
val range = integrand[IntegrationRange] ?: 0.0..1.0
val res = integrateRange(integrand, range, numPoints)
integrand.modify {
value(res)
integrand.withAttributes {
IntegrandValue(res)
IntegrandCallsPerformed(integrand.calls + numPoints)
}
}
@ -96,12 +96,12 @@ public object DoubleSimpsonIntegrator : UnivariateIntegrator<Double> {
return res
}
override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
val ranges = integrand[UnivariateIntegrandRanges]
return if (ranges != null) {
val res = ranges.ranges.sumOf { integrateRange(integrand, it.first, it.second) }
integrand.modify {
value(res)
integrand.withAttributes {
IntegrandValue(res)
IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second })
}
} else {
@ -109,8 +109,8 @@ public object DoubleSimpsonIntegrator : UnivariateIntegrator<Double> {
require(numPoints >= 4) { "Simpson integrator requires at least 4 nodes" }
val range = integrand[IntegrationRange] ?: 0.0..1.0
val res = integrateRange(integrand, range, numPoints)
integrand.modify {
value(res)
integrand.withAttributes {
IntegrandValue(res)
IntegrandCallsPerformed(integrand.calls + numPoints)
}
}

View File

@ -54,7 +54,7 @@ public class SplineIntegrator<T : Comparable<T>>(
public val algebra: Field<T>,
public val bufferFactory: MutableBufferFactory<T>,
) : UnivariateIntegrator<T> {
override fun process(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> = algebra {
override fun integrate(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> = algebra {
val range = integrand[IntegrationRange] ?: 0.0..1.0
val interpolator: PolynomialInterpolator<T> = SplineInterpolator(algebra, bufferFactory)
@ -71,8 +71,8 @@ public class SplineIntegrator<T : Comparable<T>>(
values
)
val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive))
integrand.modify {
value(res)
integrand.withAttributes {
IntegrandValue(res)
IntegrandCallsPerformed(integrand.calls + nodes.size)
}
}
@ -86,7 +86,7 @@ public class SplineIntegrator<T : Comparable<T>>(
*/
@UnstableKMathAPI
public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
val range = integrand[IntegrationRange] ?: 0.0..1.0
val interpolator: PolynomialInterpolator<Double> = SplineInterpolator(Float64Field, ::Float64Buffer)
@ -99,8 +99,8 @@ public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
val values = nodes.mapToBuffer(::Float64Buffer) { integrand.function(it) }
val polynomials = interpolator.interpolatePolynomials(nodes, values)
val res = polynomials.integrate(Float64Field, range)
return integrand.modify {
value(res)
return integrand.withAttributes {
IntegrandValue(res)
IntegrandCallsPerformed(integrand.calls + nodes.size)
}
}

View File

@ -16,19 +16,25 @@ public class UnivariateIntegrand<T>(
public val function: (Double) -> T,
) : Integrand<T> {
override fun <A : Any> withAttribute(attribute: Attribute<A>, value: A): UnivariateIntegrand<T> =
UnivariateIntegrand(type, attributes.withAttribute(attribute, value), function)
override fun modify(block: AttributesBuilder.() -> Unit): UnivariateIntegrand<T> =
UnivariateIntegrand(type, attributes.modify(block), function)
override fun withAttributes(attributes: Attributes): UnivariateIntegrand<T> =
UnivariateIntegrand(type, attributes, function)
}
public fun <T, A : Any> UnivariateIntegrand<T>.withAttribute(
attribute: Attribute<A>,
value: A,
): UnivariateIntegrand<T> = withAttributes(attributes.withAttribute(attribute, value))
public fun <T> UnivariateIntegrand<T>.withAttributes(
block: TypedAttributesBuilder<UnivariateIntegrand<T>>.() -> Unit,
): UnivariateIntegrand<T> = withAttributes(attributes.modify(block))
public inline fun <reified T : Any> UnivariateIntegrand(
attributeBuilder: AttributesBuilder.() -> Unit,
attributeBuilder: TypedAttributesBuilder<UnivariateIntegrand<T>>.() -> Unit,
noinline function: (Double) -> T,
): UnivariateIntegrand<T> = UnivariateIntegrand(safeTypeOf(), Attributes(attributeBuilder), function)
public typealias UnivariateIntegrator<T> = Integrator<UnivariateIntegrand<T>>
public typealias UnivariateIntegrator<T> = Integrator<T, UnivariateIntegrand<T>>
public object IntegrationRange : IntegrandAttribute<ClosedRange<Double>>
@ -52,7 +58,7 @@ public class UnivariateIntegrandRanges(public val ranges: List<Pair<ClosedRange<
public object UnivariateIntegrationNodes : IntegrandAttribute<Buffer<Double>>
public fun AttributesBuilder.integrationNodes(vararg nodes: Double) {
public fun TypedAttributesBuilder<UnivariateIntegrand<*>>.integrationNodes(vararg nodes: Double) {
UnivariateIntegrationNodes(Float64Buffer(nodes))
}
@ -62,9 +68,9 @@ public fun AttributesBuilder.integrationNodes(vararg nodes: Double) {
*/
@UnstableKMathAPI
public inline fun <reified T : Any> UnivariateIntegrator<T>.integrate(
attributesBuilder: AttributesBuilder.() -> Unit,
attributesBuilder: TypedAttributesBuilder<UnivariateIntegrand<T>>.() -> Unit,
noinline function: (Double) -> T,
): UnivariateIntegrand<T> = process(UnivariateIntegrand(attributesBuilder, function))
): UnivariateIntegrand<T> = integrate(UnivariateIntegrand(attributesBuilder, function))
/**
* A shortcut method to integrate a [function] in [range] with additional features.
@ -73,11 +79,11 @@ public inline fun <reified T : Any> UnivariateIntegrator<T>.integrate(
@UnstableKMathAPI
public inline fun <reified T : Any> UnivariateIntegrator<T>.integrate(
range: ClosedRange<Double>,
attributeBuilder: AttributesBuilder.() -> Unit = {},
attributeBuilder: TypedAttributesBuilder<UnivariateIntegrand<T>>.() -> Unit = {},
noinline function: (Double) -> T,
): UnivariateIntegrand<T> {
return process(
return integrate(
UnivariateIntegrand(
attributeBuilder = {
IntegrationRange(range)

View File

@ -6,16 +6,26 @@
package space.kscience.kmath.geometry.euclidean2d
import kotlinx.serialization.Serializable
import space.kscience.kmath.geometry.Vector2D
import kotlin.math.PI
public interface Circle2D<T>{
public val center: Vector2D<T>
public val radius: Double
}
public val Circle2D<*>.circumference: Double get() = radius * 2 * PI
/**
* A circle in 2D space
*/
@Serializable
public data class Circle2D(
@Serializable(Float64Space2D.VectorSerializer::class) public val center: DoubleVector2D,
public val radius: Double,
)
public data class Float64Circle2D(
@Serializable(Float64Space2D.VectorSerializer::class) override val center: Float64Vector2D,
override val radius: Double
): Circle2D<Double>
public fun Circle2D(center: Float64Vector2D, radius: Double): Circle2D<Double> = Float64Circle2D(center, radius)
public val Circle2D.circumference: Double get() = radius * 2 * PI

View File

@ -15,6 +15,7 @@ import space.kscience.kmath.geometry.GeometrySpace
import space.kscience.kmath.geometry.Vector2D
import space.kscience.kmath.linear.Float64LinearSpace
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.ScaleOperations
import kotlin.math.pow
import kotlin.math.sqrt
@ -28,9 +29,7 @@ public val Vector2D<Double>.r: Double get() = Float64Space2D.norm(this)
/**
* 2D Euclidean space
*/
public object Float64Space2D : GeometrySpace<DoubleVector2D, Double> {
public val linearSpace: Float64LinearSpace = Float64LinearSpace
public object Float64Space2D : GeometrySpace<DoubleVector2D>, ScaleOperations<DoubleVector2D> {
@Serializable
@SerialName("Float64Vector2D")
@ -72,4 +71,6 @@ public object Float64Space2D : GeometrySpace<DoubleVector2D, Double> {
override val defaultPrecision: Double = 1e-6
}
public fun Float64Vector2D(x: Number, y: Number): Float64Vector2D = Float64Space2D.vector(x, y)
public val Float64Field.euclidean2D: Float64Space2D get() = Float64Space2D

View File

@ -0,0 +1,33 @@
/*
* Copyright 2018-2023 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.geometry
import space.kscience.kmath.complex.Quaternion
import space.kscience.kmath.complex.QuaternionAlgebra
import space.kscience.kmath.complex.conjugate
import space.kscience.kmath.geometry.euclidean3d.theta
public operator fun Quaternion.times(other: Quaternion): Quaternion = QuaternionAlgebra.multiply(this, other)
public operator fun Quaternion.div(other: Quaternion): Quaternion = QuaternionAlgebra.divide(this, other)
public fun Quaternion.power(number: Number): Quaternion = QuaternionAlgebra.power(this, number)
/**
* Linear interpolation between [from] and [to] in spherical space
*/
public fun QuaternionAlgebra.slerp(from: Quaternion, to: Quaternion, fraction: Double): Quaternion =
(to / from).pow(fraction) * from
/**
* Scalar angle between two quaternions
*/
public fun QuaternionAlgebra.angleBetween(q1: Quaternion, q2: Quaternion): Angle = (q1.conjugate * q2).theta
/**
* Euclidean product of two quaternions
*/
public infix fun Quaternion.dot(other: Quaternion): Double = w * other.w + x * other.x + y * other.y + z * other.z

View File

@ -147,12 +147,12 @@ public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
bufferFactory: BufferFactory<V> = valueAlgebraND.elementAlgebra.bufferFactory,
): UniformHistogramGroupND<V, A> = UniformHistogramGroupND(
valueAlgebraND,
ListBuffer(
DoubleBuffer(
ranges
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
.map(ClosedFloatingPointRange<Double>::start)
),
ListBuffer(
DoubleBuffer(
ranges
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
.map(ClosedFloatingPointRange<Double>::endInclusive)

View File

@ -15,3 +15,6 @@ readme {
An API and basic implementation for arranging objects in a continuous memory block.
""".trimIndent()
}
//rootProject.the<NodeJsRootExtension>().versions.webpack.version = "5.76.2"
//rootProject.the<NodeJsRootExtension>().nodeVersion = "20.8.0"

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.memory
import kotlin.experimental.ExperimentalNativeApi
@PublishedApi
internal class NativeMemory(
val array: ByteArray,
@ -26,6 +28,7 @@ internal class NativeMemory(
return NativeMemory(copy)
}
@OptIn(ExperimentalNativeApi::class)
private val reader: MemoryReader = object : MemoryReader {
override val memory: Memory get() = this@NativeMemory
@ -48,6 +51,7 @@ internal class NativeMemory(
override fun reader(): MemoryReader = reader
@OptIn(ExperimentalNativeApi::class)
private val writer: MemoryWriter = object : MemoryWriter {
override val memory: Memory get() = this@NativeMemory

View File

@ -6,7 +6,7 @@ kscience{
jvm()
js {
browser {
testTask {
testTask{
useMocha().timeout = "0"
}
}

View File

@ -310,7 +310,11 @@ internal fun DoubleTensorAlgebra.svdHelper(
}
}
private fun pythag(a: Double, b: Double): Double {
internal fun MutableStructure2D<Double>.svdGolubKahanHelper(
u: MutableStructure2D<Double>, w: BufferedTensor<Double>,
v: MutableStructure2D<Double>, iterations: Int, epsilon: Double,
) {
fun pythag(a: Double, b: Double): Double {
val at: Double = abs(a)
val bt: Double = abs(b)
val ct: Double
@ -323,19 +327,9 @@ private fun pythag(a: Double, b: Double): Double {
result = bt * sqrt(1.0 + ct * ct)
} else result = 0.0
return result
}
}
private fun SIGN(a: Double, b: Double): Double {
if (b >= 0.0)
return abs(a)
else
return -abs(a)
}
internal fun MutableStructure2D<Double>.svdGolubKahanHelper(
u: MutableStructure2D<Double>, w: BufferedTensor<Double>,
v: MutableStructure2D<Double>, iterations: Int, epsilon: Double,
) {
val shape = this.shape
val m = shape.component1()
val n = shape.component2()
@ -553,7 +547,7 @@ internal fun MutableStructure2D<Double>.svdGolubKahanHelper(
h = rv1[k]
f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y)
g = pythag(f, 1.0)
f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x
f = ((x - z) * (x + z) + h * ((y / (f + if (f >= 0.0) abs(g) else -abs(g) )) - h)) / x
c = 1.0
s = 1.0
@ -563,7 +557,7 @@ internal fun MutableStructure2D<Double>.svdGolubKahanHelper(
g = rv1[i]
y = wBuffer[wStart + i]
h = s * g
g = c * g
g *= c
z = pythag(f, h)
rv1[j] = z
c = f / z