From ca02f5406d06d18d07909f3d48508e1a99701fa5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 8 May 2021 18:07:53 +0300 Subject: [PATCH 01/39] Update gradle.properties Increase metaspace for dokka --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7e9516660..3aaade368 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,5 +9,5 @@ kotlin.mpp.stability.nowarn=true kotlin.native.enableDependencyPropagation=false kotlin.parallel.tasks.in.project=true org.gradle.configureondemand=true -org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G +org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G org.gradle.parallel=true From b94172fd2208c6b27447dc8265116a3f1b31ee82 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 14 May 2021 21:15:24 +0700 Subject: [PATCH 02/39] Link to Kotlingrad documentation --- build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle.kts b/build.gradle.kts index 406a46810..1b9eb2801 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,6 +32,7 @@ subprojects { externalDocumentationLink("https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/") externalDocumentationLink("https://deeplearning4j.org/api/latest/") externalDocumentationLink("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/") + externalDocumentationLink("https://breandan.net/kotlingrad/kotlingrad/kotlingrad/") } } } From b33c68e315c086d91446bec4f7554cd32d6b82ca Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 14 May 2021 21:47:21 +0700 Subject: [PATCH 03/39] Link to Kotlingrad documentation --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1b9eb2801..63fddae3d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,12 +27,12 @@ subprojects { dokkaSourceSets.all { val readmeFile = File(this@subprojects.projectDir, "README.md") - if (readmeFile.exists()) includes.setFrom(includes + readmeFile.absolutePath) + if (readmeFile.exists()) includes.from(readmeFile.absolutePath) externalDocumentationLink("http://ejml.org/javadoc/") externalDocumentationLink("https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/") externalDocumentationLink("https://deeplearning4j.org/api/latest/") externalDocumentationLink("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/") - externalDocumentationLink("https://breandan.net/kotlingrad/kotlingrad/kotlingrad/") + externalDocumentationLink("https://breandan.net/kotlingrad/kotlingrad/", "https://breandan.net/kotlingrad/kotlingrad/kotlingrad/package-list") } } } From a722cf0cdb7810c5cf1bde7c076fcef28f0d7452 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 21 May 2021 15:47:35 +0700 Subject: [PATCH 04/39] Integration between MST and Symja IExpr --- CHANGELOG.md | 9 +- examples/build.gradle.kts | 2 +- .../kscience/kmath/ast/kotlingradSupport.kt | 20 ++-- .../space/kscience/kmath/ast/symjaSupport.kt | 27 ++++++ .../kmath/kotlingrad/KotlingradExpression.kt | 4 +- kmath-symja/build.gradle.kts | 21 ++++ .../kscience/kmath/symja/SymjaExpression.kt | 34 +++++++ .../space/kscience/kmath/symja/adapters.kt | 95 +++++++++++++++++++ settings.gradle.kts | 1 + 9 files changed, 195 insertions(+), 18 deletions(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt create mode 100644 kmath-symja/build.gradle.kts create mode 100644 kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt create mode 100644 kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c6b14b95..2ff5dd623 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,18 +2,19 @@ ## [Unreleased] ### Added -- ScaleOperations interface -- Field extends ScaleOperations +- `ScaleOperations` interface +- `Field` extends `ScaleOperations` - Basic integration API - Basic MPP distributions and samplers -- bindSymbolOrNull +- `bindSymbolOrNull` - Blocking chains and Statistics - Multiplatform integration - Integration for any Field element - Extended operations for ND4J fields - Jupyter Notebook integration module (kmath-jupyter) - `@PerformancePitfall` annotation to mark possibly slow API -- BigInt operation performance improvement and fixes by @zhelenskiy (#328) +- `BigInt` operation performance improvement and fixes by @zhelenskiy (#328) +- Integration between `MST` and Symja `IExpr` ### Changed - Exponential operations merged with hyperbolic functions diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index d095db1ba..568bde153 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -26,7 +26,7 @@ dependencies { implementation(project(":kmath-ejml")) implementation(project(":kmath-nd4j")) implementation(project(":kmath-tensors")) - + implementation(project(":kmath-symja")) implementation(project(":kmath-for-real")) implementation("org.nd4j:nd4j-native:1.0.0-beta7") diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt index 420b23f9f..6ceaa962a 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt @@ -5,25 +5,23 @@ package space.kscience.kmath.ast -import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.expressions.derivative import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.kotlingrad.toDiffExpression +import space.kscience.kmath.expressions.Symbol.Companion.x +import space.kscience.kmath.expressions.toExpression +import space.kscience.kmath.kotlingrad.toKotlingradExpression import space.kscience.kmath.operations.DoubleField /** * In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with - * valid derivative. + * valid derivative in a certain point. */ fun main() { - val x by symbol - - val actualDerivative = "x^2-4*x-44".parseMath() - .toDiffExpression(DoubleField) + val actualDerivative = "x^2-4*x-44" + .parseMath() + .toKotlingradExpression(DoubleField) .derivative(x) - - val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField) - assert(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0)) + val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField) + check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0)) } diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt new file mode 100644 index 000000000..a9eca0500 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.ast + +import space.kscience.kmath.expressions.Symbol.Companion.x +import space.kscience.kmath.expressions.derivative +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.expressions.toExpression +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.symja.toSymjaExpression + +/** + * In this example, x^2-4*x-44 function is differentiated with Symja, and the autodiff result is compared with + * valid derivative in a certain point. + */ +fun main() { + val actualDerivative = "x^2-4*x-44" + .parseMath() + .toSymjaExpression(DoubleField) + .derivative(x) + + val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField) + check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0)) +} diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt index 72ecee4f1..8312eaff3 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt @@ -39,7 +39,7 @@ public class KotlingradExpression>( } /** - * Wraps this [MST] into [KotlingradExpression]. + * Wraps this [MST] into [KotlingradExpression] in the context of [algebra]. */ -public fun > MST.toDiffExpression(algebra: A): KotlingradExpression = +public fun > MST.toKotlingradExpression(algebra: A): KotlingradExpression = KotlingradExpression(algebra, this) diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts new file mode 100644 index 000000000..c06020bb6 --- /dev/null +++ b/kmath-symja/build.gradle.kts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +plugins { + kotlin("jvm") + id("ru.mipt.npm.gradle.common") +} + +description = "Symja integration module" + +dependencies { + api("org.matheclipse:matheclipse-core:2.0.0-SNAPSHOT") + api(project(":kmath-core")) + testImplementation("org.slf4j:slf4j-simple:1.7.30") +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE +} diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt new file mode 100644 index 000000000..301678916 --- /dev/null +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.symja + +import org.matheclipse.core.eval.ExprEvaluator +import org.matheclipse.core.expression.F +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.interpret +import space.kscience.kmath.operations.NumericAlgebra + +public class SymjaExpression>( + public val algebra: A, + public val mst: MST, + public val evaluator: ExprEvaluator = DEFAULT_EVALUATOR, +) : DifferentiableExpression> { + public override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) + + public override fun derivativeOrNull(symbols: List): SymjaExpression = SymjaExpression( + algebra, + symbols.map(Symbol::toIExpr).fold(mst.toIExpr(), F::D).toMst(evaluator), + evaluator, + ) +} + +/** + * Wraps this [MST] into [SymjaExpression] in the context of [algebra]. + */ +public fun > MST.toSymjaExpression(algebra: A): SymjaExpression = + SymjaExpression(algebra, this) diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt new file mode 100644 index 000000000..95dd1ebbf --- /dev/null +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.symja + +import org.matheclipse.core.eval.ExprEvaluator +import org.matheclipse.core.expression.ComplexNum +import org.matheclipse.core.expression.F +import org.matheclipse.core.interfaces.IExpr +import org.matheclipse.core.interfaces.ISymbol +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.MstExtendedField +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.operations.* + +internal val DEFAULT_EVALUATOR = ExprEvaluator(false, 100) + +/** + * Matches the given [IExpr] instance to appropriate [MST] node or evaluates it with [evaluator]. + */ +public fun IExpr.toMst(evaluator: ExprEvaluator = DEFAULT_EVALUATOR): MST = MstExtendedField { + when { + isPlus -> first().toMst(evaluator) + second().toMst(evaluator) + isSin -> sin(first().toMst(evaluator)) + isSinh -> sinh(first().toMst(evaluator)) + isCos -> cos(first().toMst(evaluator)) + isCosh -> cosh(first().toMst(evaluator)) + isTan -> tan(first().toMst(evaluator)) + isTanh -> tanh(first().toMst(evaluator)) + isArcSin -> asin(first().toMst(evaluator)) + isArcCos -> acos(first().toMst(evaluator)) + isArcTan -> atan(first().toMst(evaluator)) + isArcTanh -> atanh(first().toMst(evaluator)) + isE -> bindSymbol("e") + isPi -> bindSymbol("pi") + isTimes -> first().toMst(evaluator) * second().toMst(evaluator) + isOne -> one + isZero -> zero + isImaginaryUnit -> bindSymbol("i") + isMinusOne -> -one + this@toMst is ISymbol -> bindSymbol(symbolName) + isPower -> power(first().toMst(evaluator), evaluator.evalf(second())) + isExp -> exp(first().toMst(evaluator)) + isNumber -> number(evaluator.evalf(this@toMst)) + this@toMst === F.NIL -> error("NIL cannot be converted to MST") + else -> evaluator.eval(this@toMst.toString()).toMst(evaluator) + } +} + +/** + * Matches the given [MST] instance to appropriate [IExpr] node, only standard operations and symbols (which are + * present in, say, [MstExtendedField]) are supported. + */ +public fun MST.toIExpr(): IExpr = when (this) { + is MST.Numeric -> F.symjify(value) + + is Symbol -> when (identity) { + "e" -> F.E + "pi" -> F.Pi + "i" -> ComplexNum.I + else -> F.Dummy(identity) + } + + is MST.Unary -> when (operation) { + GroupOperations.PLUS_OPERATION -> value.toIExpr() + GroupOperations.MINUS_OPERATION -> F.Negate(value.toIExpr()) + TrigonometricOperations.SIN_OPERATION -> F.Sin(value.toIExpr()) + TrigonometricOperations.COS_OPERATION -> F.Cos(value.toIExpr()) + TrigonometricOperations.TAN_OPERATION -> F.Tan(value.toIExpr()) + TrigonometricOperations.ASIN_OPERATION -> F.ArcSin(value.toIExpr()) + TrigonometricOperations.ACOS_OPERATION -> F.ArcCos(value.toIExpr()) + TrigonometricOperations.ATAN_OPERATION -> F.ArcTan(value.toIExpr()) + ExponentialOperations.SINH_OPERATION -> F.Sinh(value.toIExpr()) + ExponentialOperations.COSH_OPERATION -> F.Cosh(value.toIExpr()) + ExponentialOperations.TANH_OPERATION -> F.Tanh(value.toIExpr()) + ExponentialOperations.ASINH_OPERATION -> F.ArcSinh(value.toIExpr()) + ExponentialOperations.ACOSH_OPERATION -> F.ArcCosh(value.toIExpr()) + ExponentialOperations.ATANH_OPERATION -> F.ArcTanh(value.toIExpr()) + PowerOperations.SQRT_OPERATION -> F.Sqrt(value.toIExpr()) + ExponentialOperations.EXP_OPERATION -> F.Exp(value.toIExpr()) + ExponentialOperations.LN_OPERATION -> F.Log(value.toIExpr()) + else -> error("Unary operation $operation not defined in $this") + } + + is MST.Binary -> when (operation) { + GroupOperations.PLUS_OPERATION -> left.toIExpr() + right.toIExpr() + GroupOperations.MINUS_OPERATION -> left.toIExpr() - right.toIExpr() + RingOperations.TIMES_OPERATION -> left.toIExpr() * right.toIExpr() + FieldOperations.DIV_OPERATION -> F.Divide(left.toIExpr(), right.toIExpr()) + PowerOperations.POW_OPERATION -> F.Power(left.toIExpr(), F.symjify((right as MST.Numeric).value)) + else -> error("Binary operation $operation not defined in $this") + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index cc9eb4860..d47aea2a7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -42,6 +42,7 @@ include( ":kmath-kotlingrad", ":kmath-tensors", ":kmath-jupyter", + ":kmath-symja", ":examples", ":benchmarks" ) From 65e05605533a033fff621b83a447c7a78a07cd58 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 29 May 2021 15:50:16 +0700 Subject: [PATCH 05/39] Fix Symja build issues --- build.gradle.kts | 5 ++++- kmath-symja/build.gradle.kts | 9 ++++++++- .../space/kscience/kmath/symja/SymjaExpression.kt | 15 +++++++++++++-- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4de6d8bad..1826a2e7e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,9 @@ allprojects { maven("http://logicrunch.research.it.uu.se/maven") { isAllowInsecureProtocol = true } - maven("https://oss.sonatype.org/content/repositories/snapshots") + maven("https://oss.sonatype.org/content/repositories/snapshots") { + + } mavenCentral() } @@ -31,6 +33,7 @@ subprojects { externalDocumentationLink("http://ejml.org/javadoc/") externalDocumentationLink("https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/") externalDocumentationLink("https://deeplearning4j.org/api/latest/") + externalDocumentationLink("https://axelclk.bitbucket.io/symja/javadoc/") externalDocumentationLink("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/") } } diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts index c06020bb6..c67b42e3f 100644 --- a/kmath-symja/build.gradle.kts +++ b/kmath-symja/build.gradle.kts @@ -11,7 +11,14 @@ plugins { description = "Symja integration module" dependencies { - api("org.matheclipse:matheclipse-core:2.0.0-SNAPSHOT") + api("org.matheclipse:matheclipse-core:2.0.0-SNAPSHOT") { + // Incorrect transitive dependency org.apfloat:apfloat:1.10.0-SNAPSHOT + exclude("org.apfloat", "apfloat") + } + + // Replace for org.apfloat:apfloat:1.10.0-SNAPSHOT + api("org.apfloat:apfloat:1.10.0") + api(project(":kmath-core")) testImplementation("org.slf4j:slf4j-simple:1.7.30") } diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt index 301678916..a6773c709 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt @@ -7,17 +7,28 @@ package space.kscience.kmath.symja import org.matheclipse.core.eval.ExprEvaluator import org.matheclipse.core.expression.F -import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.SpecialDifferentiableExpression import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.interpret import space.kscience.kmath.operations.NumericAlgebra +/** + * Represents [MST] based [DifferentiableExpression] relying on [Symja](https://github.com/axkr/symja_android_library). + * + * The principle of this API is converting the [mst] to an [org.matheclipse.core.interfaces.IExpr], differentiating it + * with Symja's [F.D], then converting [org.matheclipse.core.interfaces.IExpr] back to [MST]. + * + * @param T The type of number. + * @param A The [NumericAlgebra] of [T]. + * @property algebra The [A] instance. + * @property mst The [MST] node. + */ public class SymjaExpression>( public val algebra: A, public val mst: MST, public val evaluator: ExprEvaluator = DEFAULT_EVALUATOR, -) : DifferentiableExpression> { +) : SpecialDifferentiableExpression> { public override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) public override fun derivativeOrNull(symbols: List): SymjaExpression = SymjaExpression( From 7d0eff74f6b48f26d16343f5a0c4e9d38fe73e68 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 8 Jun 2021 20:39:47 +0700 Subject: [PATCH 06/39] Fix shield README.md, fix build --- README.md | 2 +- docs/templates/README-TEMPLATE.md | 2 +- kmath-symja/build.gradle.kts | 18 ++++++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9117582ac..dfb9cba9c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) ![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) -[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) +[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) # KMath diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index 6bb1e9085..c981cb0bd 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -2,7 +2,7 @@ [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) ![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) -[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) +[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) # KMath diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts index c67b42e3f..f305c03b8 100644 --- a/kmath-symja/build.gradle.kts +++ b/kmath-symja/build.gradle.kts @@ -12,12 +12,26 @@ description = "Symja integration module" dependencies { api("org.matheclipse:matheclipse-core:2.0.0-SNAPSHOT") { - // Incorrect transitive dependency org.apfloat:apfloat:1.10.0-SNAPSHOT + // Incorrect transitive dependencies exclude("org.apfloat", "apfloat") + exclude("org.hipparchus", "hipparchus-clustering") + exclude("org.hipparchus", "hipparchus-core") + exclude("org.hipparchus", "hipparchus-fft") + exclude("org.hipparchus", "hipparchus-fitting") + exclude("org.hipparchus", "hipparchus-ode") + exclude("org.hipparchus", "hipparchus-optim") + exclude("org.hipparchus", "hipparchus-stat") } - // Replace for org.apfloat:apfloat:1.10.0-SNAPSHOT + // Replaces for incorrect transitive dependencies api("org.apfloat:apfloat:1.10.0") + api("org.hipparchus:hipparchus-clustering:1.8") + api("org.hipparchus:hipparchus-core:1.8") + api("org.hipparchus:hipparchus-fft:1.8") + api("org.hipparchus:hipparchus-fitting:1.8") + api("org.hipparchus:hipparchus-ode:1.8") + api("org.hipparchus:hipparchus-optim:1.8") + api("org.hipparchus:hipparchus-stat:1.8") api(project(":kmath-core")) testImplementation("org.slf4j:slf4j-simple:1.7.30") From c0ab082d240d64f3476707912ba4aea31ecae6bc Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 8 Jun 2021 20:53:33 +0700 Subject: [PATCH 07/39] Run build workflow for PRs --- .github/workflows/build.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a9f04621..98f4d2ec2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,9 @@ name: Gradle build -on: [ push ] +on: + push: + pull_request: + types: [opened, edited] jobs: build: From 7b736a7c81391493c48eea54bdb4f263c01b1cb7 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 9 Jun 2021 21:40:47 +0700 Subject: [PATCH 08/39] Fix README.md again --- README.md | 18 ++++++++++++------ docs/templates/README-TEMPLATE.md | 2 +- kmath-ast/README.md | 6 +++--- kmath-complex/README.md | 6 +++--- kmath-core/README.md | 6 +++--- kmath-ejml/README.md | 6 +++--- kmath-for-real/README.md | 6 +++--- kmath-functions/README.md | 6 +++--- kmath-kotlingrad/README.md | 6 +++--- kmath-nd4j/README.md | 6 +++--- kmath-tensors/README.md | 6 +++--- 11 files changed, 40 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index dfb9cba9c..7c6f7ea2b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) ![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) -[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) +[![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) # KMath @@ -207,7 +207,7 @@ One can still use generic algebras though.
* ### [kmath-kotlingrad](kmath-kotlingrad) -> Functions, integration and interpolation +> > > **Maturity**: EXPERIMENTAL > @@ -218,13 +218,13 @@ One can still use generic algebras though.
* ### [kmath-memory](kmath-memory) -> An API and basic implementation for arranging objects in a continous memory block. +> An API and basic implementation for arranging objects in a continuous memory block. > > **Maturity**: DEVELOPMENT
* ### [kmath-nd4j](kmath-nd4j) -> ND4J NDStructure implementation and according NDAlgebra classes +> > > **Maturity**: EXPERIMENTAL > @@ -241,6 +241,12 @@ One can still use generic algebras though. > **Maturity**: EXPERIMENTAL
+* ### [kmath-symja](kmath-symja) +> +> +> **Maturity**: PROTOTYPE +
+ * ### [kmath-tensors](kmath-tensors) > > @@ -293,8 +299,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:0.3.0-dev-11") - // api("space.kscience:kmath-core-jvm:0.3.0-dev-11") for jvm-specific version + api("space.kscience:kmath-core:0.3.0-dev-13") + // api("space.kscience:kmath-core-jvm:0.3.0-dev-13") for jvm-specific version } ``` diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index c981cb0bd..bad11a31a 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -2,7 +2,7 @@ [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) ![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) -[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) +[![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) # KMath diff --git a/kmath-ast/README.md b/kmath-ast/README.md index b0f2d59e5..2f6b21094 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Performance and visualization extensions to MST API. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-13`. **Gradle:** ```gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-11' + implementation 'space.kscience:kmath-ast:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-11") + implementation("space.kscience:kmath-ast:0.3.0-dev-13") } ``` diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 04431cf6c..18a83756d 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,7 +8,7 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-13`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-11' + implementation 'space.kscience:kmath-complex:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-11") + implementation("space.kscience:kmath-complex:0.3.0-dev-13") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index 700eaef38..6ca8c8ef8 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-13`. **Gradle:** ```gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-11' + implementation 'space.kscience:kmath-core:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-11") + implementation("space.kscience:kmath-core:0.3.0-dev-13") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index 79a28b824..10e7bd606 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-13`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-11' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-11") + implementation("space.kscience:kmath-ejml:0.3.0-dev-13") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 5ca805093..6339782dd 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-13`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-11' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0-dev-11") + implementation("space.kscience:kmath-for-real:0.3.0-dev-13") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 2497f7102..77f55528a 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-13`. **Gradle:** ```gradle @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-11' + implementation 'space.kscience:kmath-functions:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0-dev-11") + implementation("space.kscience:kmath-functions:0.3.0-dev-13") } ``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 4393cbf8c..31c7bb819 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-13`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-11' + implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-11") + implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-13") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 6408be13b..1c945f06a 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-13`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-11' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-11") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-13") } ``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 75de2bf35..dd21a9f2f 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-13`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-11' + implementation 'space.kscience:kmath-tensors:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-11") + implementation("space.kscience:kmath-tensors:0.3.0-dev-13") } ``` From 46bf66c8ee28f6c3fa1645e19001b878cef60b7e Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 26 May 2021 20:24:29 +0700 Subject: [PATCH 09/39] Add justCalculate benchmark, some minor refactorings --- .../ExpressionsInterpretersBenchmark.kt | 46 ++++++++++++++--- .../space/kscience/kmath/ast/expressions.kt | 2 - kmath-ast/README.md | 15 +++--- kmath-ast/docs/README-TEMPLATE.md | 9 ++-- .../TestCompilerConsistencyWithInterpreter.kt | 4 +- .../kmath/ast/TestCompilerOperations.kt | 6 +-- .../kmath/ast/TestCompilerVariables.kt | 4 +- .../kmath/wasm/internal/WasmBuilder.kt | 6 +-- .../kscience/kmath/ast/TestExecutionTime.kt | 51 +++++++++++++++++-- .../kscience/kmath/wasm/TestWasmSpecific.kt | 4 +- .../kmath/asm/internal/codegenUtils.kt | 2 +- .../kmath/kotlingrad/AdaptingTests.kt | 7 ++- 12 files changed, 113 insertions(+), 43 deletions(-) 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 15cd14399..0294f924b 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -14,22 +14,51 @@ import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke +import kotlin.math.sin import kotlin.random.Random @State(Scope.Benchmark) internal class ExpressionsInterpretersBenchmark { + /** + * Benchmark case for [Expression] created with [expressionInExtendedField]. + */ @Benchmark fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, blackhole) + /** + * Benchmark case for [Expression] created with [toExpression]. + */ @Benchmark fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, blackhole) + /** + * Benchmark case for [Expression] created with [compileToExpression]. + */ @Benchmark fun asmExpression(blackhole: Blackhole) = invokeAndSum(asm, blackhole) + /** + * Benchmark case for [Expression] implemented manually with `kotlin.math` functions. + */ @Benchmark fun rawExpression(blackhole: Blackhole) = invokeAndSum(raw, blackhole) + /** + * Benchmark case for direct computation w/o [Expression]. + */ + @Benchmark + fun justCalculate(blackhole: Blackhole) { + val random = Random(0) + var sum = 0.0 + + repeat(times) { + val x = random.nextDouble() + sum += x * 2.0 + 2.0 / x - 16.0 / sin(x) + } + + blackhole.consume(sum) + } + private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { val random = Random(0) var sum = 0.0 @@ -42,23 +71,24 @@ internal class ExpressionsInterpretersBenchmark { } private companion object { - private val x: Symbol by symbol - private val algebra: DoubleField = DoubleField + private val x by symbol + private val algebra = DoubleField private const val times = 1_000_000 - private val functional: Expression = DoubleField.expressionInExtendedField { + private val functional = DoubleField.expressionInExtendedField { bindSymbol(x) * number(2.0) + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x)) } private val node = MstExtendedField { - bindSymbol(x) * 2.0 + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x)) + x * 2.0 + number(2.0) / x - number(16.0) / sin(x) } - private val mst: Expression = node.toExpression(DoubleField) - private val asm: Expression = node.compileToExpression(DoubleField) + private val mst = node.toExpression(DoubleField) + private val asm = node.compileToExpression(DoubleField) - private val raw: Expression = Expression { args -> - args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 / kotlin.math.sin(args.getValue(x)) + private val raw = Expression { args -> + val x = args[x]!! + x * 2.0 + 2.0 / x - 16.0 / sin(x) } } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt index d5a82590f..96c9856cf 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt @@ -9,12 +9,10 @@ import space.kscience.kmath.expressions.MstField import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.interpret import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke fun main() { val expr = MstField { - val x = bindSymbol(x) x * 2.0 + number(2.0) / x - 16.0 } diff --git a/kmath-ast/README.md b/kmath-ast/README.md index b0f2d59e5..026c5a625 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Performance and visualization extensions to MST API. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-13`. **Gradle:** ```gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-11' + implementation 'space.kscience:kmath-ast:0.3.0-dev-13' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-11") + implementation("space.kscience:kmath-ast:0.3.0-dev-13") } ``` @@ -45,11 +45,12 @@ special implementation of `Expression` with implemented `invoke` function. For example, the following builder: ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.asm.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` ... leads to generation of bytecode, which can be decompiled to the following Java class: @@ -89,11 +90,12 @@ public final class AsmCompiledExpression_45045_0 implements Expression { A similar feature is also available on JS. ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.estree.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` The code above returns expression implemented with such a JS function: @@ -108,11 +110,12 @@ JS also supports very experimental expression optimization with [WebAssembly](ht Currently, only expressions inside `DoubleField` and `IntRing` are supported. ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.wasm.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` An example of emitted Wasm IR in the form of WAT: diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md index 80ea31642..b90f8ff08 100644 --- a/kmath-ast/docs/README-TEMPLATE.md +++ b/kmath-ast/docs/README-TEMPLATE.md @@ -16,11 +16,12 @@ special implementation of `Expression` with implemented `invoke` function. For example, the following builder: ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.asm.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` ... leads to generation of bytecode, which can be decompiled to the following Java class: @@ -60,11 +61,12 @@ public final class AsmCompiledExpression_45045_0 implements Expression { A similar feature is also available on JS. ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.estree.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` The code above returns expression implemented with such a JS function: @@ -79,11 +81,12 @@ JS also supports very experimental expression optimization with [WebAssembly](ht Currently, only expressions inside `DoubleField` and `IntRing` are supported. ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.wasm.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` An example of emitted Wasm IR in the form of WAT: diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt index 6209661b3..3116466e6 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt @@ -22,7 +22,7 @@ internal class TestCompilerConsistencyWithInterpreter { val mst = MstRing { binaryOperationFunction("+")( unaryOperationFunction("+")( - (bindSymbol(x) - (2.toByte() + (scale( + (x - (2.toByte() + (scale( add(number(1), number(1)), 2.0, ) + 1.toByte()))) * 3.0 - 1.toByte() @@ -42,7 +42,7 @@ internal class TestCompilerConsistencyWithInterpreter { fun doubleField() = runCompilerTest { val mst = MstField { +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( - (3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 + (3.0 - (x + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one, ) + zero diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt index 073a03f14..f869efd62 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt @@ -47,19 +47,19 @@ internal class TestCompilerOperations { @Test fun testSubtract() = runCompilerTest { - val expr = MstExtendedField { bindSymbol(x) - bindSymbol(x) }.compileToExpression(DoubleField) + val expr = MstExtendedField { x - x }.compileToExpression(DoubleField) assertEquals(0.0, expr(x to 2.0)) } @Test fun testDivide() = runCompilerTest { - val expr = MstExtendedField { bindSymbol(x) / bindSymbol(x) }.compileToExpression(DoubleField) + val expr = MstExtendedField { x / x }.compileToExpression(DoubleField) assertEquals(1.0, expr(x to 2.0)) } @Test fun testPower() = runCompilerTest { - val expr = MstExtendedField { bindSymbol(x) pow 2 }.compileToExpression(DoubleField) + val expr = MstExtendedField { x pow 2 }.compileToExpression(DoubleField) assertEquals(4.0, expr(x to 2.0)) } } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt index dcc15b311..bed5bc7fa 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt @@ -18,13 +18,13 @@ import kotlin.test.assertFailsWith internal class TestCompilerVariables { @Test fun testVariable() = runCompilerTest { - val expr = MstRing { bindSymbol(x) }.compileToExpression(IntRing) + val expr = MstRing { x }.compileToExpression(IntRing) assertEquals(1, expr(x to 1)) } @Test fun testUndefinedVariableFails() = runCompilerTest { - val expr = MstRing { bindSymbol(x) }.compileToExpression(IntRing) + val expr = MstRing { x }.compileToExpression(IntRing) assertFailsWith { expr() } } } 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 95ace1bad..c89ad83c4 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 @@ -27,11 +27,7 @@ internal sealed class WasmBuilder( lateinit var ctx: BinaryenModule open fun visitSymbolic(mst: Symbol): ExpressionRef { - try { - algebra.bindSymbol(mst) - } catch (ignored: Throwable) { - null - }?.let { return visitNumeric(Numeric(it)) } + algebra.bindSymbolOrNull(mst)?.let { return visitNumeric(Numeric(it)) } var idx = keys.indexOf(mst) diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt index 6cb378182..d0e8128b4 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.ast import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.math.sin @@ -17,18 +16,19 @@ import kotlin.time.measureTime import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression +// TODO move to benchmarks when https://github.com/Kotlin/kotlinx-benchmark/pull/38 or similar feature is merged internal class TestExecutionTime { private companion object { private const val times = 1_000_000 private val x by symbol - private val algebra: ExtendedField = DoubleField + private val algebra = DoubleField private val functional = DoubleField.expressionInExtendedField { bindSymbol(x) * const(2.0) + const(2.0) / bindSymbol(x) - const(16.0) / sin(bindSymbol(x)) } private val node = MstExtendedField { - bindSymbol(x) * number(2.0) + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x)) + x * number(2.0) + number(2.0) / x - number(16.0) / sin(x) } private val mst = node.toExpression(DoubleField) @@ -43,7 +43,13 @@ internal class TestExecutionTime { // }; private val raw = Expression { args -> - args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 / sin(args.getValue(x)) + val x = args[x]!! + x * 2.0 + 2.0 / x - 16.0 / sin(x) + } + + private val justCalculate = { args: dynamic -> + val x = args[x].unsafeCast() + x * 2.0 + 2.0 / x - 16.0 / sin(x) } } @@ -51,21 +57,56 @@ internal class TestExecutionTime { println(name) val rng = Random(0) var sum = 0.0 - measureTime { repeat(times) { sum += expr(x to rng.nextDouble()) } }.also(::println) + measureTime { + repeat(times) { sum += expr(x to rng.nextDouble()) } + }.also(::println) } + /** + * [Expression] created with [expressionInExtendedField]. + */ @Test fun functionalExpression() = invokeAndSum("functional", functional) + /** + * [Expression] created with [mstExpression]. + */ @Test fun mstExpression() = invokeAndSum("mst", mst) + /** + * [Expression] created with [wasmCompileToExpression]. + */ @Test fun wasmExpression() = invokeAndSum("wasm", wasm) + /** + * [Expression] created with [estreeCompileToExpression]. + */ @Test fun estreeExpression() = invokeAndSum("estree", wasm) + /** + * [Expression] implemented manually with `kotlin.math`. + */ @Test fun rawExpression() = invokeAndSum("raw", raw) + + /** + * Direct computation w/o [Expression]. + */ + @Test + fun justCalculateExpression() { + println("justCalculate") + val rng = Random(0) + var sum = 0.0 + measureTime { + repeat(times) { + val arg = rng.nextDouble() + val o = js("{}") + o["x"] = arg + sum += justCalculate(o) + } + }.also(::println) + } } diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt index abdf865c7..45776c191 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt @@ -31,7 +31,7 @@ internal class TestWasmSpecific { @Test fun argsPassing() { - val res = MstExtendedField { bindSymbol(y) + bindSymbol(x).pow(10) }.compile( + val res = MstExtendedField { y + x.pow(10) }.compile( DoubleField, x to 2.0, y to 100000000.0, @@ -42,7 +42,7 @@ internal class TestWasmSpecific { @Test fun powFunction() { - val expr = MstExtendedField { bindSymbol(x).pow(1.0 / 6.0) }.compileToExpression(DoubleField) + val expr = MstExtendedField { x.pow(1.0 / 6.0) }.compileToExpression(DoubleField) assertEquals(0.9730585187140817, expr(x to 0.8488554755054833)) } diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt index cfac59847..a84248f63 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt @@ -63,7 +63,7 @@ internal fun MethodVisitor.label(): Label = Label().also(::visitLabel) * @author Iaroslav Postovalov */ internal tailrec fun buildName(mst: MST, collision: Int = 0): String { - val name = "kscience.kmath.asm.generated.AsmCompiledExpression_${mst.hashCode()}_$collision" + val name = "space.kscience.kmath.asm.generated.AsmCompiledExpression_${mst.hashCode()}_$collision" try { Class.forName(name) diff --git a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt index 57fe2411c..9378adfea 100644 --- a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt +++ b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt @@ -20,8 +20,7 @@ import kotlin.test.fail internal class AdaptingTests { @Test fun symbol() { - val c1 = MstNumericAlgebra.bindSymbol(x.identity) - assertEquals(x.identity, c1.toSVar>().name) + assertEquals(x.identity, x.toSVar>().name) val c2 = "kitten".parseMath().toSFun>() if (c2 is SVar) assertTrue(c2.name == "kitten") else fail() } @@ -46,7 +45,7 @@ internal class AdaptingTests { @Test fun simpleFunctionDerivative() { - val xSVar = MstNumericAlgebra.bindSymbol(x.identity).toSVar>() + val xSVar = x.toSVar>() val quadratic = "x^2-4*x-44".parseMath().toSFun>() val actualDerivative = quadratic.d(xSVar).toMst().compileToExpression(DoubleField) val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField) @@ -55,7 +54,7 @@ internal class AdaptingTests { @Test fun moreComplexDerivative() { - val xSVar = MstNumericAlgebra.bindSymbol(x.identity).toSVar>() + val xSVar = x.toSVar>() val composition = "-sqrt(sin(x^2)-cos(x)^2-16*x)".parseMath().toSFun>() val actualDerivative = composition.d(xSVar).toMst().compileToExpression(DoubleField) From 2dff15c5aa2afe2ce99edfe8ae0fe4dc1db64087 Mon Sep 17 00:00:00 2001 From: therealansh Date: Thu, 3 Jun 2021 01:14:19 +0530 Subject: [PATCH 10/39] integrate: Jafama + KMath --- kmath-jafama/build.gradle.kts | 21 + .../kscience/kmath/jafama/CmnFastMath.java | 2112 ++++++++++++ .../kscience/kmath/jafama/DoubleWrapper.java | 13 + .../space/kscience/kmath/jafama/FastMath.java | 2986 ++++++++++++++++ .../kscience/kmath/jafama/IntWrapper.java | 13 + .../kscience/kmath/jafama/KMathJafama.kt | 102 + .../kscience/kmath/jafama/NumbersUtils.java | 2647 +++++++++++++++ .../kscience/kmath/jafama/StrictFastMath.java | 2998 +++++++++++++++++ settings.gradle.kts | 1 + 9 files changed, 10893 insertions(+) create mode 100644 kmath-jafama/build.gradle.kts create mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/CmnFastMath.java create mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/DoubleWrapper.java create mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/FastMath.java create mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/IntWrapper.java create mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt create mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/NumbersUtils.java create mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/StrictFastMath.java diff --git a/kmath-jafama/build.gradle.kts b/kmath-jafama/build.gradle.kts new file mode 100644 index 000000000..22d50f89c --- /dev/null +++ b/kmath-jafama/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + id("ru.mipt.npm.gradle.jvm") +} + +dependencies { + api(project(":kmath-ast")) + api(project(":kmath-complex")) + api(project(":kmath-for-real")) +} + +kscience{ + useHtml() +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE +} + +kotlin.sourceSets.all { + languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") +} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/CmnFastMath.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/CmnFastMath.java new file mode 100644 index 000000000..0abc5d95d --- /dev/null +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/CmnFastMath.java @@ -0,0 +1,2112 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.jafama; + +/** + * Stuffs for FastMath and StrictFastMath. + */ +abstract class CmnFastMath { + + /* + * For trigonometric functions, use of look-up tables and Taylor-Lagrange formula + * with 4 derivatives (more take longer to compute and don't add much accuracy, + * less require larger tables (which use more memory, take more time to initialize, + * and are slower to access (at least on the machine they were developed on))). + * + * For angles reduction of cos/sin/tan functions: + * - for small values, instead of reducing angles, and then computing the best index + * for look-up tables, we compute this index right away, and use it for reduction, + * - for large values, treatments derived from fdlibm package are used, as done in + * java.lang.Math. They are faster but still "slow", so if you work with + * large numbers and need speed over accuracy for them, you might want to use + * normalizeXXXFast treatments before your function, or modify cos/sin/tan + * so that they call the fast normalization treatments instead of the accurate ones. + * NB: If an angle is huge (like PI*1e20), in double precision format its last digits + * are zeros, which most likely is not the case for the intended value, and doing + * an accurate reduction on a very inaccurate value is most likely pointless. + * But it gives some sort of coherence that could be needed in some cases. + * + * Multiplication on double appears to be about as fast (or not much slower) than call + * to [], and regrouping some doubles in a private class, to use + * index only once, does not seem to speed things up, so: + * - for uniformly tabulated values, to retrieve the parameter corresponding to + * an index, we recompute it rather than using an array to store it, + * - for cos/sin, we recompute derivatives divided by (multiplied by inverse of) + * factorial each time, rather than storing them in arrays. + * + * Lengths of look-up tables are usually of the form 2^n+1, for their values to be + * of the form ( * k/2^n, k in 0 .. 2^n), so that particular values + * (PI/2, etc.) are "exactly" computed, as well as for other reasons. + * + * Tables are put in specific inner classes, to be lazily initialized. + * Always doing strict tables initialization, even if StrictFastMath delegates + * to StrictMath and doesn't use tables, which makes tables initialization a bit + * slower but code simpler. + * Using redefined pure Java treatments during tables initialization, + * instead of Math or StrictMath ones (even asin(double)), can be very slow, + * because class loading is likely not to be optimized. + * + * Most math treatments I could find on the web, including "fast" ones, + * usually take care of special cases (NaN, etc.) at the beginning, and + * then deal with the general case, which adds a useless overhead for the + * general (and common) case. In this class, special cases are only dealt + * with when needed, and if the general case does not already handle them. + */ + + /* + * Regarding strictfp-ness: + * + * Switching from/to strictfp has some overhead, so we try to only + * strictfp-ize when needed (or when clueless). + * Compile-time constants are computed in a FP-strict way, so no need + * to make this whole class strictfp. + */ + + //-------------------------------------------------------------------------- + // CONFIGURATION + //-------------------------------------------------------------------------- + + /* + * FastMath + */ + + static final boolean FM_USE_JDK_MATH = getBooleanProperty("jafama.usejdk", false); + + /** + * Used for both FastMath.log(double) and FastMath.log10(double). + */ + static final boolean FM_USE_REDEFINED_LOG = getBooleanProperty("jafama.fastlog", false); + + static final boolean FM_USE_REDEFINED_SQRT = getBooleanProperty("jafama.fastsqrt", false); + + /** + * Set it to true if FastMath.sqrt(double) is slow + * (more tables, but less calls to FastMath.sqrt(double)). + */ + static final boolean FM_USE_POWTABS_FOR_ASIN = false; + + /* + * StrictFastMath + */ + + static final boolean SFM_USE_JDK_MATH = getBooleanProperty("jafama.strict.usejdk", false); + + /** + * Used for both StrictFastMath.log(double) and StrictFastMath.log10(double). + * True by default because the StrictMath implementations can be slow. + */ + static final boolean SFM_USE_REDEFINED_LOG = getBooleanProperty("jafama.strict.fastlog", true); + + static final boolean SFM_USE_REDEFINED_SQRT = getBooleanProperty("jafama.strict.fastsqrt", false); + + /** + * Set it to true if StrictFastMath.sqrt(double) is slow + * (more tables, but less calls to StrictFastMath.sqrt(double)). + */ + static final boolean SFM_USE_POWTABS_FOR_ASIN = false; + + /* + * Common to FastMath and StrictFastMath. + */ + + /** + * Using two pow tab can just make things barely faster, + * and could relatively hurt in case of cache-misses, + * especially for methods that otherwise wouldn't rely + * on any tab, so we don't use it. + */ + static final boolean USE_TWO_POW_TAB = false; + + /** + * Because on some architectures, some casts can be slow, + * especially for large values. + * Might make things a bit slower for latest architectures, + * but not as much as it makes them faster for older ones. + */ + static final boolean ANTI_SLOW_CASTS = true; + + /** + * If some methods get JIT-optimized, they might crash + * if they contain "(var == xxx)" with var being NaN + * (can happen with Java 6u29). + * + * The crash does not happen if we replace "==" with "<" or ">". + * + * Only the code that has been observed to trigger the bug + * has been modified. + */ + static final boolean ANTI_JIT_OPTIM_CRASH_ON_NAN = true; + + //-------------------------------------------------------------------------- + // GENERAL CONSTANTS + //-------------------------------------------------------------------------- + + /** + * Closest double approximation of e. + */ + public static final double E = Math.E; + + /** + * Closest double approximation of pi, which is inferior to mathematical pi: + * pi ~= 3.14159265358979323846... + * PI ~= 3.141592653589793 + */ + public static final double PI = Math.PI; + + /** + * High double approximation of pi, which is further from pi + * than the low approximation PI: + * pi ~= 3.14159265358979323846... + * PI ~= 3.141592653589793 + * PI_SUP ~= 3.1415926535897936 + */ + public static final double PI_SUP = Double.longBitsToDouble(Double.doubleToRawLongBits(Math.PI)+1); + + static final double ONE_DIV_F2 = 1/2.0; + static final double ONE_DIV_F3 = 1/6.0; + static final double ONE_DIV_F4 = 1/24.0; + + static final float TWO_POW_23_F = (float)NumbersUtils.twoPow(23); + + static final double TWO_POW_24 = NumbersUtils.twoPow(24); + private static final double TWO_POW_N24 = NumbersUtils.twoPow(-24); + + static final double TWO_POW_26 = NumbersUtils.twoPow(26); + static final double TWO_POW_N26 = NumbersUtils.twoPow(-26); + + // First double value (from zero) such as (value+-1/value == value). + static final double TWO_POW_27 = NumbersUtils.twoPow(27); + static final double TWO_POW_N27 = NumbersUtils.twoPow(-27); + + static final double TWO_POW_N28 = NumbersUtils.twoPow(-28); + + static final double TWO_POW_52 = NumbersUtils.twoPow(52); + + static final double TWO_POW_N55 = NumbersUtils.twoPow(-55); + + static final double TWO_POW_66 = NumbersUtils.twoPow(66); + + static final double TWO_POW_512 = NumbersUtils.twoPow(512); + static final double TWO_POW_N512 = NumbersUtils.twoPow(-512); + + /** + * Double.MIN_NORMAL since Java 6. + */ + static final double DOUBLE_MIN_NORMAL = Double.longBitsToDouble(0x0010000000000000L); // 2.2250738585072014E-308 + + // Not storing float/double mantissa size in constants, + // for 23 and 52 are shorter to read and more + // bitwise-explicit than some constant's name. + + static final int MIN_DOUBLE_EXPONENT = -1074; + static final int MIN_DOUBLE_NORMAL_EXPONENT = -1022; + static final int MAX_DOUBLE_EXPONENT = 1023; + + static final int MIN_FLOAT_NORMAL_EXPONENT = -126; + static final int MAX_FLOAT_EXPONENT = 127; + + private static final double SQRT_2 = StrictMath.sqrt(2.0); + + static final double LOG_2 = StrictMath.log(2.0); + static final double LOG_TWO_POW_27 = StrictMath.log(TWO_POW_27); + static final double LOG_DOUBLE_MAX_VALUE = StrictMath.log(Double.MAX_VALUE); + + static final double INV_LOG_10 = 1.0/StrictMath.log(10.0); + + static final double DOUBLE_BEFORE_60 = Double.longBitsToDouble(Double.doubleToRawLongBits(60.0)-1); + + //-------------------------------------------------------------------------- + // CONSTANTS FOR NORMALIZATIONS + //-------------------------------------------------------------------------- + + /** + * Table of constants for 1/(PI/2), 282 Hex digits (enough for normalizing doubles). + * 1/(PI/2) approximation = sum of TWO_OVER_PI_TAB[i]*2^(-24*(i+1)). + * + * double and not int, to avoid int-to-double cast during computations. + */ + private static final double TWO_OVER_PI_TAB[] = { + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xe00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991d6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B}; + + /* + * Constants for PI/2. Only the 23 most significant bits of each mantissa are used. + * 2*PI approximation = sum of TWOPI_TAB. + */ + private static final double PIO2_TAB0 = Double.longBitsToDouble(0x3FF921FB40000000L); + private static final double PIO2_TAB1 = Double.longBitsToDouble(0x3E74442D00000000L); + private static final double PIO2_TAB2 = Double.longBitsToDouble(0x3CF8469880000000L); + private static final double PIO2_TAB3 = Double.longBitsToDouble(0x3B78CC5160000000L); + private static final double PIO2_TAB4 = Double.longBitsToDouble(0x39F01B8380000000L); + private static final double PIO2_TAB5 = Double.longBitsToDouble(0x387A252040000000L); + + static final double PIO2_INV = Double.longBitsToDouble(0x3FE45F306DC9C883L); // 6.36619772367581382433e-01 53 bits of 2/pi + static final double PIO2_HI = Double.longBitsToDouble(0x3FF921FB54400000L); // 1.57079632673412561417e+00 first 33 bits of pi/2 + static final double PIO2_LO = Double.longBitsToDouble(0x3DD0B4611A626331L); // 6.07710050650619224932e-11 pi/2 - PIO2_HI + static final double PI_INV = PIO2_INV/2; + static final double PI_HI = 2*PIO2_HI; + static final double PI_LO = 2*PIO2_LO; + static final double TWOPI_INV = PIO2_INV/4; + static final double TWOPI_HI = 4*PIO2_HI; + static final double TWOPI_LO = 4*PIO2_LO; + + /** + * Bit = 0 where quadrant is encoded in remainder bits. + */ + private static final long QUADRANT_BITS_0_MASK = 0xCFFFFFFFFFFFFFFFL; + + /** + * Remainder bits where quadrant is encoded, 0 elsewhere. + */ + private static final long QUADRANT_PLACE_BITS = 0x3000000000000000L; + + /** + * fdlibm uses 2^19*PI/2 here. + * With 2^18*PI/2 we would be more accurate, for example when normalizing + * 822245.903631403, which is close to 2^19*PI/2, but we are still in + * our accuracy tolerance with fdlibm's value (but not 2^20*PI/2) so we + * stick to it, to help being faster than (Strict)Math for values in + * [2^18*PI/2,2^19*PI/2]. + * + * For tests, can use a smaller value, for heavy remainder + * not to only be used with huge values. + */ + static final double NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2 = StrictMath.pow(2.0,19.0)*(Math.PI/2); + + /** + * 2*Math.PI, normalized into [-PI,PI], as returned by + * StrictMath.asin(StrictMath.sin(2*Math.PI)) + * (asin behaves as identity for this). + * + * NB: NumbersUtils.minus2PI(2*Math.PI) returns -2.449293598153844E-16, + * which is different due to not using an accurate enough definition of PI. + */ + static final double TWO_MATH_PI_IN_MINUS_PI_PI = -2.4492935982947064E-16; + + //-------------------------------------------------------------------------- + // CONSTANTS AND TABLES FOR SIN AND COS + //-------------------------------------------------------------------------- + + static final int SIN_COS_TABS_SIZE = (1<>9) / SIN_COS_INDEXER) * 0.99; + + //-------------------------------------------------------------------------- + // CONSTANTS AND TABLES FOR TAN + //-------------------------------------------------------------------------- + + // We use the following formula: + // 1) tan(-x) = -tan(x) + // 2) tan(x) = 1/tan(PI/2-x) + // ---> we only have to compute tan(x) on [0,A] with PI/4<=A= 45deg, and supposed to be >= 51.4deg, as fdlibm code is not + * supposed to work with values inferior to that (51.4deg is about + * (PI/2-Double.longBitsToDouble(0x3FE5942800000000L))). + */ + static final double TAN_MAX_VALUE_FOR_TABS = StrictMath.toRadians(77.0); + + static final int TAN_TABS_SIZE = (int)((TAN_MAX_VALUE_FOR_TABS/(Math.PI/2)) * (TAN_VIRTUAL_TABS_SIZE-1)) + 1; + static final double TAN_DELTA_HI = PIO2_HI/(TAN_VIRTUAL_TABS_SIZE-1); + static final double TAN_DELTA_LO = PIO2_LO/(TAN_VIRTUAL_TABS_SIZE-1); + static final double TAN_INDEXER = 1/(TAN_DELTA_HI+TAN_DELTA_LO); + + static final class MyTTan { + static final double[] tanTab = new double[TAN_TABS_SIZE]; + static final double[] tanDer1DivF1Tab = new double[TAN_TABS_SIZE]; + static final double[] tanDer2DivF2Tab = new double[TAN_TABS_SIZE]; + static final double[] tanDer3DivF3Tab = new double[TAN_TABS_SIZE]; + static final double[] tanDer4DivF4Tab = new double[TAN_TABS_SIZE]; + static { + init(); + } + private static strictfp void init() { + for (int i=0;i>9) / TAN_INDEXER) * 0.99); + + //-------------------------------------------------------------------------- + // CONSTANTS AND TABLES FOR ACOS, ASIN + //-------------------------------------------------------------------------- + + // We use the following formula: + // 1) acos(x) = PI/2 - asin(x) + // 2) asin(-x) = -asin(x) + // ---> we only have to compute asin(x) on [0,1]. + // For values not close to +-1, we use look-up tables; + // for values near +-1, we use code derived from fdlibm. + + /** + * Supposed to be >= sin(77.2deg), as fdlibm code is supposed to work with values > 0.975, + * but seems to work well enough as long as value >= sin(25deg). + */ + static final double ASIN_MAX_VALUE_FOR_TABS = StrictMath.sin(StrictMath.toRadians(73.0)); + + static final int ASIN_TABS_SIZE = (1< we only have to compute atan(x) on [0,+Infinity[. + // For values corresponding to angles not close to +-PI/2, we use look-up tables; + // for values corresponding to angles near +-PI/2, we use code derived from fdlibm. + + /** + * Supposed to be >= tan(67.7deg), as fdlibm code is supposed to work with values > 2.4375. + */ + static final double ATAN_MAX_VALUE_FOR_TABS = StrictMath.tan(StrictMath.toRadians(74.0)); + + static final int ATAN_TABS_SIZE = (1<>SQRT_LO_BITS)); + for (int i=1;i>CBRT_LO_BITS)); + for (int i=1;i= MIN_DOUBLE_EXPONENT) { + if (power <= MAX_DOUBLE_EXPONENT) { // Normal or subnormal. + return MyTTwoPow.twoPowTab[power-MIN_DOUBLE_EXPONENT]; + } else { // Overflow. + return Double.POSITIVE_INFINITY; + } + } else { // Underflow. + return 0.0; + } + } else { + return NumbersUtils.twoPow(power); + } + } + + /** + * @param value An int value. + * @return value*value. + */ + public static int pow2(int value) { + return value*value; + } + + /** + * @param value A long value. + * @return value*value. + */ + public static long pow2(long value) { + return value*value; + } + + /** + * @param value An int value. + * @return value*value*value. + */ + public static int pow3(int value) { + return value*value*value; + } + + /** + * @param value A long value. + * @return value*value*value. + */ + public static long pow3(long value) { + return value*value*value; + } + + /* + * absolute values + */ + + /** + * @param value An int value. + * @return The absolute value, except if value is Integer.MIN_VALUE, for which it returns Integer.MIN_VALUE. + */ + public static int abs(int value) { + if (FM_USE_JDK_MATH || SFM_USE_JDK_MATH) { + return Math.abs(value); + } + return NumbersUtils.abs(value); + } + + /** + * @param value A long value. + * @return The absolute value, except if value is Long.MIN_VALUE, for which it returns Long.MIN_VALUE. + */ + public static long abs(long value) { + if (FM_USE_JDK_MATH || SFM_USE_JDK_MATH) { + return Math.abs(value); + } + return NumbersUtils.abs(value); + } + + /* + * close values + */ + + /** + * @param value A long value. + * @return The specified value as int. + * @throws ArithmeticException if the specified value is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int toIntExact(long value) { + return NumbersUtils.asInt(value); + } + + /** + * @param value A long value. + * @return The closest int value in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int toInt(long value) { + return NumbersUtils.toInt(value); + } + + /* + * ranges + */ + + /** + * @param min An int value. + * @param max An int value. + * @param value An int value. + * @return minValue if value < minValue, maxValue if value > maxValue, value otherwise. + */ + public static int toRange(int min, int max, int value) { + return NumbersUtils.toRange(min, max, value); + } + + /** + * @param min A long value. + * @param max A long value. + * @param value A long value. + * @return min if value < min, max if value > max, value otherwise. + */ + public static long toRange(long min, long max, long value) { + return NumbersUtils.toRange(min, max, value); + } + + /* + * unary operators (increment,decrement,negate) + */ + + /** + * @param value An int value. + * @return The argument incremented by one. + * @throws ArithmeticException if the mathematical result + * is not in int range. + */ + public static int incrementExact(int value) { + if (value == Integer.MAX_VALUE) { + throw new ArithmeticException("integer overflow"); + } + return value + 1; + } + + /** + * @param value A long value. + * @return The argument incremented by one. + * @throws ArithmeticException if the mathematical result + * is not in long range. + */ + public static long incrementExact(long value) { + if (value == Long.MAX_VALUE) { + throw new ArithmeticException("long overflow"); + } + return value + 1L; + } + + /** + * @param value An int value. + * @return The argument incremented by one, or the argument + * if the mathematical result is not in int range. + */ + public static int incrementBounded(int value) { + if (value == Integer.MAX_VALUE) { + return value; + } + return value + 1; + } + + /** + * @param value A long value. + * @return The argument incremented by one, or the argument + * if the mathematical result is not in long range. + */ + public static long incrementBounded(long value) { + if (value == Long.MAX_VALUE) { + return value; + } + return value + 1L; + } + + /** + * @param value An int value. + * @return The argument decremented by one. + * @throws ArithmeticException if the mathematical result + * is not in int range. + */ + public static int decrementExact(int value) { + if (value == Integer.MIN_VALUE) { + throw new ArithmeticException("integer overflow"); + } + return value - 1; + } + + /** + * @param value A long value. + * @return The argument decremented by one. + * @throws ArithmeticException if the mathematical result + * is not in long range. + */ + public static long decrementExact(long value) { + if (value == Long.MIN_VALUE) { + throw new ArithmeticException("long overflow"); + } + return value - 1L; + } + + /** + * @param value An int value. + * @return The argument decremented by one, or the argument + * if the mathematical result is not in int range. + */ + public static int decrementBounded(int value) { + if (value == Integer.MIN_VALUE) { + return value; + } + return value - 1; + } + + /** + * @param value A long value. + * @return The argument decremented by one, or the argument + * if the mathematical result is not in long range. + */ + public static long decrementBounded(long value) { + if (value == Long.MIN_VALUE) { + return value; + } + return value - 1L; + } + + /** + * @param value An int value. + * @return The argument negated. + * @throws ArithmeticException if the mathematical result + * is not in int range. + */ + public static int negateExact(int value) { + if (value == Integer.MIN_VALUE) { + throw new ArithmeticException("integer overflow"); + } + return -value; + } + + /** + * @param value A long value. + * @return The argument negated. + * @throws ArithmeticException if the mathematical result + * is not in long range. + */ + public static long negateExact(long value) { + if (value == Long.MIN_VALUE) { + throw new ArithmeticException("long overflow"); + } + return -value; + } + + /** + * @param value An int value. + * @return The argument negated, or Integer.MAX_VALUE + * if the argument is Integer.MIN_VALUE. + */ + public static int negateBounded(int value) { + if (value == Integer.MIN_VALUE) { + return Integer.MAX_VALUE; + } + return -value; + } + + /** + * @param value A long value. + * @return The argument negated, or Long.MAX_VALUE + * if the argument is Long.MIN_VALUE. + */ + public static long negateBounded(long value) { + if (value == Long.MIN_VALUE) { + return Long.MAX_VALUE; + } + return -value; + } + + /* + * binary operators (+,-,*) + */ + + /** + * @param a An int value. + * @param b An int value. + * @return The mathematical result of a+b. + * @throws ArithmeticException if the mathematical result of a+b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int addExact(int a, int b) { + return NumbersUtils.plusExact(a, b); + } + + /** + * @param a A long value. + * @param b A long value. + * @return The mathematical result of a+b. + * @throws ArithmeticException if the mathematical result of a+b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. + */ + public static long addExact(long a, long b) { + return NumbersUtils.plusExact(a, b); + } + + /** + * @param a An int value. + * @param b An int value. + * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a+b. + */ + public static int addBounded(int a, int b) { + return NumbersUtils.plusBounded(a, b); + } + + /** + * @param a A long value. + * @param b A long value. + * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a+b. + */ + public static long addBounded(long a, long b) { + return NumbersUtils.plusBounded(a, b); + } + + /** + * @param a An int value. + * @param b An int value. + * @return The mathematical result of a-b. + * @throws ArithmeticException if the mathematical result of a-b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int subtractExact(int a, int b) { + return NumbersUtils.minusExact(a, b); + } + + /** + * @param a A long value. + * @param b A long value. + * @return The mathematical result of a-b. + * @throws ArithmeticException if the mathematical result of a-b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. + */ + public static long subtractExact(long a, long b) { + return NumbersUtils.minusExact(a, b); + } + + /** + * @param a An int value. + * @param b An int value. + * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a-b. + */ + public static int subtractBounded(int a, int b) { + return NumbersUtils.minusBounded(a, b); + } + + /** + * @param a A long value. + * @param b A long value. + * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a-b. + */ + public static long subtractBounded(long a, long b) { + return NumbersUtils.minusBounded(a, b); + } + + /** + * @param a An int value. + * @param b An int value. + * @return The mathematical result of a*b. + * @throws ArithmeticException if the mathematical result of a*b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int multiplyExact(int a, int b) { + return NumbersUtils.timesExact(a, b); + } + + /** + * @param a A long value. + * @param b An int value. + * @return The mathematical result of a*b. + * @throws ArithmeticException if the mathematical result of a*b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. + */ + public static long multiplyExact(long a, int b) { + return NumbersUtils.timesExact(a, (long) b); + } + + /** + * @param a A long value. + * @param b A long value. + * @return The mathematical result of a*b. + * @throws ArithmeticException if the mathematical result of a*b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. + */ + public static long multiplyExact(long a, long b) { + return NumbersUtils.timesExact(a, b); + } + + /** + * @param a An int value. + * @param b An int value. + * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a*b. + */ + public static int multiplyBounded(int a, int b) { + return NumbersUtils.timesBounded(a, b); + } + + /** + * @param a A long value. + * @param b An int value. + * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a*b. + */ + public static long multiplyBounded(long a, int b) { + return NumbersUtils.timesBounded(a, (long) b); + } + + /** + * @param a A long value. + * @param b A long value. + * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a*b. + */ + public static long multiplyBounded(long a, long b) { + return NumbersUtils.timesBounded(a, b); + } + + /** + * @param x An int value. + * @param y An int value. + * @return The mathematical product as a long. + */ + public static long multiplyFull(int x, int y) { + return ((long) x) * ((long) y); + } + + /** + * @param x A long value. + * @param y A long value. + * @return The most significant 64 bits of the 128-bit product of two 64-bit factors. + */ + public static long multiplyHigh(long x, long y) { + if ((x|y) < 0) { + // Use technique from section 8-2 of Henry S. Warren, Jr., + // Hacker's Delight (2nd ed.) (Addison Wesley, 2013), 173-174. + long x1 = (x >> 32); + long y1 = (y >> 32); + long x2 = (x & 0xFFFFFFFFL); + long y2 = (y & 0xFFFFFFFFL); + long z2 = x2 * y2; + long t = x1 * y2 + (z2 >>> 32); + long z1 = (t & 0xFFFFFFFFL) + x2 * y1; + long z0 = (t >> 32); + return x1 * y1 + z0 + (z1 >> 32); + } else { + // Use Karatsuba technique with two base 2^32 digits. + long x1 = (x >>> 32); + long y1 = (y >>> 32); + long x2 = (x & 0xFFFFFFFFL); + long y2 = (y & 0xFFFFFFFFL); + long A = x1 * y1; + long B = x2 * y2; + long C = (x1 + x2) * (y1 + y2); + long K = C - A - B; + return (((B >>> 32) + K) >>> 32) + A; + } + } + + /* + * binary operators (/,%) + */ + + /** + * Returns the largest int <= dividend/divisor. + * + * Unlike "/" operator, which rounds towards 0, this division + * rounds towards -Infinity (which give different result + * when the exact result is negative). + * + * @param x The dividend. + * @param y The divisor. + * @return The largest int <= dividend/divisor, unless dividend is + * Integer.MIN_VALUE and divisor is -1, in which case + * Integer.MIN_VALUE is returned. + * @throws ArithmeticException if the divisor is zero. + */ + public static int floorDiv(int x, int y) { + int r = x / y; + // If the signs are different and modulo not zero, rounding down. + if (((x ^ y) < 0) && ((r * y) != x)) { + r--; + } + return r; + } + + /** + * Returns the largest long <= dividend/divisor. + * + * Unlike "/" operator, which rounds towards 0, this division + * rounds towards -Infinity (which give different result + * when the exact result is negative). + * + * @param x The dividend. + * @param y The divisor. + * @return The largest long <= dividend/divisor, unless dividend is + * Long.MIN_VALUE and divisor is -1, in which case + * Long.MIN_VALUE is returned. + * @throws ArithmeticException if the divisor is zero. + */ + public static long floorDiv(long x, int y) { + return floorDiv(x, (long) y); + } + + /** + * Returns the largest long <= dividend/divisor. + * + * Unlike "/" operator, which rounds towards 0, this division + * rounds towards -Infinity (which give different result + * when the exact result is negative). + * + * @param x The dividend. + * @param y The divisor. + * @return The largest long <= dividend/divisor, unless dividend is + * Long.MIN_VALUE and divisor is -1, in which case + * Long.MIN_VALUE is returned. + * @throws ArithmeticException if the divisor is zero. + */ + public static long floorDiv(long x, long y) { + long r = x / y; + // If the signs are different and modulo not zero, rounding down. + if (((x ^ y) < 0) && ((r * y) != x)) { + r--; + } + return r; + } + + /** + * Returns the floor modulus, which is "x - floorDiv(x,y) * y", + * has the same sign as y, and is in ]-abs(y),abs(y)[. + * + * The relationship between floorMod and floorDiv is the same + * than between "%" and "/". + * + * @param x The dividend. + * @param y The divisor. + * @return The floor modulus, i.e. "x - (floorDiv(x, y) * y)". + * @throws ArithmeticException if the divisor is zero. + */ + public static int floorMod(int x, int y) { + return x - floorDiv(x, y) * y; + } + + /** + * Returns the floor modulus, which is "x - floorDiv(x,y) * y", + * has the same sign as y, and is in ]-abs(y),abs(y)[. + * + * The relationship between floorMod and floorDiv is the same + * than between "%" and "/". + * + * @param x The dividend. + * @param y The divisor. + * @return The floor modulus, i.e. "x - (floorDiv(x, y) * y)". + * @throws ArithmeticException if the divisor is zero. + */ + public static int floorMod(long x, int y) { + // No overflow so can cast. + return (int) (x - floorDiv(x,y) * y); + } + + /** + * Returns the floor modulus, which is "x - floorDiv(x,y) * y", + * has the same sign as y, and is in ]-abs(y),abs(y)[. + * + * The relationship between floorMod and floorDiv is the same + * than between "%" and "/". + * + * @param x The dividend. + * @param y The divisor. + * @return The floor modulus, i.e. "x - (floorDiv(x, y) * y)". + * @throws ArithmeticException if the divisor is zero. + */ + public static long floorMod(long x, long y) { + return x - floorDiv(x, y) * y; + } + + /* + * Non-redefined Math public values and treatments. + */ + + public static int min(int a, int b) { + return Math.min(a,b); + } + + public static long min(long a, long b) { + return Math.min(a,b); + } + + public static int max(int a, int b) { + return Math.max(a,b); + } + + public static long max(long a, long b) { + return Math.max(a,b); + } + + //-------------------------------------------------------------------------- + // PACKAGE-PRIVATE METHODS + //-------------------------------------------------------------------------- + + /** + * @param power Must be in normal values range. + */ + static double twoPowNormal(int power) { + if (USE_TWO_POW_TAB) { + return MyTTwoPow.twoPowTab[power-MIN_DOUBLE_EXPONENT]; + } else { + return Double.longBitsToDouble(((long)(power+MAX_DOUBLE_EXPONENT))<<52); + } + } + + /** + * @param power Must be in normal or subnormal values range. + */ + static double twoPowNormalOrSubnormal(int power) { + if (USE_TWO_POW_TAB) { + return MyTTwoPow.twoPowTab[power-MIN_DOUBLE_EXPONENT]; + } else { + if (power <= -MAX_DOUBLE_EXPONENT) { // Not normal. + return Double.longBitsToDouble(0x0008000000000000L>>(-(power+MAX_DOUBLE_EXPONENT))); + } else { // Normal. + return Double.longBitsToDouble(((long)(power+MAX_DOUBLE_EXPONENT))<<52); + } + } + } + + static double atan2_pinf_yyy(double y) { + if (y == Double.POSITIVE_INFINITY) { + return Math.PI/4; + } else if (y == Double.NEGATIVE_INFINITY) { + return -Math.PI/4; + } else if (y > 0.0) { + return 0.0; + } else if (y < 0.0) { + return -0.0; + } else { + return Double.NaN; + } + } + + static double atan2_ninf_yyy(double y) { + if (y == Double.POSITIVE_INFINITY) { + return 3*Math.PI/4; + } else if (y == Double.NEGATIVE_INFINITY) { + return -3*Math.PI/4; + } else if (y > 0.0) { + return Math.PI; + } else if (y < 0.0) { + return -Math.PI; + } else { + return Double.NaN; + } + } + + static double atan2_yyy_zeroOrNaN(double y, double x) { + if (x == 0.0) { + if (y == 0.0) { + if (signFromBit_antiCyclic(x) < 0) { + // x is -0.0 + return signFromBit_antiCyclic(y) * Math.PI; + } else { + // +-0.0 + return y; + } + } + if (y > 0.0) { + return Math.PI/2; + } else if (y < 0.0) { + return -Math.PI/2; + } else { + return Double.NaN; + } + } else { + return Double.NaN; + } + } + + /** + * At least one of the arguments must be NaN. + */ + static double hypot_NaN(double xAbs, double yAbs) { + if ((xAbs == Double.POSITIVE_INFINITY) || (yAbs == Double.POSITIVE_INFINITY)) { + return Double.POSITIVE_INFINITY; + } else { + return Double.NaN; + } + } + + /** + * At least one of the arguments must be NaN. + */ + static double hypot_NaN(double xAbs, double yAbs, double zAbs) { + if ((xAbs == Double.POSITIVE_INFINITY) || (yAbs == Double.POSITIVE_INFINITY) || (zAbs == Double.POSITIVE_INFINITY)) { + return Double.POSITIVE_INFINITY; + } else { + return Double.NaN; + } + } + + /* + * + */ + + /** + * @param remainder Must have 1 for 2nd and 3rd exponent bits, which is the + * case for heavyRemPiO2 remainders (their absolute values are >= + * Double.longBitsToDouble(0x3000000000000000L) + * = 1.727233711018889E-77, and even if they were not, turning these + * bits from 0 to 1 on decoding would not change the absolute error + * much), and also works for +-Infinity or NaN encoding. + * @param quadrant Must be in [0,3]. + * @return Bits holding remainder, and quadrant instead of + * reamainder's 2nd and 3rd exponent bits. + */ + static long encodeRemainderAndQuadrant(double remainder, int quadrant) { + final long bits = Double.doubleToRawLongBits(remainder); + return (bits&QUADRANT_BITS_0_MASK)|(((long)quadrant)<<60); + } + + static double decodeRemainder(long bits) { + return Double.longBitsToDouble((bits&QUADRANT_BITS_0_MASK)|QUADRANT_PLACE_BITS); + } + + static int decodeQuadrant(long bits) { + return ((int)(bits>>60))&3; + } + + /* + * JDK-based remainders. + * Since a strict one for (% (PI/2)) is needed for heavyRemainderPiO2, + * we need it in this class. + * Then, for homogeneity, we put them all in this class. + * Then, to avoid code duplication for these slow-anyway methods, + * we just stick with strict versions, for both FastMath and StrictFastMath. + */ + + /** + * @param angle Angle, in radians. + * @return Remainder of (angle % (2*PI)), in [-PI,PI]. + */ + static strictfp double jdkRemainderTwoPi(double angle) { + final double sin = StrictMath.sin(angle); + final double cos = StrictMath.cos(angle); + return StrictMath.atan2(sin, cos); + } + + /** + * @param angle Angle, in radians. + * @return Remainder of (angle % PI), in [-PI/2,PI/2]. + */ + static strictfp double jdkRemainderPi(double angle) { + final double sin = StrictMath.sin(angle); + final double cos = StrictMath.cos(angle); + /* + * Making sure atan2's result ends up in [-PI/2,PI/2], + * i.e. has maximum accuracy. + */ + return StrictMath.atan2(sin, Math.abs(cos)); + } + + /** + * @param angle Angle, in radians. + * @return Bits of double corresponding to remainder of (angle % (PI/2)), + * in [-PI/4,PI/4], with quadrant encoded in exponent bits. + */ + static strictfp long jdkRemainderPiO2(double angle, boolean negateRem) { + final double sin = StrictMath.sin(angle); + final double cos = StrictMath.cos(angle); + + /* + * Computing quadrant first, and then computing + * atan2, to make sure its result ends up in [-PI/4,PI/4], + * i.e. has maximum accuracy. + */ + + final int q; + final double sinForAtan2; + final double cosForAtan2; + if (cos >= (SQRT_2/2)) { + // [-PI/4,PI/4] + q = 0; + sinForAtan2 = sin; + cosForAtan2 = cos; + } else if (cos <= -(SQRT_2/2)) { + // [3*PI/4,5*PI/4] + q = 2; + sinForAtan2 = -sin; + cosForAtan2 = -cos; + } else if (sin > 0.0) { + // [PI/4,3*PI/4] + q = 1; + sinForAtan2 = -cos; + cosForAtan2 = sin; + } else { + // [5*PI/4,7*PI/4] + q = 3; + sinForAtan2 = cos; + cosForAtan2 = -sin; + } + + double fw = StrictMath.atan2(sinForAtan2, cosForAtan2); + + return encodeRemainderAndQuadrant(negateRem ? -fw : fw, q); + } + + /* + * Our remainders implementations. + */ + + /** + * @param angle Angle, in radians. Must not be NaN nor +-Infinity. + * @return Remainder of (angle % (2*PI)), in [-PI,PI]. + */ + static strictfp double heavyRemainderTwoPi(double angle) { + final long remAndQuad = heavyRemainderPiO2(angle, false); + final double rem = decodeRemainder(remAndQuad); + final int q = decodeQuadrant(remAndQuad); + if (q == 0) { + return rem; + } else if (q == 1) { + return (rem + PIO2_LO) + PIO2_HI; + } else if (q == 2) { + if (rem < 0.0) { + return (rem + PI_LO) + PI_HI; + } else { + return (rem - PI_LO) - PI_HI; + } + } else { + return (rem - PIO2_LO) - PIO2_HI; + } + } + + /** + * @param angle Angle, in radians. Must not be NaN nor +-Infinity. + * @return Remainder of (angle % PI), in [-PI/2,PI/2]. + */ + static strictfp double heavyRemainderPi(double angle) { + final long remAndQuad = heavyRemainderPiO2(angle, false); + final double rem = decodeRemainder(remAndQuad); + final int q = decodeQuadrant(remAndQuad); + if ((q&1) != 0) { + // q is 1 or 3 + if (rem < 0.0) { + return (rem + PIO2_LO) + PIO2_HI; + } else { + return (rem - PIO2_LO) - PIO2_HI; + } + } + return rem; + } + + /** + * Remainder using an accurate definition of PI. + * Derived from a fdlibm treatment called __kernel_rem_pio2. + * + * Not defining a non-strictfp version for FastMath, to avoid duplicating + * its long and messy code, and because it's slow anyway, and should be + * rarely used when speed matters. + * + * @param angle Angle, in radians. Must not be NaN nor +-Infinity. + * @param negateRem True if remainder must be negated before encoded into returned long. + * @return Bits of double corresponding to remainder of (angle % (PI/2)), + * in [-PI/4,PI/4], with quadrant encoded in exponent bits. + */ + static strictfp long heavyRemainderPiO2(double angle, boolean negateRem) { + + /* + * fdlibm treatments unrolled, to avoid garbage and be OOME-free, + * corresponding to: + * 1) initial jk = 4 (precision = 3 = 64 bits (extended)), + * which is more accurate than using precision = 2 + * (53 bits, double), even though we work with doubles + * and use strictfp! + * 2) max lengths of 8 for f[], 6 for q[], fq[] and iq[]. + * 3) at most one recomputation (one goto). + * These limitations were experimentally found to + * be sufficient for billions of random doubles + * of random magnitudes. + * For the rare cases that our unrolled treatments can't handle, + * we fall back to a JDK-based implementation. + */ + + int n,i,j,ih; + double fw; + + /* + * Turning angle into 24-bits integer chunks. + * Done outside __kernel_rem_pio2, but we factor it inside our method. + */ + + // Reworking exponent to have a value < 2^24. + final long lx = Double.doubleToRawLongBits(angle); + final long exp = ((lx>>52)&0x7FF) - (1023+23); + double z = Double.longBitsToDouble(lx - (exp<<52)); + + double x0 = (double)(int)z; + z = (z-x0)*TWO_POW_24; + double x1 = (double)(int)z; + z = (z-x1)*TWO_POW_24; + double x2 = (double)(int)z; + + final int e0 = (int)exp; + // in [1,3] + final int nx = (x2 == 0.0) ? ((x1 == 0.0) ? 1 : 2) : 3; + + /* + * + */ + + double f0,f1,f2,f3,f4,f5,f6,f7; + double q0,q1,q2,q3,q4,q5; + int iq0,iq1,iq2,iq3,iq4,iq5; + + int jk = 4; + + int jx = nx-1; + int jv = Math.max(0,(e0-3)/24); + // In fdlibm, this is q0, but we prefer to use q0 for q[0]. + int qZero = e0-24*(jv+1); + + j = jv-jx; + if (jx == 0) { + f6 = 0.0; + f5 = 0.0; + f4 = (j >= -4) ? TWO_OVER_PI_TAB[j+4] : 0.0; + f3 = (j >= -3) ? TWO_OVER_PI_TAB[j+3] : 0.0; + f2 = (j >= -2) ? TWO_OVER_PI_TAB[j+2] : 0.0; + f1 = (j >= -1) ? TWO_OVER_PI_TAB[j+1] : 0.0; + f0 = (j >= 0) ? TWO_OVER_PI_TAB[j] : 0.0; + + q0 = x0*f0; + q1 = x0*f1; + q2 = x0*f2; + q3 = x0*f3; + q4 = x0*f4; + } else if (jx == 1) { + f6 = 0.0; + f5 = (j >= -5) ? TWO_OVER_PI_TAB[j+5] : 0.0; + f4 = (j >= -4) ? TWO_OVER_PI_TAB[j+4] : 0.0; + f3 = (j >= -3) ? TWO_OVER_PI_TAB[j+3] : 0.0; + f2 = (j >= -2) ? TWO_OVER_PI_TAB[j+2] : 0.0; + f1 = (j >= -1) ? TWO_OVER_PI_TAB[j+1] : 0.0; + f0 = (j >= 0) ? TWO_OVER_PI_TAB[j] : 0.0; + + q0 = x0*f1 + x1*f0; + q1 = x0*f2 + x1*f1; + q2 = x0*f3 + x1*f2; + q3 = x0*f4 + x1*f3; + q4 = x0*f5 + x1*f4; + } else { // jx == 2 + f6 = (j >= -6) ? TWO_OVER_PI_TAB[j+6] : 0.0; + f5 = (j >= -5) ? TWO_OVER_PI_TAB[j+5] : 0.0; + f4 = (j >= -4) ? TWO_OVER_PI_TAB[j+4] : 0.0; + f3 = (j >= -3) ? TWO_OVER_PI_TAB[j+3] : 0.0; + f2 = (j >= -2) ? TWO_OVER_PI_TAB[j+2] : 0.0; + f1 = (j >= -1) ? TWO_OVER_PI_TAB[j+1] : 0.0; + f0 = (j >= 0) ? TWO_OVER_PI_TAB[j] : 0.0; + + q0 = x0*f2 + x1*f1 + x2*f0; + q1 = x0*f3 + x1*f2 + x2*f1; + q2 = x0*f4 + x1*f3 + x2*f2; + q3 = x0*f5 + x1*f4 + x2*f3; + q4 = x0*f6 + x1*f5 + x2*f4; + } + + double twoPowQZero = twoPowNormal(qZero); + + int jz = jk; + + /* + * Unrolling of first round. + */ + + z = q4; + fw = (double)(int)(TWO_POW_N24*z); + iq0 = (int)(z-TWO_POW_24*fw); + z = q3+fw; + fw = (double)(int)(TWO_POW_N24*z); + iq1 = (int)(z-TWO_POW_24*fw); + z = q2+fw; + fw = (double)(int)(TWO_POW_N24*z); + iq2 = (int)(z-TWO_POW_24*fw); + z = q1+fw; + fw = (double)(int)(TWO_POW_N24*z); + iq3 = (int)(z-TWO_POW_24*fw); + z = q0+fw; + iq4 = 0; + iq5 = 0; + + z = (z*twoPowQZero) % 8.0; + n = (int)z; + z -= (double)n; + + ih = 0; + if (qZero > 0) { + // Parentheses against code formatter bug. + i = (iq3>>(24-qZero)); + n += i; + iq3 -= i<<(24-qZero); + ih = iq3>>(23-qZero); + } else if (qZero == 0) { + ih = iq3>>23; + } else if (z >= 0.5) { + ih = 2; + } + + if (ih > 0) { + n += 1; + // carry = 1 is common case, + // so using it as initial value. + int carry = 1; + if (iq0 != 0) { + iq0 = 0x1000000 - iq0; + iq1 = 0xFFFFFF - iq1; + iq2 = 0xFFFFFF - iq2; + iq3 = 0xFFFFFF - iq3; + } else if (iq1 != 0) { + iq1 = 0x1000000 - iq1; + iq2 = 0xFFFFFF - iq2; + iq3 = 0xFFFFFF - iq3; + } else if (iq2 != 0) { + iq2 = 0x1000000 - iq2; + iq3 = 0xFFFFFF - iq3; + } else if (iq3 != 0) { + iq3 = 0x1000000 - iq3; + } else { + carry = 0; + } + if (qZero > 0) { + if (qZero == 1) { + iq3 &= 0x7FFFFF; + } else if (qZero == 2) { + iq3 &= 0x3FFFFF; + } + } + if (ih == 2) { + z = 1.0 - z; + if (carry != 0) { + z -= twoPowQZero; + } + } + } + + if (z == 0.0) { + if (iq3 == 0) { + // With random values of random magnitude, + // probability for this to happen seems lower than 1e-6. + // jz would be more than just incremented by one, + // which our unrolling doesn't support. + return jdkRemainderPiO2(angle, negateRem); + } + if (jx == 0) { + f5 = TWO_OVER_PI_TAB[jv+5]; + q5 = x0*f5; + } else if (jx == 1) { + f6 = TWO_OVER_PI_TAB[jv+5]; + q5 = x0*f6 + x1*f5; + } else { // jx == 2 + f7 = TWO_OVER_PI_TAB[jv+5]; + q5 = x0*f7 + x1*f6 + x2*f5; + } + + jz++; + + /* + * Unrolling of second round. + */ + + z = q5; + fw = (double)(int)(TWO_POW_N24*z); + iq0 = (int)(z-TWO_POW_24*fw); + z = q4+fw; + fw = (double)(int)(TWO_POW_N24*z); + iq1 = (int)(z-TWO_POW_24*fw); + z = q3+fw; + fw = (double)(int)(TWO_POW_N24*z); + iq2 = (int)(z-TWO_POW_24*fw); + z = q2+fw; + fw = (double)(int)(TWO_POW_N24*z); + iq3 = (int)(z-TWO_POW_24*fw); + z = q1+fw; + fw = (double)(int)(TWO_POW_N24*z); + iq4 = (int)(z-TWO_POW_24*fw); + z = q0+fw; + iq5 = 0; + + z = (z*twoPowQZero) % 8.0; + n = (int)z; + z -= (double)n; + + ih = 0; + if (qZero > 0) { + // Parentheses against code formatter bug. + i = (iq4>>(24-qZero)); + n += i; + iq4 -= i<<(24-qZero); + ih = iq4>>(23-qZero); + } else if (qZero == 0) { + ih = iq4>>23; + } else if (z >= 0.5) { + ih = 2; + } + + if (ih > 0) { + n += 1; + // carry = 1 is common case, + // so using it as initial value. + int carry = 1; + if (iq0 != 0) { + iq0 = 0x1000000 - iq0; + iq1 = 0xFFFFFF - iq1; + iq2 = 0xFFFFFF - iq2; + iq3 = 0xFFFFFF - iq3; + iq4 = 0xFFFFFF - iq4; + } else if (iq1 != 0) { + iq1 = 0x1000000 - iq1; + iq2 = 0xFFFFFF - iq2; + iq3 = 0xFFFFFF - iq3; + iq4 = 0xFFFFFF - iq4; + } else if (iq2 != 0) { + iq2 = 0x1000000 - iq2; + iq3 = 0xFFFFFF - iq3; + iq4 = 0xFFFFFF - iq4; + } else if (iq3 != 0) { + iq3 = 0x1000000 - iq3; + iq4 = 0xFFFFFF - iq4; + } else if (iq4 != 0) { + iq4 = 0x1000000 - iq4; + } else { + carry = 0; + } + if (qZero > 0) { + if (qZero == 1) { + iq4 &= 0x7FFFFF; + } else if (qZero == 2) { + iq4 &= 0x3FFFFF; + } + } + if (ih == 2) { + z = 1.0 - z; + if (carry != 0) { + z -= twoPowQZero; + } + } + } + + if (z == 0.0) { + if (iq4 == 0) { + // Case not encountered in tests, but still handling it. + // Would require a third loop unrolling. + return jdkRemainderPiO2(angle, negateRem); + } else { + // z == 0.0, and iq4 != 0, + // so we remove 24 from qZero only once, + // but since we no longer use qZero, + // we just bother to multiply its 2-power + // by 2^-24. + jz--; + twoPowQZero *= TWO_POW_N24; + } + } else { + // z != 0.0 at end of second round. + } + } else { + // z != 0.0 at end of first round. + } + + /* + * After loop. + */ + + if (z != 0.0) { + z /= twoPowQZero; + if (z >= TWO_POW_24) { + fw = (double)(int)(TWO_POW_N24*z); + if (jz == jk) { + iq4 = (int)(z-TWO_POW_24*fw); + jz++; // jz to 5 + // Not using qZero anymore so not updating it. + twoPowQZero *= TWO_POW_24; + iq5 = (int)fw; + } else { // jz == jk+1 == 5 + // Case not encountered in tests, but still handling it. + // Would require use of iq6, with jz = 6. + return jdkRemainderPiO2(angle, negateRem); + } + } else { + if (jz == jk) { + iq4 = (int)z; + } else { // jz == jk+1 == 5 + // Case not encountered in tests, but still handling it. + iq5 = (int)z; + } + } + } + + fw = twoPowQZero; + + if (jz == 5) { + q5 = fw*(double)iq5; + fw *= TWO_POW_N24; + } else { + q5 = 0.0; + } + q4 = fw*(double)iq4; + fw *= TWO_POW_N24; + q3 = fw*(double)iq3; + fw *= TWO_POW_N24; + q2 = fw*(double)iq2; + fw *= TWO_POW_N24; + q1 = fw*(double)iq1; + fw *= TWO_POW_N24; + q0 = fw*(double)iq0; + + /* + * We just use HI part of the result. + */ + + fw = PIO2_TAB0*q5; + fw += PIO2_TAB0*q4 + PIO2_TAB1*q5; + fw += PIO2_TAB0*q3 + PIO2_TAB1*q4 + PIO2_TAB2*q5; + fw += PIO2_TAB0*q2 + PIO2_TAB1*q3 + PIO2_TAB2*q4 + PIO2_TAB3*q5; + fw += PIO2_TAB0*q1 + PIO2_TAB1*q2 + PIO2_TAB2*q3 + PIO2_TAB3*q4 + PIO2_TAB4*q5; + fw += PIO2_TAB0*q0 + PIO2_TAB1*q1 + PIO2_TAB2*q2 + PIO2_TAB3*q3 + PIO2_TAB4*q4 + PIO2_TAB5*q5; + + if ((ih != 0) ^ negateRem) { + fw = -fw; + } + + return encodeRemainderAndQuadrant(fw, n&3); + } + + //-------------------------------------------------------------------------- + // PRIVATE METHODS + //-------------------------------------------------------------------------- + + /** + * Redefined here, to avoid cyclic dependency with (Strict)FastMath. + * + * @param value A double value. + * @return -1 if sign bit is 1, 1 if sign bit is 0. + */ + private static long signFromBit_antiCyclic(double value) { + // Returning a long, to avoid useless cast into int. + return ((Double.doubleToRawLongBits(value)>>62)|1); + } + + private static boolean getBooleanProperty( + final String key, + boolean defaultValue) { + final String tmp = System.getProperty(key); + if (tmp != null) { + return Boolean.parseBoolean(tmp); + } else { + return defaultValue; + } + } + + /** + * Use look-up tables size power through this method, + * to make sure is it small in case java.lang.Math + * is directly used. + */ + private static int getTabSizePower(int tabSizePower) { + return (FM_USE_JDK_MATH && SFM_USE_JDK_MATH) ? Math.min(2, tabSizePower) : tabSizePower; + } +} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/DoubleWrapper.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/DoubleWrapper.java new file mode 100644 index 000000000..e7adc8d59 --- /dev/null +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/DoubleWrapper.java @@ -0,0 +1,13 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package space.kscience.kmath.jafama; + +public class DoubleWrapper { + public double value; + @Override + public String toString() { + return Double.toString(this.value); + } +} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/FastMath.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/FastMath.java new file mode 100644 index 000000000..a83c01f7b --- /dev/null +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/FastMath.java @@ -0,0 +1,2986 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.jafama; + +/** + * Faster (hopefully) versions of java.lang.Math methods, plus additional ones. + * Cf. README.txt for more info. + */ +public final class FastMath extends CmnFastMath { + + //-------------------------------------------------------------------------- + // CONFIGURATION + //-------------------------------------------------------------------------- + + private static final boolean USE_JDK_MATH = FM_USE_JDK_MATH; + + private static final boolean USE_REDEFINED_LOG = FM_USE_REDEFINED_LOG; + + private static final boolean USE_REDEFINED_SQRT = FM_USE_REDEFINED_SQRT; + + private static final boolean USE_POWTABS_FOR_ASIN = FM_USE_POWTABS_FOR_ASIN; + + //-------------------------------------------------------------------------- + // PUBLIC METHODS + //-------------------------------------------------------------------------- + + /* + * trigonometry + */ + + /** + * @param angle Angle in radians. + * @return Angle sine. + */ + public static double sin(double angle) { + if (USE_JDK_MATH) { + return Math.sin(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { + if (false) { + // Can give very bad relative error near PI (mod 2*PI). + angle = remainderTwoPi(angle); + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } else { + final long remAndQuad = remainderPiO2(angle); + angle = decodeRemainder(remAndQuad); + final double sin; + final int q = decodeQuadrant(remAndQuad); + if (q == 0) { + sin = sin(angle); + } else if (q == 1) { + sin = cos(angle); + } else if (q == 2) { + sin = -sin(angle); + } else { + sin = -cos(angle); + } + return (negateResult ? -sin : sin); + } + } + // index: possibly outside tables range. + int index = (int)(angle * SIN_COS_INDEXER + 0.5); + double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; + // Making sure index is within tables range. + // Last value of each table is the same than first, + // so we ignore it (tabs size minus one) for modulo. + index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) + double indexSin = MyTSinCos.sinTab[index]; + double indexCos = MyTSinCos.cosTab[index]; + double result = indexSin + delta * (indexCos + delta * (-indexSin * ONE_DIV_F2 + delta * (-indexCos * ONE_DIV_F3 + delta * indexSin * ONE_DIV_F4))); + return negateResult ? -result : result; + } + + /** + * Quick sin, with accuracy of about 1.6e-3 (PI/) + * for |angle| < 6588395.0 (Integer.MAX_VALUE * (2*PI/) - 2) + * (- 2 due to removing PI/2 before using cosine tab), + * and no accuracy at all for larger values. + * + * @param angle Angle in radians. + * @return Angle sine. + */ + public static double sinQuick(double angle) { + if (USE_JDK_MATH) { + return Math.sin(angle); + } + return MyTSinCos.cosTab[((int)(Math.abs(angle-Math.PI/2) * SIN_COS_INDEXER + 0.5)) & (SIN_COS_TABS_SIZE-2)]; + } + + /** + * @param angle Angle in radians. + * @return Angle cosine. + */ + public static double cos(double angle) { + if (USE_JDK_MATH) { + return Math.cos(angle); + } + angle = Math.abs(angle); + if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { + if (false) { + // Can give very bad relative error near PI (mod 2*PI). + angle = remainderTwoPi(angle); + if (angle < 0.0) { + angle = -angle; + } + } else { + final long remAndQuad = remainderPiO2(angle); + angle = decodeRemainder(remAndQuad); + final double cos; + final int q = decodeQuadrant(remAndQuad); + if (q == 0) { + cos = cos(angle); + } else if (q == 1) { + cos = -sin(angle); + } else if (q == 2) { + cos = -cos(angle); + } else { + cos = sin(angle); + } + return cos; + } + } + // index: possibly outside tables range. + int index = (int)(angle * SIN_COS_INDEXER + 0.5); + double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; + // Making sure index is within tables range. + // Last value of each table is the same than first, + // so we ignore it (tabs size minus one) for modulo. + index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) + double indexCos = MyTSinCos.cosTab[index]; + double indexSin = MyTSinCos.sinTab[index]; + return indexCos + delta * (-indexSin + delta * (-indexCos * ONE_DIV_F2 + delta * (indexSin * ONE_DIV_F3 + delta * indexCos * ONE_DIV_F4))); + } + + /** + * Quick cos, with accuracy of about 1.6e-3 (PI/) + * for |angle| < 6588397.0 (Integer.MAX_VALUE * (2*PI/)), + * and no accuracy at all for larger values. + * + * @param angle Angle in radians. + * @return Angle cosine. + */ + public static double cosQuick(double angle) { + if (USE_JDK_MATH) { + return Math.cos(angle); + } + return MyTSinCos.cosTab[((int)(Math.abs(angle) * SIN_COS_INDEXER + 0.5)) & (SIN_COS_TABS_SIZE-2)]; + } + + /** + * Computes sine and cosine together. + * + * @param angle Angle in radians. + * @param cosine (out) Angle cosine. + * @return Angle sine. + */ + public static double sinAndCos(double angle, DoubleWrapper cosine) { + if (USE_JDK_MATH) { + cosine.value = Math.cos(angle); + return Math.sin(angle); + } + // Using the same algorithm than sin(double) method, + // and computing also cosine at the end. + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { + if (false) { + // Can give very bad relative error near PI (mod 2*PI). + angle = remainderTwoPi(angle); + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } else { + final long remAndQuad = remainderPiO2(angle); + angle = decodeRemainder(remAndQuad); + final double sin; + final int q = decodeQuadrant(remAndQuad); + if (q == 0) { + sin = sin(angle); + cosine.value = cos(angle); + } else if (q == 1) { + sin = cos(angle); + cosine.value = -sin(angle); + } else if (q == 2) { + sin = -sin(angle); + cosine.value = -cos(angle); + } else { + sin = -cos(angle); + cosine.value = sin(angle); + } + return (negateResult ? -sin : sin); + } + } + int index = (int)(angle * SIN_COS_INDEXER + 0.5); + double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; + index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) + double indexSin = MyTSinCos.sinTab[index]; + double indexCos = MyTSinCos.cosTab[index]; + // Could factor some multiplications (delta * factorials), but then is less accurate. + cosine.value = indexCos + delta * (-indexSin + delta * (-indexCos * ONE_DIV_F2 + delta * (indexSin * ONE_DIV_F3 + delta * indexCos * ONE_DIV_F4))); + double result = indexSin + delta * (indexCos + delta * (-indexSin * ONE_DIV_F2 + delta * (-indexCos * ONE_DIV_F3 + delta * indexSin * ONE_DIV_F4))); + return negateResult ? -result : result; + } + + /** + * Can have very bad relative error near +-PI/2, + * but of the same magnitude than the relative delta between + * StrictMath.tan(PI/2) and StrictMath.tan(nextDown(PI/2)). + * + * @param angle Angle in radians. + * @return Angle tangent. + */ + public static double tan(double angle) { + if (USE_JDK_MATH) { + return Math.tan(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle > TAN_MAX_VALUE_FOR_INT_MODULO) { + angle = remainderPi(angle); + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } + // index: possibly outside tables range. + int index = (int)(angle * TAN_INDEXER + 0.5); + double delta = (angle - index * TAN_DELTA_HI) - index * TAN_DELTA_LO; + // Making sure index is within tables range. + // index modulo PI, i.e. 2*(virtual tab size minus one). + index &= (2*(TAN_VIRTUAL_TABS_SIZE-1)-1); // index % (2*(TAN_VIRTUAL_TABS_SIZE-1)) + // Here, index is in [0,2*(TAN_VIRTUAL_TABS_SIZE-1)-1], i.e. indicates an angle in [0,PI[. + if (index > (TAN_VIRTUAL_TABS_SIZE-1)) { + index = (2*(TAN_VIRTUAL_TABS_SIZE-1)) - index; + delta = -delta; + negateResult = !negateResult; + } + double result; + if (index < TAN_TABS_SIZE) { + result = MyTTan.tanTab[index] + + delta * (MyTTan.tanDer1DivF1Tab[index] + + delta * (MyTTan.tanDer2DivF2Tab[index] + + delta * (MyTTan.tanDer3DivF3Tab[index] + + delta * MyTTan.tanDer4DivF4Tab[index]))); + } else { // angle in ]TAN_MAX_VALUE_FOR_TABS,TAN_MAX_VALUE_FOR_INT_MODULO], or angle is NaN + // Using tan(angle) == 1/tan(PI/2-angle) formula: changing angle (index and delta), and inverting. + index = (TAN_VIRTUAL_TABS_SIZE-1) - index; + result = 1/(MyTTan.tanTab[index] + - delta * (MyTTan.tanDer1DivF1Tab[index] + - delta * (MyTTan.tanDer2DivF2Tab[index] + - delta * (MyTTan.tanDer3DivF3Tab[index] + - delta * MyTTan.tanDer4DivF4Tab[index])))); + } + return negateResult ? -result : result; + } + + /** + * @param value Value in [-1,1]. + * @return Value arcsine, in radians, in [-PI/2,PI/2]. + */ + public static double asin(double value) { + if (USE_JDK_MATH) { + return Math.asin(value); + } + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + if (value <= ASIN_MAX_VALUE_FOR_TABS) { + int index = (int)(value * ASIN_INDEXER + 0.5); + double delta = value - index * ASIN_DELTA; + double result = MyTAsin.asinTab[index] + + delta * (MyTAsin.asinDer1DivF1Tab[index] + + delta * (MyTAsin.asinDer2DivF2Tab[index] + + delta * (MyTAsin.asinDer3DivF3Tab[index] + + delta * MyTAsin.asinDer4DivF4Tab[index]))); + return negateResult ? -result : result; + } else if (USE_POWTABS_FOR_ASIN && (value <= ASIN_MAX_VALUE_FOR_POWTABS)) { + int index = (int)(powFast(value * ASIN_POWTABS_ONE_DIV_MAX_VALUE, ASIN_POWTABS_POWER) * ASIN_POWTABS_SIZE_MINUS_ONE + 0.5); + double delta = value - MyTAsinPow.asinParamPowTab[index]; + double result = MyTAsinPow.asinPowTab[index] + + delta * (MyTAsinPow.asinDer1DivF1PowTab[index] + + delta * (MyTAsinPow.asinDer2DivF2PowTab[index] + + delta * (MyTAsinPow.asinDer3DivF3PowTab[index] + + delta * MyTAsinPow.asinDer4DivF4PowTab[index]))); + return negateResult ? -result : result; + } else { // value > ASIN_MAX_VALUE_FOR_TABS, or value is NaN + // This part is derived from fdlibm. + if (value < 1.0) { + double t = (1.0 - value)*0.5; + double p = t*(ASIN_PS0+t*(ASIN_PS1+t*(ASIN_PS2+t*(ASIN_PS3+t*(ASIN_PS4+t*ASIN_PS5))))); + double q = 1.0+t*(ASIN_QS1+t*(ASIN_QS2+t*(ASIN_QS3+t*ASIN_QS4))); + double s = sqrt(t); + double z = s+s*(p/q); + double result = ASIN_PIO2_HI-((z+z)-ASIN_PIO2_LO); + return negateResult ? -result : result; + } else { // value >= 1.0, or value is NaN + if (value == 1.0) { + return negateResult ? -Math.PI/2 : Math.PI/2; + } else { + return Double.NaN; + } + } + } + } + + /** + * If value is not NaN and is outside [-1,1] range, closest value in this range is used. + * + * @param value Value in [-1,1]. + * @return Value arcsine, in radians, in [-PI/2,PI/2]. + */ + public static double asinInRange(double value) { + if (value <= -1.0) { + return -Math.PI/2; + } else if (value >= 1.0) { + return Math.PI/2; + } else { + return asin(value); + } + } + + /** + * @param value Value in [-1,1]. + * @return Value arccosine, in radians, in [0,PI]. + */ + public static double acos(double value) { + if (USE_JDK_MATH) { + return Math.acos(value); + } + return Math.PI/2 - asin(value); + } + + /** + * If value is not NaN and is outside [-1,1] range, + * closest value in this range is used. + * + * @param value Value in [-1,1]. + * @return Value arccosine, in radians, in [0,PI]. + */ + public static double acosInRange(double value) { + if (value <= -1.0) { + return Math.PI; + } else if (value >= 1.0) { + return 0.0; + } else { + return acos(value); + } + } + + /** + * @param value A double value. + * @return Value arctangent, in radians, in [-PI/2,PI/2]. + */ + public static double atan(double value) { + if (USE_JDK_MATH) { + return Math.atan(value); + } + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + if (value == 1.0) { + // We want "exact" result for 1.0. + return negateResult ? -Math.PI/4 : Math.PI/4; + } else if (value <= ATAN_MAX_VALUE_FOR_TABS) { + int index = (int)(value * ATAN_INDEXER + 0.5); + double delta = value - index * ATAN_DELTA; + double result = MyTAtan.atanTab[index] + + delta * (MyTAtan.atanDer1DivF1Tab[index] + + delta * (MyTAtan.atanDer2DivF2Tab[index] + + delta * (MyTAtan.atanDer3DivF3Tab[index] + + delta * MyTAtan.atanDer4DivF4Tab[index]))); + return negateResult ? -result : result; + } else { // value > ATAN_MAX_VALUE_FOR_TABS, or value is NaN + // This part is derived from fdlibm. + if (value < TWO_POW_66) { + double x = -1/value; + double x2 = x*x; + double x4 = x2*x2; + double s1 = x2*(ATAN_AT0+x4*(ATAN_AT2+x4*(ATAN_AT4+x4*(ATAN_AT6+x4*(ATAN_AT8+x4*ATAN_AT10))))); + double s2 = x4*(ATAN_AT1+x4*(ATAN_AT3+x4*(ATAN_AT5+x4*(ATAN_AT7+x4*ATAN_AT9)))); + double result = ATAN_HI3-((x*(s1+s2)-ATAN_LO3)-x); + return negateResult ? -result : result; + } else { // value >= 2^66, or value is NaN + if (value != value) { + return Double.NaN; + } else { + return negateResult ? -Math.PI/2 : Math.PI/2; + } + } + } + } + + /** + * For special values for which multiple conventions could be adopted, + * behaves like Math.atan2(double,double). + * + * @param y Coordinate on y axis. + * @param x Coordinate on x axis. + * @return Angle from x axis positive side to (x,y) position, in radians, in [-PI,PI]. + * Angle measure is positive when going from x axis to y axis (positive sides). + */ + public static double atan2(double y, double x) { + if (USE_JDK_MATH) { + return Math.atan2(y,x); + } + /* + * Using sub-methods, to make method lighter for general case, + * and to avoid JIT-optimization crash on NaN. + */ + if (x > 0.0) { + if (y == 0.0) { + // +-0.0 + return y; + } + if (x == Double.POSITIVE_INFINITY) { + return atan2_pinf_yyy(y); + } else { + return atan(y/x); + } + } else if (x < 0.0) { + if (y == 0.0) { + return signFromBit(y) * Math.PI; + } + if (x == Double.NEGATIVE_INFINITY) { + return atan2_ninf_yyy(y); + } else if (y > 0.0) { + return Math.PI/2 - atan(x/y); + } else if (y < 0.0) { + return -Math.PI/2 - atan(x/y); + } else { + return Double.NaN; + } + } else { + return atan2_yyy_zeroOrNaN(y, x); + } + } + + /** + * Gives same result as Math.toRadians for some particular values + * like 90.0, 180.0 or 360.0, but is faster (no division). + * + * @param angdeg Angle value in degrees. + * @return Angle value in radians. + */ + public static double toRadians(double angdeg) { + if (USE_JDK_MATH) { + return Math.toRadians(angdeg); + } + return angdeg * (Math.PI/180); + } + + /** + * Gives same result as Math.toDegrees for some particular values + * like Math.PI/2, Math.PI or 2*Math.PI, but is faster (no division). + * + * @param angrad Angle value in radians. + * @return Angle value in degrees. + */ + public static double toDegrees(double angrad) { + if (USE_JDK_MATH) { + return Math.toDegrees(angrad); + } + return angrad * (180/Math.PI); + } + + /** + * @param sign Sign of the angle: true for positive, false for negative. + * @param degrees Degrees, in [0,180]. + * @param minutes Minutes, in [0,59]. + * @param seconds Seconds, in [0.0,60.0[. + * @return Angle in radians. + */ + public static double toRadians(boolean sign, int degrees, int minutes, double seconds) { + return toRadians(toDegrees(sign, degrees, minutes, seconds)); + } + + /** + * @param sign Sign of the angle: true for positive, false for negative. + * @param degrees Degrees, in [0,180]. + * @param minutes Minutes, in [0,59]. + * @param seconds Seconds, in [0.0,60.0[. + * @return Angle in degrees. + */ + public static double toDegrees(boolean sign, int degrees, int minutes, double seconds) { + double signFactor = sign ? 1.0 : -1.0; + return signFactor * (degrees + (1.0/60)*(minutes + (1.0/60)*seconds)); + } + + /** + * @param angrad Angle in radians. + * @param degrees (out) Degrees, in [0,180]. + * @param minutes (out) Minutes, in [0,59]. + * @param seconds (out) Seconds, in [0.0,60.0[. + * @return true if the resulting angle in [-180deg,180deg] is positive, false if it is negative. + */ + public static boolean toDMS(double angrad, IntWrapper degrees, IntWrapper minutes, DoubleWrapper seconds) { + // Computing longitude DMS. + double tmp = toDegrees(normalizeMinusPiPi(angrad)); + boolean isNeg = (tmp < 0.0); + if (isNeg) { + tmp = -tmp; + } + degrees.value = (int)tmp; + tmp = (tmp-degrees.value)*60.0; + minutes.value = (int)tmp; + seconds.value = Math.min((tmp-minutes.value)*60.0,DOUBLE_BEFORE_60); + return !isNeg; + } + + /** + * NB: Since 2*Math.PI < 2*PI, a span of 2*Math.PI does not mean full angular range. + * ex.: isInClockwiseDomain(0.0, 2*Math.PI, -1e-20) returns false. + * ---> For full angular range, use a span > 2*Math.PI, like 2*PI_SUP constant of this class. + * + * @param startAngRad An angle, in radians. + * @param angSpanRad An angular span, >= 0.0, in radians. + * @param angRad An angle, in radians. + * @return true if angRad is in the clockwise angular domain going from startAngRad, over angSpanRad, + * extremities included, false otherwise. + */ + public static boolean isInClockwiseDomain(double startAngRad, double angSpanRad, double angRad) { + if (Math.abs(angRad) < -TWO_MATH_PI_IN_MINUS_PI_PI) { + // special case for angular values of small magnitude + if (angSpanRad <= 2*Math.PI) { + if (angSpanRad < 0.0) { + // empty domain + return false; + } + // angSpanRad is in [0,2*PI] + startAngRad = normalizeMinusPiPi(startAngRad); + double endAngRad = normalizeMinusPiPi(startAngRad + angSpanRad); + if (startAngRad <= endAngRad) { + return (angRad >= startAngRad) && (angRad <= endAngRad); + } else { + return (angRad >= startAngRad) || (angRad <= endAngRad); + } + } else { // angSpanRad > 2*Math.PI, or is NaN + return (angSpanRad == angSpanRad); + } + } else { + // general case + return (normalizeZeroTwoPi(angRad - startAngRad) <= angSpanRad); + } + } + + /* + * hyperbolic trigonometry + */ + + /** + * Some properties of sinh(x) = (exp(x)-exp(-x))/2: + * 1) defined on ]-Infinity,+Infinity[ + * 2) result in ]-Infinity,+Infinity[ + * 3) sinh(x) = -sinh(-x) (implies sinh(0) = 0) + * 4) sinh(epsilon) ~= epsilon + * 5) lim(sinh(x),x->+Infinity) = +Infinity + * (y increasing exponentially faster than x) + * 6) reaches +Infinity (double overflow) for x >= 710.475860073944, + * i.e. a bit further than exp(x) + * + * @param value A double value. + * @return Value hyperbolic sine. + */ + public static double sinh(double value) { + if (USE_JDK_MATH) { + return Math.sinh(value); + } + // sinh(x) = (exp(x)-exp(-x))/2 + double h; + if (value < 0.0) { + value = -value; + h = -0.5; + } else { + h = 0.5; + } + if (value < 22.0) { + if (value < TWO_POW_N28) { + return (h < 0.0) ? -value : value; + } else { + // sinh(x) + // = (exp(x)-exp(-x))/2 + // = (exp(x)-1/exp(x))/2 + // = (expm1(x) + 1 - 1/(expm1(x)+1))/2 + // = (expm1(x) + (expm1(x)+1)/(expm1(x)+1) - 1/(expm1(x)+1))/2 + // = (expm1(x) + expm1(x)/(expm1(x)+1))/2 + double t = expm1(value); + // Might be more accurate, if value < 1: return h*((t+t)-t*t/(t+1.0)). + return h * (t + t/(t+1.0)); + } + } else if (value < LOG_DOUBLE_MAX_VALUE) { + return h * exp(value); + } else { + double t = exp(value*0.5); + return (h*t)*t; + } + } + + /** + * Some properties of cosh(x) = (exp(x)+exp(-x))/2: + * 1) defined on ]-Infinity,+Infinity[ + * 2) result in [1,+Infinity[ + * 3) cosh(0) = 1 + * 4) cosh(x) = cosh(-x) + * 5) lim(cosh(x),x->+Infinity) = +Infinity + * (y increasing exponentially faster than x) + * 6) reaches +Infinity (double overflow) for x >= 710.475860073944, + * i.e. a bit further than exp(x) + * + * @param value A double value. + * @return Value hyperbolic cosine. + */ + public static double cosh(double value) { + if (USE_JDK_MATH) { + return Math.cosh(value); + } + // cosh(x) = (exp(x)+exp(-x))/2 + if (value < 0.0) { + value = -value; + } + if (value < LOG_TWO_POW_27) { + if (value < TWO_POW_N27) { + // cosh(x) + // = (exp(x)+exp(-x))/2 + // = ((1+x+x^2/2!+...) + (1-x+x^2/2!-...))/2 + // = 1+x^2/2!+x^4/4!+... + // For value of x small in magnitude, the sum of the terms does not add to 1. + return 1; + } else { + // cosh(x) + // = (exp(x)+exp(-x))/2 + // = (exp(x)+1/exp(x))/2 + double t = exp(value); + return 0.5 * (t+1/t); + } + } else if (value < LOG_DOUBLE_MAX_VALUE) { + return 0.5 * exp(value); + } else { + double t = exp(value*0.5); + return (0.5*t)*t; + } + } + + /** + * Much more accurate than cosh(value)-1, + * for arguments (and results) close to zero. + * + * coshm1(-0.0) = -0.0, for homogeneity with + * acosh1p(-0.0) = -0.0. + * + * @param value A double value. + * @return Value hyperbolic cosine, minus 1. + */ + public static double coshm1(double value) { + // cosh(x)-1 = (exp(x)+exp(-x))/2 - 1 + if (value < 0.0) { + value = -value; + } + if (value < LOG_TWO_POW_27) { + if (value < TWO_POW_N27) { + if (value == 0.0) { + // +-0.0 + return value; + } + // Using (expm1(x)+expm1(-x))/2 + // is not accurate for tiny values, + // for expm1 results are of higher + // magnitude than the result and + // of different signs, such as their + // sum is not accurate. + // cosh(x) - 1 + // = (exp(x)+exp(-x))/2 - 1 + // = ((1+x+x^2/2!+...) + (1-x+x^2/2!-...))/2 - 1 + // = x^2/2!+x^4/4!+... + // ~= x^2 * (1/2 + x^2 * 1/24) + // = x^2 * 0.5 (since x < 2^-27) + return 0.5 * value*value; + } else { + // cosh(x) - 1 + // = (exp(x)+exp(-x))/2 - 1 + // = (exp(x)-1+exp(-x)-1)/2 + // = (expm1(x)+expm1(-x))/2 + return 0.5 * (expm1(value)+expm1(-value)); + } + } else if (value < LOG_DOUBLE_MAX_VALUE) { + return 0.5 * exp(value) - 1.0; + } else { + // No need to subtract 1 from result. + double t = exp(value*0.5); + return (0.5*t)*t; + } + } + + /** + * Computes hyperbolic sine and hyperbolic cosine together. + * + * @param value A double value. + * @param hcosine (out) Value hyperbolic cosine. + * @return Value hyperbolic sine. + */ + public static double sinhAndCosh(double value, DoubleWrapper hcosine) { + if (USE_JDK_MATH) { + hcosine.value = Math.cosh(value); + return Math.sinh(value); + } + // Mixup of sinh and cosh treatments: if you modify them, + // you might want to also modify this. + double h; + if (value < 0.0) { + value = -value; + h = -0.5; + } else { + h = 0.5; + } + final double hsine; + // LOG_TWO_POW_27 = 18.714973875118524 + if (value < LOG_TWO_POW_27) { // test from cosh + // sinh + if (value < TWO_POW_N28) { + hsine = (h < 0.0) ? -value : value; + } else { + double t = expm1(value); + hsine = h * (t + t/(t+1.0)); + } + // cosh + if (value < TWO_POW_N27) { + hcosine.value = 1; + } else { + double t = exp(value); + hcosine.value = 0.5 * (t+1/t); + } + } else if (value < 22.0) { // test from sinh + // Here, value is in [18.714973875118524,22.0[. + double t = expm1(value); + hsine = h * (t + t/(t+1.0)); + hcosine.value = 0.5 * (t+1.0); + } else { + if (value < LOG_DOUBLE_MAX_VALUE) { + hsine = h * exp(value); + } else { + double t = exp(value*0.5); + hsine = (h*t)*t; + } + hcosine.value = Math.abs(hsine); + } + return hsine; + } + + /** + * Some properties of tanh(x) = sinh(x)/cosh(x) = (exp(2*x)-1)/(exp(2*x)+1): + * 1) defined on ]-Infinity,+Infinity[ + * 2) result in ]-1,1[ + * 3) tanh(x) = -tanh(-x) (implies tanh(0) = 0) + * 4) tanh(epsilon) ~= epsilon + * 5) lim(tanh(x),x->+Infinity) = 1 + * 6) reaches 1 (double loss of precision) for x = 19.061547465398498 + * + * @param value A double value. + * @return Value hyperbolic tangent. + */ + public static double tanh(double value) { + if (USE_JDK_MATH) { + return Math.tanh(value); + } + // tanh(x) = sinh(x)/cosh(x) + // = (exp(x)-exp(-x))/(exp(x)+exp(-x)) + // = (exp(2*x)-1)/(exp(2*x)+1) + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + double z; + if (value < TANH_1_THRESHOLD) { + if (value < TWO_POW_N55) { + return negateResult ? -value*(1.0-value) : value*(1.0+value); + } else if (value >= 1) { + z = 1.0-2.0/(expm1(value+value)+2.0); + } else { + double t = expm1(-(value+value)); + z = -t/(t+2.0); + } + } else { + z = (value != value) ? Double.NaN : 1.0; + } + return negateResult ? -z : z; + } + + /** + * Some properties of asinh(x) = log(x + sqrt(x^2 + 1)) + * 1) defined on ]-Infinity,+Infinity[ + * 2) result in ]-Infinity,+Infinity[ + * 3) asinh(x) = -asinh(-x) (implies asinh(0) = 0) + * 4) asinh(epsilon) ~= epsilon + * 5) lim(asinh(x),x->+Infinity) = +Infinity + * (y increasing logarithmically slower than x) + * + * @param value A double value. + * @return Value hyperbolic arcsine. + */ + public static double asinh(double value) { + // asinh(x) = log(x + sqrt(x^2 + 1)) + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + double result; + // (about) smallest possible for + // non-log1p case to be accurate. + if (value < ASINH_LOG1P_THRESHOLD) { + // Around this range, FDLIBM uses + // log1p(value+value*value/(1+sqrt(value*value+1))), + // but it's slower, so we don't use it. + /* + * If x is close to zero, log argument is close to 1, + * so to avoid precision loss we use log1p(double), + * with + * (1+x)^p = 1 + p * x + (p*(p-1))/2! * x^2 + (p*(p-1)*(p-2))/3! * x^3 + ... + * (1+x)^p = 1 + p * x * (1 + (p-1)/2 * x * (1 + (p-2)/3 * x + ...) + * (1+x)^0.5 = 1 + 0.5 * x * (1 + (0.5-1)/2 * x * (1 + (0.5-2)/3 * x + ...) + * (1+x^2)^0.5 = 1 + 0.5 * x^2 * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...) + * x + (1+x^2)^0.5 = 1 + x * (1 + 0.5 * x * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...)) + * so + * asinh(x) = log1p(x * (1 + 0.5 * x * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...))) + */ + final double x = value; + final double x2 = x*x; + // Enough terms for good accuracy, + // given our threshold. + final double argLog1p = (x * + (1 + 0.5 * x + * (1 + (0.5-1)/2 * x2 + * (1 + (0.5-2)/3 * x2 + * (1 + (0.5-3)/4 * x2 + * (1 + (0.5-4)/5 * x2 + )))))); + result = log1p(argLog1p); + } else if (value < ASINH_ACOSH_SQRT_ELISION_THRESHOLD) { + // Around this range, FDLIBM uses + // log(2*value+1/(value+sqrt(value*value+1))), + // but it involves an additional division + // so we don't use it. + result = log(value + sqrt(value*value + 1.0)); + } else { + // log(2*value) would overflow for value > Double.MAX_VALUE/2, + // so we compute otherwise. + result = LOG_2 + log(value); + } + return negateResult ? -result : result; + } + + /** + * Some properties of acosh(x) = log(x + sqrt(x^2 - 1)): + * 1) defined on [1,+Infinity[ + * 2) result in ]0,+Infinity[ (by convention, since cosh(x) = cosh(-x)) + * 3) acosh(1) = 0 + * 4) acosh(1+epsilon) ~= log(1 + sqrt(2*epsilon)) ~= sqrt(2*epsilon) + * 5) lim(acosh(x),x->+Infinity) = +Infinity + * (y increasing logarithmically slower than x) + * + * @param value A double value. + * @return Value hyperbolic arccosine. + */ + public static double acosh(double value) { + if (!(value > 1.0)) { + // NaN, or value <= 1 + if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { + return (value < 1.0) ? Double.NaN : value - 1.0; + } else { + return (value == 1.0) ? 0.0 : Double.NaN; + } + } + double result; + if (value < ASINH_ACOSH_SQRT_ELISION_THRESHOLD) { + // Around this range, FDLIBM uses + // log(2*value-1/(value+sqrt(value*value-1))), + // but it involves an additional division + // so we don't use it. + result = log(value + sqrt(value*value - 1.0)); + } else { + // log(2*value) would overflow for value > Double.MAX_VALUE/2, + // so we compute otherwise. + result = LOG_2 + log(value); + } + return result; + } + + /** + * Much more accurate than acosh(1+value), + * for arguments (and results) close to zero. + * + * acosh1p(-0.0) = -0.0, for homogeneity with + * sqrt(-0.0) = -0.0, which looks about the same + * near 0. + * + * @param value A double value. + * @return Hyperbolic arccosine of (1+value). + */ + public static double acosh1p(double value) { + if (!(value > 0.0)) { + // NaN, or value <= 0. + // If value is -0.0, returning -0.0. + if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { + return (value < 0.0) ? Double.NaN : value; + } else { + return (value == 0.0) ? value : Double.NaN; + } + } + double result; + if (value < (ASINH_ACOSH_SQRT_ELISION_THRESHOLD-1)) { + // acosh(1+x) + // = log((1+x) + sqrt((1+x)^2 - 1)) + // = log(1 + x + sqrt(1 + 2*x + x^2 - 1)) + // = log1p(x + sqrt(2*x + x^2)) + // = log1p(x + sqrt(x * (2 + x)) + result = log1p(value + sqrt(value * (2 + value))); + } else { + result = LOG_2 + log(1+value); + } + return result; + } + + /** + * Some properties of atanh(x) = log((1+x)/(1-x))/2: + * 1) defined on ]-1,1[ + * 2) result in ]-Infinity,+Infinity[ + * 3) atanh(-1) = -Infinity (by continuity) + * 4) atanh(1) = +Infinity (by continuity) + * 5) atanh(epsilon) ~= epsilon + * 6) lim(atanh(x),x->1) = +Infinity + * + * @param value A double value. + * @return Value hyperbolic arctangent. + */ + public static double atanh(double value) { + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + double result; + if (!(value < 1.0)) { + // NaN, or value >= 1 + if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { + result = (value > 1.0) ? Double.NaN : Double.POSITIVE_INFINITY + value; + } else { + result = (value == 1.0) ? Double.POSITIVE_INFINITY : Double.NaN; + } + } else { + // For value < 0.5, FDLIBM uses + // 0.5 * log1p((value+value) + (value+value)*value/(1-value)), + // instead, but this is good enough for us. + // atanh(x) + // = log((1+x)/(1-x))/2 + // = log((1-x+2x)/(1-x))/2 + // = log1p(2x/(1-x))/2 + result = 0.5 * log1p((value+value)/(1.0-value)); + } + return negateResult ? -result : result; + } + + /* + * exponentials + */ + + /** + * @param value A double value. + * @return e^value. + */ + public static double exp(double value) { + if (USE_JDK_MATH) { + return Math.exp(value); + } + // exp(x) = exp([x])*exp(y) + // with [x] the integer part of x, and y = x-[x] + // ===> + // We find an approximation of y, called z. + // ===> + // exp(x) = exp([x])*(exp(z)*exp(epsilon)) + // with epsilon = y - z + // ===> + // We have exp([x]) and exp(z) pre-computed in tables, we "just" have to compute exp(epsilon). + // + // We use the same indexing (cast to int) to compute x integer part and the + // table index corresponding to z, to avoid two int casts. + // Also, to optimize index multiplication and division, we use powers of two, + // so that we can do it with bits shifts. + + if (value > EXP_OVERFLOW_LIMIT) { + return Double.POSITIVE_INFINITY; + } else if (!(value >= EXP_UNDERFLOW_LIMIT)) { + return (value != value) ? Double.NaN : 0.0; + } + + final int indexes = (int)(value*EXP_LO_INDEXING); + + final int valueInt; + if (indexes >= 0) { + valueInt = (indexes>>EXP_LO_INDEXING_DIV_SHIFT); + } else { + valueInt = -((-indexes)>>EXP_LO_INDEXING_DIV_SHIFT); + } + final double hiTerm = MyTExp.expHiTab[valueInt-(int)EXP_UNDERFLOW_LIMIT]; + + final int zIndex = indexes - (valueInt< 0.0) { + if (value == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + + // For normal values not close to 1.0, we use the following formula: + // log(value) + // = log(2^exponent*1.mantissa) + // = log(2^exponent) + log(1.mantissa) + // = exponent * log(2) + log(1.mantissa) + // = exponent * log(2) + log(1.mantissaApprox) + log(1.mantissa/1.mantissaApprox) + // = exponent * log(2) + log(1.mantissaApprox) + log(1+epsilon) + // = exponent * log(2) + log(1.mantissaApprox) + epsilon-epsilon^2/2+epsilon^3/3-epsilon^4/4+... + // with: + // 1.mantissaApprox <= 1.mantissa, + // log(1.mantissaApprox) in table, + // epsilon = (1.mantissa/1.mantissaApprox)-1 + // + // To avoid bad relative error for small results, + // values close to 1.0 are treated aside, with the formula: + // log(x) = z*(2+z^2*((2.0/3)+z^2*((2.0/5))+z^2*((2.0/7))+...))) + // with z=(x-1)/(x+1) + + double h; + if (value > 0.95) { + if (value < 1.14) { + double z = (value-1.0)/(value+1.0); + double z2 = z*z; + return z*(2+z2*((2.0/3)+z2*((2.0/5)+z2*((2.0/7)+z2*((2.0/9)+z2*((2.0/11))))))); + } + h = 0.0; + } else if (value < DOUBLE_MIN_NORMAL) { + // Ensuring value is normal. + value *= TWO_POW_52; + // log(x*2^52) + // = log(x)-ln(2^52) + // = log(x)-52*ln(2) + h = -52*LOG_2; + } else { + h = 0.0; + } + + int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); + int valueExp = (valueBitsHi>>20)-MAX_DOUBLE_EXPONENT; + // Getting the first LOG_BITS bits of the mantissa. + int xIndex = ((valueBitsHi<<12)>>>(32-LOG_BITS)); + + // 1.mantissa/1.mantissaApprox - 1 + double z = (value * twoPowNormalOrSubnormal(-valueExp)) * MyTLog.logXInvTab[xIndex] - 1; + + z *= (1-z*((1.0/2)-z*((1.0/3)))); + + return h + valueExp * LOG_2 + (MyTLog.logXLogTab[xIndex] + z); + + } else if (value == 0.0) { + return Double.NEGATIVE_INFINITY; + } else { // value < 0.0, or value is NaN + return Double.NaN; + } + } + + /** + * Quick log, with a max relative error of about 1.9e-3 + * for values in ]Double.MIN_NORMAL,+Infinity[, and + * worse accuracy outside this range. + * + * @param value A double value, in ]0,+Infinity[ (strictly positive and finite). + * @return Value logarithm (base e). + */ + public static double logQuick(double value) { + if (USE_JDK_MATH) { + return Math.log(value); + } + /* + * Inverse of Schraudolph's method for exp, is very inaccurate near 1, + * and not that fast (even using floats), especially with added if's + * to deal with values near 1, so we don't use it, and use a simplified + * version of our log's redefined algorithm. + */ + + // Simplified version of log's redefined algorithm: + // log(value) ~= exponent * log(2) + log(1.mantissaApprox) + + double h; + if (value > 0.87) { + if (value < 1.16) { + return 2.0 * (value-1.0)/(value+1.0); + } + h = 0.0; + } else if (value < DOUBLE_MIN_NORMAL) { + value *= TWO_POW_52; + h = -52*LOG_2; + } else { + h = 0.0; + } + + int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); + int valueExp = (valueBitsHi>>20)-MAX_DOUBLE_EXPONENT; + int xIndex = ((valueBitsHi<<12)>>>(32-LOG_BITS)); + + return h + valueExp * LOG_2 + MyTLog.logXLogTab[xIndex]; + } + + /** + * @param value A double value. + * @return Value logarithm (base 10). + */ + public static double log10(double value) { + if (USE_JDK_MATH || (!USE_REDEFINED_LOG)) { + return Math.log10(value); + } + // INV_LOG_10 is < 1, but there is no risk of log(double) + // overflow (positive or negative) while the end result shouldn't, + // since log(Double.MIN_VALUE) and log(Double.MAX_VALUE) have + // magnitudes of just a few hundreds. + return log(value) * INV_LOG_10; + } + + /** + * Much more accurate than log(1+value), + * for arguments (and results) close to zero. + * + * @param value A double value. + * @return Logarithm (base e) of (1+value). + */ + public static double log1p(double value) { + if (USE_JDK_MATH) { + return Math.log1p(value); + } + if (false) { + // This also works. Simpler but a bit slower. + if (value == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + double valuePlusOne = 1+value; + if (valuePlusOne == 1.0) { + return value; + } else { + return log(valuePlusOne)*(value/(valuePlusOne-1.0)); + } + } + if (value > -1.0) { + if (value == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + + // ln'(x) = 1/x + // so + // log(x+epsilon) ~= log(x) + epsilon/x + // + // Let u be 1+value rounded: + // 1+value = u+epsilon + // + // log(1+value) + // = log(u+epsilon) + // ~= log(u) + epsilon/value + // We compute log(u) as done in log(double), and then add the corrective term. + + double valuePlusOne = 1.0+value; + if (valuePlusOne == 1.0) { + return value; + } else if (Math.abs(value) < 0.15) { + double z = value/(value+2.0); + double z2 = z*z; + return z*(2+z2*((2.0/3)+z2*((2.0/5)+z2*((2.0/7)+z2*((2.0/9)+z2*((2.0/11))))))); + } + + int valuePlusOneBitsHi = (int)(Double.doubleToRawLongBits(valuePlusOne)>>32) & 0x7FFFFFFF; + int valuePlusOneExp = (valuePlusOneBitsHi>>20)-MAX_DOUBLE_EXPONENT; + // Getting the first LOG_BITS bits of the mantissa. + int xIndex = ((valuePlusOneBitsHi<<12)>>>(32-LOG_BITS)); + + // 1.mantissa/1.mantissaApprox - 1 + double z = (valuePlusOne * twoPowNormalOrSubnormal(-valuePlusOneExp)) * MyTLog.logXInvTab[xIndex] - 1; + + z *= (1-z*((1.0/2)-z*(1.0/3))); + + // Adding epsilon/valuePlusOne to z, + // with + // epsilon = value - (valuePlusOne-1) + // (valuePlusOne + epsilon ~= 1+value (not rounded)) + + return valuePlusOneExp * LOG_2 + MyTLog.logXLogTab[xIndex] + (z + (value - (valuePlusOne-1))/valuePlusOne); + } else if (value == -1.0) { + return Double.NEGATIVE_INFINITY; + } else { // value < -1.0, or value is NaN + return Double.NaN; + } + } + + /* + * powers + */ + + /** + * 1e-13ish accuracy or better on whole double range. + * + * @param value A double value. + * @param power A power. + * @return value^power. + */ + public static double pow(double value, double power) { + if (USE_JDK_MATH) { + return Math.pow(value,power); + } + if (power == 0.0) { + return 1.0; + } else if (power == 1.0) { + return value; + } + if (value <= 0.0) { + // powerInfo: 0 if not integer, 1 if even integer, -1 if odd integer + int powerInfo; + if (Math.abs(power) >= (TWO_POW_52*2)) { + // The binary digit just before comma is outside mantissa, + // thus it is always 0: power is an even integer. + powerInfo = 1; + } else { + // If power's magnitude permits, we cast into int instead of into long, + // as it is faster. + if (Math.abs(power) <= (double)Integer.MAX_VALUE) { + int powerAsInt = (int)power; + if (power == (double)powerAsInt) { + powerInfo = ((powerAsInt & 1) == 0) ? 1 : -1; + } else { // power is not an integer (and not NaN, due to test against Integer.MAX_VALUE) + powerInfo = 0; + } + } else { + long powerAsLong = (long)power; + if (power == (double)powerAsLong) { + powerInfo = ((powerAsLong & 1) == 0) ? 1 : -1; + } else { // power is not an integer, or is NaN + if (power != power) { + return Double.NaN; + } + powerInfo = 0; + } + } + } + + if (value == 0.0) { + if (power < 0.0) { + return (powerInfo < 0) ? 1/value : Double.POSITIVE_INFINITY; + } else { // power > 0.0 (0 and NaN cases already treated) + return (powerInfo < 0) ? value : 0.0; + } + } else { // value < 0.0 + if (value == Double.NEGATIVE_INFINITY) { + if (powerInfo < 0) { // power odd integer + return (power < 0.0) ? -0.0 : Double.NEGATIVE_INFINITY; + } else { // power even integer, or not an integer + return (power < 0.0) ? 0.0 : Double.POSITIVE_INFINITY; + } + } else { + return (powerInfo == 0) ? Double.NaN : powerInfo * exp(power*log(-value)); + } + } + } else { // value > 0.0, or value is NaN + return exp(power*log(value)); + } + } + + /** + * Quick pow, with a max relative error of about 1e-2 + * for value >= Double.MIN_NORMAL and 1e-10 < |value^power| < 1e10, + * of about 6e-2 for value >= Double.MIN_NORMAL and 1e-40 < |value^power| < 1e40, + * and worse accuracy otherwise. + * + * @param value A double value, in ]0,+Infinity[ (strictly positive and finite). + * @param power A double value. + * @return value^power. + */ + public static double powQuick(double value, double power) { + if (USE_JDK_MATH) { + return Math.pow(value,power); + } + return exp(power*logQuick(value)); + } + + /** + * This treatment is somehow accurate for low values of |power|, + * and for |power*getExponent(value)| < 1023 or so (to stay away + * from double extreme magnitudes (large and small)). + * + * @param value A double value. + * @param power A power. + * @return value^power. + */ + public static double powFast(double value, int power) { + if (USE_JDK_MATH) { + return Math.pow(value,power); + } + if (power < 3) { + if (power < 0) { + // Opposite of Integer.MIN_VALUE does not exist as int. + if (power == Integer.MIN_VALUE) { + // Integer.MAX_VALUE = -(power+1) + return 1.0/(powFast(value,Integer.MAX_VALUE) * value); + } else { + return 1.0/powFast(value,-power); + } + } else { + // Here, power is in [0,2]. + if (power == 2) { // Most common case first. + return value * value; + } else if (power == 0) { + return 1.0; + } else { // power == 1 + return value; + } + } + } else { // power >= 4 + double oddRemains = 1.0; + // If power <= 5, faster to finish outside the loop. + while (power > 5) { + // Test if power is odd. + if ((power & 1) != 0) { + oddRemains *= value; + } + value *= value; + power >>= 1; // power = power / 2 + } + // Here, power is in [3,5]. + if (power == 3) { + return oddRemains * value * value * value; + } else { // power in [4,5]. + double v2 = value * value; + if (power == 4) { + return oddRemains * v2 * v2; + } else { // power == 5 + return oddRemains * v2 * v2 * value; + } + } + } + } + + /** + * @param value A float value. + * @return value*value. + */ + public static float pow2(float value) { + return value*value; + } + + /** + * @param value A double value. + * @return value*value. + */ + public static double pow2(double value) { + return value*value; + } + + /** + * @param value A float value. + * @return value*value*value. + */ + public static float pow3(float value) { + return value*value*value; + } + + /** + * @param value A double value. + * @return value*value*value. + */ + public static double pow3(double value) { + return value*value*value; + } + + /* + * roots + */ + + /** + * @param value A double value. + * @return Value square root. + */ + public static double sqrt(double value) { + if (USE_JDK_MATH || (!USE_REDEFINED_SQRT)) { + return Math.sqrt(value); + } + // See cbrt for comments, sqrt uses the same ideas. + + if (!(value > 0.0)) { // value <= 0.0, or value is NaN + if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { + return (value < 0.0) ? Double.NaN : value; + } else { + return (value == 0.0) ? value : Double.NaN; + } + } else if (value == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + + double h; + if (value < DOUBLE_MIN_NORMAL) { + value *= TWO_POW_52; + h = 2*TWO_POW_N26; + } else { + h = 2.0; + } + + int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); + int valueExponentIndex = (valueBitsHi>>20)+(-MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT); + int xIndex = ((valueBitsHi<<12)>>>(32-SQRT_LO_BITS)); + + double result = MyTSqrt.sqrtXSqrtHiTab[valueExponentIndex] * MyTSqrt.sqrtXSqrtLoTab[xIndex]; + double slope = MyTSqrt.sqrtSlopeHiTab[valueExponentIndex] * MyTSqrt.sqrtSlopeLoTab[xIndex]; + value *= 0.25; + + result += (value - result * result) * slope; + result += (value - result * result) * slope; + return h*(result + (value - result * result) * slope); + } + + /** + * Quick sqrt, with with a max relative error of about 3.41e-2 + * for values in [Double.MIN_NORMAL,Double.MAX_VALUE], and worse + * accuracy outside this range. + * + * @param value A double value. + * @return Value square root. + */ + public static double sqrtQuick(double value) { + if (USE_JDK_MATH) { + return Math.sqrt(value); + } + final long bits = Double.doubleToRawLongBits(value); + /* + * Constant determined empirically, using a random-based metaheuristic. + * Should be possible to find a better one. + */ + return Double.longBitsToDouble((bits+4606859074900000000L)>>>1); + } + + /** + * Quick inverse of square root, with a max relative error of about 3.44e-2 + * for values in [Double.MIN_NORMAL,Double.MAX_VALUE], and worse accuracy + * outside this range. + * + * This implementation uses zero step of Newton's method. + * Here are the max relative errors on [Double.MIN_NORMAL,Double.MAX_VALUE] + * depending on number of steps, if you want to copy-paste this code + * and use your own number: + * n=0: about 3.44e-2 + * n=1: about 1.75e-3 + * n=2: about 4.6e-6 + * n=3: about 3.17e-11 + * n=4: about 3.92e-16 + * n=5: about 3.03e-16 + * + * @param value A double value. + * @return Inverse of value square root. + */ + public static double invSqrtQuick(double value) { + if (USE_JDK_MATH) { + return 1/Math.sqrt(value); + } + /* + * http://en.wikipedia.org/wiki/Fast_inverse_square_root + */ + if (false) { + // With one Newton step (much slower than + // 1/Math.sqrt(double) if not optimized). + final double halfInitial = value * 0.5; + long bits = Double.doubleToRawLongBits(value); + // If n=0, 6910474759270000000L might be better (3.38e-2 max relative error). + bits = 0x5FE6EB50C7B537A9L - (bits>>1); + value = Double.longBitsToDouble(bits); + value = value * (1.5 - halfInitial * value * value); // Newton step, can repeat. + return value; + } else { + return Double.longBitsToDouble(0x5FE6EB50C7B537A9L - (Double.doubleToRawLongBits(value)>>1)); + } + } + + /** + * @param value A double value. + * @return Value cubic root. + */ + public static double cbrt(double value) { + if (USE_JDK_MATH) { + return Math.cbrt(value); + } + double h; + if (value < 0.0) { + if (value == Double.NEGATIVE_INFINITY) { + return Double.NEGATIVE_INFINITY; + } + value = -value; + // Making sure value is normal. + if (value < DOUBLE_MIN_NORMAL) { + value *= (TWO_POW_52*TWO_POW_26); + // h = * / + h = -2*TWO_POW_N26; + } else { + h = -2.0; + } + } else { + if (!(value < Double.POSITIVE_INFINITY)) { // value is +Infinity, or value is NaN + return value; + } + // Making sure value is normal. + if (value < DOUBLE_MIN_NORMAL) { + if (value == 0.0) { + // cbrt(0.0) = 0.0, cbrt(-0.0) = -0.0 + return value; + } + value *= (TWO_POW_52*TWO_POW_26); + h = 2*TWO_POW_N26; + } else { + h = 2.0; + } + } + + // Normal value is (2^ * ). + // First member cubic root is computed, and multiplied with an approximation + // of the cubic root of the second member, to end up with a good guess of + // the result before using Newton's (or Archimedes's) method. + // To compute the cubic root approximation, we use the formula "cbrt(value) = cbrt(x) * cbrt(value/x)", + // choosing x as close to value as possible but inferior to it, so that cbrt(value/x) is close to 1 + // (we could iterate on this method, using value/x as new value for each iteration, + // but finishing with Newton's method is faster). + + // Shift and cast into an int, which overall is faster than working with a long. + int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); + int valueExponentIndex = (valueBitsHi>>20)+(-MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT); + // Getting the first CBRT_LO_BITS bits of the mantissa. + int xIndex = ((valueBitsHi<<12)>>>(32-CBRT_LO_BITS)); + double result = MyTCbrt.cbrtXCbrtHiTab[valueExponentIndex] * MyTCbrt.cbrtXCbrtLoTab[xIndex]; + double slope = MyTCbrt.cbrtSlopeHiTab[valueExponentIndex] * MyTCbrt.cbrtSlopeLoTab[xIndex]; + + // Lowering values to avoid overflows when using Newton's method + // (we will then just have to return twice the result). + // result^3 = value + // (result/2)^3 = value/8 + value *= 0.125; + // No need to divide result here, as division is factorized in result computation tables. + // result *= 0.5; + + // Newton's method, looking for y = x^(1/p): + // y(n) = y(n-1) + (x-y(n-1)^p) * slope(y(n-1)) + // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(x(n-1)^(1/p-1)) + // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(x(n-1)^((1-p)/p)) + // with x(n-1)=y(n-1)^p, i.e.: + // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(y(n-1)^(1-p)) + // + // For p=3: + // y(n) = y(n-1) + (x-y(n-1)^3) * (1/(3*y(n-1)^2)) + + // To save time, we don't recompute the slope between Newton's method steps, + // as initial slope is good enough for a few iterations. + // + // NB: slope = 1/(3*trueResult*trueResult) + // As we have result = trueResult/2 (to avoid overflows), we have: + // slope = 4/(3*result*result) + // = (4/3)*resultInv*resultInv + // with newResultInv = 1/newResult + // = 1/(oldResult+resultDelta) + // = (oldResultInv)*1/(1+resultDelta/oldResult) + // = (oldResultInv)*1/(1+resultDelta*oldResultInv) + // ~= (oldResultInv)*(1-resultDelta*oldResultInv) + // ===> Successive slopes could be computed without division, if needed, + // by computing resultInv (instead of slope right away) and retrieving + // slopes from it. + + result += (value - result * result * result) * slope; + result += (value - result * result * result) * slope; + return h*(result + (value - result * result * result) * slope); + } + + /** + * @return sqrt(x^2+y^2) without intermediate overflow or underflow. + */ + public static double hypot(double x, double y) { + if (USE_JDK_MATH) { + return Math.hypot(x,y); + } + x = Math.abs(x); + y = Math.abs(y); + // Ensuring x <= y. + if (y < x) { + double a = x; + x = y; + y = a; + } else if (!(y >= x)) { // Testing if we have some NaN. + return hypot_NaN(x, y); + } + + if (y-x == y) { + // x too small to subtract from y. + return y; + } else { + double factor; + if (y > HYPOT_MAX_MAG) { + // y is too large: scaling down. + x *= (1/HYPOT_FACTOR); + y *= (1/HYPOT_FACTOR); + factor = HYPOT_FACTOR; + } else if (x < (1/HYPOT_MAX_MAG)) { + // x is too small: scaling up. + x *= HYPOT_FACTOR; + y *= HYPOT_FACTOR; + factor = (1/HYPOT_FACTOR); + } else { + factor = 1.0; + } + return factor * sqrt(x*x+y*y); + } + } + + /** + * @return sqrt(x^2+y^2+z^2) without intermediate overflow or underflow. + */ + public static double hypot(double x, double y, double z) { + if (USE_JDK_MATH) { + // No simple JDK equivalent. + } + x = Math.abs(x); + y = Math.abs(y); + z = Math.abs(z); + /* + * Considering that z magnitude is the most likely to be the smaller, + * hence ensuring z <= y <= x, and not x <= y <= z, for less swaps. + */ + // Ensuring z <= y. + if (z > y) { + // y < z: swapping y and z + double a = z; + z = y; + y = a; + } else if (!(z <= y)) { // Testing if y or z is NaN. + return hypot_NaN(x, y, z); + } + // Ensuring y <= x. + if (z > x) { + // x < z <= y: moving x + double oldZ = z; + z = x; + double oldY = y; + y = oldZ; + x = oldY; + } else if (y > x) { + // z <= x < y: swapping x and y + double a = y; + y = x; + x = a; + } else if (x != x) { // Testing if x is NaN. + return hypot_NaN(x, y, z); + } + + if (x-y == x) { + // y, hence z, too small to subtract from x. + return x; + } else if (y-z == y) { + // z too small to subtract from y, hence x. + double factor; + if (x > HYPOT_MAX_MAG) { + // x is too large: scaling down. + x *= (1/HYPOT_FACTOR); + y *= (1/HYPOT_FACTOR); + factor = HYPOT_FACTOR; + } else if (y < (1/HYPOT_MAX_MAG)) { + // y is too small: scaling up. + x *= HYPOT_FACTOR; + y *= HYPOT_FACTOR; + factor = (1/HYPOT_FACTOR); + } else { + factor = 1.0; + } + return factor * sqrt(x*x+y*y); + } else { + double factor; + if (x > HYPOT_MAX_MAG) { + // x is too large: scaling down. + x *= (1/HYPOT_FACTOR); + y *= (1/HYPOT_FACTOR); + z *= (1/HYPOT_FACTOR); + factor = HYPOT_FACTOR; + } else if (z < (1/HYPOT_MAX_MAG)) { + // z is too small: scaling up. + x *= HYPOT_FACTOR; + y *= HYPOT_FACTOR; + z *= HYPOT_FACTOR; + factor = (1/HYPOT_FACTOR); + } else { + factor = 1.0; + } + // Adding smaller magnitudes together first. + return factor * sqrt(x*x+(y*y+z*z)); + } + } + + /* + * close values + */ + + /** + * @param value A float value. + * @return Floor of value. + */ + public static float floor(float value) { + final int exponent = getExponent(value); + if (exponent < 0) { + // abs(value) < 1. + if (value < 0.0f) { + return -1.0f; + } else { + // 0.0f, or -0.0f if value is -0.0f + return 0.0f * value; + } + } else if (exponent < 23) { + // A bit faster than using casts. + final int bits = Float.floatToRawIntBits(value); + final int anteCommaBits = bits & (0xFF800000>>exponent); + if ((value < 0.0f) && (anteCommaBits != bits)) { + return Float.intBitsToFloat(anteCommaBits) - 1.0f; + } else { + return Float.intBitsToFloat(anteCommaBits); + } + } else { + // +-Infinity, NaN, or a mathematical integer. + return value; + } + } + + /** + * @param value A double value. + * @return Floor of value. + */ + public static double floor(double value) { + if (USE_JDK_MATH) { + return Math.floor(value); + } + if (ANTI_SLOW_CASTS) { + double valueAbs = Math.abs(value); + if (valueAbs <= (double)Integer.MAX_VALUE) { + if (value > 0.0) { + return (double)(int)value; + } else if (value < 0.0) { + double anteCommaDigits = (double)(int)value; + if (value != anteCommaDigits) { + return anteCommaDigits - 1.0; + } else { + return anteCommaDigits; + } + } else { // value is +-0.0 (not NaN due to test against Integer.MAX_VALUE) + return value; + } + } else if (valueAbs < TWO_POW_52) { + // We split the value in two: + // high part, which is a mathematical integer, + // and the rest, for which we can get rid of the + // post comma digits by casting into an int. + double highPart = ((int)(value * TWO_POW_N26)) * TWO_POW_26; + if (value > 0.0) { + return highPart + (double)((int)(value - highPart)); + } else { + double anteCommaDigits = highPart + (double)((int)(value - highPart)); + if (value != anteCommaDigits) { + return anteCommaDigits - 1.0; + } else { + return anteCommaDigits; + } + } + } else { // abs(value) >= 2^52, or value is NaN + return value; + } + } else { + final int exponent = getExponent(value); + if (exponent < 0) { + // abs(value) < 1. + if (value < 0.0) { + return -1.0; + } else { + // 0.0, or -0.0 if value is -0.0 + return 0.0 * value; + } + } else if (exponent < 52) { + // A bit faster than working on bits. + final long matIntPart = (long)value; + final double matIntToValue = value-(double)matIntPart; + if (matIntToValue >= 0.0) { + return (double)matIntPart; + } else { + return (double)(matIntPart - 1); + } + } else { + // +-Infinity, NaN, or a mathematical integer. + return value; + } + } + } + + /** + * @param value A float value. + * @return Ceiling of value. + */ + public static float ceil(float value) { + return -floor(-value); + } + + /** + * @param value A double value. + * @return Ceiling of value. + */ + public static double ceil(double value) { + if (USE_JDK_MATH) { + return Math.ceil(value); + } + return -floor(-value); + } + + /** + * Might have different semantics than Math.round(float), + * see bugs 6430675 and 8010430. + * + * @param value A double value. + * @return Value rounded to nearest int, choosing superior int in case two + * are equally close (i.e. rounding-up). + */ + public static int round(float value) { + /* + * Not delegating to JDK, because we want delegation to provide + * at least as good results, and some supported JDK versions + * have bugged round() methods. + */ + // Algorithm by Dmitry Nadezhin (but replaced an if by a multiply) + // (http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-August/020247.html). + final int bits = Float.floatToRawIntBits(value); + final int biasedExp = ((bits>>23)&0xFF); + // Shift to get rid of bits past comma except first one: will need to + // 1-shift to the right to end up with correct magnitude. + final int shift = (23 - 1 + MAX_FLOAT_EXPONENT) - biasedExp; + if ((shift & -32) == 0) { + int bitsSignum = (((bits >> 31) << 1) + 1); + // shift in [0,31], so unbiased exp in [-9,22]. + int extendedMantissa = (0x00800000 | (bits & 0x007FFFFF)) * bitsSignum; + // If value is positive and first bit past comma is 0, rounding + // to lower integer, else to upper one, which is what "+1" and + // then ">>1" do. + return ((extendedMantissa >> shift) + 1) >> 1; + } else { + // +-Infinity, NaN, or a mathematical integer, or tiny. + if (false && ANTI_SLOW_CASTS) { // not worth it + if (Math.abs(value) >= -(float)Integer.MIN_VALUE) { + // +-Infinity or a mathematical integer (mostly) out of int range. + return (value < 0.0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; + } + // NaN or a mathematical integer (mostly) in int range. + } + return (int)value; + } + } + + /** + * Might have different semantics than Math.round(double), + * see bugs 6430675 and 8010430. + * + * @param value A double value. + * @return Value rounded to nearest long, choosing superior long in case two + * are equally close (i.e. rounding-up). + */ + public static long round(double value) { + /* + * Not delegating to JDK, because we want delegation to provide + * at least as good results, and some supported JDK versions + * have bugged round() methods. + */ + final long bits = Double.doubleToRawLongBits(value); + final int biasedExp = (((int)(bits>>52))&0x7FF); + // Shift to get rid of bits past comma except first one: will need to + // 1-shift to the right to end up with correct magnitude. + final int shift = (52 - 1 + MAX_DOUBLE_EXPONENT) - biasedExp; + if ((shift & -64) == 0) { + long bitsSignum = (((bits >> 63) << 1) + 1); + // shift in [0,63], so unbiased exp in [-12,51]. + long extendedMantissa = (0x0010000000000000L | (bits & 0x000FFFFFFFFFFFFFL)) * bitsSignum; + // If value is positive and first bit past comma is 0, rounding + // to lower integer, else to upper one, which is what "+1" and + // then ">>1" do. + return ((extendedMantissa >> shift) + 1L) >> 1; + } else { + // +-Infinity, NaN, or a mathematical integer, or tiny. + if (ANTI_SLOW_CASTS) { + if (Math.abs(value) >= -(double)Long.MIN_VALUE) { + // +-Infinity or a mathematical integer (mostly) out of long range. + return (value < 0.0) ? Long.MIN_VALUE : Long.MAX_VALUE; + } + // NaN or a mathematical integer (mostly) in long range. + } + return (long)value; + } + } + + /** + * @param value A float value. + * @return Value rounded to nearest int, choosing even int in case two + * are equally close. + */ + public static int roundEven(float value) { + final int sign = signFromBit(value); + value = Math.abs(value); + if (ANTI_SLOW_CASTS) { + if (value < TWO_POW_23_F) { + // Getting rid of post-comma bits. + value = ((value + TWO_POW_23_F) - TWO_POW_23_F); + return sign * (int)value; + } else if (value < (float)Integer.MAX_VALUE) { // "<=" doesn't work, because of float precision + // value is in [-Integer.MAX_VALUE,Integer.MAX_VALUE] + return sign * (int)value; + } + } else { + if (value < TWO_POW_23_F) { + // Getting rid of post-comma bits. + value = ((value + TWO_POW_23_F) - TWO_POW_23_F); + } + } + return (int)(sign * value); + } + + /** + * @param value A double value. + * @return Value rounded to nearest long, choosing even long in case two + * are equally close. + */ + public static long roundEven(double value) { + final int sign = (int)signFromBit(value); + value = Math.abs(value); + if (value < TWO_POW_52) { + // Getting rid of post-comma bits. + value = ((value + TWO_POW_52) - TWO_POW_52); + } + if (ANTI_SLOW_CASTS) { + if (value <= (double)Integer.MAX_VALUE) { + // value is in [-Integer.MAX_VALUE,Integer.MAX_VALUE] + return sign * (int)value; + } + } + return (long)(sign * value); + } + + /** + * @param value A float value. + * @return The float mathematical integer closest to the specified value, + * choosing even one if two are equally close, or respectively + * NaN, +-Infinity or +-0.0f if the value is any of these. + */ + public static float rint(float value) { + final int sign = signFromBit(value); + value = Math.abs(value); + if (value < TWO_POW_23_F) { + // Getting rid of post-comma bits. + value = ((TWO_POW_23_F + value ) - TWO_POW_23_F); + } + // Restoring original sign. + return sign * value; + } + + /** + * @param value A double value. + * @return The double mathematical integer closest to the specified value, + * choosing even one if two are equally close, or respectively + * NaN, +-Infinity or +-0.0 if the value is any of these. + */ + public static double rint(double value) { + if (USE_JDK_MATH) { + return Math.rint(value); + } + final int sign = (int)signFromBit(value); + value = Math.abs(value); + if (value < TWO_POW_52) { + // Getting rid of post-comma bits. + value = ((TWO_POW_52 + value ) - TWO_POW_52); + } + // Restoring original sign. + return sign * value; + } + + /* + * close int values + * + * Never delegating to JDK for these methods, for we should always + * be faster and exact, and JDK doesn't exactly have such methods. + */ + + /** + * @param value A double value. + * @return Floor of value as int, or closest int if floor is out + * of int range, or 0 if value is NaN. + */ + public static int floorToInt(double value) { + int valueInt = (int) value; + if (value < 0.0) { + if (value == (double) valueInt) { + return valueInt; + } else { + if (valueInt == Integer.MIN_VALUE) { + return valueInt; + } else { + return valueInt - 1; + } + } + } else { // >= 0 or NaN. + return valueInt; + } + } + + /** + * @param value A double value. + * @return Ceiling of value as int, or closest int if ceiling is out + * of int range, or 0 if value is NaN. + */ + public static int ceilToInt(double value) { + int valueInt = (int) value; + if (value > 0.0) { + if (value == (double) valueInt) { + return valueInt; + } else { + if (valueInt == Integer.MAX_VALUE) { + return valueInt; + } else { + return valueInt + 1; + } + } + } else { // <= 0 or NaN. + return valueInt; + } + } + + /** + * @param value A double value. + * @return Value rounded to nearest int, choosing superior int in case two + * are equally close (i.e. rounding-up). + */ + public static int roundToInt(double value) { + /* + * We don't gain much by reimplementing rounding, except for + * pathologically large values, which should not be a common case + * when dealing with ints, so we just use round(double). + */ + return NumbersUtils.toInt(round(value)); + } + + /** + * @param value A double value. + * @return Value rounded to nearest int, choosing even int in case two + * are equally close. + */ + public static int roundEvenToInt(double value) { + final int sign = (int)signFromBit(value); + value = Math.abs(value); + /* + * Applying the post-comma bits removal logic even if value is out + * of int range, to avoid a test, for it doesn't mess up the result, + * and we want to optimize for the case of values in int range. + */ + value = ((value + TWO_POW_52) - TWO_POW_52); + return (int)(sign * value); + } + + /* + * ranges + */ + + /** + * @param min A float value. + * @param max A float value. + * @param value A float value. + * @return min if value < min, max if value > max, value otherwise. + */ + public static float toRange(float min, float max, float value) { + return NumbersUtils.toRange(min, max, value); + } + + /** + * @param min A double value. + * @param max A double value. + * @param value A double value. + * @return min if value < min, max if value > max, value otherwise. + */ + public static double toRange(double min, double max, double value) { + return NumbersUtils.toRange(min, max, value); + } + + /* + * binary operators (/,%) + */ + + /** + * Returns dividend - divisor * n, where n is the mathematical integer + * closest to dividend/divisor. + * If dividend/divisor is equally close to surrounding integers, + * we choose n to be the integer of smallest magnitude, which makes + * this treatment differ from Math.IEEEremainder(double,double), + * where n is chosen to be the even integer. + * Note that the choice of n is not done considering the double + * approximation of dividend/divisor, because it could cause + * result to be outside [-|divisor|/2,|divisor|/2] range. + * The practical effect is that if multiple results would be possible, + * we always choose the result that is the closest to (and has the same + * sign as) the dividend. + * Ex. : + * - for (-3.0,2.0), this method returns -1.0, + * whereas Math.IEEEremainder returns 1.0. + * - for (-5.0,2.0), both this method and Math.IEEEremainder return -1.0. + * + * If the remainder is zero, its sign is the same as the sign of the first argument. + * If either argument is NaN, or the first argument is infinite, + * or the second argument is positive zero or negative zero, + * then the result is NaN. + * If the first argument is finite and the second argument is + * infinite, then the result is the same as the first argument. + * + * NB: + * - Modulo operator (%) returns a value in ]-|divisor|,|divisor|[, + * which sign is the same as dividend. + * - As for modulo operator, the sign of the divisor has no effect on the result. + * - On some architecture, % operator has been observed to return NaN + * for some subnormal values of divisor, when dividend exponent is 1023, + * which impacts the correctness of this method. + * + * @param dividend Dividend. + * @param divisor Divisor. + * @return Remainder of dividend/divisor, i.e. a value in [-|divisor|/2,|divisor|/2]. + */ + public static double remainder(double dividend, double divisor) { + if (Double.isInfinite(divisor)) { + if (Double.isInfinite(dividend)) { + return Double.NaN; + } else { + return dividend; + } + } + double value = dividend % divisor; + if (Math.abs(value+value) > Math.abs(divisor)) { + return value + ((value > 0.0) ? -Math.abs(divisor) : Math.abs(divisor)); + } else { + return value; + } + } + + /** + * @param angle Angle in radians. + * @return The same angle, in radians, but in [-PI,PI]. + */ + public static double normalizeMinusPiPi(double angle) { + // Not modifying values in output range. + if ((angle >= -Math.PI) && (angle <= Math.PI)) { + return angle; + } + return remainderTwoPi(angle); + } + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return The same angle, in radians, but in [-PI,PI]. + */ + public static double normalizeMinusPiPiFast(double angle) { + // Not modifying values in output range. + if ((angle >= -Math.PI) && (angle <= Math.PI)) { + return angle; + } + return remainderTwoPiFast(angle); + } + + /** + * @param angle Angle in radians. + * @return The same angle, in radians, but in [0,2*PI]. + */ + public static double normalizeZeroTwoPi(double angle) { + // Not modifying values in output range. + if ((angle >= 0.0) && (angle <= 2*Math.PI)) { + return angle; + } + angle = remainderTwoPi(angle); + if (angle < 0.0) { + // LO then HI is theoretically better (when starting near 0). + return (angle + TWOPI_LO) + TWOPI_HI; + } else { + return angle; + } + } + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return The same angle, in radians, but in [0,2*PI]. + */ + public static double normalizeZeroTwoPiFast(double angle) { + // Not modifying values in output range. + if ((angle >= 0.0) && (angle <= 2*Math.PI)) { + return angle; + } + angle = remainderTwoPiFast(angle); + if (angle < 0.0) { + // LO then HI is theoretically better (when starting near 0). + return (angle + TWOPI_LO) + TWOPI_HI; + } else { + return angle; + } + } + + /** + * @param angle Angle in radians. + * @return Angle value modulo PI, in radians, in [-PI/2,PI/2]. + */ + public static double normalizeMinusHalfPiHalfPi(double angle) { + // Not modifying values in output range. + if ((angle >= -Math.PI/2) && (angle <= Math.PI/2)) { + return angle; + } + return remainderPi(angle); + } + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return Angle value modulo PI, in radians, in [-PI/2,PI/2]. + */ + public static double normalizeMinusHalfPiHalfPiFast(double angle) { + // Not modifying values in output range. + if ((angle >= -Math.PI/2) && (angle <= Math.PI/2)) { + return angle; + } + return remainderPiFast(angle); + } + + /* + * floating points utils + */ + + /** + * @param value A float value. + * @return true if the specified value is NaN or +-Infinity, false otherwise. + */ + public static boolean isNaNOrInfinite(float value) { + return NumbersUtils.isNaNOrInfinite(value); + } + + /** + * @param value A double value. + * @return true if the specified value is NaN or +-Infinity, false otherwise. + */ + public static boolean isNaNOrInfinite(double value) { + return NumbersUtils.isNaNOrInfinite(value); + } + + /** + * @param value A float value. + * @return Value unbiased exponent. + */ + public static int getExponent(float value) { + return ((Float.floatToRawIntBits(value)>>23)&0xFF)-MAX_FLOAT_EXPONENT; + } + + /** + * @param value A double value. + * @return Value unbiased exponent. + */ + public static int getExponent(double value) { + return (((int)(Double.doubleToRawLongBits(value)>>52))&0x7FF)-MAX_DOUBLE_EXPONENT; + } + + /** + * @param value A float value. + * @return -1.0f if the specified value is < 0, 1.0f if it is > 0, + * and the value itself if it is NaN or +-0.0f. + */ + public static float signum(float value) { + if (USE_JDK_MATH) { + return Math.signum(value); + } + if ((value == 0.0f) || (value != value)) { + return value; + } + return (float)signFromBit(value); + } + + /** + * @param value A double value. + * @return -1.0 if the specified value is < 0, 1.0 if it is > 0, + * and the value itself if it is NaN or +-0.0. + */ + public static double signum(double value) { + if (USE_JDK_MATH) { + return Math.signum(value); + } + if ((value == 0.0) || (value != value)) { + return value; + } + if (ANTI_SLOW_CASTS) { + return (double)(int)signFromBit(value); + } else { + return (double)signFromBit(value); + } + } + + /** + * @param value A float value. + * @return -1 if sign bit is 1, 1 if sign bit is 0. + */ + public static int signFromBit(float value) { + return ((Float.floatToRawIntBits(value)>>30)|1); + } + + /** + * @param value A double value. + * @return -1 if sign bit is 1, 1 if sign bit is 0. + */ + public static long signFromBit(double value) { + // Returning a long, to avoid useless cast into int. + return ((Double.doubleToRawLongBits(value)>>62)|1); + } + + /** + * A sign of NaN can be interpreted as positive or negative. + * + * @param magnitude A float value. + * @param sign A float value. + * @return A value with the magnitude of the first argument, and the sign + * of the second argument. + */ + public static float copySign(float magnitude, float sign) { + return Float.intBitsToFloat( + (Float.floatToRawIntBits(sign) & Integer.MIN_VALUE) + | (Float.floatToRawIntBits(magnitude) & Integer.MAX_VALUE)); + } + + /** + * A sign of NaN can be interpreted as positive or negative. + * + * @param magnitude A double value. + * @param sign A double value. + * @return A value with the magnitude of the first argument, and the sign + * of the second argument. + */ + public static double copySign(double magnitude, double sign) { + return Double.longBitsToDouble( + (Double.doubleToRawLongBits(sign) & Long.MIN_VALUE) + | (Double.doubleToRawLongBits(magnitude) & Long.MAX_VALUE)); + } + + /** + * The ULP (Unit in the Last Place) is the distance to the next value larger + * in magnitude. + * + * @param value A float value. + * @return The size of an ulp of the specified value, or Float.MIN_VALUE + * if it is +-0.0f, or +Infinity if it is +-Infinity, or NaN + * if it is NaN. + */ + public static float ulp(float value) { + if (USE_JDK_MATH) { + return Math.ulp(value); + } + /* + * Look-up table not really worth it in micro-benchmark, + * so should be worse with cache-misses. + */ + final int exponent = getExponent(value); + if (exponent >= (MIN_FLOAT_NORMAL_EXPONENT+23)) { + if (exponent == MAX_FLOAT_EXPONENT+1) { + // NaN or +-Infinity + return Math.abs(value); + } + // normal: returning 2^(exponent-23) + return Float.intBitsToFloat((exponent+(MAX_FLOAT_EXPONENT-23))<<23); + } else { + if (exponent == MIN_FLOAT_NORMAL_EXPONENT-1) { + // +-0.0f or subnormal + return Float.MIN_VALUE; + } + // subnormal result + return Float.intBitsToFloat(1<<(exponent-MIN_FLOAT_NORMAL_EXPONENT)); + } + } + + /** + * The ULP (Unit in the Last Place) is the distance to the next value larger + * in magnitude. + * + * @param value A double value. + * @return The size of an ulp of the specified value, or Double.MIN_VALUE + * if it is +-0.0, or +Infinity if it is +-Infinity, or NaN + * if it is NaN. + */ + public static double ulp(double value) { + if (USE_JDK_MATH) { + return Math.ulp(value); + } + /* + * Look-up table not really worth it in micro-benchmark, + * so should be worse with cache-misses. + */ + final int exponent = getExponent(value); + if (exponent >= (MIN_DOUBLE_NORMAL_EXPONENT+52)) { + if (exponent == MAX_DOUBLE_EXPONENT+1) { + // NaN or +-Infinity + return Math.abs(value); + } + // normal: returning 2^(exponent-52) + return Double.longBitsToDouble((exponent+(MAX_DOUBLE_EXPONENT-52L))<<52); + } else { + if (exponent == MIN_DOUBLE_NORMAL_EXPONENT-1) { + // +-0.0f or subnormal + return Double.MIN_VALUE; + } + // subnormal result + return Double.longBitsToDouble(1L<<(exponent-MIN_DOUBLE_NORMAL_EXPONENT)); + } + } + + /** + * If both arguments are +-0.0(f), (float)direction is returned. + * + * If both arguments are +Infinity or -Infinity, + * respectively +Infinity or -Infinity is returned. + * + * @param start A float value. + * @param direction A double value. + * @return The float adjacent to start towards direction, considering that + * +(-)Float.MIN_VALUE is adjacent to +(-)0.0f, and that + * +(-)Float.MAX_VALUE is adjacent to +(-)Infinity, + * or NaN if any argument is NaN. + */ + public static float nextAfter(float start, double direction) { + if (direction < start) { + // Going towards -Infinity. + if (start == 0.0f) { + // +-0.0f + return -Float.MIN_VALUE; + } + final int bits = Float.floatToRawIntBits(start); + return Float.intBitsToFloat(bits + ((bits > 0) ? -1 : 1)); + } else if (direction > start) { + // Going towards +Infinity. + // +0.0f to get rid of eventual -0.0f + final int bits = Float.floatToRawIntBits(start + 0.0f); + return Float.intBitsToFloat(bits + (bits >= 0 ? 1 : -1)); + } else if (start == direction) { + return (float)direction; + } else { + // Returning a NaN derived from the input NaN(s). + return start + (float)direction; + } + } + + /** + * If both arguments are +-0.0, direction is returned. + * + * If both arguments are +Infinity or -Infinity, + * respectively +Infinity or -Infinity is returned. + * + * @param start A double value. + * @param direction A double value. + * @return The double adjacent to start towards direction, considering that + * +(-)Double.MIN_VALUE is adjacent to +(-)0.0, and that + * +(-)Double.MAX_VALUE is adjacent to +(-)Infinity, + * or NaN if any argument is NaN. + */ + public static double nextAfter(double start, double direction) { + if (direction < start) { + // Going towards -Infinity. + if (start == 0.0) { + // +-0.0 + return -Double.MIN_VALUE; + } + final long bits = Double.doubleToRawLongBits(start); + return Double.longBitsToDouble(bits + ((bits > 0) ? -1 : 1)); + } else if (direction > start) { + // Going towards +Infinity. + // +0.0 to get rid of eventual -0.0 + final long bits = Double.doubleToRawLongBits(start + 0.0f); + return Double.longBitsToDouble(bits + (bits >= 0 ? 1 : -1)); + } else if (start == direction) { + return direction; + } else { + // Returning a NaN derived from the input NaN(s). + return start + direction; + } + } + + /** + * Semantically equivalent to nextAfter(start,Double.NEGATIVE_INFINITY). + */ + public static float nextDown(float start) { + if (start > Float.NEGATIVE_INFINITY) { + if (start == 0.0f) { + // +-0.0f + return -Float.MIN_VALUE; + } + final int bits = Float.floatToRawIntBits(start); + return Float.intBitsToFloat(bits + ((bits > 0) ? -1 : 1)); + } else if (start == Float.NEGATIVE_INFINITY) { + return Float.NEGATIVE_INFINITY; + } else { + // NaN + return start; + } + } + + /** + * Semantically equivalent to nextAfter(start,Double.NEGATIVE_INFINITY). + */ + public static double nextDown(double start) { + if (start > Double.NEGATIVE_INFINITY) { + if (start == 0.0) { + // +-0.0 + return -Double.MIN_VALUE; + } + final long bits = Double.doubleToRawLongBits(start); + return Double.longBitsToDouble(bits + ((bits > 0) ? -1 : 1)); + } else if (start == Double.NEGATIVE_INFINITY) { + return Double.NEGATIVE_INFINITY; + } else { + // NaN + return start; + } + } + + /** + * Semantically equivalent to nextAfter(start,Double.POSITIVE_INFINITY). + */ + public static float nextUp(float start) { + if (start < Float.POSITIVE_INFINITY) { + // +0.0f to get rid of eventual -0.0f + final int bits = Float.floatToRawIntBits(start + 0.0f); + return Float.intBitsToFloat(bits + (bits >= 0 ? 1 : -1)); + } else if (start == Float.POSITIVE_INFINITY) { + return Float.POSITIVE_INFINITY; + } else { + // NaN + return start; + } + } + + /** + * Semantically equivalent to nextAfter(start,Double.POSITIVE_INFINITY). + */ + public static double nextUp(double start) { + if (start < Double.POSITIVE_INFINITY) { + // +0.0 to get rid of eventual -0.0 + final long bits = Double.doubleToRawLongBits(start + 0.0); + return Double.longBitsToDouble(bits + (bits >= 0 ? 1 : -1)); + } else if (start == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } else { + // NaN + return start; + } + } + + /** + * Precision may be lost if the result is subnormal. + * + * @param value A float value. + * @param scaleFactor An int value. + * @return value * 2^scaleFactor, or a value equivalent to the specified + * one if it is NaN, +-Infinity or +-0.0f. + */ + public static float scalb(float value, int scaleFactor) { + // Large enough to imply overflow or underflow for + // a finite non-zero value. + final int MAX_SCALE = 2*MAX_FLOAT_EXPONENT+23+1; + + // Making sure scaling factor is in a reasonable range. + scaleFactor = Math.max(Math.min(scaleFactor, MAX_SCALE), -MAX_SCALE); + + return (float)(((double)value) * twoPowNormal(scaleFactor)); + } + + /** + * Precision may be lost if the result is subnormal. + * + * @param value A double value. + * @param scaleFactor An int value. + * @return value * 2^scaleFactor, or a value equivalent to the specified + * one if it is NaN, +-Infinity or +-0.0. + */ + public static double scalb(double value, int scaleFactor) { + if ((scaleFactor > -MAX_DOUBLE_EXPONENT) && (scaleFactor <= MAX_DOUBLE_EXPONENT)) { + // Quick case (as done in apache FastMath). + return value * twoPowNormal(scaleFactor); + } + + // Large enough to imply overflow or underflow for + // a finite non-zero value. + final int MAX_SCALE = 2*MAX_DOUBLE_EXPONENT+52+1; + + // Making sure scaling factor is in a reasonable range. + final int exponentAdjust; + final int scaleIncrement; + final double exponentDelta; + if (scaleFactor < 0) { + scaleFactor = Math.max(scaleFactor, -MAX_SCALE); + scaleIncrement = -512; + exponentDelta = TWO_POW_N512; + } else { + scaleFactor = Math.min(scaleFactor, MAX_SCALE); + scaleIncrement = 512; + exponentDelta = TWO_POW_512; + } + + // Calculating (scaleFactor % +-512), 512 = 2^9, using + // technique from "Hacker's Delight" section 10-2. + final int t = ((scaleFactor >> (9-1)) >>> (32-9)); + exponentAdjust = ((scaleFactor + t) & (512-1)) - t; + + value *= twoPowNormal(exponentAdjust); + scaleFactor -= exponentAdjust; + + while (scaleFactor != 0) { + value *= exponentDelta; + scaleFactor -= scaleIncrement; + } + + return value; + } + + /* + * Non-redefined Math public values and treatments. + */ + + public static float abs(float a) { + return Math.abs(a); + } + + public static double abs(double a) { + return Math.abs(a); + } + + public static float min(float a, float b) { + return Math.min(a,b); + } + + public static double min(double a, double b) { + return Math.min(a,b); + } + + public static float max(float a, float b) { + return Math.max(a,b); + } + + public static double max(double a, double b) { + return Math.max(a,b); + } + + public static double IEEEremainder(double f1, double f2) { + return Math.IEEEremainder(f1,f2); + } + + public static double random() { + return Math.random(); + } + + //-------------------------------------------------------------------------- + // PRIVATE METHODS + //-------------------------------------------------------------------------- + + /** + * Non-instantiable. + */ + private FastMath() { + } + + /* + * Remainders (accurate). + */ + + /** + * @param angle Angle in radians. + * @return Remainder of (angle % (2*PI)), in [-PI,PI]. + */ + private static double remainderTwoPi(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderTwoPi(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle <= (4*NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2)) { + double fn = (double)(int)(angle*TWOPI_INV+0.5); + angle = (angle - fn*TWOPI_HI) - fn*TWOPI_LO; + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI) { + angle = (angle + TWOPI_HI) + TWOPI_LO; + } else if (angle > Math.PI) { + angle = (angle - TWOPI_HI) - TWOPI_LO; + } + return negateResult ? -angle : angle; + } else if (angle < Double.POSITIVE_INFINITY) { + angle = heavyRemainderTwoPi(angle); + return negateResult ? -angle : angle; + } else { // angle is +Infinity or NaN + return Double.NaN; + } + } + + /** + * @param angle Angle in radians. + * @return Remainder of (angle % PI), in [-PI/2,PI/2]. + */ + private static double remainderPi(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderPi(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle <= (2*NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2)) { + double fn = (double)(int)(angle*PI_INV+0.5); + angle = (angle - fn*PI_HI) - fn*PI_LO; + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI/2) { + angle = (angle + PI_HI) + PI_LO; + } else if (angle > Math.PI/2) { + angle = (angle - PI_HI) - PI_LO; + } + return negateResult ? -angle : angle; + } else if (angle < Double.POSITIVE_INFINITY) { + angle = heavyRemainderPi(angle); + return negateResult ? -angle : angle; + } else { // angle is +Infinity or NaN + return Double.NaN; + } + } + + /** + * @param angle Angle in radians. + * @return Bits of double corresponding to remainder of (angle % (PI/2)), + * in [-PI/4,PI/4], with quadrant encoded in exponent bits. + */ + private static long remainderPiO2(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderPiO2(angle, false); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle <= NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2) { + int n = (int)(angle*PIO2_INV+0.5); + double fn = (double)n; + angle = (angle - fn*PIO2_HI) - fn*PIO2_LO; + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI/4) { + angle = (angle + PIO2_HI) + PIO2_LO; + n--; + } else if (angle > Math.PI/4) { + angle = (angle - PIO2_HI) - PIO2_LO; + n++; + } + if (negateResult) { + angle = -angle; + } + return encodeRemainderAndQuadrant(angle, n&3); + } else if (angle < Double.POSITIVE_INFINITY) { + return heavyRemainderPiO2(angle, negateResult); + } else { // angle is +Infinity or NaN + return encodeRemainderAndQuadrant(Double.NaN, 0); + } + } + + /* + * Remainders (fast). + */ + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return Remainder of (angle % (2*PI)), in [-PI,PI]. + */ + private static double remainderTwoPiFast(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderTwoPi(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + // - We don't bother with values higher than (2*PI*(2^52)), + // since they are spaced by 2*PI or more from each other. + // - For large values, we don't use % because it might be very slow, + // and we split computation in two, because cast from double to int + // with large numbers might be very slow also. + if (angle <= TWO_POW_26*(2*Math.PI)) { + // ok + } else if (angle <= TWO_POW_52*(2*Math.PI)) { + // Computing remainder of angle modulo TWO_POW_26*(2*PI). + double fn = (double)(int)(angle*(TWOPI_INV/TWO_POW_26)+0.5); + angle = (angle - fn*(TWOPI_HI*TWO_POW_26)) - fn*(TWOPI_LO*TWO_POW_26); + // Here, angle is in [-TWO_POW_26*PI,TWO_POW_26*PI], or so. + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } else if (angle < Double.POSITIVE_INFINITY) { + return 0.0; + } else { // angle is +Infinity or NaN + return Double.NaN; + } + + // Computing remainder of angle modulo 2*PI. + double fn = (double)(int)(angle*TWOPI_INV+0.5); + angle = (angle - fn*TWOPI_HI) - fn*TWOPI_LO; + + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI) { + angle = (angle + TWOPI_HI) + TWOPI_LO; + } else if (angle > Math.PI) { + angle = (angle - TWOPI_HI) - TWOPI_LO; + } + return negateResult ? -angle : angle; + } + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return Remainder of (angle % PI), in [-PI/2,PI/2]. + */ + private static double remainderPiFast(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderPi(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + // - We don't bother with values higher than (PI*(2^52)), + // since they are spaced by PI or more from each other. + // - For large values, we don't use % because it might be very slow, + // and we split computation in two, because cast from double to int + // with large numbers might be very slow also. + if (angle <= TWO_POW_26*Math.PI) { + // ok + } else if (angle <= TWO_POW_52*Math.PI) { + // Computing remainder of angle modulo TWO_POW_26*PI. + double fn = (double)(int)(angle*(PI_INV/TWO_POW_26)+0.5); + angle = (angle - fn*(PI_HI*TWO_POW_26)) - fn*(PI_LO*TWO_POW_26); + // Here, angle is in [-TWO_POW_26*PI/2,TWO_POW_26*PI/2], or so. + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } else if (angle < Double.POSITIVE_INFINITY) { + return 0.0; + } else { // angle is +Infinity or NaN + return Double.NaN; + } + + // Computing remainder of angle modulo PI. + double fn = (double)(int)(angle*PI_INV+0.5); + angle = (angle - fn*PI_HI) - fn*PI_LO; + + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI/2) { + angle = (angle + PI_HI) + PI_LO; + } else if (angle > Math.PI/2) { + angle = (angle - PI_HI) - PI_LO; + } + return negateResult ? -angle : angle; + } +} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/IntWrapper.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/IntWrapper.java new file mode 100644 index 000000000..812e5a22d --- /dev/null +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/IntWrapper.java @@ -0,0 +1,13 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package space.kscience.kmath.jafama; + +public class IntWrapper { + public int value; + @Override + public String toString() { + return Integer.toString(this.value); + } +} 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 new file mode 100644 index 000000000..2b6cc3a5a --- /dev/null +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt @@ -0,0 +1,102 @@ +package space.kscience.kmath.jafama + +import space.kscience.kmath.operations.* + +/** + * Advanced Number-like semifield that implements basic operations. + */ +public interface ExtendedFieldOperations : + FieldOperations, + TrigonometricOperations, + PowerOperations, + ExponentialOperations { + public override fun tan(arg: T): T = sin(arg) / cos(arg) + public override fun tanh(arg: T): T = sinh(arg) / cosh(arg) + + public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { + TrigonometricOperations.COS_OPERATION -> ::cos + TrigonometricOperations.SIN_OPERATION -> ::sin + TrigonometricOperations.TAN_OPERATION -> ::tan + TrigonometricOperations.ACOS_OPERATION -> ::acos + TrigonometricOperations.ASIN_OPERATION -> ::asin + TrigonometricOperations.ATAN_OPERATION -> ::atan + PowerOperations.SQRT_OPERATION -> ::sqrt + ExponentialOperations.EXP_OPERATION -> ::exp + ExponentialOperations.LN_OPERATION -> ::ln + ExponentialOperations.COSH_OPERATION -> ::cosh + ExponentialOperations.SINH_OPERATION -> ::sinh + ExponentialOperations.TANH_OPERATION -> ::tanh + ExponentialOperations.ACOSH_OPERATION -> ::acosh + ExponentialOperations.ASINH_OPERATION -> ::asinh + ExponentialOperations.ATANH_OPERATION -> ::atanh + else -> super.unaryOperationFunction(operation) + } +} + +/** + * Advanced Number-like field that implements basic operations. + */ +public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra, ScaleOperations { + public override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 + public override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 + public override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) + public override fun asinh(arg: T): T = ln(sqrt(arg * arg + one) + arg) + public override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) + public override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0 + + public override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = + when (operation) { + PowerOperations.POW_OPERATION -> ::power + else -> super.rightSideNumberOperationFunction(operation) + } +} + +/** + * A field for [Double] without boxing. Does not produce appropriate field element. + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public object DoubleField : ExtendedField, Norm, ScaleOperations { + public override inline val zero: Double get() = 0.0 + public override inline val one: Double get() = 1.0 + + public override fun number(value: Number): Double = value.toDouble() + + public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = + when (operation) { + PowerOperations.POW_OPERATION -> ::power + else -> super.binaryOperationFunction(operation) + } + + public override inline fun add(a: Double, b: Double): Double = a + b + + public override inline fun multiply(a: Double, b: Double): Double = a * b + public override inline fun divide(a: Double, b: Double): Double = a / b + + public override fun scale(a: Double, value: Double): Double = a * value + + public override inline fun sin(arg: Double): Double = FastMath.sin(arg) + public override inline fun cos(arg: Double): Double = FastMath.cos(arg) + public override inline fun tan(arg: Double): Double = FastMath.tan(arg) + public override inline fun acos(arg: Double): Double = FastMath.acos(arg) + public override inline fun asin(arg: Double): Double = FastMath.asin(arg) + public override inline fun atan(arg: Double): Double = FastMath.atan(arg) + + public override inline fun sinh(arg: Double): Double = FastMath.sinh(arg) + public override inline fun cosh(arg: Double): Double = FastMath.cosh(arg) + public override inline fun tanh(arg: Double): Double = FastMath.tanh(arg) + public override inline fun asinh(arg: Double): Double = FastMath.asinh(arg) + public override inline fun acosh(arg: Double): Double = FastMath.acosh(arg) + public override inline fun atanh(arg: Double): Double = FastMath.atanh(arg) + + public override inline fun power(arg: Double, pow: Number): Double = FastMath.pow(arg, pow.toDouble()) + public override inline fun exp(arg: Double): Double = FastMath.exp(arg) + public override inline fun ln(arg: Double): Double = FastMath.log(arg) + + public override inline fun norm(arg: Double): Double = FastMath.abs(arg) + + public override inline fun Double.unaryMinus(): Double = -this + public override inline fun Double.plus(b: Double): Double = this + b + public override inline fun Double.minus(b: Double): Double = this - b + public override inline fun Double.times(b: Double): Double = this * b + public override inline fun Double.div(b: Double): Double = this / b +} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/NumbersUtils.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/NumbersUtils.java new file mode 100644 index 000000000..6fdd9dea5 --- /dev/null +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/NumbersUtils.java @@ -0,0 +1,2647 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package space.kscience.kmath.jafama; + +/** + * Class containing various basic utility methods to deal with numbers. + * This class is meant to be light (no big look-up tables or such). + * + * Check methods return boolean if success, + * for it allows to use them in assertions. + * + * toString methods use capital letters, unlike JDK's toStrings, for it is more + * readable (especially, "l" and "1" can easily be confused with one another). + * + * Some methods have an int version additionally to the long version, + * even though long version could be used instead, for performance reasons, + * either for the methods themselves (if they do computations with ints + * instead of longs), or to be used in an int use case (like methods + * checking whether or not a signed int can fit in such number of bits). + */ +public final class NumbersUtils { + + //-------------------------------------------------------------------------- + // MEMBERS + //-------------------------------------------------------------------------- + + /** + * Double.MIN_NORMAL since Java 6. + */ + public static final double DOUBLE_MIN_NORMAL = Double.longBitsToDouble(0x0010000000000000L); // 2.2250738585072014E-308 + + /** + * Float.MIN_NORMAL since Java 6. + */ + public static final float FLOAT_MIN_NORMAL = Float.intBitsToFloat(0x00800000); // 1.17549435E-38f + + private static final int MIN_DOUBLE_EXPONENT = -1074; + private static final int MAX_DOUBLE_EXPONENT = 1023; + + /** + * All possible upper case chars for representing a number as a String. + */ + private final static char[] CHAR_BY_DIGIT; + static { + final char minDecimal = '0'; + final char maxDecimal = '9'; + final int n1 = maxDecimal - minDecimal + 1; + final char minLetter = 'A'; + final char maxLetter = 'Z'; + final int n2 = maxLetter - minLetter + 1; + CHAR_BY_DIGIT = new char[n1+n2]; + int i=0; + for (char c=minDecimal;c<=maxDecimal;c++) { + CHAR_BY_DIGIT[i++] = c; + } + for (char c=minLetter;c<=maxLetter;c++) { + CHAR_BY_DIGIT[i++] = c; + } + } + + /** + * For power-of-two radixes only. + */ + private static final int[] DIV_SHIFT_BY_RADIX; + static { + DIV_SHIFT_BY_RADIX = new int[32+1]; + int shift=1; + for (int radix=2;radix<=32;radix*=2) { + DIV_SHIFT_BY_RADIX[radix] = shift++; + } + } + + private final static int[] MAX_NBR_OF_NEG_INT_DIGITS_BY_RADIX = new int[Character.MAX_RADIX+1]; + private final static int[] MAX_NBR_OF_NEG_LONG_DIGITS_BY_RADIX = new int[Character.MAX_RADIX+1]; + static { + for (int radix=Character.MIN_RADIX;radix<=Character.MAX_RADIX;radix++) { + /* + * Brutal but works. + * -1 for the sign. + */ + MAX_NBR_OF_NEG_INT_DIGITS_BY_RADIX[radix] = Integer.toString(Integer.MIN_VALUE, radix).length()-1; + MAX_NBR_OF_NEG_LONG_DIGITS_BY_RADIX[radix] = Long.toString(Long.MIN_VALUE, radix).length()-1; + } + } + + static final double NO_CSN_MIN_BOUND_INCL = 1e-3; + static final double NO_CSN_MAX_BOUND_EXCL = 1e7; + + private static final double PIO2_HI = Double.longBitsToDouble(0x3FF921FB54400000L); // 1.57079632673412561417e+00 first 33 bits of pi/2 + private static final double PIO2_LO = Double.longBitsToDouble(0x3DD0B4611A626331L); // 6.07710050650619224932e-11 pi/2 - PIO2_HI + private static final double PI_HI = 2*PIO2_HI; + private static final double PI_LO = 2*PIO2_LO; + private static final double TWOPI_HI = 4*PIO2_HI; + private static final double TWOPI_LO = 4*PIO2_LO; + + //-------------------------------------------------------------------------- + // PUBLIC METHODS + //-------------------------------------------------------------------------- + + /** + * @return True if the specified values are equal or both NaN, false otherwise. + */ + public static boolean equal(float a, float b) { + // Only does one test if a == b. + return (a == b) ? true : ((a != a) && (b != b)); + } + + /** + * @return True if the specified values are equal or both NaN, false otherwise. + */ + public static boolean equal(double a, double b) { + // Only does one test if a == b. + return (a == b) ? true : ((a != a) && (b != b)); + } + + /** + * @return True if the specified value is a mathematical integer, + * false otherwise (which includes NaN and +-Infinity). + */ + public static boolean isMathematicalInteger(float value) { + // Doing magnitude test first, for cast + // might be very slow for huge values. + // It also helps be faster for huge values, + // for which the test with cast always fail. + value = Math.abs(value); + return ((value >= (float)(1<<23) + && (value != Float.POSITIVE_INFINITY))) + || (value == (float)(int)value); + } + + /** + * @return True if the specified value is a mathematical integer, + * false otherwise (which includes NaN and +-Infinity). + */ + public static boolean isMathematicalInteger(double value) { + // Doing magnitude test first, for cast + // might be very slow for huge values. + // It also helps be faster for huge values, + // for which the test with cast always fail. + value = Math.abs(value); + return ((value >= (double)(1L<<52)) + && (value != Double.POSITIVE_INFINITY)) + || (value == (double)(long)value); + } + + /** + * @param value A float value. + * @return True if the specified value is equidistant from two adjacent + * mathematical integers, false otherwise (which includes NaN + * and +-Infinity). + */ + public static boolean isEquidistant(float value) { + if (false) { + // Also works, but slower. + final int bits = Float.floatToRawIntBits(value); + final int exponent = ((bits>>23)&0xFF)-127; + final int nbrOfPostCommaBits = 23 - exponent; + if ((nbrOfPostCommaBits <= 0) || (nbrOfPostCommaBits >= 25)) { + // No mantissa bit after comma, or all mantissa bits + // (including implicit 1) are at least one bit away from it. + //System.out.println("can't be"); + return false; + } + final int mantissa = 0x00800000|(bits&0x007FFFFF); + final int postCommaMask = ~((-1)<>52))&0x7FF)-1023; + final int nbrOfPostCommaBits = 52 - exponent; + if ((nbrOfPostCommaBits <= 0) || (nbrOfPostCommaBits >= 54)) { + // No mantissa bit after comma, or all mantissa bits + // (including implicit 1) are at least one bit away from it. + return false; + } + final long mantissa = 0x0010000000000000L|(bits&0x000FFFFFFFFFFFFFL); + final long postCommaMask = ~((-1L)< value is NaN or +-Infinity + return !(value-value == 0.0f); + } + + /** + * @param value A double value. + * @return True if the specified value is NaN or +-Infinity, false otherwise. + */ + public static boolean isNaNOrInfinite(double value) { + // value-value is not equal to 0.0 (and is NaN) <-> value is NaN or +-Infinity + return !(value-value == 0.0); + } + + /** + * @param value A float value. + * @return -1 if sign bit is 1, 1 if sign bit is 0. + */ + public static int signFromBit(float value) { + return ((Float.floatToRawIntBits(value)>>30)|1); + } + + /** + * @param value A double value. + * @return -1 if sign bit is 1, 1 if sign bit is 0. + */ + public static long signFromBit(double value) { + // Returning a long, to avoid useless cast into int. + return ((Double.doubleToRawLongBits(value)>>62)|1); + } + + /* + * min/max ranges + */ + + /** + * @return True if the specified value is in the specified range (inclusive), false otherwise. + */ + public static boolean isInRange(int min, int max, int a) { + return (min <= a) && (a <= max); + } + + /** + * @return True if the specified value is in the specified range (inclusive), false otherwise. + */ + public static boolean isInRange(long min, long max, long a) { + return (min <= a) && (a <= max); + } + + /** + * Returns false if any value is NaN. + * + * @return True if the specified value is in the specified range (inclusive), false otherwise. + */ + public static boolean isInRange(float min, float max, float a) { + return (min <= a) && (a <= max); + } + + /** + * Returns false if any value is NaN. + * + * @return True if the specified value is in the specified range (inclusive), false otherwise. + */ + public static boolean isInRange(double min, double max, double a) { + return (min <= a) && (a <= max); + } + + /* + * + */ + + /** + * @return True if does not throw. + * @throws IllegalArgumentException if the specified value is not in the specified range (inclusive). + */ + public static boolean checkIsInRange(int min, int max, int a) { + if (!isInRange(min, max, a)) { + throw new IllegalArgumentException(a+" not in ["+min+","+max+"]"); + } + return true; + } + + /** + * @return True if does not throw. + * @throws IllegalArgumentException if the specified value is not in the specified range (inclusive). + */ + public static boolean checkIsInRange(long min, long max, long a) { + if (!isInRange(min, max, a)) { + throw new IllegalArgumentException(a+" not in ["+min+","+max+"]"); + } + return true; + } + + /** + * @return True if does not throw. + * @throws IllegalArgumentException if the specified value is not in the specified range (inclusive) + * or any parameter is NaN. + */ + public static boolean checkIsInRange(float min, float max, float a) { + if (!isInRange(min, max, a)) { + throw new IllegalArgumentException(a+" not in ["+min+","+max+"]"); + } + return true; + } + + /** + * @return True if does not throw. + * @throws IllegalArgumentException if the specified value is not in the specified range (inclusive) + * or any parameter is NaN. + */ + public static boolean checkIsInRange(double min, double max, double a) { + if (!isInRange(min, max, a)) { + throw new IllegalArgumentException(a+" not in ["+min+","+max+"]"); + } + return true; + } + + /* + * + */ + + /** + * @param min A value. + * @param max A value. + * @param a A value. + * @return min if a <= min, else max if a >= max, else a. + */ + public static int toRange(int min, int max, int a) { + if (a <= min) { + return min; + } else if (a >= max) { + return max; + } else { + return a; + } + } + + /** + * @param min A value. + * @param max A value. + * @param a A value. + * @return min if a <= min, else max if a >= max, else a. + */ + public static long toRange(long min, long max, long a) { + if (a <= min) { + return min; + } else if (a >= max) { + return max; + } else { + return a; + } + } + + /** + * @param min A value. + * @param max A value. + * @param a A value. + * @return min if a <= min, else max if a >= max, else a. + */ + public static float toRange(float min, float max, float a) { + if (a <= min) { + return min; + } else if (a >= max) { + return max; + } else { + return a; + } + } + + /** + * @param min A value. + * @param max A value. + * @param a A value. + * @return min if a <= min, else max if a >= max, else a. + */ + public static double toRange(double min, double max, double a) { + if (a <= min) { + return min; + } else if (a >= max) { + return max; + } else { + return a; + } + } + + /* + * bitwise ranges + */ + + /** + * @param bitSize A number of bits, in [1,32]. + * @return True if the specified value fits as a signed integer + * over the specified number of bits, false otherwise. + * @throws IllegalArgumentException if the specified number of bits is not in [1,32]. + */ + public static boolean isInRangeSigned(int a, int bitSize) { + checkBitSizeForSignedInt(bitSize); + return (minSignedIntForBitSize_noCheck(bitSize) <= a) && (a <= maxSignedIntForBitSize_noCheck(bitSize)); + } + + /** + * @param bitSize A number of bits, in [1,64]. + * @return True if the specified value fits as a signed integer + * over the specified number of bits, false otherwise. + * @throws IllegalArgumentException if the specified number of bits is not in [1,64]. + */ + public static boolean isInRangeSigned(long a, int bitSize) { + checkBitSizeForSignedLong(bitSize); + return (minSignedLongForBitSize_noCheck(bitSize) <= a) && (a <= maxSignedLongForBitSize_noCheck(bitSize)); + } + + /** + * @param bitSize A number of bits, in [1,31]. + * @return True if the specified value fits as an unsigned integer + * over the specified number of bits, false otherwise. + * @throws IllegalArgumentException if the specified number of bits is not in [1,31]. + */ + public static boolean isInRangeUnsigned(int a, int bitSize) { + return isInRange(0, maxUnsignedIntForBitSize(bitSize), a); + } + + /** + * @param bitSize A number of bits, in [1,63]. + * @return True if the specified value fits as an unsigned integer + * over the specified number of bits, false otherwise. + * @throws IllegalArgumentException if the specified number of bits is not in [1,63]. + */ + public static boolean isInRangeUnsigned(long a, int bitSize) { + return isInRange(0, maxUnsignedLongForBitSize(bitSize), a); + } + + /* + * + */ + + /** + * @param bitSize A number of bits, in [1,32]. + * @return True if does not throw. + * @throws IllegalArgumentException if the specified value does not fit + * as a signed integer over the specified number of bits. + */ + public static boolean checkIsInRangeSigned(int a, int bitSize) { + if (!isInRangeSigned(a, bitSize)) { + throw new IllegalArgumentException(a+" does not fit as a signed value over "+bitSize+" bits"); + } + return true; + } + + /** + * @param bitSize A number of bits, in [1,64]. + * @return True if does not throw. + * @throws IllegalArgumentException if the specified value does not fit + * as a signed integer over the specified number of bits. + */ + public static boolean checkIsInRangeSigned(long a, int bitSize) { + if (!isInRangeSigned(a, bitSize)) { + throw new IllegalArgumentException(a+" does not fit as a signed value over "+bitSize+" bits"); + } + return true; + } + + /** + * @param bitSize A number of bits, in [1,31]. + * @return True if does not throw. + * @throws IllegalArgumentException if the specified value does not fit + * as an unsigned integer over the specified number of bits. + */ + public static boolean checkIsInRangeUnsigned(int a, int bitSize) { + if (!isInRangeUnsigned(a, bitSize)) { + throw new IllegalArgumentException(a+" does not fit as an unsigned value over "+bitSize+" bits"); + } + return true; + } + + /** + * @param bitSize A number of bits, in [1,63]. + * @return True if does not throw. + * @throws IllegalArgumentException if the specified value does not fit + * as an unsigned integer over the specified number of bits. + */ + public static boolean checkIsInRangeUnsigned(long a, int bitSize) { + if (!isInRangeUnsigned(a, bitSize)) { + throw new IllegalArgumentException(a+" does not fit as an unsigned value over "+bitSize+" bits"); + } + return true; + } + + /* + * masks (int) + */ + + /** + * @param bitSize A number of bits, in [0,32]. + * @return Mask with the specified number of left bits set with 0, + * and other bits set with 1. + */ + public static int intMaskMSBits0(int bitSize) { + checkIsInRange(0, 32, bitSize); + // Shifting in two times, for >>> doesn't work for full bit size (<< as well). + final int halfish = (bitSize>>1); + return ((-1)>>>halfish)>>>(bitSize-halfish); + } + + /** + * @param bitSize A number of bits, in [0,32]. + * @return Mask with the specified number of left bits set with 1, + * and other bits set with 0. + */ + public static int intMaskMSBits1(int bitSize) { + return ~intMaskMSBits0(bitSize); + } + + /** + * @param bitSize A number of bits, in [0,32]. + * @return Mask with the specified number of right bits set with 0, + * and other bits set with 1. + */ + public static int intMaskLSBits0(int bitSize) { + return ~intMaskMSBits0(32-bitSize); + } + + /** + * @param bitSize A number of bits, in [0,32]. + * @return Mask with the specified number of right bits set with 1, + * and other bits set with 0. + */ + public static int intMaskLSBits1(int bitSize) { + return intMaskMSBits0(32-bitSize); + } + + /* + * masks (long) + */ + + /** + * @param bitSize A number of bits, in [0,64]. + * @return Mask with the specified number of left bits set with 0, + * and other bits set with 1. + */ + public static long longMaskMSBits0(int bitSize) { + checkIsInRange(0, 64, bitSize); + // Shifting in two times, for >>> doesn't work for full bit size (<< as well). + final int halfish = (bitSize>>1); + return ((-1L)>>>halfish)>>>(bitSize-halfish); + } + + /** + * @param bitSize A number of bits, in [0,64]. + * @return Mask with the specified number of left bits set with 1, + * and other bits set with 0. + */ + public static long longMaskMSBits1(int bitSize) { + return ~longMaskMSBits0(bitSize); + } + + /** + * @param bitSize A number of bits, in [0,64]. + * @return Mask with the specified number of right bits set with 0, + * and other bits set with 1. + */ + public static long longMaskLSBits0(int bitSize) { + return ~longMaskMSBits0(64-bitSize); + } + + /** + * @param bitSize A number of bits, in [0,64]. + * @return Mask with the specified number of right bits set with 1, + * and other bits set with 0. + */ + public static long longMaskLSBits1(int bitSize) { + return longMaskMSBits0(64-bitSize); + } + + /* + * signed/unsigned + */ + + /** + * @return Unsigned value corresponding to bits of the specified byte. + */ + public static short byteAsUnsigned(byte value) { + return (short)(((short)value) & 0xFF); + } + + /** + * @return Unsigned value corresponding to bits of the specified short. + */ + public static int shortAsUnsigned(short value) { + return ((int)value) & 0xFFFF; + } + + /** + * @return Unsigned value corresponding to bits of the specified int. + */ + public static long intAsUnsigned(int value) { + return ((long)value) & 0xFFFFFFFF; + } + + /* + * bitwise ranges + */ + + /** + * @return True if a signed int value can be read over the specified number of bits, + * i.e. if it is in [1,32], false otherwise. + */ + public static boolean isValidBitSizeForSignedInt(int bitSize) { + return (bitSize > 0) && (bitSize <= 32); + } + + /** + * @return True if a signed long value can be read over the specified number of bits, + * i.e. if it is in [1,64], false otherwise. + */ + public static boolean isValidBitSizeForSignedLong(int bitSize) { + return (bitSize > 0) && (bitSize <= 64); + } + + /** + * @return True if an unsigned int value can be read over the specified number of bits, + * i.e. if it is in [1,31], false otherwise. + */ + public static boolean isValidBitSizeForUnsignedInt(int bitSize) { + return (bitSize > 0) && (bitSize < 32); + } + + /** + * @return True if an unsigned long value can be read over the specified number of bits, + * i.e. if it is in [1,63], false otherwise. + */ + public static boolean isValidBitSizeForUnsignedLong(int bitSize) { + return (bitSize > 0) && (bitSize < 64); + } + + /* + * + */ + + /** + * @return True if does not throw. + * @throws IllegalArgumentException if a signed int value can't be read over the + * specified number of bits, i.e. if it is not in [1,32]. + */ + public static boolean checkBitSizeForSignedInt(int bitSize) { + if (!isValidBitSizeForSignedInt(bitSize)) { + throw new IllegalArgumentException("bit size ["+bitSize+"] must be in [1,32] for signed int values"); + } + return true; + } + + /** + * @return True if does not throw. + * @throws IllegalArgumentException if a signed long value can't be read over the + * specified number of bits, i.e. if it is not in [1,64]. + */ + public static boolean checkBitSizeForSignedLong(int bitSize) { + if (!isValidBitSizeForSignedLong(bitSize)) { + throw new IllegalArgumentException("bit size ["+bitSize+"] must be in [1,64] for signed long values"); + } + return true; + } + + /** + * @return True if does not throw. + * @throws IllegalArgumentException if an unsigned int value can't be read over the + * specified number of bits, i.e. if it is not in [1,31]. + */ + public static boolean checkBitSizeForUnsignedInt(int bitSize) { + if (!isValidBitSizeForUnsignedInt(bitSize)) { + throw new IllegalArgumentException("bit size ["+bitSize+"] must be in [1,31] for unsigned int values"); + } + return true; + } + + /** + * @return True if does not throw. + * @throws IllegalArgumentException if an unsigned long value can't be read over the + * specified number of bits, i.e. if it is not in [1,63]. + */ + public static boolean checkBitSizeForUnsignedLong(int bitSize) { + if (!isValidBitSizeForUnsignedLong(bitSize)) { + throw new IllegalArgumentException("bit size ["+bitSize+"] must be in [1,63] for unsigned long values"); + } + return true; + } + + /* + * + */ + + /** + * @param bitSize A number of bits in [1,32]. + * @return The min signed int value that can be stored over the specified number of bits. + * @throws IllegalArgumentException if the specified number of bits is out of range. + */ + public static int minSignedIntForBitSize(int bitSize) { + checkBitSizeForSignedInt(bitSize); + return minSignedIntForBitSize_noCheck(bitSize); + } + + /** + * @param bitSize A number of bits in [1,64]. + * @return The min signed long value that can be stored over the specified number of bits. + * @throws IllegalArgumentException if the specified number of bits is out of range. + */ + public static long minSignedLongForBitSize(int bitSize) { + checkBitSizeForSignedLong(bitSize); + return minSignedLongForBitSize_noCheck(bitSize); + } + + /** + * @param bitSize A number of bits in [1,32]. + * @return The max signed int value that can be stored over the specified number of bits. + * @throws IllegalArgumentException if the specified number of bits is out of range. + */ + public static int maxSignedIntForBitSize(int bitSize) { + checkBitSizeForSignedInt(bitSize); + return maxSignedIntForBitSize_noCheck(bitSize); + } + + /** + * @param bitSize A number of bits in [1,64]. + * @return The max signed long value that can be stored over the specified number of bits. + * @throws IllegalArgumentException if the specified number of bits is out of range. + */ + public static long maxSignedLongForBitSize(int bitSize) { + checkBitSizeForSignedLong(bitSize); + return maxSignedLongForBitSize_noCheck(bitSize); + } + + /** + * @param bitSize A number of bits in [1,31]. + * @return The max unsigned int value that can be stored over the specified number of bits. + * @throws IllegalArgumentException if the specified number of bits is out of range. + */ + public static int maxUnsignedIntForBitSize(int bitSize) { + checkBitSizeForUnsignedInt(bitSize); + // i.e. (1<>(31-bitSize)); + } + + /** + * @param bitSize A number of bits in [1,63]. + * @return The max unsigned long value that can be stored over the specified number of bits. + * @throws IllegalArgumentException if the specified number of bits is out of range. + */ + public static long maxUnsignedLongForBitSize(int bitSize) { + checkBitSizeForUnsignedLong(bitSize); + // i.e. (1L<>(63-bitSize)); + } + + /* + * + */ + + /** + * @return The number of bits required to store the specified value as a signed integer, + * i.e. a result in [1,32]. + */ + public static int bitSizeForSignedValue(int value) { + if (value > 0) { + return 33-Integer.numberOfLeadingZeros(value); + } else if (value == 0) { + return 1; + } else { + // Works for Integer.MIN_VALUE as well. + return 33-Integer.numberOfLeadingZeros(-value-1); + } + } + + /** + * @return The number of bits required to store the specified value as a signed integer, + * i.e. a result in [1,64]. + */ + public static int bitSizeForSignedValue(long value) { + if (value > 0) { + return 65-Long.numberOfLeadingZeros(value); + } else if (value == 0) { + return 1; + } else { + // Works for Long.MIN_VALUE as well. + return 65-Long.numberOfLeadingZeros(-value-1); + } + } + + /** + * @param value An integer value in [0,Integer.MAX_VALUE]. + * @return The number of bits required to store the specified value as an unsigned integer, + * i.e. a result in [1,31]. + * @throws IllegalArgumentException if the specified value is < 0. + */ + public static int bitSizeForUnsignedValue(int value) { + if (value > 0) { + return 32-Integer.numberOfLeadingZeros(value); + } else { + if (value == 0) { + return 1; + } else { + throw new IllegalArgumentException("unsigned value ["+value+"] must be >= 0"); + } + } + } + + /** + * @param value An integer value in [0,Long.MAX_VALUE]. + * @return The number of bits required to store the specified value as an unsigned integer, + * i.e. a result in [1,63]. + * @throws IllegalArgumentException if the specified value is < 0. + */ + public static int bitSizeForUnsignedValue(long value) { + if (value > 0) { + return 64-Long.numberOfLeadingZeros(value); + } else { + if (value == 0) { + return 1; + } else { + throw new IllegalArgumentException("unsigned value ["+value+"] must be >= 0"); + } + } + } + + /* + * integer functions + */ + + /** + * @return 1 if the specified value is > 0, 0 if it is 0, -1 otherwise. + */ + public static int signum(int a) { + return (a < 0) ? -1 : ((a == 0) ? 0 : 1); + } + + /** + * @return 1 if the specified value is > 0, 0 if it is 0, -1 otherwise. + */ + public static int signum(long a) { + return (a < 0) ? -1 : ((a == 0) ? 0 : 1); + } + + /** + * @return True if the specified value is even, false otherwise. + */ + public static boolean isEven(int a) { + return ((a&1) == 0); + } + + /** + * @return True if the specified value is even, false otherwise. + */ + public static boolean isEven(long a) { + // faster to work on ints + return isEven((int)a); + } + + /** + * @return True if the specified value is odd, false otherwise. + */ + public static boolean isOdd(int a) { + return ((a&1) != 0); + } + + /** + * @return True if the specified value is odd, false otherwise. + */ + public static boolean isOdd(long a) { + // faster to work on ints + return isOdd((int)a); + } + + /** + * @return True if the specified values are both even or both odd, false otherwise. + */ + public static boolean haveSameEvenness(int a, int b) { + return (((a^b)&1) == 0); + } + + /** + * @return True if the specified values are both even or both odd, false otherwise. + */ + public static boolean haveSameEvenness(long a, long b) { + // faster to work on ints + return haveSameEvenness((int)a, (int)b); + } + + /** + * @return True if the specified values are both >= 0 or both < 0, false otherwise. + */ + public static boolean haveSameSign(int a, int b) { + return ((a^b) >= 0); + } + + /** + * @return True if the specified values are both >= 0 or both < 0, false otherwise. + */ + public static boolean haveSameSign(long a, long b) { + return ((a^b) >= 0); + } + + /** + * @return True if the specified value is a power of two, + * i.e. a value of the form 2^k, with k >= 0. + */ + public static boolean isPowerOfTwo(int a) { + if (a <= 0) { + return false; + } + if (false) { + // also works + return (a & -a) == a; + } + return (a & (a-1)) == 0; + } + + /** + * @return True if the specified value is a power of two, + * i.e. a value of the form 2^k, with k >= 0. + */ + public static boolean isPowerOfTwo(long a) { + if (a <= 0) { + return false; + } + if (false) { + // also works + return (a & -a) == a; + } + return (a & (a-1)) == 0; + } + + /** + * @return True if the specified value is a signed power of two, + * i.e. a value of the form +-2^k, with k >= 0. + */ + public static boolean isSignedPowerOfTwo(int a) { + if (a > 0) { + return (a & (a-1)) == 0; + } else { + if (a == -a) { + // a is 0 or Integer.MIN_VALUE + return (a != 0); + } + return ((-a) & (-a-1)) == 0; + } + } + + /** + * @return True if the specified value is a signed power of two, + * i.e. a value of the form +-2^k, with k >= 0. + */ + public static boolean isSignedPowerOfTwo(long a) { + if (a > 0) { + return (a & (a-1)) == 0; + } else { + if (a == -a) { + // a is 0 or Long.MIN_VALUE + return (a != 0); + } + return ((-a) & (-a-1)) == 0; + } + } + + /** + * @param a A value in [1,Integer.MAX_VALUE]. + * @return The highest power of two <= a. + */ + public static int floorPowerOfTwo(int a) { + if (a <= 0) { + throw new IllegalArgumentException("a ["+a+"] must be > 0"); + } + return Integer.highestOneBit(a); + } + + /** + * @param a A value in [1,Long.MAX_VALUE]. + * @return The highest power of two <= a. + */ + public static long floorPowerOfTwo(long a) { + if (a <= 0) { + throw new IllegalArgumentException("a ["+a+"] must be > 0"); + } + // Faster than copying int method + // (less computations on long). + return 1L << (63 - Long.numberOfLeadingZeros(a)); + } + + /** + * @param a A value in [0,2^30]. + * @return The lowest power of two >= a. + */ + public static int ceilingPowerOfTwo(int a) { + checkIsInRange(0, (1<<30), a); + return (a >= 2) ? Integer.highestOneBit((a-1)<<1) : 1; + } + + /** + * @param a A value in [0,2^62]. + * @return The lowest power of two >= a. + */ + public static long ceilingPowerOfTwo(long a) { + checkIsInRange(0L, (1L<<62), a); + // Faster than copying int method + // (less computations on long). + return 1L << (64 - Long.numberOfLeadingZeros(a - 1)); + } + + /** + * @return Mean without overflow, rounded to the lowest value (i.e. mathematical floor((a+b)/2), using floating point division). + */ + public static int meanLow(int a, int b) { + return (a & b) + ((a ^ b) >> 1); + } + + /** + * @return Mean without overflow, rounded to the lowest value (i.e. mathematical floor((a+b)/2), using floating point division). + */ + public static long meanLow(long a, long b) { + return (a & b) + ((a ^ b) >> 1); + } + + /** + * @return Mean without overflow, rounded to the value of smallest magnitude (i.e. mathematical (a+b)/2, using integer division). + */ + public static int meanSml(int a, int b) { + int result = meanLow(a,b); + if (!haveSameEvenness(a, b)) { + // inexact + if (((a&b) < 0) || (((a|b) < 0) && (a+b < 0))) { + // both < 0, or only one is < 0 and it has the largest magnitude + result++; + } + } + return result; + } + + /** + * @return Mean without overflow, rounded to the value of smallest magnitude (i.e. mathematical (a+b)/2, using integer division). + */ + public static long meanSml(long a, long b) { + long result = meanLow(a,b); + if (!haveSameEvenness(a, b)) { + // inexact + if (((a&b) < 0) || (((a|b) < 0) && (a+b < 0))) { + // both < 0, or only one is < 0 and it has the largest magnitude + result++; + } + } + return result; + } + + /** + * Useful because a positive int value could not represent half the width + * of full int range width, which is mathematically Integer.MAX_VALUE+1. + * + * @return Minus half the range width (inclusive, and rounded to the value of smaller magnitude) + * between the specified bounds. + * @throws IllegalArgumentException if min > max. + */ + public static int negHalfWidth(int min, int max) { + if (min > max) { + throw new IllegalArgumentException("min ["+min+"] must be <= max ["+max+"]"); + } + int mean = meanLow(min, max); + return min - mean - ((min^max)&1); + } + + /** + * Useful because a positive long value could not represent half the width + * of full long range width, which is mathematically Long.MAX_VALUE+1. + * + * @return Minus half the range width (inclusive, and rounded to the value of smaller magnitude) + * between the specified bounds. + * @throws IllegalArgumentException if min > max. + */ + public static long negHalfWidth(long min, long max) { + if (min > max) { + throw new IllegalArgumentException("min ["+min+"] must be <= max ["+max+"]"); + } + long mean = meanLow(min, max); + return min - mean - ((min^max)&1); + } + + /** + * This treatment being designed for optimization, the fact that spot + * is a signed power of two is not checked. + * + * @param value A value. + * @param spot A signed power of two (i.e. a value of the form +-2^k, k >= 0). + * @return value % spot, i.e. a value in ]-|spot|,|spot|[. + */ + public static int moduloSignedPowerOfTwo(int value, int spot) { + if (spot == Integer.MIN_VALUE) { + return (value != Integer.MIN_VALUE) ? value : 0; + } else { + int s = (value>>31); + return ((((value+s) ^ s) & (abs(spot)-1)) + s) ^ s; + } + } + + /** + * This treatment being designed for optimization, the fact that spot + * is a signed power of two is not checked. + * + * @param value A value. + * @param spot A signed power of two (i.e. a value of the form +-2^k, k >= 0). + * @return value % spot, i.e. a value in ]-|spot|,|spot|[. + */ + public static long moduloSignedPowerOfTwo(long value, long spot) { + if (spot == Long.MIN_VALUE) { + return (value != Long.MIN_VALUE) ? value : 0; + } else { + long s = (value>>63); + return ((((value+s) ^ s) & (abs(spot)-1)) + s) ^ s; + } + } + + /** + * @param value An integer value > 0. + * @return The integer part of the logarithm, in base 2, of the specified value, + * i.e. a result in [0,30] + * @throws IllegalArgumentException if the specified value is <= 0. + */ + public static int log2(int value) { + if (value <= 0) { + throw new IllegalArgumentException("value ["+value+"] must be > 0"); + } + return 31-Integer.numberOfLeadingZeros(value); + } + + /** + * @param value An integer value > 0. + * @return The integer part of the logarithm, in base 2, of the specified value, + * i.e. a result in [0,62] + * @throws IllegalArgumentException if the specified value is <= 0. + */ + public static int log2(long value) { + if (value <= 0) { + throw new IllegalArgumentException("value ["+value+"] must be > 0"); + } + return 63-Long.numberOfLeadingZeros(value); + } + + /** + * Possibly faster than java.lang.Math.abs(int). + * + * @return The absolute value, except if value is Integer.MIN_VALUE, for which it returns Integer.MIN_VALUE. + */ + public static int abs(int a) { + return (a^(a>>31))-(a>>31); + } + + /** + * Possibly faster than java.lang.Math.abs(long). + * + * @return The absolute value, except if value is Long.MIN_VALUE, for which it returns Long.MIN_VALUE. + */ + public static long abs(long a) { + return (a^(a>>63))-(a>>63); + } + + /** + * @return The negative of the absolute value (always exact). + */ + public static int absNeg(int a) { + return (a>>31)-(a^(a>>31)); + } + + /** + * @return The negative of the absolute value (always exact). + */ + public static long absNeg(long a) { + return (a>>63)-(a^(a>>63)); + } + + /** + * If the specified value is in int range, the returned value is identical. + * + * @return An int hash of the specified value. + */ + public static int intHash(long a) { + if (false) { + // also works + int hash = ((int)(a>>32)) ^ ((int)a); + if (a < 0) { + hash = -hash-1; + } + return hash; + } + int hash = ((int)(a>>32)) + ((int)a); + if (a < 0) { + hash++; + } + return hash; + } + + /** + * @param a An int value. + * @return The specified value as byte. + * @throws ArithmeticException if the specified value is not in [Byte.MIN_VALUE,Byte.MAX_VALUE] range. + */ + public static byte asByte(int a) { + if (a != (byte)a) { + throw new ArithmeticException("overflow: "+a); + } + return (byte)a; + } + + /** + * @param a A long value. + * @return The specified value as int. + * @throws ArithmeticException if the specified value is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int asInt(long a) { + if (a != (int)a) { + throw new ArithmeticException("overflow: "+a); + } + return (int)a; + } + + /** + * @param a A long value. + * @return The closest int value in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int toInt(long a) { + if (a != (int)a) { + return (a < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; + } + return (int)a; + } + + /** + * @param a An int value. + * @param b An int value. + * @return The mathematical result of a+b. + * @throws ArithmeticException if the mathematical result of a+b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int plusExact(int a, int b) { + final int sum = a + b; + // HD 2-12 Overflow iff both arguments + // have the opposite sign of the result. + if (((a ^ sum) & (b ^ sum)) < 0) { + throw new ArithmeticException("overflow: "+a+"+"+b); + } + return sum; + } + + /** + * @param a A long value. + * @param b A long value. + * @return The mathematical result of a+b. + * @throws ArithmeticException if the mathematical result of a+b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. + */ + public static long plusExact(long a, long b) { + final long sum = a + b; + // HD 2-12 Overflow iff both arguments + // have the opposite sign of the result. + if (((a ^ sum) & (b ^ sum)) < 0) { + throw new ArithmeticException("overflow: "+a+"+"+b); + } + return sum; + } + + /** + * @param a An int value. + * @param b An int value. + * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a+b. + */ + public static int plusBounded(int a, int b) { + return toInt(((long)a) + ((long)b)); + } + + /** + * @param a A long value. + * @param b A long value. + * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a+b. + */ + public static long plusBounded(long a, long b) { + final long sum = a + b; + if (((a ^ sum) & (b ^ sum)) < 0) { + return (sum >= 0) ? Long.MIN_VALUE : Long.MAX_VALUE; + } + return sum; + } + + /** + * @param a An int value. + * @param b An int value. + * @return The mathematical result of a-b. + * @throws ArithmeticException if the mathematical result of a-b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int minusExact(int a, int b) { + final int diff = a - b; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of "a". + if (((a ^ b) & (a ^ diff)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return diff; + } + + /** + * @param a A long value. + * @param b A long value. + * @return The mathematical result of a-b. + * @throws ArithmeticException if the mathematical result of a-b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. + */ + public static long minusExact(long a, long b) { + final long diff = a - b; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of "a". + if (((a ^ b) & (a ^ diff)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return diff; + } + + /** + * @param a An int value. + * @param b An int value. + * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a-b. + */ + public static int minusBounded(int a, int b) { + return toInt(((long)a) - ((long)b)); + } + + /** + * @param a A long value. + * @param b A long value. + * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a-b. + */ + public static long minusBounded(long a, long b) { + final long diff = a - b; + if (((a ^ b) & (a ^ diff)) < 0) { + return (diff >= 0) ? Long.MIN_VALUE : Long.MAX_VALUE; + } + return diff; + } + + /** + * @param a An int value. + * @param b An int value. + * @return The mathematical result of a*b. + * @throws ArithmeticException if the mathematical result of a*b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. + */ + public static int timesExact(int a, int b) { + final long prod = a * (long)b; + if (prod != (int)prod) { + throw new ArithmeticException("overflow: "+a+"*"+b); + } + return (int)prod; + } + + /** + * @param a A long value. + * @param b A long value. + * @return The mathematical result of a*b. + * @throws ArithmeticException if the mathematical result of a*b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. + */ + public static long timesExact(long a, long b) { + final long prod = a * b; + final long absA = abs(a); + final long absB = abs(b); + if (((absA|absB)>>>31) != 0) { + // Some bits greater than 2^31 that might cause overflow + // Check the result using the divide operator + // and check for the special case of Long.MIN_VALUE * -1 + if (((b != 0) && (prod/b != a)) || + ((a == Long.MIN_VALUE) && (b == -1))) { + throw new ArithmeticException("overflow: "+a+"*"+b); + } + } + return prod; + } + + /** + * @param a An int value. + * @param b An int value. + * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a*b. + */ + public static int timesBounded(int a, int b) { + return (int)(a * (double)b); + } + + /** + * @param a A long value. + * @param b A long value. + * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a*b. + */ + public static long timesBounded(long a, long b) { + final long prod = a * b; + final long absA = abs(a); + final long absB = abs(b); + if (((absA|absB)>>>31) != 0) { + // Some bits greater than 2^31 that might cause overflow + // Check the result using the divide operator + // and check for the special case of Long.MIN_VALUE * -1 + if (((b != 0) && (prod/b != a)) || + ((a == Long.MIN_VALUE) && (b == -1))) { + return ((a^b) >= 0) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + return prod; + } + + /* + * powers + */ + + /** + * Returns the exact result, provided it's in double range, + * i.e. if power is in [-1074,1023]. + * + * @param power An int power. + * @return 2^power as a double, or +-Infinity in case of overflow. + */ + public static double twoPow(int power) { + if (power <= -MAX_DOUBLE_EXPONENT) { // Not normal. + if (power >= MIN_DOUBLE_EXPONENT) { // Subnormal. + return Double.longBitsToDouble(0x0008000000000000L>>(-(power+MAX_DOUBLE_EXPONENT))); + } else { // Underflow. + return 0.0; + } + } else if (power > MAX_DOUBLE_EXPONENT) { // Overflow. + return Double.POSITIVE_INFINITY; + } else { // Normal. + return Double.longBitsToDouble(((long)(power+MAX_DOUBLE_EXPONENT))<<52); + } + } + + /** + * @param power An int power. + * @return 2^power as an int. + * @throws ArithmeticException if the mathematical result + * is not in int range, i.e. if power is not in [0,30]. + */ + public static int twoPowAsIntExact(int power) { + if ((power < 0) || (power > 30)) { + throw new ArithmeticException("integer overflow"); + } + return 1 << power; + } + + /** + * @param power An int power. + * @return 2^power as an int, or the closest power of two in int range + * in case of overflow, i.e. if power is not in [0,30]. + */ + public static int twoPowAsIntBounded(int power) { + power = toRange(0, 30, power); + return 1 << power; + } + + /** + * @param power An int power. + * @return 2^power as a long. + * @throws ArithmeticException if the mathematical result + * is not in long range, i.e. if power is not in [0,62]. + */ + public static long twoPowAsLongExact(int power) { + if ((power < 0) || (power > 62)) { + throw new ArithmeticException("long overflow"); + } + return 1L << power; + } + + /** + * @param power An int power. + * @return 2^power as a long, or the closest power of two in long range + * in case of overflow, i.e. if power is not in [0,62]. + */ + public static long twoPowAsLongBounded(int power) { + power = toRange(0, 62, power); + return 1L << power; + } + + /** + * @param a A value. + * @return a*a. + */ + public static int pow2(int a) { + return a*a; + } + + /** + * @param a A value. + * @return a*a. + */ + public static long pow2(long a) { + return a*a; + } + + /** + * @param a A value. + * @return a*a. + */ + public static float pow2(float a) { + return a*a; + } + + /** + * Strict version. + * + * @param a A value. + * @return a*a. + */ + public static strictfp float pow2_strict(float a) { + return a*a; + } + + /** + * @param a A value. + * @return a*a. + */ + public static double pow2(double a) { + return a*a; + } + + /** + * Strict version. + * + * @param a A value. + * @return a*a. + */ + public static strictfp double pow2_strict(double a) { + return a*a; + } + + /** + * @param a A value. + * @return a*a*a. + */ + public static int pow3(int a) { + return a*a*a; + } + + /** + * @param a A value. + * @return a*a*a. + */ + public static long pow3(long a) { + return a*a*a; + } + + /** + * @param a A value. + * @return a*a*a. + */ + public static float pow3(float a) { + return a*a*a; + } + + /** + * Strict version. + * + * @param a A value. + * @return a*a*a. + */ + public static strictfp float pow3_strict(float a) { + return a*a*a; + } + + /** + * @param a A value. + * @return a*a*a. + */ + public static double pow3(double a) { + return a*a*a; + } + + /** + * Strict version. + * + * @param a A value. + * @return a*a*a. + */ + public static strictfp double pow3_strict(double a) { + return a*a*a; + } + + /* + * Accurate +-m*PI/n. + */ + + /** + * @param angRad An angle, in radians. + * @return angRad + 2*PI, accurately computed. + */ + public static double plus2PI(double angRad) { + if (angRad > -Math.PI) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad + TWOPI_LO) + TWOPI_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad + TWOPI_HI) + TWOPI_LO; + } + } + + /** + * Strict version. + * + * @param angRad An angle, in radians. + * @return angRad + 2*PI, accurately computed. + */ + public static strictfp double plus2PI_strict(double angRad) { + if (angRad > -Math.PI) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad + TWOPI_LO) + TWOPI_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad + TWOPI_HI) + TWOPI_LO; + } + } + + /** + * @param angRad An angle, in radians. + * @return angRad - 2*PI, accurately computed. + */ + public static double minus2PI(double angRad) { + if (angRad < Math.PI) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad - TWOPI_LO) - TWOPI_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad - TWOPI_HI) - TWOPI_LO; + } + } + + /** + * Strict version. + * + * @param angRad An angle, in radians. + * @return angRad - 2*PI, accurately computed. + */ + public static strictfp double minus2PI_strict(double angRad) { + if (angRad < Math.PI) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad - TWOPI_LO) - TWOPI_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad - TWOPI_HI) - TWOPI_LO; + } + } + + /** + * @param angRad An angle, in radians. + * @return angRad + PI, accurately computed. + */ + public static double plusPI(double angRad) { + if (angRad > -Math.PI/2) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad + PI_LO) + PI_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad + PI_HI) + PI_LO; + } + } + + /** + * Strict version. + * + * @param angRad An angle, in radians. + * @return angRad + PI, accurately computed. + */ + public static strictfp double plusPI_strict(double angRad) { + if (angRad > -Math.PI/2) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad + PI_LO) + PI_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad + PI_HI) + PI_LO; + } + } + + /** + * @param angRad An angle, in radians. + * @return angRad - PI, accurately computed. + */ + public static double minusPI(double angRad) { + if (angRad < Math.PI/2) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad - PI_LO) - PI_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad - PI_HI) - PI_LO; + } + } + + /** + * Strict version. + * + * @param angRad An angle, in radians. + * @return angRad - PI, accurately computed. + */ + public static strictfp double minusPI_strict(double angRad) { + if (angRad < Math.PI/2) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad - PI_LO) - PI_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad - PI_HI) - PI_LO; + } + } + + /** + * @param angRad An angle, in radians. + * @return angRad + PI/2, accurately computed. + */ + public static double plusPIO2(double angRad) { + if (angRad > -Math.PI/4) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad + PIO2_LO) + PIO2_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad + PIO2_HI) + PIO2_LO; + } + } + + /** + * Strict version. + * + * @param angRad An angle, in radians. + * @return angRad + PI/2, accurately computed. + */ + public static strictfp double plusPIO2_strict(double angRad) { + if (angRad > -Math.PI/4) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad + PIO2_LO) + PIO2_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad + PIO2_HI) + PIO2_LO; + } + } + + /** + * @param angRad An angle, in radians. + * @return angRad - PI/2, accurately computed. + */ + public static double minusPIO2(double angRad) { + if (angRad < Math.PI/4) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad - PIO2_LO) - PIO2_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad - PIO2_HI) - PIO2_LO; + } + } + + /** + * Strict version. + * + * @param angRad An angle, in radians. + * @return angRad - PI/2, accurately computed. + */ + public static strictfp double minusPIO2_strict(double angRad) { + if (angRad < Math.PI/4) { + // LO then HI, for better accuracy (if starting near 0). + return (angRad - PIO2_LO) - PIO2_HI; + } else { + // HI then LO, for better accuracy (if ending near 0). + return (angRad - PIO2_HI) - PIO2_LO; + } + } + + /* + * toString (radix) + */ + + /** + * @param radix Radix to be checked. + * @return True if does not throw. + * @throws IllegalArgumentException if the specified radix is not in [2,36]. + */ + public static boolean checkRadix(int radix) { + if (!isInRange(Character.MIN_RADIX, Character.MAX_RADIX, radix)) { + throw new IllegalArgumentException("radix ["+radix+"] must be in ["+Character.MIN_RADIX+","+Character.MAX_RADIX+"]"); + } + return true; + } + + /** + * @param radix A radix in [2,36]. + * @return Number of characters (minus sign included) + * to represent the specified value in the specified radix. + */ + public static int computeNbrOfChars(int value, int radix) { + if (value < 0) { + // 1 for sign + return 1 + computeNbrOfDigits_negValue(value, radix); + } else { + return computeNbrOfDigits_negValue(-value, radix); + } + } + + /** + * @param radix A radix in [2,36]. + * @return Number of characters (minus sign included) + * to represent the specified value in the specified radix. + */ + public static int computeNbrOfChars(long value, int radix) { + if (value < 0) { + // 1 for sign + return 1 + computeNbrOfDigits_negValue(value, radix); + } else { + return computeNbrOfDigits_negValue(-value, radix); + } + } + + /** + * @param radix A radix in [2,36]. + * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. + * @return Number of characters (minus sign included) + * to represent the specified value in the specified radix. + */ + public static int computeNbrOfChars(int value, int radix, int paddingUpTo) { + if (value < 0) { + // 1 for sign + return 1 + Math.max(paddingUpTo, computeNbrOfDigits_negValue(value, radix)); + } else { + return Math.max(paddingUpTo, computeNbrOfDigits_negValue(-value, radix)); + } + } + + /** + * @param radix A radix in [2,36]. + * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. + * @return Number of characters (minus sign included) + * to represent the specified value in the specified radix. + */ + public static int computeNbrOfChars(long value, int radix, int paddingUpTo) { + if (value < 0) { + // 1 for sign + return 1 + Math.max(paddingUpTo, computeNbrOfDigits_negValue(value, radix)); + } else { + return Math.max(paddingUpTo, computeNbrOfDigits_negValue(-value, radix)); + } + } + + /** + * @param radix A radix in [2,36]. + * @return Number of digits of the specified value in the specified radix. + */ + public static int computeNbrOfDigits(int value, int radix) { + return computeNbrOfDigits_negValue(-abs(value), radix); + } + + /** + * @param radix A radix in [2,36]. + * @return Number of digits of the specified value in the specified radix. + */ + public static int computeNbrOfDigits(long value, int radix) { + return computeNbrOfDigits_negValue(-abs(value), radix); + } + + /** + * @param radix A radix in [2,36]. + * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. + * @return Number of digits of the specified value in the specified radix, + * including the specified padding. + */ + public static int computeNbrOfDigits(int value, int radix, int paddingUpTo) { + return Math.max(paddingUpTo,computeNbrOfDigits(value, radix)); + } + + /** + * @param radix A radix in [2,36]. + * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. + * @return Number of digits of the specified value in the specified radix, + * including the specified padding. + */ + public static int computeNbrOfDigits(long value, int radix, int paddingUpTo) { + return Math.max(paddingUpTo,computeNbrOfDigits(value, radix)); + } + + /** + * This method just delegates to Integer.toString(int), + * but is defined here to complete the API. + * + * @return String representation of the specified value in base 10. + */ + public static String toString(int value) { + return Integer.toString(value); + } + + /** + * This method just delegates to Long.toString(long), + * but is defined here to complete the API. + * + * @return String representation of the specified value in base 10. + */ + public static String toString(long value) { + return Long.toString(value); + } + + /** + * @param radix A radix in [2,36]. + * @return String representation of the specified value in the specified radix. + * @throws IllegalArgumentException if the specified radix is out of range. + */ + public static String toString(int value, int radix) { + return toString(value, radix, 0); + } + + /** + * @param radix A radix in [2,36]. + * @return String representation of the specified value in the specified radix. + * @throws IllegalArgumentException if the specified radix is out of range. + */ + public static String toString(long value, int radix) { + return toString(value, radix, 0); + } + + /** + * @param radix A radix in [2,36]. + * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. + * @return String representation of the specified value in the specified radix. + * @throws IllegalArgumentException if the specified radix is out of range. + */ + public static String toString(int value, int radix, int paddingUpTo) { + // Only one test if radix+paddingUpTo != 10. + if ((radix+paddingUpTo == 10) && (paddingUpTo == 0)) { + // Using JDK's optimized algorithm. + return Integer.toString(value); + } + + int negValue; + final int signSize; + final boolean negative = (value < 0); + if (negative) { + negValue = value; + signSize = 1; + } else { + negValue = -value; + signSize = 0; + } + // Faster if we just use max possible number of characters (33), + // but we prefer to take care of garbage's memory footprint. + // Checks radix. + final int nbrOfChars = signSize + Math.max(paddingUpTo, computeNbrOfDigits_negValue(negValue, radix)); + + final char[] chars = new char[nbrOfChars]; + + int charPos = nbrOfChars; + + final boolean radixIsPowerOfTwo = ((radix & (radix-1)) == 0); + // Not allowing Integer.MIN_VALUE so it can be negated. + if (radixIsPowerOfTwo && (negValue != Integer.MIN_VALUE)) { + final int mask = radix-1; + final int divShift = DIV_SHIFT_BY_RADIX[radix]; + while (negValue <= -radix) { + chars[--charPos] = CHAR_BY_DIGIT[(int)((-negValue) & mask)]; + negValue = -((-negValue) >> divShift); + } + } else { + while (negValue <= -radix) { + chars[--charPos] = CHAR_BY_DIGIT[(int)(-(negValue % radix))]; + negValue /= radix; + } + } + chars[--charPos] = CHAR_BY_DIGIT[(int)(-negValue)]; + + while (charPos > signSize) { + chars[--charPos] = '0'; + } + + if (negative) { + chars[0] = '-'; + } + + return new String(chars); + } + + /** + * @param radix A radix in [2,36]. + * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. + * @return String representation of the specified value in the specified radix. + * @throws IllegalArgumentException if the specified radix is out of range. + */ + public static String toString(long value, int radix, int paddingUpTo) { + // Only one test if radix+paddingUpTo != 10. + if ((radix+paddingUpTo == 10) && (paddingUpTo == 0)) { + // Using JDK's optimized algorithm. + return Long.toString(value); + } + + long negValue; + final int signSize; + final boolean negative = (value < 0); + if (negative) { + negValue = value; + signSize = 1; + } else { + negValue = -value; + signSize = 0; + } + // Checks radix. + final int nbrOfChars = signSize + Math.max(paddingUpTo, computeNbrOfDigits_negValue(negValue, radix)); + + final char[] chars = new char[nbrOfChars]; + + int charPos = nbrOfChars; + + final boolean radixIsPowerOfTwo = ((radix & (radix-1)) == 0); + // Not allowing Long.MIN_VALUE so it can be negated. + if (radixIsPowerOfTwo && (negValue != Long.MIN_VALUE)) { + final int mask = radix-1; + final int divShift = DIV_SHIFT_BY_RADIX[radix]; + while (negValue <= -radix) { + chars[--charPos] = CHAR_BY_DIGIT[(int)((-negValue) & mask)]; + negValue = -((-negValue) >> divShift); + } + } else { + while (negValue <= -radix) { + chars[--charPos] = CHAR_BY_DIGIT[(int)(-(negValue % radix))]; + negValue /= radix; + } + } + chars[--charPos] = CHAR_BY_DIGIT[(int)(-negValue)]; + + while (charPos > signSize) { + chars[--charPos] = '0'; + } + + if (negative) { + chars[0] = '-'; + } + + return new String(chars); + } + + /* + * toString (bits) + */ + + /** + * @param firstBitPos First bit position (inclusive). + * @param lastBitPosExcl Last bit position (exclusive). + * @return True if does not throw. + * @throws IllegalArgumentException if the specified bit range does not fit in a byte. + */ + public static boolean checkBitPositionsByte(int firstBitPos, int lastBitPosExcl) { + return checkBitPositions(firstBitPos, lastBitPosExcl, 8); + } + + /** + * @param firstBitPos First bit position (inclusive). + * @param lastBitPosExcl Last bit position (exclusive). + * @return True if does not throw. + * @throws IllegalArgumentException if the specified bit range does not fit in a short. + */ + public static boolean checkBitPositionsShort(int firstBitPos, int lastBitPosExcl) { + return checkBitPositions(firstBitPos, lastBitPosExcl, 16); + } + + /** + * @param firstBitPos First bit position (inclusive). + * @param lastBitPosExcl Last bit position (exclusive). + * @return True if does not throw. + * @throws IllegalArgumentException if the specified bit range does not fit in an int. + */ + public static boolean checkBitPositionsInt(int firstBitPos, int lastBitPosExcl) { + return checkBitPositions(firstBitPos, lastBitPosExcl, 32); + } + + /** + * @param firstBitPos First bit position (inclusive). + * @param lastBitPosExcl Last bit position (exclusive). + * @return True if does not throw. + * @throws IllegalArgumentException if the specified bit range does not fit in a long. + */ + public static boolean checkBitPositionsLong(int firstBitPos, int lastBitPosExcl) { + return checkBitPositions(firstBitPos, lastBitPosExcl, 64); + } + + /** + * @return String representation of specified bits, in big endian. + */ + public static String toStringBits(byte bits) { + final char[] chars = new char[8]; + int bitIndex = 8; + while (--bitIndex >= 0) { + chars[7-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + } + return new String(chars); + } + + /** + * @return String representation of specified bits, in big endian. + */ + public static String toStringBits(short bits) { + final char[] chars = new char[16]; + int bitIndex = 16; + while (--bitIndex >= 0) { + chars[15-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + } + return new String(chars); + } + + /** + * @return String representation of specified bits, in big endian. + */ + public static String toStringBits(int bits) { + final char[] chars = new char[32]; + int bitIndex = 32; + while (--bitIndex >= 0) { + chars[31-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + } + return new String(chars); + } + + /** + * @return String representation of specified bits, in big endian. + */ + public static String toStringBits(long bits) { + final char[] chars = new char[64]; + int bitIndex = 64; + while (--bitIndex >= 0) { + chars[63-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + } + return new String(chars); + } + + /** + * @param firstBitPos First bit position (inclusive). + * @param lastBitPosExcl Last bit position (exclusive). + * @param bigEndian True for bits to be added in big endian order (MSBit to LSBit) + * false for little endian order. + * @param padding True if underscores must be added instead of out-of-range bits, + * false to just add characters corresponding to in-range bits. + * @return String representation of specified bits. + */ + public static String toStringBits( + byte bits, + int firstBitPos, + int lastBitPosExcl, + boolean bigEndian, + boolean padding) { + checkBitPositionsByte(firstBitPos, lastBitPosExcl); + return toStringBits_0_32_bitPosAlreadyChecked(8,bits, firstBitPos, lastBitPosExcl, bigEndian, padding); + } + + /** + * @param firstBitPos First bit position (inclusive). + * @param lastBitPosExcl Last bit position (exclusive). + * @param bigEndian True for bits to be added in big endian order (MSBit to LSBit) + * false for little endian order. + * @param padding True if underscores must be added instead of out-of-range bits, + * false to just add characters corresponding to in-range bits. + * @return String representation of specified bits. + */ + public static String toStringBits( + short bits, + int firstBitPos, + int lastBitPosExcl, + boolean bigEndian, + boolean padding) { + checkBitPositionsShort(firstBitPos, lastBitPosExcl); + return toStringBits_0_32_bitPosAlreadyChecked(16,bits, firstBitPos, lastBitPosExcl, bigEndian, padding); + } + + /** + * @param firstBitPos First bit position (inclusive). + * @param lastBitPosExcl Last bit position (exclusive). + * @param bigEndian True for bits to be added in big endian order (MSBit to LSBit) + * false for little endian order. + * @param padding True if underscores must be added instead of out-of-range bits, + * false to just add characters corresponding to in-range bits. + * @return String representation of specified bits. + */ + public static String toStringBits( + int bits, + int firstBitPos, + int lastBitPosExcl, + boolean bigEndian, + boolean padding) { + checkBitPositionsInt(firstBitPos, lastBitPosExcl); + return toStringBits_0_32_bitPosAlreadyChecked(32,bits, firstBitPos, lastBitPosExcl, bigEndian, padding); + } + + /** + * @param firstBitPos First bit position (inclusive). + * @param lastBitPosExcl Last bit position (exclusive). + * @param bigEndian True for bits to be added in big endian order (MSBit to LSBit) + * false for little endian order. + * @param padding True if underscores must be added instead of out-of-range bits, + * false to just add characters corresponding to in-range bits. + * @return String representation of specified bits. + */ + public static String toStringBits( + long bits, + int firstBitPos, + int lastBitPosExcl, + boolean bigEndian, + boolean padding) { + checkBitPositionsLong(firstBitPos, lastBitPosExcl); + final int bitSize = 64; + final int bitSizeM1 = bitSize-1; + final int lastBitPos = lastBitPosExcl-1; + if (padding) { + final int nbrOfChars = bitSize; + final char[] chars = new char[nbrOfChars]; + int bitIndex = bitSizeM1; + if (bigEndian) { + final int firstBitIndex = bitSizeM1-lastBitPos; + final int lastBitIndex = bitSizeM1-firstBitPos; + while (bitIndex > lastBitIndex) { + chars[bitSizeM1-bitIndex] = '_'; + --bitIndex; + } + while (bitIndex >= firstBitIndex) { + chars[bitSizeM1-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + --bitIndex; + } + while (bitIndex >= 0) { + chars[bitSizeM1-bitIndex] = '_'; + --bitIndex; + } + } else { + while (bitIndex > lastBitPos) { + chars[bitIndex] = '_'; + --bitIndex; + } + while (bitIndex >= firstBitPos) { + chars[bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + --bitIndex; + } + while (bitIndex >= 0) { + chars[bitIndex] = '_'; + --bitIndex; + } + } + return new String(chars); + } else { + final int nbrOfChars = (lastBitPosExcl - firstBitPos); + final char[] chars = new char[nbrOfChars]; + if (bigEndian) { + final int firstBitIndex = bitSizeM1-lastBitPos; + final int lastBitIndex = bitSizeM1-firstBitPos; + int bitIndex = lastBitIndex; + while (bitIndex >= firstBitIndex) { + chars[lastBitIndex-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + --bitIndex; + } + } else { + int bitIndex = lastBitPos; + while (bitIndex >= firstBitPos) { + chars[bitIndex-firstBitPos] = (char)('0'+((bits>>bitIndex)&1)); + --bitIndex; + } + } + return new String(chars); + } + } + + /* + * toString (floating points) + * + * toStringCSN(double) and toStringNoCSN(double) + * could be made faster, by using directly internals + * of Double.toString(double), but this would require + * copy-paste of much tricky code from JDK, and + * the overhead of our little rework is relatively + * negligible. + */ + + /** + * @param value A double value. + * @return String representing the specified value, + * using "computerized scientific notation", + * which Double.toString(double) uses for non-infinite + * values, when |value| < 1e-3 or |value| >= 1e7. + */ + public static String toStringCSN(double value) { + // Quick case (also to get rid of +-0.0, + // for which Double.toString(double) doesn't use CSN). + if (value == 0.0) { + if (Double.doubleToRawLongBits(value) < 0) { + return "-0.0E0"; + } else { + return "0.0E0"; + } + } + + final double abs = Math.abs(value); + if ((abs >= NO_CSN_MIN_BOUND_INCL) && (abs < NO_CSN_MAX_BOUND_EXCL)) { + final boolean neg = (value < 0.0); + + final String rawAbs = Double.toString(abs); + if (abs >= 1.0) { + /* + * 0123456 + * 12.3456 ===> 1.23456E1 + * 123.0 ===> 1.23E2 + */ + final int dotIndex = rawAbs.indexOf((int)'.'); + final int powerOfTen = dotIndex-1; + final StringBuilder sb = new StringBuilder(); + if (neg) { + sb.append('-'); + } + // Adding unit-or-above digits, with dot after first one. + sb.append(rawAbs.charAt(0)); + sb.append('.'); + sb.append(rawAbs,1,dotIndex); + if ((value != (int)value) || (abs < 10.0)) { + // Adding below-unit digits (possibly just 0 if abs < 10.0, + // to end up for example with "3.0E0" instead of "3.E0"). + sb.append(rawAbs,dotIndex+1,rawAbs.length()); + } + sb.append('E'); + sb.append(CHAR_BY_DIGIT[powerOfTen]); + return sb.toString(); + } else { + /* + * 012345678 + * 0.0123456 ===> 1.23456E-2 + * 0.01 ===> 1.0E-2 + */ + int nonZeroIndex = 1; + while (rawAbs.charAt(++nonZeroIndex) == '0') { + } + // Negative. + final int powerOfTen = 1-nonZeroIndex; + final int nbrOfSignificantDigitsPastDot = (rawAbs.length() - (nonZeroIndex+1)); + final StringBuilder sb = new StringBuilder(); + if (neg) { + sb.append('-'); + } + sb.append(rawAbs.charAt(nonZeroIndex)); + sb.append('.'); + if (nbrOfSignificantDigitsPastDot > 0) { + // If bug 4428022 make rawAbs being something like "0.0010", + // we add the last '0' here after the dot, which is fine. + sb.append(rawAbs,nonZeroIndex+1,rawAbs.length()); + } else { + sb.append('0'); + } + sb.append("E-"); + sb.append(CHAR_BY_DIGIT[-powerOfTen]); + return sb.toString(); + } + } else { + return Double.toString(value); + } + } + + /** + * @param value A double value. + * @return String representing the specified value, + * not in "computerized scientific notation", + * which Double.toString(double) uses for non-infinite + * values, when |value| < 1e-3 or |value| >= 1e7. + */ + public static String toStringNoCSN(double value) { + // Quick case. + // Should also work with long instead of int, + // but less obvious (due to roundings...), + // and we just want to speed up the more common + // case of "small" integer values. + final int intValue = (int)value; + if (value == intValue) { + if (value == 0.0) { + if (Double.doubleToRawLongBits(value) < 0) { + return "-0.0"; + } else { + return "0.0"; + } + } else { + return Integer.toString(intValue)+".0"; + } + } + + final String raw = Double.toString(value); + final double abs = Math.abs(value); + if (abs >= NO_CSN_MAX_BOUND_EXCL) { + if (abs == Double.POSITIVE_INFINITY) { + return raw; + } + /* + * 0123456789 + * 1.234567E5 ===> 123456.7 + * 1.23456E5 ===> 123456.0 (adding 0) + * 1.23E5 ===> 123000.0 + * 1.0E5 ===> 100000.0 + */ + // "." close to start, so using indexOf. + final int dotIndex = raw.indexOf((int)'.'); + // "E" close to end, so using lastIndexOf. + final int eIndex = raw.lastIndexOf((int)'E'); + final int powerOfTen = Integer.parseInt(raw.substring(eIndex+1)); + final int nbrOfSignificantLoDigits = (eIndex - dotIndex - 1); + final int nbrOfZerosToAddBeforeDot = (powerOfTen - nbrOfSignificantLoDigits); + + int start; + int end; + + final StringBuilder sb = new StringBuilder(); + sb.append(raw,0,dotIndex); + if (nbrOfZerosToAddBeforeDot >= 0) { + // Can copy all digits that were between '.' and 'E'. + sb.append(raw,dotIndex+1,eIndex); + for (int i=0;i 0.0001234 + * 1.0E-4 ===> 0.0001 + */ + // "." close to start, so using indexOf. + final int dotIndex = raw.indexOf((int)'.'); + // "E" close to end, so using lastIndexOf. + final int eIndex = raw.lastIndexOf((int)'E'); + // Negative. + final int powerOfTen = Integer.parseInt(raw.substring(eIndex+1)); + final int nbrOfZerosToAddAfterDot = (-powerOfTen-1); + + final StringBuilder sb = new StringBuilder(); + if (value < 0.0) { + sb.append("-0."); + } else { + sb.append("0."); + } + for (int i=0;i>(32-bitSize)); + } + + private static long minSignedLongForBitSize_noCheck(int bitSize) { + // i.e. (-1L<<(bitSize-1)) + return (Long.MIN_VALUE>>(64-bitSize)); + } + + private static int maxSignedIntForBitSize_noCheck(int bitSize) { + // i.e. (1<<(bitSize-1))-1 + return (Integer.MAX_VALUE>>(32-bitSize)); + } + + private static long maxSignedLongForBitSize_noCheck(int bitSize) { + // i.e. (1L<<(bitSize-1))-1 + return (Long.MAX_VALUE>>(64-bitSize)); + } + + /* + * + */ + + /** + * @throws IllegalArgumentException if the specified radix is out of range. + */ + private static int computeNbrOfDigits_negValue(int negValue, int radix) { + checkRadix(radix); + final int maxNbrOfDigits = MAX_NBR_OF_NEG_INT_DIGITS_BY_RADIX[radix]; + int p = radix; + for (int i=1;i -p) { + return i; + } + p *= radix; + } + return maxNbrOfDigits; + } + + /** + * @throws IllegalArgumentException if the specified radix is out of range. + */ + private static int computeNbrOfDigits_negValue(long negValue, int radix) { + checkRadix(radix); + final int maxNbrOfDigits = MAX_NBR_OF_NEG_LONG_DIGITS_BY_RADIX[radix]; + long p = radix; + for (int i=1;i -p) { + return i; + } + p *= radix; + } + return maxNbrOfDigits; + } + + /* + * + */ + + private static boolean checkBitPositions(int firstBitPos, int lastBitPosExcl, int bitSize) { + if ((firstBitPos < 0) || (firstBitPos > lastBitPosExcl) || (lastBitPosExcl > bitSize)) { + throw new IllegalArgumentException( + "bit positions (first="+firstBitPos+",lastExcl="+lastBitPosExcl + +") must verify 0 <= first <= lastExcl <= "+bitSize); + } + return true; + } + + /** + * Common method for byte, short and int. + * Could be a bit faster to have specific methods for byte and short, + * but not much, and that would also make more messy (byte-)code. + * + * @param bitSize Must be in [0,32]. + */ + private static String toStringBits_0_32_bitPosAlreadyChecked( + int bitSize, + int bits, + int firstBitPos, + int lastBitPosExcl, + boolean bigEndian, + boolean padding) { + final int bitSizeM1 = bitSize-1; + final int lastBitPos = lastBitPosExcl-1; + if (padding) { + final int nbrOfChars = bitSize; + final char[] chars = new char[nbrOfChars]; + int bitIndex = bitSizeM1; + if (bigEndian) { + final int firstBitIndex = bitSizeM1-lastBitPos; + final int lastBitIndex = bitSizeM1-firstBitPos; + while (bitIndex > lastBitIndex) { + chars[bitSizeM1-bitIndex] = '_'; + --bitIndex; + } + while (bitIndex >= firstBitIndex) { + chars[bitSizeM1-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + --bitIndex; + } + while (bitIndex >= 0) { + chars[bitSizeM1-bitIndex] = '_'; + --bitIndex; + } + } else { + while (bitIndex > lastBitPos) { + chars[bitIndex] = '_'; + --bitIndex; + } + while (bitIndex >= firstBitPos) { + chars[bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + --bitIndex; + } + while (bitIndex >= 0) { + chars[bitIndex] = '_'; + --bitIndex; + } + } + return new String(chars); + } else { + final int nbrOfChars = (lastBitPosExcl - firstBitPos); + final char[] chars = new char[nbrOfChars]; + if (bigEndian) { + final int firstBitIndex = bitSizeM1-lastBitPos; + final int lastBitIndex = bitSizeM1-firstBitPos; + int bitIndex = lastBitIndex; + while (bitIndex >= firstBitIndex) { + chars[lastBitIndex-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); + --bitIndex; + } + } else { + int bitIndex = lastBitPos; + while (bitIndex >= firstBitPos) { + chars[bitIndex-firstBitPos] = (char)('0'+((bits>>bitIndex)&1)); + --bitIndex; + } + } + return new String(chars); + } + } +} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/StrictFastMath.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/StrictFastMath.java new file mode 100644 index 000000000..a61ac9772 --- /dev/null +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/StrictFastMath.java @@ -0,0 +1,2998 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.jafama; + +/** + * Strict versions of FastMath methods. + * Cf. README.txt for more info. + */ +public final strictfp class StrictFastMath extends CmnFastMath { + + /* + * We use strictfp for the whole class: + * - for simplicity, + * - to reduce strictfp/non-strictfp switching, which can add overhead, + * when these treatments are used from within strictfp code, + * - to make sure that we only use and return non-extended values, + * else if strictfp gets added later to some treatments they might then + * behave differently due to no longer being inlinable into FP-wide + * expressions, + * - to make sure we don't mistakenly not use it. + */ + + //-------------------------------------------------------------------------- + // CONFIGURATION + //-------------------------------------------------------------------------- + + private static final boolean USE_JDK_MATH = SFM_USE_JDK_MATH; + + private static final boolean USE_REDEFINED_LOG = SFM_USE_REDEFINED_LOG; + + private static final boolean USE_REDEFINED_SQRT = SFM_USE_REDEFINED_SQRT; + + private static final boolean USE_POWTABS_FOR_ASIN = SFM_USE_POWTABS_FOR_ASIN; + + //-------------------------------------------------------------------------- + // PUBLIC METHODS + //-------------------------------------------------------------------------- + + /* + * trigonometry + */ + + /** + * @param angle Angle in radians. + * @return Angle sine. + */ + public static double sin(double angle) { + if (USE_JDK_MATH) { + return StrictMath.sin(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { + if (false) { + // Can give very bad relative error near PI (mod 2*PI). + angle = remainderTwoPi(angle); + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } else { + final long remAndQuad = remainderPiO2(angle); + angle = decodeRemainder(remAndQuad); + final double sin; + final int q = decodeQuadrant(remAndQuad); + if (q == 0) { + sin = sin(angle); + } else if (q == 1) { + sin = cos(angle); + } else if (q == 2) { + sin = -sin(angle); + } else { + sin = -cos(angle); + } + return (negateResult ? -sin : sin); + } + } + // index: possibly outside tables range. + int index = (int)(angle * SIN_COS_INDEXER + 0.5); + double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; + // Making sure index is within tables range. + // Last value of each table is the same than first, + // so we ignore it (tabs size minus one) for modulo. + index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) + double indexSin = MyTSinCos.sinTab[index]; + double indexCos = MyTSinCos.cosTab[index]; + double result = indexSin + delta * (indexCos + delta * (-indexSin * ONE_DIV_F2 + delta * (-indexCos * ONE_DIV_F3 + delta * indexSin * ONE_DIV_F4))); + return negateResult ? -result : result; + } + + /** + * Quick sin, with accuracy of about 1.6e-3 (PI/) + * for |angle| < 6588395.0 (Integer.MAX_VALUE * (2*PI/) - 2) + * (- 2 due to removing PI/2 before using cosine tab), + * and no accuracy at all for larger values. + * + * @param angle Angle in radians. + * @return Angle sine. + */ + public static double sinQuick(double angle) { + if (USE_JDK_MATH) { + return StrictMath.sin(angle); + } + return MyTSinCos.cosTab[((int)(Math.abs(angle-Math.PI/2) * SIN_COS_INDEXER + 0.5)) & (SIN_COS_TABS_SIZE-2)]; + } + + /** + * @param angle Angle in radians. + * @return Angle cosine. + */ + public static double cos(double angle) { + if (USE_JDK_MATH) { + return StrictMath.cos(angle); + } + angle = Math.abs(angle); + if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { + if (false) { + // Can give very bad relative error near PI (mod 2*PI). + angle = remainderTwoPi(angle); + if (angle < 0.0) { + angle = -angle; + } + } else { + final long remAndQuad = remainderPiO2(angle); + angle = decodeRemainder(remAndQuad); + final double cos; + final int q = decodeQuadrant(remAndQuad); + if (q == 0) { + cos = cos(angle); + } else if (q == 1) { + cos = -sin(angle); + } else if (q == 2) { + cos = -cos(angle); + } else { + cos = sin(angle); + } + return cos; + } + } + // index: possibly outside tables range. + int index = (int)(angle * SIN_COS_INDEXER + 0.5); + double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; + // Making sure index is within tables range. + // Last value of each table is the same than first, + // so we ignore it (tabs size minus one) for modulo. + index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) + double indexCos = MyTSinCos.cosTab[index]; + double indexSin = MyTSinCos.sinTab[index]; + return indexCos + delta * (-indexSin + delta * (-indexCos * ONE_DIV_F2 + delta * (indexSin * ONE_DIV_F3 + delta * indexCos * ONE_DIV_F4))); + } + + /** + * Quick cos, with accuracy of about 1.6e-3 (PI/) + * for |angle| < 6588397.0 (Integer.MAX_VALUE * (2*PI/)), + * and no accuracy at all for larger values. + * + * @param angle Angle in radians. + * @return Angle cosine. + */ + public static double cosQuick(double angle) { + if (USE_JDK_MATH) { + return StrictMath.cos(angle); + } + return MyTSinCos.cosTab[((int)(Math.abs(angle) * SIN_COS_INDEXER + 0.5)) & (SIN_COS_TABS_SIZE-2)]; + } + + /** + * Computes sine and cosine together. + * + * @param angle Angle in radians. + * @param cosine (out) Angle cosine. + * @return Angle sine. + */ + public static double sinAndCos(double angle, DoubleWrapper cosine) { + if (USE_JDK_MATH) { + cosine.value = StrictMath.cos(angle); + return StrictMath.sin(angle); + } + // Using the same algorithm than sin(double) method, + // and computing also cosine at the end. + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { + if (false) { + // Can give very bad relative error near PI (mod 2*PI). + angle = remainderTwoPi(angle); + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } else { + final long remAndQuad = remainderPiO2(angle); + angle = decodeRemainder(remAndQuad); + final double sin; + final int q = decodeQuadrant(remAndQuad); + if (q == 0) { + sin = sin(angle); + cosine.value = cos(angle); + } else if (q == 1) { + sin = cos(angle); + cosine.value = -sin(angle); + } else if (q == 2) { + sin = -sin(angle); + cosine.value = -cos(angle); + } else { + sin = -cos(angle); + cosine.value = sin(angle); + } + return (negateResult ? -sin : sin); + } + } + int index = (int)(angle * SIN_COS_INDEXER + 0.5); + double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; + index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) + double indexSin = MyTSinCos.sinTab[index]; + double indexCos = MyTSinCos.cosTab[index]; + // Could factor some multiplications (delta * factorials), but then is less accurate. + cosine.value = indexCos + delta * (-indexSin + delta * (-indexCos * ONE_DIV_F2 + delta * (indexSin * ONE_DIV_F3 + delta * indexCos * ONE_DIV_F4))); + double result = indexSin + delta * (indexCos + delta * (-indexSin * ONE_DIV_F2 + delta * (-indexCos * ONE_DIV_F3 + delta * indexSin * ONE_DIV_F4))); + return negateResult ? -result : result; + } + + /** + * Can have very bad relative error near +-PI/2, + * but of the same magnitude than the relative delta between + * StrictMath.tan(PI/2) and StrictMath.tan(nextDown(PI/2)). + * + * @param angle Angle in radians. + * @return Angle tangent. + */ + public static double tan(double angle) { + if (USE_JDK_MATH) { + return StrictMath.tan(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle > TAN_MAX_VALUE_FOR_INT_MODULO) { + angle = remainderPi(angle); + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } + // index: possibly outside tables range. + int index = (int)(angle * TAN_INDEXER + 0.5); + double delta = (angle - index * TAN_DELTA_HI) - index * TAN_DELTA_LO; + // Making sure index is within tables range. + // index modulo PI, i.e. 2*(virtual tab size minus one). + index &= (2*(TAN_VIRTUAL_TABS_SIZE-1)-1); // index % (2*(TAN_VIRTUAL_TABS_SIZE-1)) + // Here, index is in [0,2*(TAN_VIRTUAL_TABS_SIZE-1)-1], i.e. indicates an angle in [0,PI[. + if (index > (TAN_VIRTUAL_TABS_SIZE-1)) { + index = (2*(TAN_VIRTUAL_TABS_SIZE-1)) - index; + delta = -delta; + negateResult = !negateResult; + } + double result; + if (index < TAN_TABS_SIZE) { + result = MyTTan.tanTab[index] + + delta * (MyTTan.tanDer1DivF1Tab[index] + + delta * (MyTTan.tanDer2DivF2Tab[index] + + delta * (MyTTan.tanDer3DivF3Tab[index] + + delta * MyTTan.tanDer4DivF4Tab[index]))); + } else { // angle in ]TAN_MAX_VALUE_FOR_TABS,TAN_MAX_VALUE_FOR_INT_MODULO], or angle is NaN + // Using tan(angle) == 1/tan(PI/2-angle) formula: changing angle (index and delta), and inverting. + index = (TAN_VIRTUAL_TABS_SIZE-1) - index; + result = 1/(MyTTan.tanTab[index] + - delta * (MyTTan.tanDer1DivF1Tab[index] + - delta * (MyTTan.tanDer2DivF2Tab[index] + - delta * (MyTTan.tanDer3DivF3Tab[index] + - delta * MyTTan.tanDer4DivF4Tab[index])))); + } + return negateResult ? -result : result; + } + + /** + * @param value Value in [-1,1]. + * @return Value arcsine, in radians, in [-PI/2,PI/2]. + */ + public static double asin(double value) { + if (USE_JDK_MATH) { + return StrictMath.asin(value); + } + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + if (value <= ASIN_MAX_VALUE_FOR_TABS) { + int index = (int)(value * ASIN_INDEXER + 0.5); + double delta = value - index * ASIN_DELTA; + double result = MyTAsin.asinTab[index] + + delta * (MyTAsin.asinDer1DivF1Tab[index] + + delta * (MyTAsin.asinDer2DivF2Tab[index] + + delta * (MyTAsin.asinDer3DivF3Tab[index] + + delta * MyTAsin.asinDer4DivF4Tab[index]))); + return negateResult ? -result : result; + } else if (USE_POWTABS_FOR_ASIN && (value <= ASIN_MAX_VALUE_FOR_POWTABS)) { + int index = (int)(powFast(value * ASIN_POWTABS_ONE_DIV_MAX_VALUE, ASIN_POWTABS_POWER) * ASIN_POWTABS_SIZE_MINUS_ONE + 0.5); + double delta = value - MyTAsinPow.asinParamPowTab[index]; + double result = MyTAsinPow.asinPowTab[index] + + delta * (MyTAsinPow.asinDer1DivF1PowTab[index] + + delta * (MyTAsinPow.asinDer2DivF2PowTab[index] + + delta * (MyTAsinPow.asinDer3DivF3PowTab[index] + + delta * MyTAsinPow.asinDer4DivF4PowTab[index]))); + return negateResult ? -result : result; + } else { // value > ASIN_MAX_VALUE_FOR_TABS, or value is NaN + // This part is derived from fdlibm. + if (value < 1.0) { + double t = (1.0 - value)*0.5; + double p = t*(ASIN_PS0+t*(ASIN_PS1+t*(ASIN_PS2+t*(ASIN_PS3+t*(ASIN_PS4+t*ASIN_PS5))))); + double q = 1.0+t*(ASIN_QS1+t*(ASIN_QS2+t*(ASIN_QS3+t*ASIN_QS4))); + double s = sqrt(t); + double z = s+s*(p/q); + double result = ASIN_PIO2_HI-((z+z)-ASIN_PIO2_LO); + return negateResult ? -result : result; + } else { // value >= 1.0, or value is NaN + if (value == 1.0) { + return negateResult ? -Math.PI/2 : Math.PI/2; + } else { + return Double.NaN; + } + } + } + } + + /** + * If value is not NaN and is outside [-1,1] range, closest value in this range is used. + * + * @param value Value in [-1,1]. + * @return Value arcsine, in radians, in [-PI/2,PI/2]. + */ + public static double asinInRange(double value) { + if (value <= -1.0) { + return -Math.PI/2; + } else if (value >= 1.0) { + return Math.PI/2; + } else { + return asin(value); + } + } + + /** + * @param value Value in [-1,1]. + * @return Value arccosine, in radians, in [0,PI]. + */ + public static double acos(double value) { + if (USE_JDK_MATH) { + return StrictMath.acos(value); + } + return Math.PI/2 - asin(value); + } + + /** + * If value is not NaN and is outside [-1,1] range, + * closest value in this range is used. + * + * @param value Value in [-1,1]. + * @return Value arccosine, in radians, in [0,PI]. + */ + public static double acosInRange(double value) { + if (value <= -1.0) { + return Math.PI; + } else if (value >= 1.0) { + return 0.0; + } else { + return acos(value); + } + } + + /** + * @param value A double value. + * @return Value arctangent, in radians, in [-PI/2,PI/2]. + */ + public static double atan(double value) { + if (USE_JDK_MATH) { + return StrictMath.atan(value); + } + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + if (value == 1.0) { + // We want "exact" result for 1.0. + return negateResult ? -Math.PI/4 : Math.PI/4; + } else if (value <= ATAN_MAX_VALUE_FOR_TABS) { + int index = (int)(value * ATAN_INDEXER + 0.5); + double delta = value - index * ATAN_DELTA; + double result = MyTAtan.atanTab[index] + + delta * (MyTAtan.atanDer1DivF1Tab[index] + + delta * (MyTAtan.atanDer2DivF2Tab[index] + + delta * (MyTAtan.atanDer3DivF3Tab[index] + + delta * MyTAtan.atanDer4DivF4Tab[index]))); + return negateResult ? -result : result; + } else { // value > ATAN_MAX_VALUE_FOR_TABS, or value is NaN + // This part is derived from fdlibm. + if (value < TWO_POW_66) { + double x = -1/value; + double x2 = x*x; + double x4 = x2*x2; + double s1 = x2*(ATAN_AT0+x4*(ATAN_AT2+x4*(ATAN_AT4+x4*(ATAN_AT6+x4*(ATAN_AT8+x4*ATAN_AT10))))); + double s2 = x4*(ATAN_AT1+x4*(ATAN_AT3+x4*(ATAN_AT5+x4*(ATAN_AT7+x4*ATAN_AT9)))); + double result = ATAN_HI3-((x*(s1+s2)-ATAN_LO3)-x); + return negateResult ? -result : result; + } else { // value >= 2^66, or value is NaN + if (value != value) { + return Double.NaN; + } else { + return negateResult ? -Math.PI/2 : Math.PI/2; + } + } + } + } + + /** + * For special values for which multiple conventions could be adopted, + * behaves like StrictMath.atan2(double,double). + * + * @param y Coordinate on y axis. + * @param x Coordinate on x axis. + * @return Angle from x axis positive side to (x,y) position, in radians, in [-PI,PI]. + * Angle measure is positive when going from x axis to y axis (positive sides). + */ + public static double atan2(double y, double x) { + if (USE_JDK_MATH) { + return StrictMath.atan2(y,x); + } + /* + * Using sub-methods, to make method lighter for general case, + * and to avoid JIT-optimization crash on NaN. + */ + if (x > 0.0) { + if (y == 0.0) { + // +-0.0 + return y; + } + if (x == Double.POSITIVE_INFINITY) { + return atan2_pinf_yyy(y); + } else { + return atan(y/x); + } + } else if (x < 0.0) { + if (y == 0.0) { + return signFromBit(y) * Math.PI; + } + if (x == Double.NEGATIVE_INFINITY) { + return atan2_ninf_yyy(y); + } else if (y > 0.0) { + return Math.PI/2 - atan(x/y); + } else if (y < 0.0) { + return -Math.PI/2 - atan(x/y); + } else { + return Double.NaN; + } + } else { + return atan2_yyy_zeroOrNaN(y, x); + } + } + + /** + * Gives same result as StrictMath.toRadians for some particular values + * like 90.0, 180.0 or 360.0, but is faster (no division). + * + * @param angdeg Angle value in degrees. + * @return Angle value in radians. + */ + public static double toRadians(double angdeg) { + if (USE_JDK_MATH) { + return StrictMath.toRadians(angdeg); + } + return angdeg * (Math.PI/180); + } + + /** + * Gives same result as StrictMath.toDegrees for some particular values + * like Math.PI/2, Math.PI or 2*Math.PI, but is faster (no division). + * + * @param angrad Angle value in radians. + * @return Angle value in degrees. + */ + public static double toDegrees(double angrad) { + if (USE_JDK_MATH) { + return StrictMath.toDegrees(angrad); + } + return angrad * (180/Math.PI); + } + + /** + * @param sign Sign of the angle: true for positive, false for negative. + * @param degrees Degrees, in [0,180]. + * @param minutes Minutes, in [0,59]. + * @param seconds Seconds, in [0.0,60.0[. + * @return Angle in radians. + */ + public static double toRadians(boolean sign, int degrees, int minutes, double seconds) { + return toRadians(toDegrees(sign, degrees, minutes, seconds)); + } + + /** + * @param sign Sign of the angle: true for positive, false for negative. + * @param degrees Degrees, in [0,180]. + * @param minutes Minutes, in [0,59]. + * @param seconds Seconds, in [0.0,60.0[. + * @return Angle in degrees. + */ + public static double toDegrees(boolean sign, int degrees, int minutes, double seconds) { + double signFactor = sign ? 1.0 : -1.0; + return signFactor * (degrees + (1.0/60)*(minutes + (1.0/60)*seconds)); + } + + /** + * @param angrad Angle in radians. + * @param degrees (out) Degrees, in [0,180]. + * @param minutes (out) Minutes, in [0,59]. + * @param seconds (out) Seconds, in [0.0,60.0[. + * @return true if the resulting angle in [-180deg,180deg] is positive, false if it is negative. + */ + public static boolean toDMS(double angrad, IntWrapper degrees, IntWrapper minutes, DoubleWrapper seconds) { + // Computing longitude DMS. + double tmp = toDegrees(normalizeMinusPiPi(angrad)); + boolean isNeg = (tmp < 0.0); + if (isNeg) { + tmp = -tmp; + } + degrees.value = (int)tmp; + tmp = (tmp-degrees.value)*60.0; + minutes.value = (int)tmp; + seconds.value = Math.min((tmp-minutes.value)*60.0,DOUBLE_BEFORE_60); + return !isNeg; + } + + /** + * NB: Since 2*Math.PI < 2*PI, a span of 2*Math.PI does not mean full angular range. + * ex.: isInClockwiseDomain(0.0, 2*Math.PI, -1e-20) returns false. + * ---> For full angular range, use a span > 2*Math.PI, like 2*PI_SUP constant of this class. + * + * @param startAngRad An angle, in radians. + * @param angSpanRad An angular span, >= 0.0, in radians. + * @param angRad An angle, in radians. + * @return true if angRad is in the clockwise angular domain going from startAngRad, over angSpanRad, + * extremities included, false otherwise. + */ + public static boolean isInClockwiseDomain(double startAngRad, double angSpanRad, double angRad) { + if (Math.abs(angRad) < -TWO_MATH_PI_IN_MINUS_PI_PI) { + // special case for angular values of small magnitude + if (angSpanRad <= 2*Math.PI) { + if (angSpanRad < 0.0) { + // empty domain + return false; + } + // angSpanRad is in [0,2*PI] + startAngRad = normalizeMinusPiPi(startAngRad); + double endAngRad = normalizeMinusPiPi(startAngRad + angSpanRad); + if (startAngRad <= endAngRad) { + return (angRad >= startAngRad) && (angRad <= endAngRad); + } else { + return (angRad >= startAngRad) || (angRad <= endAngRad); + } + } else { // angSpanRad > 2*Math.PI, or is NaN + return (angSpanRad == angSpanRad); + } + } else { + // general case + return (normalizeZeroTwoPi(angRad - startAngRad) <= angSpanRad); + } + } + + /* + * hyperbolic trigonometry + */ + + /** + * Some properties of sinh(x) = (exp(x)-exp(-x))/2: + * 1) defined on ]-Infinity,+Infinity[ + * 2) result in ]-Infinity,+Infinity[ + * 3) sinh(x) = -sinh(-x) (implies sinh(0) = 0) + * 4) sinh(epsilon) ~= epsilon + * 5) lim(sinh(x),x->+Infinity) = +Infinity + * (y increasing exponentially faster than x) + * 6) reaches +Infinity (double overflow) for x >= 710.475860073944, + * i.e. a bit further than exp(x) + * + * @param value A double value. + * @return Value hyperbolic sine. + */ + public static double sinh(double value) { + if (USE_JDK_MATH) { + return StrictMath.sinh(value); + } + // sinh(x) = (exp(x)-exp(-x))/2 + double h; + if (value < 0.0) { + value = -value; + h = -0.5; + } else { + h = 0.5; + } + if (value < 22.0) { + if (value < TWO_POW_N28) { + return (h < 0.0) ? -value : value; + } else { + // sinh(x) + // = (exp(x)-exp(-x))/2 + // = (exp(x)-1/exp(x))/2 + // = (expm1(x) + 1 - 1/(expm1(x)+1))/2 + // = (expm1(x) + (expm1(x)+1)/(expm1(x)+1) - 1/(expm1(x)+1))/2 + // = (expm1(x) + expm1(x)/(expm1(x)+1))/2 + double t = expm1(value); + // Might be more accurate, if value < 1: return h*((t+t)-t*t/(t+1.0)). + return h * (t + t/(t+1.0)); + } + } else if (value < LOG_DOUBLE_MAX_VALUE) { + return h * exp(value); + } else { + double t = exp(value*0.5); + return (h*t)*t; + } + } + + /** + * Some properties of cosh(x) = (exp(x)+exp(-x))/2: + * 1) defined on ]-Infinity,+Infinity[ + * 2) result in [1,+Infinity[ + * 3) cosh(0) = 1 + * 4) cosh(x) = cosh(-x) + * 5) lim(cosh(x),x->+Infinity) = +Infinity + * (y increasing exponentially faster than x) + * 6) reaches +Infinity (double overflow) for x >= 710.475860073944, + * i.e. a bit further than exp(x) + * + * @param value A double value. + * @return Value hyperbolic cosine. + */ + public static double cosh(double value) { + if (USE_JDK_MATH) { + return StrictMath.cosh(value); + } + // cosh(x) = (exp(x)+exp(-x))/2 + if (value < 0.0) { + value = -value; + } + if (value < LOG_TWO_POW_27) { + if (value < TWO_POW_N27) { + // cosh(x) + // = (exp(x)+exp(-x))/2 + // = ((1+x+x^2/2!+...) + (1-x+x^2/2!-...))/2 + // = 1+x^2/2!+x^4/4!+... + // For value of x small in magnitude, the sum of the terms does not add to 1. + return 1; + } else { + // cosh(x) + // = (exp(x)+exp(-x))/2 + // = (exp(x)+1/exp(x))/2 + double t = exp(value); + return 0.5 * (t+1/t); + } + } else if (value < LOG_DOUBLE_MAX_VALUE) { + return 0.5 * exp(value); + } else { + double t = exp(value*0.5); + return (0.5*t)*t; + } + } + + /** + * Much more accurate than cosh(value)-1, + * for arguments (and results) close to zero. + * + * coshm1(-0.0) = -0.0, for homogeneity with + * acosh1p(-0.0) = -0.0. + * + * @param value A double value. + * @return Value hyperbolic cosine, minus 1. + */ + public static double coshm1(double value) { + // cosh(x)-1 = (exp(x)+exp(-x))/2 - 1 + if (value < 0.0) { + value = -value; + } + if (value < LOG_TWO_POW_27) { + if (value < TWO_POW_N27) { + if (value == 0.0) { + // +-0.0 + return value; + } + // Using (expm1(x)+expm1(-x))/2 + // is not accurate for tiny values, + // for expm1 results are of higher + // magnitude than the result and + // of different signs, such as their + // sum is not accurate. + // cosh(x) - 1 + // = (exp(x)+exp(-x))/2 - 1 + // = ((1+x+x^2/2!+...) + (1-x+x^2/2!-...))/2 - 1 + // = x^2/2!+x^4/4!+... + // ~= x^2 * (1/2 + x^2 * 1/24) + // = x^2 * 0.5 (since x < 2^-27) + return 0.5 * value*value; + } else { + // cosh(x) - 1 + // = (exp(x)+exp(-x))/2 - 1 + // = (exp(x)-1+exp(-x)-1)/2 + // = (expm1(x)+expm1(-x))/2 + return 0.5 * (expm1(value)+expm1(-value)); + } + } else if (value < LOG_DOUBLE_MAX_VALUE) { + return 0.5 * exp(value) - 1.0; + } else { + // No need to subtract 1 from result. + double t = exp(value*0.5); + return (0.5*t)*t; + } + } + + /** + * Computes hyperbolic sine and hyperbolic cosine together. + * + * @param value A double value. + * @param hcosine (out) Value hyperbolic cosine. + * @return Value hyperbolic sine. + */ + public static double sinhAndCosh(double value, DoubleWrapper hcosine) { + if (USE_JDK_MATH) { + hcosine.value = StrictMath.cosh(value); + return StrictMath.sinh(value); + } + // Mixup of sinh and cosh treatments: if you modify them, + // you might want to also modify this. + double h; + if (value < 0.0) { + value = -value; + h = -0.5; + } else { + h = 0.5; + } + final double hsine; + // LOG_TWO_POW_27 = 18.714973875118524 + if (value < LOG_TWO_POW_27) { // test from cosh + // sinh + if (value < TWO_POW_N28) { + hsine = (h < 0.0) ? -value : value; + } else { + double t = expm1(value); + hsine = h * (t + t/(t+1.0)); + } + // cosh + if (value < TWO_POW_N27) { + hcosine.value = 1; + } else { + double t = exp(value); + hcosine.value = 0.5 * (t+1/t); + } + } else if (value < 22.0) { // test from sinh + // Here, value is in [18.714973875118524,22.0[. + double t = expm1(value); + hsine = h * (t + t/(t+1.0)); + hcosine.value = 0.5 * (t+1.0); + } else { + if (value < LOG_DOUBLE_MAX_VALUE) { + hsine = h * exp(value); + } else { + double t = exp(value*0.5); + hsine = (h*t)*t; + } + hcosine.value = Math.abs(hsine); + } + return hsine; + } + + /** + * Some properties of tanh(x) = sinh(x)/cosh(x) = (exp(2*x)-1)/(exp(2*x)+1): + * 1) defined on ]-Infinity,+Infinity[ + * 2) result in ]-1,1[ + * 3) tanh(x) = -tanh(-x) (implies tanh(0) = 0) + * 4) tanh(epsilon) ~= epsilon + * 5) lim(tanh(x),x->+Infinity) = 1 + * 6) reaches 1 (double loss of precision) for x = 19.061547465398498 + * + * @param value A double value. + * @return Value hyperbolic tangent. + */ + public static double tanh(double value) { + if (USE_JDK_MATH) { + return StrictMath.tanh(value); + } + // tanh(x) = sinh(x)/cosh(x) + // = (exp(x)-exp(-x))/(exp(x)+exp(-x)) + // = (exp(2*x)-1)/(exp(2*x)+1) + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + double z; + if (value < TANH_1_THRESHOLD) { + if (value < TWO_POW_N55) { + return negateResult ? -value*(1.0-value) : value*(1.0+value); + } else if (value >= 1) { + z = 1.0-2.0/(expm1(value+value)+2.0); + } else { + double t = expm1(-(value+value)); + z = -t/(t+2.0); + } + } else { + z = (value != value) ? Double.NaN : 1.0; + } + return negateResult ? -z : z; + } + + /** + * Some properties of asinh(x) = log(x + sqrt(x^2 + 1)) + * 1) defined on ]-Infinity,+Infinity[ + * 2) result in ]-Infinity,+Infinity[ + * 3) asinh(x) = -asinh(-x) (implies asinh(0) = 0) + * 4) asinh(epsilon) ~= epsilon + * 5) lim(asinh(x),x->+Infinity) = +Infinity + * (y increasing logarithmically slower than x) + * + * @param value A double value. + * @return Value hyperbolic arcsine. + */ + public static double asinh(double value) { + // asinh(x) = log(x + sqrt(x^2 + 1)) + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + double result; + // (about) smallest possible for + // non-log1p case to be accurate. + if (value < ASINH_LOG1P_THRESHOLD) { + // Around this range, FDLIBM uses + // log1p(value+value*value/(1+sqrt(value*value+1))), + // but it's slower, so we don't use it. + /* + * If x is close to zero, log argument is close to 1, + * so to avoid precision loss we use log1p(double), + * with + * (1+x)^p = 1 + p * x + (p*(p-1))/2! * x^2 + (p*(p-1)*(p-2))/3! * x^3 + ... + * (1+x)^p = 1 + p * x * (1 + (p-1)/2 * x * (1 + (p-2)/3 * x + ...) + * (1+x)^0.5 = 1 + 0.5 * x * (1 + (0.5-1)/2 * x * (1 + (0.5-2)/3 * x + ...) + * (1+x^2)^0.5 = 1 + 0.5 * x^2 * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...) + * x + (1+x^2)^0.5 = 1 + x * (1 + 0.5 * x * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...)) + * so + * asinh(x) = log1p(x * (1 + 0.5 * x * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...))) + */ + final double x = value; + final double x2 = x*x; + // Enough terms for good accuracy, + // given our threshold. + final double argLog1p = (x * + (1 + 0.5 * x + * (1 + (0.5-1)/2 * x2 + * (1 + (0.5-2)/3 * x2 + * (1 + (0.5-3)/4 * x2 + * (1 + (0.5-4)/5 * x2 + )))))); + result = log1p(argLog1p); + } else if (value < ASINH_ACOSH_SQRT_ELISION_THRESHOLD) { + // Around this range, FDLIBM uses + // log(2*value+1/(value+sqrt(value*value+1))), + // but it involves an additional division + // so we don't use it. + result = log(value + sqrt(value*value + 1.0)); + } else { + // log(2*value) would overflow for value > Double.MAX_VALUE/2, + // so we compute otherwise. + result = LOG_2 + log(value); + } + return negateResult ? -result : result; + } + + /** + * Some properties of acosh(x) = log(x + sqrt(x^2 - 1)): + * 1) defined on [1,+Infinity[ + * 2) result in ]0,+Infinity[ (by convention, since cosh(x) = cosh(-x)) + * 3) acosh(1) = 0 + * 4) acosh(1+epsilon) ~= log(1 + sqrt(2*epsilon)) ~= sqrt(2*epsilon) + * 5) lim(acosh(x),x->+Infinity) = +Infinity + * (y increasing logarithmically slower than x) + * + * @param value A double value. + * @return Value hyperbolic arccosine. + */ + public static double acosh(double value) { + if (!(value > 1.0)) { + // NaN, or value <= 1 + if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { + return (value < 1.0) ? Double.NaN : value - 1.0; + } else { + return (value == 1.0) ? 0.0 : Double.NaN; + } + } + double result; + if (value < ASINH_ACOSH_SQRT_ELISION_THRESHOLD) { + // Around this range, FDLIBM uses + // log(2*value-1/(value+sqrt(value*value-1))), + // but it involves an additional division + // so we don't use it. + result = log(value + sqrt(value*value - 1.0)); + } else { + // log(2*value) would overflow for value > Double.MAX_VALUE/2, + // so we compute otherwise. + result = LOG_2 + log(value); + } + return result; + } + + /** + * Much more accurate than acosh(1+value), + * for arguments (and results) close to zero. + * + * acosh1p(-0.0) = -0.0, for homogeneity with + * sqrt(-0.0) = -0.0, which looks about the same + * near 0. + * + * @param value A double value. + * @return Hyperbolic arccosine of (1+value). + */ + public static double acosh1p(double value) { + if (!(value > 0.0)) { + // NaN, or value <= 0. + // If value is -0.0, returning -0.0. + if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { + return (value < 0.0) ? Double.NaN : value; + } else { + return (value == 0.0) ? value : Double.NaN; + } + } + double result; + if (value < (ASINH_ACOSH_SQRT_ELISION_THRESHOLD-1)) { + // acosh(1+x) + // = log((1+x) + sqrt((1+x)^2 - 1)) + // = log(1 + x + sqrt(1 + 2*x + x^2 - 1)) + // = log1p(x + sqrt(2*x + x^2)) + // = log1p(x + sqrt(x * (2 + x)) + result = log1p(value + sqrt(value * (2 + value))); + } else { + result = LOG_2 + log(1+value); + } + return result; + } + + /** + * Some properties of atanh(x) = log((1+x)/(1-x))/2: + * 1) defined on ]-1,1[ + * 2) result in ]-Infinity,+Infinity[ + * 3) atanh(-1) = -Infinity (by continuity) + * 4) atanh(1) = +Infinity (by continuity) + * 5) atanh(epsilon) ~= epsilon + * 6) lim(atanh(x),x->1) = +Infinity + * + * @param value A double value. + * @return Value hyperbolic arctangent. + */ + public static double atanh(double value) { + boolean negateResult = false; + if (value < 0.0) { + value = -value; + negateResult = true; + } + double result; + if (!(value < 1.0)) { + // NaN, or value >= 1 + if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { + result = (value > 1.0) ? Double.NaN : Double.POSITIVE_INFINITY + value; + } else { + result = (value == 1.0) ? Double.POSITIVE_INFINITY : Double.NaN; + } + } else { + // For value < 0.5, FDLIBM uses + // 0.5 * log1p((value+value) + (value+value)*value/(1-value)), + // instead, but this is good enough for us. + // atanh(x) + // = log((1+x)/(1-x))/2 + // = log((1-x+2x)/(1-x))/2 + // = log1p(2x/(1-x))/2 + result = 0.5 * log1p((value+value)/(1.0-value)); + } + return negateResult ? -result : result; + } + + /* + * exponentials + */ + + /** + * @param value A double value. + * @return e^value. + */ + public static double exp(double value) { + if (USE_JDK_MATH) { + return StrictMath.exp(value); + } + // exp(x) = exp([x])*exp(y) + // with [x] the integer part of x, and y = x-[x] + // ===> + // We find an approximation of y, called z. + // ===> + // exp(x) = exp([x])*(exp(z)*exp(epsilon)) + // with epsilon = y - z + // ===> + // We have exp([x]) and exp(z) pre-computed in tables, we "just" have to compute exp(epsilon). + // + // We use the same indexing (cast to int) to compute x integer part and the + // table index corresponding to z, to avoid two int casts. + // Also, to optimize index multiplication and division, we use powers of two, + // so that we can do it with bits shifts. + + if (value > EXP_OVERFLOW_LIMIT) { + return Double.POSITIVE_INFINITY; + } else if (!(value >= EXP_UNDERFLOW_LIMIT)) { + return (value != value) ? Double.NaN : 0.0; + } + + final int indexes = (int)(value*EXP_LO_INDEXING); + + final int valueInt; + if (indexes >= 0) { + valueInt = (indexes>>EXP_LO_INDEXING_DIV_SHIFT); + } else { + valueInt = -((-indexes)>>EXP_LO_INDEXING_DIV_SHIFT); + } + final double hiTerm = MyTExp.expHiTab[valueInt-(int)EXP_UNDERFLOW_LIMIT]; + + final int zIndex = indexes - (valueInt< 0.0) { + if (value == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + + // For normal values not close to 1.0, we use the following formula: + // log(value) + // = log(2^exponent*1.mantissa) + // = log(2^exponent) + log(1.mantissa) + // = exponent * log(2) + log(1.mantissa) + // = exponent * log(2) + log(1.mantissaApprox) + log(1.mantissa/1.mantissaApprox) + // = exponent * log(2) + log(1.mantissaApprox) + log(1+epsilon) + // = exponent * log(2) + log(1.mantissaApprox) + epsilon-epsilon^2/2+epsilon^3/3-epsilon^4/4+... + // with: + // 1.mantissaApprox <= 1.mantissa, + // log(1.mantissaApprox) in table, + // epsilon = (1.mantissa/1.mantissaApprox)-1 + // + // To avoid bad relative error for small results, + // values close to 1.0 are treated aside, with the formula: + // log(x) = z*(2+z^2*((2.0/3)+z^2*((2.0/5))+z^2*((2.0/7))+...))) + // with z=(x-1)/(x+1) + + double h; + if (value > 0.95) { + if (value < 1.14) { + double z = (value-1.0)/(value+1.0); + double z2 = z*z; + return z*(2+z2*((2.0/3)+z2*((2.0/5)+z2*((2.0/7)+z2*((2.0/9)+z2*((2.0/11))))))); + } + h = 0.0; + } else if (value < DOUBLE_MIN_NORMAL) { + // Ensuring value is normal. + value *= TWO_POW_52; + // log(x*2^52) + // = log(x)-ln(2^52) + // = log(x)-52*ln(2) + h = -52*LOG_2; + } else { + h = 0.0; + } + + int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); + int valueExp = (valueBitsHi>>20)-MAX_DOUBLE_EXPONENT; + // Getting the first LOG_BITS bits of the mantissa. + int xIndex = ((valueBitsHi<<12)>>>(32-LOG_BITS)); + + // 1.mantissa/1.mantissaApprox - 1 + double z = (value * twoPowNormalOrSubnormal(-valueExp)) * MyTLog.logXInvTab[xIndex] - 1; + + z *= (1-z*((1.0/2)-z*((1.0/3)))); + + return h + valueExp * LOG_2 + (MyTLog.logXLogTab[xIndex] + z); + + } else if (value == 0.0) { + return Double.NEGATIVE_INFINITY; + } else { // value < 0.0, or value is NaN + return Double.NaN; + } + } + + /** + * Quick log, with a max relative error of about 1.9e-3 + * for values in ]Double.MIN_NORMAL,+Infinity[, and + * worse accuracy outside this range. + * + * @param value A double value, in ]0,+Infinity[ (strictly positive and finite). + * @return Value logarithm (base e). + */ + public static double logQuick(double value) { + if (USE_JDK_MATH) { + return StrictMath.log(value); + } + /* + * Inverse of Schraudolph's method for exp, is very inaccurate near 1, + * and not that fast (even using floats), especially with added if's + * to deal with values near 1, so we don't use it, and use a simplified + * version of our log's redefined algorithm. + */ + + // Simplified version of log's redefined algorithm: + // log(value) ~= exponent * log(2) + log(1.mantissaApprox) + + double h; + if (value > 0.87) { + if (value < 1.16) { + return 2.0 * (value-1.0)/(value+1.0); + } + h = 0.0; + } else if (value < DOUBLE_MIN_NORMAL) { + value *= TWO_POW_52; + h = -52*LOG_2; + } else { + h = 0.0; + } + + int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); + int valueExp = (valueBitsHi>>20)-MAX_DOUBLE_EXPONENT; + int xIndex = ((valueBitsHi<<12)>>>(32-LOG_BITS)); + + return h + valueExp * LOG_2 + MyTLog.logXLogTab[xIndex]; + } + + /** + * @param value A double value. + * @return Value logarithm (base 10). + */ + public static double log10(double value) { + if (USE_JDK_MATH || (!USE_REDEFINED_LOG)) { + return StrictMath.log10(value); + } + // INV_LOG_10 is < 1, but there is no risk of log(double) + // overflow (positive or negative) while the end result shouldn't, + // since log(Double.MIN_VALUE) and log(Double.MAX_VALUE) have + // magnitudes of just a few hundreds. + return log(value) * INV_LOG_10; + } + + /** + * Much more accurate than log(1+value), + * for arguments (and results) close to zero. + * + * @param value A double value. + * @return Logarithm (base e) of (1+value). + */ + public static double log1p(double value) { + if (USE_JDK_MATH) { + return StrictMath.log1p(value); + } + if (false) { + // This also works. Simpler but a bit slower. + if (value == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + double valuePlusOne = 1+value; + if (valuePlusOne == 1.0) { + return value; + } else { + return log(valuePlusOne)*(value/(valuePlusOne-1.0)); + } + } + if (value > -1.0) { + if (value == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + + // ln'(x) = 1/x + // so + // log(x+epsilon) ~= log(x) + epsilon/x + // + // Let u be 1+value rounded: + // 1+value = u+epsilon + // + // log(1+value) + // = log(u+epsilon) + // ~= log(u) + epsilon/value + // We compute log(u) as done in log(double), and then add the corrective term. + + double valuePlusOne = 1.0+value; + if (valuePlusOne == 1.0) { + return value; + } else if (Math.abs(value) < 0.15) { + double z = value/(value+2.0); + double z2 = z*z; + return z*(2+z2*((2.0/3)+z2*((2.0/5)+z2*((2.0/7)+z2*((2.0/9)+z2*((2.0/11))))))); + } + + int valuePlusOneBitsHi = (int)(Double.doubleToRawLongBits(valuePlusOne)>>32) & 0x7FFFFFFF; + int valuePlusOneExp = (valuePlusOneBitsHi>>20)-MAX_DOUBLE_EXPONENT; + // Getting the first LOG_BITS bits of the mantissa. + int xIndex = ((valuePlusOneBitsHi<<12)>>>(32-LOG_BITS)); + + // 1.mantissa/1.mantissaApprox - 1 + double z = (valuePlusOne * twoPowNormalOrSubnormal(-valuePlusOneExp)) * MyTLog.logXInvTab[xIndex] - 1; + + z *= (1-z*((1.0/2)-z*(1.0/3))); + + // Adding epsilon/valuePlusOne to z, + // with + // epsilon = value - (valuePlusOne-1) + // (valuePlusOne + epsilon ~= 1+value (not rounded)) + + return valuePlusOneExp * LOG_2 + MyTLog.logXLogTab[xIndex] + (z + (value - (valuePlusOne-1))/valuePlusOne); + } else if (value == -1.0) { + return Double.NEGATIVE_INFINITY; + } else { // value < -1.0, or value is NaN + return Double.NaN; + } + } + + /* + * powers + */ + + /** + * 1e-13ish accuracy or better on whole double range. + * + * @param value A double value. + * @param power A power. + * @return value^power. + */ + public static double pow(double value, double power) { + if (USE_JDK_MATH) { + return StrictMath.pow(value,power); + } + if (power == 0.0) { + return 1.0; + } else if (power == 1.0) { + return value; + } + if (value <= 0.0) { + // powerInfo: 0 if not integer, 1 if even integer, -1 if odd integer + int powerInfo; + if (Math.abs(power) >= (TWO_POW_52*2)) { + // The binary digit just before comma is outside mantissa, + // thus it is always 0: power is an even integer. + powerInfo = 1; + } else { + // If power's magnitude permits, we cast into int instead of into long, + // as it is faster. + if (Math.abs(power) <= (double)Integer.MAX_VALUE) { + int powerAsInt = (int)power; + if (power == (double)powerAsInt) { + powerInfo = ((powerAsInt & 1) == 0) ? 1 : -1; + } else { // power is not an integer (and not NaN, due to test against Integer.MAX_VALUE) + powerInfo = 0; + } + } else { + long powerAsLong = (long)power; + if (power == (double)powerAsLong) { + powerInfo = ((powerAsLong & 1) == 0) ? 1 : -1; + } else { // power is not an integer, or is NaN + if (power != power) { + return Double.NaN; + } + powerInfo = 0; + } + } + } + + if (value == 0.0) { + if (power < 0.0) { + return (powerInfo < 0) ? 1/value : Double.POSITIVE_INFINITY; + } else { // power > 0.0 (0 and NaN cases already treated) + return (powerInfo < 0) ? value : 0.0; + } + } else { // value < 0.0 + if (value == Double.NEGATIVE_INFINITY) { + if (powerInfo < 0) { // power odd integer + return (power < 0.0) ? -0.0 : Double.NEGATIVE_INFINITY; + } else { // power even integer, or not an integer + return (power < 0.0) ? 0.0 : Double.POSITIVE_INFINITY; + } + } else { + return (powerInfo == 0) ? Double.NaN : powerInfo * exp(power*log(-value)); + } + } + } else { // value > 0.0, or value is NaN + return exp(power*log(value)); + } + } + + /** + * Quick pow, with a max relative error of about 1e-2 + * for value >= Double.MIN_NORMAL and 1e-10 < |value^power| < 1e10, + * of about 6e-2 for value >= Double.MIN_NORMAL and 1e-40 < |value^power| < 1e40, + * and worse accuracy otherwise. + * + * @param value A double value, in ]0,+Infinity[ (strictly positive and finite). + * @param power A double value. + * @return value^power. + */ + public static double powQuick(double value, double power) { + if (USE_JDK_MATH) { + return StrictMath.pow(value,power); + } + return exp(power*logQuick(value)); + } + + /** + * This treatment is somehow accurate for low values of |power|, + * and for |power*getExponent(value)| < 1023 or so (to stay away + * from double extreme magnitudes (large and small)). + * + * @param value A double value. + * @param power A power. + * @return value^power. + */ + public static double powFast(double value, int power) { + if (USE_JDK_MATH) { + return StrictMath.pow(value,power); + } + if (power < 3) { + if (power < 0) { + // Opposite of Integer.MIN_VALUE does not exist as int. + if (power == Integer.MIN_VALUE) { + // Integer.MAX_VALUE = -(power+1) + return 1.0/(powFast(value,Integer.MAX_VALUE) * value); + } else { + return 1.0/powFast(value,-power); + } + } else { + // Here, power is in [0,2]. + if (power == 2) { // Most common case first. + return value * value; + } else if (power == 0) { + return 1.0; + } else { // power == 1 + return value; + } + } + } else { // power >= 4 + double oddRemains = 1.0; + // If power <= 5, faster to finish outside the loop. + while (power > 5) { + // Test if power is odd. + if ((power & 1) != 0) { + oddRemains *= value; + } + value *= value; + power >>= 1; // power = power / 2 + } + // Here, power is in [3,5]. + if (power == 3) { + return oddRemains * value * value * value; + } else { // power in [4,5]. + double v2 = value * value; + if (power == 4) { + return oddRemains * v2 * v2; + } else { // power == 5 + return oddRemains * v2 * v2 * value; + } + } + } + } + + /** + * @param value A float value. + * @return value*value. + */ + public static float pow2(float value) { + return value*value; + } + + /** + * @param value A double value. + * @return value*value. + */ + public static double pow2(double value) { + return value*value; + } + + /** + * @param value A float value. + * @return value*value*value. + */ + public static float pow3(float value) { + return value*value*value; + } + + /** + * @param value A double value. + * @return value*value*value. + */ + public static double pow3(double value) { + return value*value*value; + } + + /* + * roots + */ + + /** + * @param value A double value. + * @return Value square root. + */ + public static double sqrt(double value) { + if (USE_JDK_MATH || (!USE_REDEFINED_SQRT)) { + return StrictMath.sqrt(value); + } + // See cbrt for comments, sqrt uses the same ideas. + + if (!(value > 0.0)) { // value <= 0.0, or value is NaN + if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { + return (value < 0.0) ? Double.NaN : value; + } else { + return (value == 0.0) ? value : Double.NaN; + } + } else if (value == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + + double h; + if (value < DOUBLE_MIN_NORMAL) { + value *= TWO_POW_52; + h = 2*TWO_POW_N26; + } else { + h = 2.0; + } + + int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); + int valueExponentIndex = (valueBitsHi>>20)+(-MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT); + int xIndex = ((valueBitsHi<<12)>>>(32-SQRT_LO_BITS)); + + double result = MyTSqrt.sqrtXSqrtHiTab[valueExponentIndex] * MyTSqrt.sqrtXSqrtLoTab[xIndex]; + double slope = MyTSqrt.sqrtSlopeHiTab[valueExponentIndex] * MyTSqrt.sqrtSlopeLoTab[xIndex]; + value *= 0.25; + + result += (value - result * result) * slope; + result += (value - result * result) * slope; + return h*(result + (value - result * result) * slope); + } + + /** + * Quick sqrt, with with a max relative error of about 3.41e-2 + * for values in [Double.MIN_NORMAL,Double.MAX_VALUE], and worse + * accuracy outside this range. + * + * @param value A double value. + * @return Value square root. + */ + public static double sqrtQuick(double value) { + if (USE_JDK_MATH) { + return StrictMath.sqrt(value); + } + final long bits = Double.doubleToRawLongBits(value); + /* + * Constant determined empirically, using a random-based metaheuristic. + * Should be possible to find a better one. + */ + return Double.longBitsToDouble((bits+4606859074900000000L)>>>1); + } + + /** + * Quick inverse of square root, with a max relative error of about 3.44e-2 + * for values in [Double.MIN_NORMAL,Double.MAX_VALUE], and worse accuracy + * outside this range. + * + * This implementation uses zero step of Newton's method. + * Here are the max relative errors on [Double.MIN_NORMAL,Double.MAX_VALUE] + * depending on number of steps, if you want to copy-paste this code + * and use your own number: + * n=0: about 3.44e-2 + * n=1: about 1.75e-3 + * n=2: about 4.6e-6 + * n=3: about 3.17e-11 + * n=4: about 3.92e-16 + * n=5: about 3.03e-16 + * + * @param value A double value. + * @return Inverse of value square root. + */ + public static double invSqrtQuick(double value) { + if (USE_JDK_MATH) { + return 1/StrictMath.sqrt(value); + } + /* + * http://en.wikipedia.org/wiki/Fast_inverse_square_root + */ + if (false) { + // With one Newton step (much slower than + // 1/Math.sqrt(double) if not optimized). + final double halfInitial = value * 0.5; + long bits = Double.doubleToRawLongBits(value); + // If n=0, 6910474759270000000L might be better (3.38e-2 max relative error). + bits = 0x5FE6EB50C7B537A9L - (bits>>1); + value = Double.longBitsToDouble(bits); + value = value * (1.5 - halfInitial * value * value); // Newton step, can repeat. + return value; + } else { + return Double.longBitsToDouble(0x5FE6EB50C7B537A9L - (Double.doubleToRawLongBits(value)>>1)); + } + } + + /** + * @param value A double value. + * @return Value cubic root. + */ + public static double cbrt(double value) { + if (USE_JDK_MATH) { + return StrictMath.cbrt(value); + } + double h; + if (value < 0.0) { + if (value == Double.NEGATIVE_INFINITY) { + return Double.NEGATIVE_INFINITY; + } + value = -value; + // Making sure value is normal. + if (value < DOUBLE_MIN_NORMAL) { + value *= (TWO_POW_52*TWO_POW_26); + // h = * / + h = -2*TWO_POW_N26; + } else { + h = -2.0; + } + } else { + if (!(value < Double.POSITIVE_INFINITY)) { // value is +Infinity, or value is NaN + return value; + } + // Making sure value is normal. + if (value < DOUBLE_MIN_NORMAL) { + if (value == 0.0) { + // cbrt(0.0) = 0.0, cbrt(-0.0) = -0.0 + return value; + } + value *= (TWO_POW_52*TWO_POW_26); + h = 2*TWO_POW_N26; + } else { + h = 2.0; + } + } + + // Normal value is (2^ * ). + // First member cubic root is computed, and multiplied with an approximation + // of the cubic root of the second member, to end up with a good guess of + // the result before using Newton's (or Archimedes's) method. + // To compute the cubic root approximation, we use the formula "cbrt(value) = cbrt(x) * cbrt(value/x)", + // choosing x as close to value as possible but inferior to it, so that cbrt(value/x) is close to 1 + // (we could iterate on this method, using value/x as new value for each iteration, + // but finishing with Newton's method is faster). + + // Shift and cast into an int, which overall is faster than working with a long. + int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); + int valueExponentIndex = (valueBitsHi>>20)+(-MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT); + // Getting the first CBRT_LO_BITS bits of the mantissa. + int xIndex = ((valueBitsHi<<12)>>>(32-CBRT_LO_BITS)); + double result = MyTCbrt.cbrtXCbrtHiTab[valueExponentIndex] * MyTCbrt.cbrtXCbrtLoTab[xIndex]; + double slope = MyTCbrt.cbrtSlopeHiTab[valueExponentIndex] * MyTCbrt.cbrtSlopeLoTab[xIndex]; + + // Lowering values to avoid overflows when using Newton's method + // (we will then just have to return twice the result). + // result^3 = value + // (result/2)^3 = value/8 + value *= 0.125; + // No need to divide result here, as division is factorized in result computation tables. + // result *= 0.5; + + // Newton's method, looking for y = x^(1/p): + // y(n) = y(n-1) + (x-y(n-1)^p) * slope(y(n-1)) + // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(x(n-1)^(1/p-1)) + // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(x(n-1)^((1-p)/p)) + // with x(n-1)=y(n-1)^p, i.e.: + // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(y(n-1)^(1-p)) + // + // For p=3: + // y(n) = y(n-1) + (x-y(n-1)^3) * (1/(3*y(n-1)^2)) + + // To save time, we don't recompute the slope between Newton's method steps, + // as initial slope is good enough for a few iterations. + // + // NB: slope = 1/(3*trueResult*trueResult) + // As we have result = trueResult/2 (to avoid overflows), we have: + // slope = 4/(3*result*result) + // = (4/3)*resultInv*resultInv + // with newResultInv = 1/newResult + // = 1/(oldResult+resultDelta) + // = (oldResultInv)*1/(1+resultDelta/oldResult) + // = (oldResultInv)*1/(1+resultDelta*oldResultInv) + // ~= (oldResultInv)*(1-resultDelta*oldResultInv) + // ===> Successive slopes could be computed without division, if needed, + // by computing resultInv (instead of slope right away) and retrieving + // slopes from it. + + result += (value - result * result * result) * slope; + result += (value - result * result * result) * slope; + return h*(result + (value - result * result * result) * slope); + } + + /** + * @return sqrt(x^2+y^2) without intermediate overflow or underflow. + */ + public static double hypot(double x, double y) { + if (USE_JDK_MATH) { + return StrictMath.hypot(x,y); + } + x = Math.abs(x); + y = Math.abs(y); + // Ensuring x <= y. + if (y < x) { + double a = x; + x = y; + y = a; + } else if (!(y >= x)) { // Testing if we have some NaN. + return hypot_NaN(x, y); + } + + if (y-x == y) { + // x too small to subtract from y. + return y; + } else { + double factor; + if (y > HYPOT_MAX_MAG) { + // y is too large: scaling down. + x *= (1/HYPOT_FACTOR); + y *= (1/HYPOT_FACTOR); + factor = HYPOT_FACTOR; + } else if (x < (1/HYPOT_MAX_MAG)) { + // x is too small: scaling up. + x *= HYPOT_FACTOR; + y *= HYPOT_FACTOR; + factor = (1/HYPOT_FACTOR); + } else { + factor = 1.0; + } + return factor * sqrt(x*x+y*y); + } + } + + /** + * @return sqrt(x^2+y^2+z^2) without intermediate overflow or underflow. + */ + public static double hypot(double x, double y, double z) { + if (USE_JDK_MATH) { + // No simple JDK equivalent. + } + x = Math.abs(x); + y = Math.abs(y); + z = Math.abs(z); + /* + * Considering that z magnitude is the most likely to be the smaller, + * hence ensuring z <= y <= x, and not x <= y <= z, for less swaps. + */ + // Ensuring z <= y. + if (z > y) { + // y < z: swapping y and z + double a = z; + z = y; + y = a; + } else if (!(z <= y)) { // Testing if y or z is NaN. + return hypot_NaN(x, y, z); + } + // Ensuring y <= x. + if (z > x) { + // x < z <= y: moving x + double oldZ = z; + z = x; + double oldY = y; + y = oldZ; + x = oldY; + } else if (y > x) { + // z <= x < y: swapping x and y + double a = y; + y = x; + x = a; + } else if (x != x) { // Testing if x is NaN. + return hypot_NaN(x, y, z); + } + + if (x-y == x) { + // y, hence z, too small to subtract from x. + return x; + } else if (y-z == y) { + // z too small to subtract from y, hence x. + double factor; + if (x > HYPOT_MAX_MAG) { + // x is too large: scaling down. + x *= (1/HYPOT_FACTOR); + y *= (1/HYPOT_FACTOR); + factor = HYPOT_FACTOR; + } else if (y < (1/HYPOT_MAX_MAG)) { + // y is too small: scaling up. + x *= HYPOT_FACTOR; + y *= HYPOT_FACTOR; + factor = (1/HYPOT_FACTOR); + } else { + factor = 1.0; + } + return factor * sqrt(x*x+y*y); + } else { + double factor; + if (x > HYPOT_MAX_MAG) { + // x is too large: scaling down. + x *= (1/HYPOT_FACTOR); + y *= (1/HYPOT_FACTOR); + z *= (1/HYPOT_FACTOR); + factor = HYPOT_FACTOR; + } else if (z < (1/HYPOT_MAX_MAG)) { + // z is too small: scaling up. + x *= HYPOT_FACTOR; + y *= HYPOT_FACTOR; + z *= HYPOT_FACTOR; + factor = (1/HYPOT_FACTOR); + } else { + factor = 1.0; + } + // Adding smaller magnitudes together first. + return factor * sqrt(x*x+(y*y+z*z)); + } + } + + /* + * close values + */ + + /** + * @param value A float value. + * @return Floor of value. + */ + public static float floor(float value) { + final int exponent = getExponent(value); + if (exponent < 0) { + // abs(value) < 1. + if (value < 0.0f) { + return -1.0f; + } else { + // 0.0f, or -0.0f if value is -0.0f + return 0.0f * value; + } + } else if (exponent < 23) { + // A bit faster than using casts. + final int bits = Float.floatToRawIntBits(value); + final int anteCommaBits = bits & (0xFF800000>>exponent); + if ((value < 0.0f) && (anteCommaBits != bits)) { + return Float.intBitsToFloat(anteCommaBits) - 1.0f; + } else { + return Float.intBitsToFloat(anteCommaBits); + } + } else { + // +-Infinity, NaN, or a mathematical integer. + return value; + } + } + + /** + * @param value A double value. + * @return Floor of value. + */ + public static double floor(double value) { + if (USE_JDK_MATH) { + return StrictMath.floor(value); + } + if (ANTI_SLOW_CASTS) { + double valueAbs = Math.abs(value); + if (valueAbs <= (double)Integer.MAX_VALUE) { + if (value > 0.0) { + return (double)(int)value; + } else if (value < 0.0) { + double anteCommaDigits = (double)(int)value; + if (value != anteCommaDigits) { + return anteCommaDigits - 1.0; + } else { + return anteCommaDigits; + } + } else { // value is +-0.0 (not NaN due to test against Integer.MAX_VALUE) + return value; + } + } else if (valueAbs < TWO_POW_52) { + // We split the value in two: + // high part, which is a mathematical integer, + // and the rest, for which we can get rid of the + // post comma digits by casting into an int. + double highPart = ((int)(value * TWO_POW_N26)) * TWO_POW_26; + if (value > 0.0) { + return highPart + (double)((int)(value - highPart)); + } else { + double anteCommaDigits = highPart + (double)((int)(value - highPart)); + if (value != anteCommaDigits) { + return anteCommaDigits - 1.0; + } else { + return anteCommaDigits; + } + } + } else { // abs(value) >= 2^52, or value is NaN + return value; + } + } else { + final int exponent = getExponent(value); + if (exponent < 0) { + // abs(value) < 1. + if (value < 0.0) { + return -1.0; + } else { + // 0.0, or -0.0 if value is -0.0 + return 0.0 * value; + } + } else if (exponent < 52) { + // A bit faster than working on bits. + final long matIntPart = (long)value; + final double matIntToValue = value-(double)matIntPart; + if (matIntToValue >= 0.0) { + return (double)matIntPart; + } else { + return (double)(matIntPart - 1); + } + } else { + // +-Infinity, NaN, or a mathematical integer. + return value; + } + } + } + + /** + * @param value A float value. + * @return Ceiling of value. + */ + public static float ceil(float value) { + return -floor(-value); + } + + /** + * @param value A double value. + * @return Ceiling of value. + */ + public static double ceil(double value) { + if (USE_JDK_MATH) { + return StrictMath.ceil(value); + } + return -floor(-value); + } + + /** + * Might have different semantics than StrictMath.round(float), + * see bugs 6430675 and 8010430. + * + * @param value A double value. + * @return Value rounded to nearest int, choosing superior int in case two + * are equally close (i.e. rounding-up). + */ + public static int round(float value) { + /* + * Not delegating to JDK, because we want delegation to provide + * at least as good results, and some supported JDK versions + * have bugged round() methods. + */ + // Algorithm by Dmitry Nadezhin (but replaced an if by a multiply) + // (http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-August/020247.html). + final int bits = Float.floatToRawIntBits(value); + final int biasedExp = ((bits>>23)&0xFF); + // Shift to get rid of bits past comma except first one: will need to + // 1-shift to the right to end up with correct magnitude. + final int shift = (23 - 1 + MAX_FLOAT_EXPONENT) - biasedExp; + if ((shift & -32) == 0) { + int bitsSignum = (((bits >> 31) << 1) + 1); + // shift in [0,31], so unbiased exp in [-9,22]. + int extendedMantissa = (0x00800000 | (bits & 0x007FFFFF)) * bitsSignum; + // If value is positive and first bit past comma is 0, rounding + // to lower integer, else to upper one, which is what "+1" and + // then ">>1" do. + return ((extendedMantissa >> shift) + 1) >> 1; + } else { + // +-Infinity, NaN, or a mathematical integer, or tiny. + if (false && ANTI_SLOW_CASTS) { // not worth it + if (Math.abs(value) >= -(float)Integer.MIN_VALUE) { + // +-Infinity or a mathematical integer (mostly) out of int range. + return (value < 0.0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; + } + // NaN or a mathematical integer (mostly) in int range. + } + return (int)value; + } + } + + /** + * Might have different semantics than StrictMath.round(double), + * see bugs 6430675 and 8010430. + * + * @param value A double value. + * @return Value rounded to nearest long, choosing superior long in case two + * are equally close (i.e. rounding-up). + */ + public static long round(double value) { + /* + * Not delegating to JDK, because we want delegation to provide + * at least as good results, and some supported JDK versions + * have bugged round() methods. + */ + final long bits = Double.doubleToRawLongBits(value); + final int biasedExp = (((int)(bits>>52))&0x7FF); + // Shift to get rid of bits past comma except first one: will need to + // 1-shift to the right to end up with correct magnitude. + final int shift = (52 - 1 + MAX_DOUBLE_EXPONENT) - biasedExp; + if ((shift & -64) == 0) { + long bitsSignum = (((bits >> 63) << 1) + 1); + // shift in [0,63], so unbiased exp in [-12,51]. + long extendedMantissa = (0x0010000000000000L | (bits & 0x000FFFFFFFFFFFFFL)) * bitsSignum; + // If value is positive and first bit past comma is 0, rounding + // to lower integer, else to upper one, which is what "+1" and + // then ">>1" do. + return ((extendedMantissa >> shift) + 1L) >> 1; + } else { + // +-Infinity, NaN, or a mathematical integer, or tiny. + if (ANTI_SLOW_CASTS) { + if (Math.abs(value) >= -(double)Long.MIN_VALUE) { + // +-Infinity or a mathematical integer (mostly) out of long range. + return (value < 0.0) ? Long.MIN_VALUE : Long.MAX_VALUE; + } + // NaN or a mathematical integer (mostly) in long range. + } + return (long)value; + } + } + + /** + * @param value A float value. + * @return Value rounded to nearest int, choosing even int in case two + * are equally close. + */ + public static int roundEven(float value) { + final int sign = signFromBit(value); + value = Math.abs(value); + if (ANTI_SLOW_CASTS) { + if (value < TWO_POW_23_F) { + // Getting rid of post-comma bits. + value = ((value + TWO_POW_23_F) - TWO_POW_23_F); + return sign * (int)value; + } else if (value < (float)Integer.MAX_VALUE) { // "<=" doesn't work, because of float precision + // value is in [-Integer.MAX_VALUE,Integer.MAX_VALUE] + return sign * (int)value; + } + } else { + if (value < TWO_POW_23_F) { + // Getting rid of post-comma bits. + value = ((value + TWO_POW_23_F) - TWO_POW_23_F); + } + } + return (int)(sign * value); + } + + /** + * @param value A double value. + * @return Value rounded to nearest long, choosing even long in case two + * are equally close. + */ + public static long roundEven(double value) { + final int sign = (int)signFromBit(value); + value = Math.abs(value); + if (value < TWO_POW_52) { + // Getting rid of post-comma bits. + value = ((value + TWO_POW_52) - TWO_POW_52); + } + if (ANTI_SLOW_CASTS) { + if (value <= (double)Integer.MAX_VALUE) { + // value is in [-Integer.MAX_VALUE,Integer.MAX_VALUE] + return sign * (int)value; + } + } + return (long)(sign * value); + } + + /** + * @param value A float value. + * @return The float mathematical integer closest to the specified value, + * choosing even one if two are equally close, or respectively + * NaN, +-Infinity or +-0.0f if the value is any of these. + */ + public static float rint(float value) { + final int sign = signFromBit(value); + value = Math.abs(value); + if (value < TWO_POW_23_F) { + // Getting rid of post-comma bits. + value = ((TWO_POW_23_F + value ) - TWO_POW_23_F); + } + // Restoring original sign. + return sign * value; + } + + /** + * @param value A double value. + * @return The double mathematical integer closest to the specified value, + * choosing even one if two are equally close, or respectively + * NaN, +-Infinity or +-0.0 if the value is any of these. + */ + public static double rint(double value) { + if (USE_JDK_MATH) { + return StrictMath.rint(value); + } + final int sign = (int)signFromBit(value); + value = Math.abs(value); + if (value < TWO_POW_52) { + // Getting rid of post-comma bits. + value = ((TWO_POW_52 + value ) - TWO_POW_52); + } + // Restoring original sign. + return sign * value; + } + + /* + * close int values + * + * Never delegating to JDK for these methods, for we should always + * be faster and exact, and JDK doesn't exactly have such methods. + */ + + /** + * @param value A double value. + * @return Floor of value as int, or closest int if floor is out + * of int range, or 0 if value is NaN. + */ + public static int floorToInt(double value) { + int valueInt = (int) value; + if (value < 0.0) { + if (value == (double) valueInt) { + return valueInt; + } else { + if (valueInt == Integer.MIN_VALUE) { + return valueInt; + } else { + return valueInt - 1; + } + } + } else { // >= 0 or NaN. + return valueInt; + } + } + + /** + * @param value A double value. + * @return Ceiling of value as int, or closest int if ceiling is out + * of int range, or 0 if value is NaN. + */ + public static int ceilToInt(double value) { + int valueInt = (int) value; + if (value > 0.0) { + if (value == (double) valueInt) { + return valueInt; + } else { + if (valueInt == Integer.MAX_VALUE) { + return valueInt; + } else { + return valueInt + 1; + } + } + } else { // <= 0 or NaN. + return valueInt; + } + } + + /** + * @param value A double value. + * @return Value rounded to nearest int, choosing superior int in case two + * are equally close (i.e. rounding-up). + */ + public static int roundToInt(double value) { + /* + * We don't gain much by reimplementing rounding, except for + * pathologically large values, which should not be a common case + * when dealing with ints, so we just use round(double). + */ + return NumbersUtils.toInt(round(value)); + } + + /** + * @param value A double value. + * @return Value rounded to nearest int, choosing even int in case two + * are equally close. + */ + public static int roundEvenToInt(double value) { + final int sign = (int)signFromBit(value); + value = Math.abs(value); + /* + * Applying the post-comma bits removal logic even if value is out + * of int range, to avoid a test, for it doesn't mess up the result, + * and we want to optimize for the case of values in int range. + */ + value = ((value + TWO_POW_52) - TWO_POW_52); + return (int)(sign * value); + } + + /* + * ranges + */ + + /** + * @param min A float value. + * @param max A float value. + * @param value A float value. + * @return min if value < min, max if value > max, value otherwise. + */ + public static float toRange(float min, float max, float value) { + return NumbersUtils.toRange(min, max, value); + } + + /** + * @param min A double value. + * @param max A double value. + * @param value A double value. + * @return min if value < min, max if value > max, value otherwise. + */ + public static double toRange(double min, double max, double value) { + return NumbersUtils.toRange(min, max, value); + } + + /* + * binary operators (/,%) + */ + + /** + * Returns dividend - divisor * n, where n is the mathematical integer + * closest to dividend/divisor. + * If dividend/divisor is equally close to surrounding integers, + * we choose n to be the integer of smallest magnitude, which makes + * this treatment differ from StrictMath.IEEEremainder(double,double), + * where n is chosen to be the even integer. + * Note that the choice of n is not done considering the double + * approximation of dividend/divisor, because it could cause + * result to be outside [-|divisor|/2,|divisor|/2] range. + * The practical effect is that if multiple results would be possible, + * we always choose the result that is the closest to (and has the same + * sign as) the dividend. + * Ex. : + * - for (-3.0,2.0), this method returns -1.0, + * whereas StrictMath.IEEEremainder returns 1.0. + * - for (-5.0,2.0), both this method and StrictMath.IEEEremainder return -1.0. + * + * If the remainder is zero, its sign is the same as the sign of the first argument. + * If either argument is NaN, or the first argument is infinite, + * or the second argument is positive zero or negative zero, + * then the result is NaN. + * If the first argument is finite and the second argument is + * infinite, then the result is the same as the first argument. + * + * NB: + * - Modulo operator (%) returns a value in ]-|divisor|,|divisor|[, + * which sign is the same as dividend. + * - As for modulo operator, the sign of the divisor has no effect on the result. + * - On some architecture, % operator has been observed to return NaN + * for some subnormal values of divisor, when dividend exponent is 1023, + * which impacts the correctness of this method. + * + * @param dividend Dividend. + * @param divisor Divisor. + * @return Remainder of dividend/divisor, i.e. a value in [-|divisor|/2,|divisor|/2]. + */ + public static double remainder(double dividend, double divisor) { + if (Double.isInfinite(divisor)) { + if (Double.isInfinite(dividend)) { + return Double.NaN; + } else { + return dividend; + } + } + double value = dividend % divisor; + if (Math.abs(value+value) > Math.abs(divisor)) { + return value + ((value > 0.0) ? -Math.abs(divisor) : Math.abs(divisor)); + } else { + return value; + } + } + + /** + * @param angle Angle in radians. + * @return The same angle, in radians, but in [-PI,PI]. + */ + public static double normalizeMinusPiPi(double angle) { + // Not modifying values in output range. + if ((angle >= -Math.PI) && (angle <= Math.PI)) { + return angle; + } + return remainderTwoPi(angle); + } + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return The same angle, in radians, but in [-PI,PI]. + */ + public static double normalizeMinusPiPiFast(double angle) { + // Not modifying values in output range. + if ((angle >= -Math.PI) && (angle <= Math.PI)) { + return angle; + } + return remainderTwoPiFast(angle); + } + + /** + * @param angle Angle in radians. + * @return The same angle, in radians, but in [0,2*PI]. + */ + public static double normalizeZeroTwoPi(double angle) { + // Not modifying values in output range. + if ((angle >= 0.0) && (angle <= 2*Math.PI)) { + return angle; + } + angle = remainderTwoPi(angle); + if (angle < 0.0) { + // LO then HI is theoretically better (when starting near 0). + return (angle + TWOPI_LO) + TWOPI_HI; + } else { + return angle; + } + } + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return The same angle, in radians, but in [0,2*PI]. + */ + public static double normalizeZeroTwoPiFast(double angle) { + // Not modifying values in output range. + if ((angle >= 0.0) && (angle <= 2*Math.PI)) { + return angle; + } + angle = remainderTwoPiFast(angle); + if (angle < 0.0) { + // LO then HI is theoretically better (when starting near 0). + return (angle + TWOPI_LO) + TWOPI_HI; + } else { + return angle; + } + } + + /** + * @param angle Angle in radians. + * @return Angle value modulo PI, in radians, in [-PI/2,PI/2]. + */ + public static double normalizeMinusHalfPiHalfPi(double angle) { + // Not modifying values in output range. + if ((angle >= -Math.PI/2) && (angle <= Math.PI/2)) { + return angle; + } + return remainderPi(angle); + } + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return Angle value modulo PI, in radians, in [-PI/2,PI/2]. + */ + public static double normalizeMinusHalfPiHalfPiFast(double angle) { + // Not modifying values in output range. + if ((angle >= -Math.PI/2) && (angle <= Math.PI/2)) { + return angle; + } + return remainderPiFast(angle); + } + + /* + * floating points utils + */ + + /** + * @param value A float value. + * @return true if the specified value is NaN or +-Infinity, false otherwise. + */ + public static boolean isNaNOrInfinite(float value) { + return NumbersUtils.isNaNOrInfinite(value); + } + + /** + * @param value A double value. + * @return true if the specified value is NaN or +-Infinity, false otherwise. + */ + public static boolean isNaNOrInfinite(double value) { + return NumbersUtils.isNaNOrInfinite(value); + } + + /** + * @param value A float value. + * @return Value unbiased exponent. + */ + public static int getExponent(float value) { + return ((Float.floatToRawIntBits(value)>>23)&0xFF)-MAX_FLOAT_EXPONENT; + } + + /** + * @param value A double value. + * @return Value unbiased exponent. + */ + public static int getExponent(double value) { + return (((int)(Double.doubleToRawLongBits(value)>>52))&0x7FF)-MAX_DOUBLE_EXPONENT; + } + + /** + * @param value A float value. + * @return -1.0f if the specified value is < 0, 1.0f if it is > 0, + * and the value itself if it is NaN or +-0.0f. + */ + public static float signum(float value) { + if (USE_JDK_MATH) { + return StrictMath.signum(value); + } + if ((value == 0.0f) || (value != value)) { + return value; + } + return (float)signFromBit(value); + } + + /** + * @param value A double value. + * @return -1.0 if the specified value is < 0, 1.0 if it is > 0, + * and the value itself if it is NaN or +-0.0. + */ + public static double signum(double value) { + if (USE_JDK_MATH) { + return StrictMath.signum(value); + } + if ((value == 0.0) || (value != value)) { + return value; + } + if (ANTI_SLOW_CASTS) { + return (double)(int)signFromBit(value); + } else { + return (double)signFromBit(value); + } + } + + /** + * @param value A float value. + * @return -1 if sign bit is 1, 1 if sign bit is 0. + */ + public static int signFromBit(float value) { + return ((Float.floatToRawIntBits(value)>>30)|1); + } + + /** + * @param value A double value. + * @return -1 if sign bit is 1, 1 if sign bit is 0. + */ + public static long signFromBit(double value) { + // Returning a long, to avoid useless cast into int. + return ((Double.doubleToRawLongBits(value)>>62)|1); + } + + /** + * A sign of NaN is interpreted as positive. + * + * @param magnitude A float value. + * @param sign A float value. + * @return A value with the magnitude of the first argument, and the sign + * of the second argument. + */ + public static float copySign(float magnitude, float sign) { + return Float.intBitsToFloat( + (Float.floatToRawIntBits((sign != sign) ? 1.0f : sign) & Integer.MIN_VALUE) + | (Float.floatToRawIntBits(magnitude) & Integer.MAX_VALUE)); + } + + /** + * A sign of NaN is interpreted as positive. + * + * @param magnitude A double value. + * @param sign A double value. + * @return A value with the magnitude of the first argument, and the sign + * of the second argument. + */ + public static double copySign(double magnitude, double sign) { + return Double.longBitsToDouble( + (Double.doubleToRawLongBits((sign != sign) ? 1.0 : sign) & Long.MIN_VALUE) + | (Double.doubleToRawLongBits(magnitude) & Long.MAX_VALUE)); + } + + /** + * The ULP (Unit in the Last Place) is the distance to the next value larger + * in magnitude. + * + * @param value A float value. + * @return The size of an ulp of the specified value, or Float.MIN_VALUE + * if it is +-0.0f, or +Infinity if it is +-Infinity, or NaN + * if it is NaN. + */ + public static float ulp(float value) { + if (USE_JDK_MATH) { + return StrictMath.ulp(value); + } + /* + * Look-up table not really worth it in micro-benchmark, + * so should be worse with cache-misses. + */ + final int exponent = getExponent(value); + if (exponent >= (MIN_FLOAT_NORMAL_EXPONENT+23)) { + if (exponent == MAX_FLOAT_EXPONENT+1) { + // NaN or +-Infinity + return Math.abs(value); + } + // normal: returning 2^(exponent-23) + return Float.intBitsToFloat((exponent+(MAX_FLOAT_EXPONENT-23))<<23); + } else { + if (exponent == MIN_FLOAT_NORMAL_EXPONENT-1) { + // +-0.0f or subnormal + return Float.MIN_VALUE; + } + // subnormal result + return Float.intBitsToFloat(1<<(exponent-MIN_FLOAT_NORMAL_EXPONENT)); + } + } + + /** + * The ULP (Unit in the Last Place) is the distance to the next value larger + * in magnitude. + * + * @param value A double value. + * @return The size of an ulp of the specified value, or Double.MIN_VALUE + * if it is +-0.0, or +Infinity if it is +-Infinity, or NaN + * if it is NaN. + */ + public static double ulp(double value) { + if (USE_JDK_MATH) { + return StrictMath.ulp(value); + } + /* + * Look-up table not really worth it in micro-benchmark, + * so should be worse with cache-misses. + */ + final int exponent = getExponent(value); + if (exponent >= (MIN_DOUBLE_NORMAL_EXPONENT+52)) { + if (exponent == MAX_DOUBLE_EXPONENT+1) { + // NaN or +-Infinity + return Math.abs(value); + } + // normal: returning 2^(exponent-52) + return Double.longBitsToDouble((exponent+(MAX_DOUBLE_EXPONENT-52L))<<52); + } else { + if (exponent == MIN_DOUBLE_NORMAL_EXPONENT-1) { + // +-0.0f or subnormal + return Double.MIN_VALUE; + } + // subnormal result + return Double.longBitsToDouble(1L<<(exponent-MIN_DOUBLE_NORMAL_EXPONENT)); + } + } + + /** + * If both arguments are +-0.0(f), (float)direction is returned. + * + * If both arguments are +Infinity or -Infinity, + * respectively +Infinity or -Infinity is returned. + * + * @param start A float value. + * @param direction A double value. + * @return The float adjacent to start towards direction, considering that + * +(-)Float.MIN_VALUE is adjacent to +(-)0.0f, and that + * +(-)Float.MAX_VALUE is adjacent to +(-)Infinity, + * or NaN if any argument is NaN. + */ + public static float nextAfter(float start, double direction) { + if (direction < start) { + // Going towards -Infinity. + if (start == 0.0f) { + // +-0.0f + return -Float.MIN_VALUE; + } + final int bits = Float.floatToRawIntBits(start); + return Float.intBitsToFloat(bits + ((bits > 0) ? -1 : 1)); + } else if (direction > start) { + // Going towards +Infinity. + // +0.0f to get rid of eventual -0.0f + final int bits = Float.floatToRawIntBits(start + 0.0f); + return Float.intBitsToFloat(bits + (bits >= 0 ? 1 : -1)); + } else if (start == direction) { + return (float)direction; + } else { + // Returning a NaN derived from the input NaN(s). + return start + (float)direction; + } + } + + /** + * If both arguments are +-0.0, direction is returned. + * + * If both arguments are +Infinity or -Infinity, + * respectively +Infinity or -Infinity is returned. + * + * @param start A double value. + * @param direction A double value. + * @return The double adjacent to start towards direction, considering that + * +(-)Double.MIN_VALUE is adjacent to +(-)0.0, and that + * +(-)Double.MAX_VALUE is adjacent to +(-)Infinity, + * or NaN if any argument is NaN. + */ + public static double nextAfter(double start, double direction) { + if (direction < start) { + // Going towards -Infinity. + if (start == 0.0) { + // +-0.0 + return -Double.MIN_VALUE; + } + final long bits = Double.doubleToRawLongBits(start); + return Double.longBitsToDouble(bits + ((bits > 0) ? -1 : 1)); + } else if (direction > start) { + // Going towards +Infinity. + // +0.0 to get rid of eventual -0.0 + final long bits = Double.doubleToRawLongBits(start + 0.0f); + return Double.longBitsToDouble(bits + (bits >= 0 ? 1 : -1)); + } else if (start == direction) { + return direction; + } else { + // Returning a NaN derived from the input NaN(s). + return start + direction; + } + } + + /** + * Semantically equivalent to nextAfter(start,Double.NEGATIVE_INFINITY). + */ + public static float nextDown(float start) { + if (start > Float.NEGATIVE_INFINITY) { + if (start == 0.0f) { + // +-0.0f + return -Float.MIN_VALUE; + } + final int bits = Float.floatToRawIntBits(start); + return Float.intBitsToFloat(bits + ((bits > 0) ? -1 : 1)); + } else if (start == Float.NEGATIVE_INFINITY) { + return Float.NEGATIVE_INFINITY; + } else { + // NaN + return start; + } + } + + /** + * Semantically equivalent to nextAfter(start,Double.NEGATIVE_INFINITY). + */ + public static double nextDown(double start) { + if (start > Double.NEGATIVE_INFINITY) { + if (start == 0.0) { + // +-0.0 + return -Double.MIN_VALUE; + } + final long bits = Double.doubleToRawLongBits(start); + return Double.longBitsToDouble(bits + ((bits > 0) ? -1 : 1)); + } else if (start == Double.NEGATIVE_INFINITY) { + return Double.NEGATIVE_INFINITY; + } else { + // NaN + return start; + } + } + + /** + * Semantically equivalent to nextAfter(start,Double.POSITIVE_INFINITY). + */ + public static float nextUp(float start) { + if (start < Float.POSITIVE_INFINITY) { + // +0.0f to get rid of eventual -0.0f + final int bits = Float.floatToRawIntBits(start + 0.0f); + return Float.intBitsToFloat(bits + (bits >= 0 ? 1 : -1)); + } else if (start == Float.POSITIVE_INFINITY) { + return Float.POSITIVE_INFINITY; + } else { + // NaN + return start; + } + } + + /** + * Semantically equivalent to nextAfter(start,Double.POSITIVE_INFINITY). + */ + public static double nextUp(double start) { + if (start < Double.POSITIVE_INFINITY) { + // +0.0 to get rid of eventual -0.0 + final long bits = Double.doubleToRawLongBits(start + 0.0); + return Double.longBitsToDouble(bits + (bits >= 0 ? 1 : -1)); + } else if (start == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } else { + // NaN + return start; + } + } + + /** + * Precision may be lost if the result is subnormal. + * + * @param value A float value. + * @param scaleFactor An int value. + * @return value * 2^scaleFactor, or a value equivalent to the specified + * one if it is NaN, +-Infinity or +-0.0f. + */ + public static float scalb(float value, int scaleFactor) { + // Large enough to imply overflow or underflow for + // a finite non-zero value. + final int MAX_SCALE = 2*MAX_FLOAT_EXPONENT+23+1; + + // Making sure scaling factor is in a reasonable range. + scaleFactor = Math.max(Math.min(scaleFactor, MAX_SCALE), -MAX_SCALE); + + return (float)(((double)value) * twoPowNormal(scaleFactor)); + } + + /** + * Precision may be lost if the result is subnormal. + * + * @param value A double value. + * @param scaleFactor An int value. + * @return value * 2^scaleFactor, or a value equivalent to the specified + * one if it is NaN, +-Infinity or +-0.0. + */ + public static double scalb(double value, int scaleFactor) { + if ((scaleFactor > -MAX_DOUBLE_EXPONENT) && (scaleFactor <= MAX_DOUBLE_EXPONENT)) { + // Quick case (as done in apache FastMath). + return value * twoPowNormal(scaleFactor); + } + + // Large enough to imply overflow or underflow for + // a finite non-zero value. + final int MAX_SCALE = 2*MAX_DOUBLE_EXPONENT+52+1; + + // Making sure scaling factor is in a reasonable range. + final int exponentAdjust; + final int scaleIncrement; + final double exponentDelta; + if (scaleFactor < 0) { + scaleFactor = Math.max(scaleFactor, -MAX_SCALE); + scaleIncrement = -512; + exponentDelta = TWO_POW_N512; + } else { + scaleFactor = Math.min(scaleFactor, MAX_SCALE); + scaleIncrement = 512; + exponentDelta = TWO_POW_512; + } + + // Calculating (scaleFactor % +-512), 512 = 2^9, using + // technique from "Hacker's Delight" section 10-2. + final int t = ((scaleFactor >> (9-1)) >>> (32-9)); + exponentAdjust = ((scaleFactor + t) & (512-1)) - t; + + value *= twoPowNormal(exponentAdjust); + scaleFactor -= exponentAdjust; + + while (scaleFactor != 0) { + value *= exponentDelta; + scaleFactor -= scaleIncrement; + } + + return value; + } + + /* + * Non-redefined StrictMath public values and treatments. + */ + + public static float abs(float a) { + return StrictMath.abs(a); + } + + public static double abs(double a) { + return StrictMath.abs(a); + } + + public static float min(float a, float b) { + return StrictMath.min(a,b); + } + + public static double min(double a, double b) { + return StrictMath.min(a,b); + } + + public static float max(float a, float b) { + return StrictMath.max(a,b); + } + + public static double max(double a, double b) { + return StrictMath.max(a,b); + } + + public static double IEEEremainder(double f1, double f2) { + return StrictMath.IEEEremainder(f1,f2); + } + + public static double random() { + return StrictMath.random(); + } + + //-------------------------------------------------------------------------- + // PRIVATE METHODS + //-------------------------------------------------------------------------- + + /** + * Non-instantiable. + */ + private StrictFastMath() { + } + + /* + * Remainders (accurate). + */ + + /** + * @param angle Angle in radians. + * @return Remainder of (angle % (2*PI)), in [-PI,PI]. + */ + private static double remainderTwoPi(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderTwoPi(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle <= (4*NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2)) { + double fn = (double)(int)(angle*TWOPI_INV+0.5); + angle = (angle - fn*TWOPI_HI) - fn*TWOPI_LO; + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI) { + angle = (angle + TWOPI_HI) + TWOPI_LO; + } else if (angle > Math.PI) { + angle = (angle - TWOPI_HI) - TWOPI_LO; + } + return negateResult ? -angle : angle; + } else if (angle < Double.POSITIVE_INFINITY) { + angle = heavyRemainderTwoPi(angle); + return negateResult ? -angle : angle; + } else { // angle is +Infinity or NaN + return Double.NaN; + } + } + + /** + * @param angle Angle in radians. + * @return Remainder of (angle % PI), in [-PI/2,PI/2]. + */ + private static double remainderPi(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderPi(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle <= (2*NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2)) { + double fn = (double)(int)(angle*PI_INV+0.5); + angle = (angle - fn*PI_HI) - fn*PI_LO; + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI/2) { + angle = (angle + PI_HI) + PI_LO; + } else if (angle > Math.PI/2) { + angle = (angle - PI_HI) - PI_LO; + } + return negateResult ? -angle : angle; + } else if (angle < Double.POSITIVE_INFINITY) { + angle = heavyRemainderPi(angle); + return negateResult ? -angle : angle; + } else { // angle is +Infinity or NaN + return Double.NaN; + } + } + + /** + * @param angle Angle in radians. + * @return Bits of double corresponding to remainder of (angle % (PI/2)), + * in [-PI/4,PI/4], with quadrant encoded in exponent bits. + */ + private static long remainderPiO2(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderPiO2(angle, false); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + if (angle <= NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2) { + int n = (int)(angle*PIO2_INV+0.5); + double fn = (double)n; + angle = (angle - fn*PIO2_HI) - fn*PIO2_LO; + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI/4) { + angle = (angle + PIO2_HI) + PIO2_LO; + n--; + } else if (angle > Math.PI/4) { + angle = (angle - PIO2_HI) - PIO2_LO; + n++; + } + if (negateResult) { + angle = -angle; + } + return encodeRemainderAndQuadrant(angle, n&3); + } else if (angle < Double.POSITIVE_INFINITY) { + return heavyRemainderPiO2(angle, negateResult); + } else { // angle is +Infinity or NaN + return encodeRemainderAndQuadrant(Double.NaN, 0); + } + } + + /* + * Remainders (fast). + */ + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return Remainder of (angle % (2*PI)), in [-PI,PI]. + */ + private static double remainderTwoPiFast(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderTwoPi(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + // - We don't bother with values higher than (2*PI*(2^52)), + // since they are spaced by 2*PI or more from each other. + // - For large values, we don't use % because it might be very slow, + // and we split computation in two, because cast from double to int + // with large numbers might be very slow also. + if (angle <= TWO_POW_26*(2*Math.PI)) { + // ok + } else if (angle <= TWO_POW_52*(2*Math.PI)) { + // Computing remainder of angle modulo TWO_POW_26*(2*PI). + double fn = (double)(int)(angle*(TWOPI_INV/TWO_POW_26)+0.5); + angle = (angle - fn*(TWOPI_HI*TWO_POW_26)) - fn*(TWOPI_LO*TWO_POW_26); + // Here, angle is in [-TWO_POW_26*PI,TWO_POW_26*PI], or so. + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } else if (angle < Double.POSITIVE_INFINITY) { + return 0.0; + } else { // angle is +Infinity or NaN + return Double.NaN; + } + + // Computing remainder of angle modulo 2*PI. + double fn = (double)(int)(angle*TWOPI_INV+0.5); + angle = (angle - fn*TWOPI_HI) - fn*TWOPI_LO; + + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI) { + angle = (angle + TWOPI_HI) + TWOPI_LO; + } else if (angle > Math.PI) { + angle = (angle - TWOPI_HI) - TWOPI_LO; + } + return negateResult ? -angle : angle; + } + + /** + * Not accurate for large values. + * + * @param angle Angle in radians. + * @return Remainder of (angle % PI), in [-PI/2,PI/2]. + */ + private static double remainderPiFast(double angle) { + if (USE_JDK_MATH) { + return jdkRemainderPi(angle); + } + boolean negateResult = false; + if (angle < 0.0) { + angle = -angle; + negateResult = true; + } + // - We don't bother with values higher than (PI*(2^52)), + // since they are spaced by PI or more from each other. + // - For large values, we don't use % because it might be very slow, + // and we split computation in two, because cast from double to int + // with large numbers might be very slow also. + if (angle <= TWO_POW_26*Math.PI) { + // ok + } else if (angle <= TWO_POW_52*Math.PI) { + // Computing remainder of angle modulo TWO_POW_26*PI. + double fn = (double)(int)(angle*(PI_INV/TWO_POW_26)+0.5); + angle = (angle - fn*(PI_HI*TWO_POW_26)) - fn*(PI_LO*TWO_POW_26); + // Here, angle is in [-TWO_POW_26*PI/2,TWO_POW_26*PI/2], or so. + if (angle < 0.0) { + angle = -angle; + negateResult = !negateResult; + } + } else if (angle < Double.POSITIVE_INFINITY) { + return 0.0; + } else { // angle is +Infinity or NaN + return Double.NaN; + } + + // Computing remainder of angle modulo PI. + double fn = (double)(int)(angle*PI_INV+0.5); + angle = (angle - fn*PI_HI) - fn*PI_LO; + + // Ensuring range. + // HI/LO can help a bit, even though we are always far from 0. + if (angle < -Math.PI/2) { + angle = (angle + PI_HI) + PI_LO; + } else if (angle > Math.PI/2) { + angle = (angle - PI_HI) - PI_LO; + } + return negateResult ? -angle : angle; + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 661afa67c..15a6a176c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -43,6 +43,7 @@ include( ":kmath-tensors", ":kmath-jupyter", ":kmath-symja", + ":kmath-jafama", ":examples", ":benchmarks" ) From 6c815abd54a248cd1f95e02d580382e4b55377ba Mon Sep 17 00:00:00 2001 From: therealansh Date: Thu, 3 Jun 2021 01:37:23 +0530 Subject: [PATCH 11/39] chore: refactored and dependency add --- kmath-jafama/build.gradle.kts | 9 +- .../kscience/kmath/jafama/CmnFastMath.java | 2112 ------------ .../kscience/kmath/jafama/DoubleWrapper.java | 13 - .../space/kscience/kmath/jafama/FastMath.java | 2986 ---------------- .../kscience/kmath/jafama/IntWrapper.java | 13 - .../kscience/kmath/jafama/KMathJafama.kt | 3 +- .../kscience/kmath/jafama/NumbersUtils.java | 2647 --------------- .../kscience/kmath/jafama/StrictFastMath.java | 2998 ----------------- 8 files changed, 6 insertions(+), 10775 deletions(-) delete mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/CmnFastMath.java delete mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/DoubleWrapper.java delete mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/FastMath.java delete mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/IntWrapper.java delete mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/NumbersUtils.java delete mode 100644 kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/StrictFastMath.java diff --git a/kmath-jafama/build.gradle.kts b/kmath-jafama/build.gradle.kts index 22d50f89c..f31f2602f 100644 --- a/kmath-jafama/build.gradle.kts +++ b/kmath-jafama/build.gradle.kts @@ -3,13 +3,12 @@ plugins { } dependencies { - api(project(":kmath-ast")) - api(project(":kmath-complex")) - api(project(":kmath-for-real")) + api(project(":kmath-core")) + api("net.jafama:jafama:2.3.2") } -kscience{ - useHtml() +repositories { + mavenCentral() } readme { diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/CmnFastMath.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/CmnFastMath.java deleted file mode 100644 index 0abc5d95d..000000000 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/CmnFastMath.java +++ /dev/null @@ -1,2112 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.jafama; - -/** - * Stuffs for FastMath and StrictFastMath. - */ -abstract class CmnFastMath { - - /* - * For trigonometric functions, use of look-up tables and Taylor-Lagrange formula - * with 4 derivatives (more take longer to compute and don't add much accuracy, - * less require larger tables (which use more memory, take more time to initialize, - * and are slower to access (at least on the machine they were developed on))). - * - * For angles reduction of cos/sin/tan functions: - * - for small values, instead of reducing angles, and then computing the best index - * for look-up tables, we compute this index right away, and use it for reduction, - * - for large values, treatments derived from fdlibm package are used, as done in - * java.lang.Math. They are faster but still "slow", so if you work with - * large numbers and need speed over accuracy for them, you might want to use - * normalizeXXXFast treatments before your function, or modify cos/sin/tan - * so that they call the fast normalization treatments instead of the accurate ones. - * NB: If an angle is huge (like PI*1e20), in double precision format its last digits - * are zeros, which most likely is not the case for the intended value, and doing - * an accurate reduction on a very inaccurate value is most likely pointless. - * But it gives some sort of coherence that could be needed in some cases. - * - * Multiplication on double appears to be about as fast (or not much slower) than call - * to [], and regrouping some doubles in a private class, to use - * index only once, does not seem to speed things up, so: - * - for uniformly tabulated values, to retrieve the parameter corresponding to - * an index, we recompute it rather than using an array to store it, - * - for cos/sin, we recompute derivatives divided by (multiplied by inverse of) - * factorial each time, rather than storing them in arrays. - * - * Lengths of look-up tables are usually of the form 2^n+1, for their values to be - * of the form ( * k/2^n, k in 0 .. 2^n), so that particular values - * (PI/2, etc.) are "exactly" computed, as well as for other reasons. - * - * Tables are put in specific inner classes, to be lazily initialized. - * Always doing strict tables initialization, even if StrictFastMath delegates - * to StrictMath and doesn't use tables, which makes tables initialization a bit - * slower but code simpler. - * Using redefined pure Java treatments during tables initialization, - * instead of Math or StrictMath ones (even asin(double)), can be very slow, - * because class loading is likely not to be optimized. - * - * Most math treatments I could find on the web, including "fast" ones, - * usually take care of special cases (NaN, etc.) at the beginning, and - * then deal with the general case, which adds a useless overhead for the - * general (and common) case. In this class, special cases are only dealt - * with when needed, and if the general case does not already handle them. - */ - - /* - * Regarding strictfp-ness: - * - * Switching from/to strictfp has some overhead, so we try to only - * strictfp-ize when needed (or when clueless). - * Compile-time constants are computed in a FP-strict way, so no need - * to make this whole class strictfp. - */ - - //-------------------------------------------------------------------------- - // CONFIGURATION - //-------------------------------------------------------------------------- - - /* - * FastMath - */ - - static final boolean FM_USE_JDK_MATH = getBooleanProperty("jafama.usejdk", false); - - /** - * Used for both FastMath.log(double) and FastMath.log10(double). - */ - static final boolean FM_USE_REDEFINED_LOG = getBooleanProperty("jafama.fastlog", false); - - static final boolean FM_USE_REDEFINED_SQRT = getBooleanProperty("jafama.fastsqrt", false); - - /** - * Set it to true if FastMath.sqrt(double) is slow - * (more tables, but less calls to FastMath.sqrt(double)). - */ - static final boolean FM_USE_POWTABS_FOR_ASIN = false; - - /* - * StrictFastMath - */ - - static final boolean SFM_USE_JDK_MATH = getBooleanProperty("jafama.strict.usejdk", false); - - /** - * Used for both StrictFastMath.log(double) and StrictFastMath.log10(double). - * True by default because the StrictMath implementations can be slow. - */ - static final boolean SFM_USE_REDEFINED_LOG = getBooleanProperty("jafama.strict.fastlog", true); - - static final boolean SFM_USE_REDEFINED_SQRT = getBooleanProperty("jafama.strict.fastsqrt", false); - - /** - * Set it to true if StrictFastMath.sqrt(double) is slow - * (more tables, but less calls to StrictFastMath.sqrt(double)). - */ - static final boolean SFM_USE_POWTABS_FOR_ASIN = false; - - /* - * Common to FastMath and StrictFastMath. - */ - - /** - * Using two pow tab can just make things barely faster, - * and could relatively hurt in case of cache-misses, - * especially for methods that otherwise wouldn't rely - * on any tab, so we don't use it. - */ - static final boolean USE_TWO_POW_TAB = false; - - /** - * Because on some architectures, some casts can be slow, - * especially for large values. - * Might make things a bit slower for latest architectures, - * but not as much as it makes them faster for older ones. - */ - static final boolean ANTI_SLOW_CASTS = true; - - /** - * If some methods get JIT-optimized, they might crash - * if they contain "(var == xxx)" with var being NaN - * (can happen with Java 6u29). - * - * The crash does not happen if we replace "==" with "<" or ">". - * - * Only the code that has been observed to trigger the bug - * has been modified. - */ - static final boolean ANTI_JIT_OPTIM_CRASH_ON_NAN = true; - - //-------------------------------------------------------------------------- - // GENERAL CONSTANTS - //-------------------------------------------------------------------------- - - /** - * Closest double approximation of e. - */ - public static final double E = Math.E; - - /** - * Closest double approximation of pi, which is inferior to mathematical pi: - * pi ~= 3.14159265358979323846... - * PI ~= 3.141592653589793 - */ - public static final double PI = Math.PI; - - /** - * High double approximation of pi, which is further from pi - * than the low approximation PI: - * pi ~= 3.14159265358979323846... - * PI ~= 3.141592653589793 - * PI_SUP ~= 3.1415926535897936 - */ - public static final double PI_SUP = Double.longBitsToDouble(Double.doubleToRawLongBits(Math.PI)+1); - - static final double ONE_DIV_F2 = 1/2.0; - static final double ONE_DIV_F3 = 1/6.0; - static final double ONE_DIV_F4 = 1/24.0; - - static final float TWO_POW_23_F = (float)NumbersUtils.twoPow(23); - - static final double TWO_POW_24 = NumbersUtils.twoPow(24); - private static final double TWO_POW_N24 = NumbersUtils.twoPow(-24); - - static final double TWO_POW_26 = NumbersUtils.twoPow(26); - static final double TWO_POW_N26 = NumbersUtils.twoPow(-26); - - // First double value (from zero) such as (value+-1/value == value). - static final double TWO_POW_27 = NumbersUtils.twoPow(27); - static final double TWO_POW_N27 = NumbersUtils.twoPow(-27); - - static final double TWO_POW_N28 = NumbersUtils.twoPow(-28); - - static final double TWO_POW_52 = NumbersUtils.twoPow(52); - - static final double TWO_POW_N55 = NumbersUtils.twoPow(-55); - - static final double TWO_POW_66 = NumbersUtils.twoPow(66); - - static final double TWO_POW_512 = NumbersUtils.twoPow(512); - static final double TWO_POW_N512 = NumbersUtils.twoPow(-512); - - /** - * Double.MIN_NORMAL since Java 6. - */ - static final double DOUBLE_MIN_NORMAL = Double.longBitsToDouble(0x0010000000000000L); // 2.2250738585072014E-308 - - // Not storing float/double mantissa size in constants, - // for 23 and 52 are shorter to read and more - // bitwise-explicit than some constant's name. - - static final int MIN_DOUBLE_EXPONENT = -1074; - static final int MIN_DOUBLE_NORMAL_EXPONENT = -1022; - static final int MAX_DOUBLE_EXPONENT = 1023; - - static final int MIN_FLOAT_NORMAL_EXPONENT = -126; - static final int MAX_FLOAT_EXPONENT = 127; - - private static final double SQRT_2 = StrictMath.sqrt(2.0); - - static final double LOG_2 = StrictMath.log(2.0); - static final double LOG_TWO_POW_27 = StrictMath.log(TWO_POW_27); - static final double LOG_DOUBLE_MAX_VALUE = StrictMath.log(Double.MAX_VALUE); - - static final double INV_LOG_10 = 1.0/StrictMath.log(10.0); - - static final double DOUBLE_BEFORE_60 = Double.longBitsToDouble(Double.doubleToRawLongBits(60.0)-1); - - //-------------------------------------------------------------------------- - // CONSTANTS FOR NORMALIZATIONS - //-------------------------------------------------------------------------- - - /** - * Table of constants for 1/(PI/2), 282 Hex digits (enough for normalizing doubles). - * 1/(PI/2) approximation = sum of TWO_OVER_PI_TAB[i]*2^(-24*(i+1)). - * - * double and not int, to avoid int-to-double cast during computations. - */ - private static final double TWO_OVER_PI_TAB[] = { - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, - 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, - 0x424DD2, 0xe00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, - 0x3991d6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, - 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, - 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, - 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, - 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B}; - - /* - * Constants for PI/2. Only the 23 most significant bits of each mantissa are used. - * 2*PI approximation = sum of TWOPI_TAB. - */ - private static final double PIO2_TAB0 = Double.longBitsToDouble(0x3FF921FB40000000L); - private static final double PIO2_TAB1 = Double.longBitsToDouble(0x3E74442D00000000L); - private static final double PIO2_TAB2 = Double.longBitsToDouble(0x3CF8469880000000L); - private static final double PIO2_TAB3 = Double.longBitsToDouble(0x3B78CC5160000000L); - private static final double PIO2_TAB4 = Double.longBitsToDouble(0x39F01B8380000000L); - private static final double PIO2_TAB5 = Double.longBitsToDouble(0x387A252040000000L); - - static final double PIO2_INV = Double.longBitsToDouble(0x3FE45F306DC9C883L); // 6.36619772367581382433e-01 53 bits of 2/pi - static final double PIO2_HI = Double.longBitsToDouble(0x3FF921FB54400000L); // 1.57079632673412561417e+00 first 33 bits of pi/2 - static final double PIO2_LO = Double.longBitsToDouble(0x3DD0B4611A626331L); // 6.07710050650619224932e-11 pi/2 - PIO2_HI - static final double PI_INV = PIO2_INV/2; - static final double PI_HI = 2*PIO2_HI; - static final double PI_LO = 2*PIO2_LO; - static final double TWOPI_INV = PIO2_INV/4; - static final double TWOPI_HI = 4*PIO2_HI; - static final double TWOPI_LO = 4*PIO2_LO; - - /** - * Bit = 0 where quadrant is encoded in remainder bits. - */ - private static final long QUADRANT_BITS_0_MASK = 0xCFFFFFFFFFFFFFFFL; - - /** - * Remainder bits where quadrant is encoded, 0 elsewhere. - */ - private static final long QUADRANT_PLACE_BITS = 0x3000000000000000L; - - /** - * fdlibm uses 2^19*PI/2 here. - * With 2^18*PI/2 we would be more accurate, for example when normalizing - * 822245.903631403, which is close to 2^19*PI/2, but we are still in - * our accuracy tolerance with fdlibm's value (but not 2^20*PI/2) so we - * stick to it, to help being faster than (Strict)Math for values in - * [2^18*PI/2,2^19*PI/2]. - * - * For tests, can use a smaller value, for heavy remainder - * not to only be used with huge values. - */ - static final double NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2 = StrictMath.pow(2.0,19.0)*(Math.PI/2); - - /** - * 2*Math.PI, normalized into [-PI,PI], as returned by - * StrictMath.asin(StrictMath.sin(2*Math.PI)) - * (asin behaves as identity for this). - * - * NB: NumbersUtils.minus2PI(2*Math.PI) returns -2.449293598153844E-16, - * which is different due to not using an accurate enough definition of PI. - */ - static final double TWO_MATH_PI_IN_MINUS_PI_PI = -2.4492935982947064E-16; - - //-------------------------------------------------------------------------- - // CONSTANTS AND TABLES FOR SIN AND COS - //-------------------------------------------------------------------------- - - static final int SIN_COS_TABS_SIZE = (1<>9) / SIN_COS_INDEXER) * 0.99; - - //-------------------------------------------------------------------------- - // CONSTANTS AND TABLES FOR TAN - //-------------------------------------------------------------------------- - - // We use the following formula: - // 1) tan(-x) = -tan(x) - // 2) tan(x) = 1/tan(PI/2-x) - // ---> we only have to compute tan(x) on [0,A] with PI/4<=A= 45deg, and supposed to be >= 51.4deg, as fdlibm code is not - * supposed to work with values inferior to that (51.4deg is about - * (PI/2-Double.longBitsToDouble(0x3FE5942800000000L))). - */ - static final double TAN_MAX_VALUE_FOR_TABS = StrictMath.toRadians(77.0); - - static final int TAN_TABS_SIZE = (int)((TAN_MAX_VALUE_FOR_TABS/(Math.PI/2)) * (TAN_VIRTUAL_TABS_SIZE-1)) + 1; - static final double TAN_DELTA_HI = PIO2_HI/(TAN_VIRTUAL_TABS_SIZE-1); - static final double TAN_DELTA_LO = PIO2_LO/(TAN_VIRTUAL_TABS_SIZE-1); - static final double TAN_INDEXER = 1/(TAN_DELTA_HI+TAN_DELTA_LO); - - static final class MyTTan { - static final double[] tanTab = new double[TAN_TABS_SIZE]; - static final double[] tanDer1DivF1Tab = new double[TAN_TABS_SIZE]; - static final double[] tanDer2DivF2Tab = new double[TAN_TABS_SIZE]; - static final double[] tanDer3DivF3Tab = new double[TAN_TABS_SIZE]; - static final double[] tanDer4DivF4Tab = new double[TAN_TABS_SIZE]; - static { - init(); - } - private static strictfp void init() { - for (int i=0;i>9) / TAN_INDEXER) * 0.99); - - //-------------------------------------------------------------------------- - // CONSTANTS AND TABLES FOR ACOS, ASIN - //-------------------------------------------------------------------------- - - // We use the following formula: - // 1) acos(x) = PI/2 - asin(x) - // 2) asin(-x) = -asin(x) - // ---> we only have to compute asin(x) on [0,1]. - // For values not close to +-1, we use look-up tables; - // for values near +-1, we use code derived from fdlibm. - - /** - * Supposed to be >= sin(77.2deg), as fdlibm code is supposed to work with values > 0.975, - * but seems to work well enough as long as value >= sin(25deg). - */ - static final double ASIN_MAX_VALUE_FOR_TABS = StrictMath.sin(StrictMath.toRadians(73.0)); - - static final int ASIN_TABS_SIZE = (1< we only have to compute atan(x) on [0,+Infinity[. - // For values corresponding to angles not close to +-PI/2, we use look-up tables; - // for values corresponding to angles near +-PI/2, we use code derived from fdlibm. - - /** - * Supposed to be >= tan(67.7deg), as fdlibm code is supposed to work with values > 2.4375. - */ - static final double ATAN_MAX_VALUE_FOR_TABS = StrictMath.tan(StrictMath.toRadians(74.0)); - - static final int ATAN_TABS_SIZE = (1<>SQRT_LO_BITS)); - for (int i=1;i>CBRT_LO_BITS)); - for (int i=1;i= MIN_DOUBLE_EXPONENT) { - if (power <= MAX_DOUBLE_EXPONENT) { // Normal or subnormal. - return MyTTwoPow.twoPowTab[power-MIN_DOUBLE_EXPONENT]; - } else { // Overflow. - return Double.POSITIVE_INFINITY; - } - } else { // Underflow. - return 0.0; - } - } else { - return NumbersUtils.twoPow(power); - } - } - - /** - * @param value An int value. - * @return value*value. - */ - public static int pow2(int value) { - return value*value; - } - - /** - * @param value A long value. - * @return value*value. - */ - public static long pow2(long value) { - return value*value; - } - - /** - * @param value An int value. - * @return value*value*value. - */ - public static int pow3(int value) { - return value*value*value; - } - - /** - * @param value A long value. - * @return value*value*value. - */ - public static long pow3(long value) { - return value*value*value; - } - - /* - * absolute values - */ - - /** - * @param value An int value. - * @return The absolute value, except if value is Integer.MIN_VALUE, for which it returns Integer.MIN_VALUE. - */ - public static int abs(int value) { - if (FM_USE_JDK_MATH || SFM_USE_JDK_MATH) { - return Math.abs(value); - } - return NumbersUtils.abs(value); - } - - /** - * @param value A long value. - * @return The absolute value, except if value is Long.MIN_VALUE, for which it returns Long.MIN_VALUE. - */ - public static long abs(long value) { - if (FM_USE_JDK_MATH || SFM_USE_JDK_MATH) { - return Math.abs(value); - } - return NumbersUtils.abs(value); - } - - /* - * close values - */ - - /** - * @param value A long value. - * @return The specified value as int. - * @throws ArithmeticException if the specified value is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int toIntExact(long value) { - return NumbersUtils.asInt(value); - } - - /** - * @param value A long value. - * @return The closest int value in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int toInt(long value) { - return NumbersUtils.toInt(value); - } - - /* - * ranges - */ - - /** - * @param min An int value. - * @param max An int value. - * @param value An int value. - * @return minValue if value < minValue, maxValue if value > maxValue, value otherwise. - */ - public static int toRange(int min, int max, int value) { - return NumbersUtils.toRange(min, max, value); - } - - /** - * @param min A long value. - * @param max A long value. - * @param value A long value. - * @return min if value < min, max if value > max, value otherwise. - */ - public static long toRange(long min, long max, long value) { - return NumbersUtils.toRange(min, max, value); - } - - /* - * unary operators (increment,decrement,negate) - */ - - /** - * @param value An int value. - * @return The argument incremented by one. - * @throws ArithmeticException if the mathematical result - * is not in int range. - */ - public static int incrementExact(int value) { - if (value == Integer.MAX_VALUE) { - throw new ArithmeticException("integer overflow"); - } - return value + 1; - } - - /** - * @param value A long value. - * @return The argument incremented by one. - * @throws ArithmeticException if the mathematical result - * is not in long range. - */ - public static long incrementExact(long value) { - if (value == Long.MAX_VALUE) { - throw new ArithmeticException("long overflow"); - } - return value + 1L; - } - - /** - * @param value An int value. - * @return The argument incremented by one, or the argument - * if the mathematical result is not in int range. - */ - public static int incrementBounded(int value) { - if (value == Integer.MAX_VALUE) { - return value; - } - return value + 1; - } - - /** - * @param value A long value. - * @return The argument incremented by one, or the argument - * if the mathematical result is not in long range. - */ - public static long incrementBounded(long value) { - if (value == Long.MAX_VALUE) { - return value; - } - return value + 1L; - } - - /** - * @param value An int value. - * @return The argument decremented by one. - * @throws ArithmeticException if the mathematical result - * is not in int range. - */ - public static int decrementExact(int value) { - if (value == Integer.MIN_VALUE) { - throw new ArithmeticException("integer overflow"); - } - return value - 1; - } - - /** - * @param value A long value. - * @return The argument decremented by one. - * @throws ArithmeticException if the mathematical result - * is not in long range. - */ - public static long decrementExact(long value) { - if (value == Long.MIN_VALUE) { - throw new ArithmeticException("long overflow"); - } - return value - 1L; - } - - /** - * @param value An int value. - * @return The argument decremented by one, or the argument - * if the mathematical result is not in int range. - */ - public static int decrementBounded(int value) { - if (value == Integer.MIN_VALUE) { - return value; - } - return value - 1; - } - - /** - * @param value A long value. - * @return The argument decremented by one, or the argument - * if the mathematical result is not in long range. - */ - public static long decrementBounded(long value) { - if (value == Long.MIN_VALUE) { - return value; - } - return value - 1L; - } - - /** - * @param value An int value. - * @return The argument negated. - * @throws ArithmeticException if the mathematical result - * is not in int range. - */ - public static int negateExact(int value) { - if (value == Integer.MIN_VALUE) { - throw new ArithmeticException("integer overflow"); - } - return -value; - } - - /** - * @param value A long value. - * @return The argument negated. - * @throws ArithmeticException if the mathematical result - * is not in long range. - */ - public static long negateExact(long value) { - if (value == Long.MIN_VALUE) { - throw new ArithmeticException("long overflow"); - } - return -value; - } - - /** - * @param value An int value. - * @return The argument negated, or Integer.MAX_VALUE - * if the argument is Integer.MIN_VALUE. - */ - public static int negateBounded(int value) { - if (value == Integer.MIN_VALUE) { - return Integer.MAX_VALUE; - } - return -value; - } - - /** - * @param value A long value. - * @return The argument negated, or Long.MAX_VALUE - * if the argument is Long.MIN_VALUE. - */ - public static long negateBounded(long value) { - if (value == Long.MIN_VALUE) { - return Long.MAX_VALUE; - } - return -value; - } - - /* - * binary operators (+,-,*) - */ - - /** - * @param a An int value. - * @param b An int value. - * @return The mathematical result of a+b. - * @throws ArithmeticException if the mathematical result of a+b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int addExact(int a, int b) { - return NumbersUtils.plusExact(a, b); - } - - /** - * @param a A long value. - * @param b A long value. - * @return The mathematical result of a+b. - * @throws ArithmeticException if the mathematical result of a+b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. - */ - public static long addExact(long a, long b) { - return NumbersUtils.plusExact(a, b); - } - - /** - * @param a An int value. - * @param b An int value. - * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a+b. - */ - public static int addBounded(int a, int b) { - return NumbersUtils.plusBounded(a, b); - } - - /** - * @param a A long value. - * @param b A long value. - * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a+b. - */ - public static long addBounded(long a, long b) { - return NumbersUtils.plusBounded(a, b); - } - - /** - * @param a An int value. - * @param b An int value. - * @return The mathematical result of a-b. - * @throws ArithmeticException if the mathematical result of a-b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int subtractExact(int a, int b) { - return NumbersUtils.minusExact(a, b); - } - - /** - * @param a A long value. - * @param b A long value. - * @return The mathematical result of a-b. - * @throws ArithmeticException if the mathematical result of a-b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. - */ - public static long subtractExact(long a, long b) { - return NumbersUtils.minusExact(a, b); - } - - /** - * @param a An int value. - * @param b An int value. - * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a-b. - */ - public static int subtractBounded(int a, int b) { - return NumbersUtils.minusBounded(a, b); - } - - /** - * @param a A long value. - * @param b A long value. - * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a-b. - */ - public static long subtractBounded(long a, long b) { - return NumbersUtils.minusBounded(a, b); - } - - /** - * @param a An int value. - * @param b An int value. - * @return The mathematical result of a*b. - * @throws ArithmeticException if the mathematical result of a*b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int multiplyExact(int a, int b) { - return NumbersUtils.timesExact(a, b); - } - - /** - * @param a A long value. - * @param b An int value. - * @return The mathematical result of a*b. - * @throws ArithmeticException if the mathematical result of a*b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. - */ - public static long multiplyExact(long a, int b) { - return NumbersUtils.timesExact(a, (long) b); - } - - /** - * @param a A long value. - * @param b A long value. - * @return The mathematical result of a*b. - * @throws ArithmeticException if the mathematical result of a*b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. - */ - public static long multiplyExact(long a, long b) { - return NumbersUtils.timesExact(a, b); - } - - /** - * @param a An int value. - * @param b An int value. - * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a*b. - */ - public static int multiplyBounded(int a, int b) { - return NumbersUtils.timesBounded(a, b); - } - - /** - * @param a A long value. - * @param b An int value. - * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a*b. - */ - public static long multiplyBounded(long a, int b) { - return NumbersUtils.timesBounded(a, (long) b); - } - - /** - * @param a A long value. - * @param b A long value. - * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a*b. - */ - public static long multiplyBounded(long a, long b) { - return NumbersUtils.timesBounded(a, b); - } - - /** - * @param x An int value. - * @param y An int value. - * @return The mathematical product as a long. - */ - public static long multiplyFull(int x, int y) { - return ((long) x) * ((long) y); - } - - /** - * @param x A long value. - * @param y A long value. - * @return The most significant 64 bits of the 128-bit product of two 64-bit factors. - */ - public static long multiplyHigh(long x, long y) { - if ((x|y) < 0) { - // Use technique from section 8-2 of Henry S. Warren, Jr., - // Hacker's Delight (2nd ed.) (Addison Wesley, 2013), 173-174. - long x1 = (x >> 32); - long y1 = (y >> 32); - long x2 = (x & 0xFFFFFFFFL); - long y2 = (y & 0xFFFFFFFFL); - long z2 = x2 * y2; - long t = x1 * y2 + (z2 >>> 32); - long z1 = (t & 0xFFFFFFFFL) + x2 * y1; - long z0 = (t >> 32); - return x1 * y1 + z0 + (z1 >> 32); - } else { - // Use Karatsuba technique with two base 2^32 digits. - long x1 = (x >>> 32); - long y1 = (y >>> 32); - long x2 = (x & 0xFFFFFFFFL); - long y2 = (y & 0xFFFFFFFFL); - long A = x1 * y1; - long B = x2 * y2; - long C = (x1 + x2) * (y1 + y2); - long K = C - A - B; - return (((B >>> 32) + K) >>> 32) + A; - } - } - - /* - * binary operators (/,%) - */ - - /** - * Returns the largest int <= dividend/divisor. - * - * Unlike "/" operator, which rounds towards 0, this division - * rounds towards -Infinity (which give different result - * when the exact result is negative). - * - * @param x The dividend. - * @param y The divisor. - * @return The largest int <= dividend/divisor, unless dividend is - * Integer.MIN_VALUE and divisor is -1, in which case - * Integer.MIN_VALUE is returned. - * @throws ArithmeticException if the divisor is zero. - */ - public static int floorDiv(int x, int y) { - int r = x / y; - // If the signs are different and modulo not zero, rounding down. - if (((x ^ y) < 0) && ((r * y) != x)) { - r--; - } - return r; - } - - /** - * Returns the largest long <= dividend/divisor. - * - * Unlike "/" operator, which rounds towards 0, this division - * rounds towards -Infinity (which give different result - * when the exact result is negative). - * - * @param x The dividend. - * @param y The divisor. - * @return The largest long <= dividend/divisor, unless dividend is - * Long.MIN_VALUE and divisor is -1, in which case - * Long.MIN_VALUE is returned. - * @throws ArithmeticException if the divisor is zero. - */ - public static long floorDiv(long x, int y) { - return floorDiv(x, (long) y); - } - - /** - * Returns the largest long <= dividend/divisor. - * - * Unlike "/" operator, which rounds towards 0, this division - * rounds towards -Infinity (which give different result - * when the exact result is negative). - * - * @param x The dividend. - * @param y The divisor. - * @return The largest long <= dividend/divisor, unless dividend is - * Long.MIN_VALUE and divisor is -1, in which case - * Long.MIN_VALUE is returned. - * @throws ArithmeticException if the divisor is zero. - */ - public static long floorDiv(long x, long y) { - long r = x / y; - // If the signs are different and modulo not zero, rounding down. - if (((x ^ y) < 0) && ((r * y) != x)) { - r--; - } - return r; - } - - /** - * Returns the floor modulus, which is "x - floorDiv(x,y) * y", - * has the same sign as y, and is in ]-abs(y),abs(y)[. - * - * The relationship between floorMod and floorDiv is the same - * than between "%" and "/". - * - * @param x The dividend. - * @param y The divisor. - * @return The floor modulus, i.e. "x - (floorDiv(x, y) * y)". - * @throws ArithmeticException if the divisor is zero. - */ - public static int floorMod(int x, int y) { - return x - floorDiv(x, y) * y; - } - - /** - * Returns the floor modulus, which is "x - floorDiv(x,y) * y", - * has the same sign as y, and is in ]-abs(y),abs(y)[. - * - * The relationship between floorMod and floorDiv is the same - * than between "%" and "/". - * - * @param x The dividend. - * @param y The divisor. - * @return The floor modulus, i.e. "x - (floorDiv(x, y) * y)". - * @throws ArithmeticException if the divisor is zero. - */ - public static int floorMod(long x, int y) { - // No overflow so can cast. - return (int) (x - floorDiv(x,y) * y); - } - - /** - * Returns the floor modulus, which is "x - floorDiv(x,y) * y", - * has the same sign as y, and is in ]-abs(y),abs(y)[. - * - * The relationship between floorMod and floorDiv is the same - * than between "%" and "/". - * - * @param x The dividend. - * @param y The divisor. - * @return The floor modulus, i.e. "x - (floorDiv(x, y) * y)". - * @throws ArithmeticException if the divisor is zero. - */ - public static long floorMod(long x, long y) { - return x - floorDiv(x, y) * y; - } - - /* - * Non-redefined Math public values and treatments. - */ - - public static int min(int a, int b) { - return Math.min(a,b); - } - - public static long min(long a, long b) { - return Math.min(a,b); - } - - public static int max(int a, int b) { - return Math.max(a,b); - } - - public static long max(long a, long b) { - return Math.max(a,b); - } - - //-------------------------------------------------------------------------- - // PACKAGE-PRIVATE METHODS - //-------------------------------------------------------------------------- - - /** - * @param power Must be in normal values range. - */ - static double twoPowNormal(int power) { - if (USE_TWO_POW_TAB) { - return MyTTwoPow.twoPowTab[power-MIN_DOUBLE_EXPONENT]; - } else { - return Double.longBitsToDouble(((long)(power+MAX_DOUBLE_EXPONENT))<<52); - } - } - - /** - * @param power Must be in normal or subnormal values range. - */ - static double twoPowNormalOrSubnormal(int power) { - if (USE_TWO_POW_TAB) { - return MyTTwoPow.twoPowTab[power-MIN_DOUBLE_EXPONENT]; - } else { - if (power <= -MAX_DOUBLE_EXPONENT) { // Not normal. - return Double.longBitsToDouble(0x0008000000000000L>>(-(power+MAX_DOUBLE_EXPONENT))); - } else { // Normal. - return Double.longBitsToDouble(((long)(power+MAX_DOUBLE_EXPONENT))<<52); - } - } - } - - static double atan2_pinf_yyy(double y) { - if (y == Double.POSITIVE_INFINITY) { - return Math.PI/4; - } else if (y == Double.NEGATIVE_INFINITY) { - return -Math.PI/4; - } else if (y > 0.0) { - return 0.0; - } else if (y < 0.0) { - return -0.0; - } else { - return Double.NaN; - } - } - - static double atan2_ninf_yyy(double y) { - if (y == Double.POSITIVE_INFINITY) { - return 3*Math.PI/4; - } else if (y == Double.NEGATIVE_INFINITY) { - return -3*Math.PI/4; - } else if (y > 0.0) { - return Math.PI; - } else if (y < 0.0) { - return -Math.PI; - } else { - return Double.NaN; - } - } - - static double atan2_yyy_zeroOrNaN(double y, double x) { - if (x == 0.0) { - if (y == 0.0) { - if (signFromBit_antiCyclic(x) < 0) { - // x is -0.0 - return signFromBit_antiCyclic(y) * Math.PI; - } else { - // +-0.0 - return y; - } - } - if (y > 0.0) { - return Math.PI/2; - } else if (y < 0.0) { - return -Math.PI/2; - } else { - return Double.NaN; - } - } else { - return Double.NaN; - } - } - - /** - * At least one of the arguments must be NaN. - */ - static double hypot_NaN(double xAbs, double yAbs) { - if ((xAbs == Double.POSITIVE_INFINITY) || (yAbs == Double.POSITIVE_INFINITY)) { - return Double.POSITIVE_INFINITY; - } else { - return Double.NaN; - } - } - - /** - * At least one of the arguments must be NaN. - */ - static double hypot_NaN(double xAbs, double yAbs, double zAbs) { - if ((xAbs == Double.POSITIVE_INFINITY) || (yAbs == Double.POSITIVE_INFINITY) || (zAbs == Double.POSITIVE_INFINITY)) { - return Double.POSITIVE_INFINITY; - } else { - return Double.NaN; - } - } - - /* - * - */ - - /** - * @param remainder Must have 1 for 2nd and 3rd exponent bits, which is the - * case for heavyRemPiO2 remainders (their absolute values are >= - * Double.longBitsToDouble(0x3000000000000000L) - * = 1.727233711018889E-77, and even if they were not, turning these - * bits from 0 to 1 on decoding would not change the absolute error - * much), and also works for +-Infinity or NaN encoding. - * @param quadrant Must be in [0,3]. - * @return Bits holding remainder, and quadrant instead of - * reamainder's 2nd and 3rd exponent bits. - */ - static long encodeRemainderAndQuadrant(double remainder, int quadrant) { - final long bits = Double.doubleToRawLongBits(remainder); - return (bits&QUADRANT_BITS_0_MASK)|(((long)quadrant)<<60); - } - - static double decodeRemainder(long bits) { - return Double.longBitsToDouble((bits&QUADRANT_BITS_0_MASK)|QUADRANT_PLACE_BITS); - } - - static int decodeQuadrant(long bits) { - return ((int)(bits>>60))&3; - } - - /* - * JDK-based remainders. - * Since a strict one for (% (PI/2)) is needed for heavyRemainderPiO2, - * we need it in this class. - * Then, for homogeneity, we put them all in this class. - * Then, to avoid code duplication for these slow-anyway methods, - * we just stick with strict versions, for both FastMath and StrictFastMath. - */ - - /** - * @param angle Angle, in radians. - * @return Remainder of (angle % (2*PI)), in [-PI,PI]. - */ - static strictfp double jdkRemainderTwoPi(double angle) { - final double sin = StrictMath.sin(angle); - final double cos = StrictMath.cos(angle); - return StrictMath.atan2(sin, cos); - } - - /** - * @param angle Angle, in radians. - * @return Remainder of (angle % PI), in [-PI/2,PI/2]. - */ - static strictfp double jdkRemainderPi(double angle) { - final double sin = StrictMath.sin(angle); - final double cos = StrictMath.cos(angle); - /* - * Making sure atan2's result ends up in [-PI/2,PI/2], - * i.e. has maximum accuracy. - */ - return StrictMath.atan2(sin, Math.abs(cos)); - } - - /** - * @param angle Angle, in radians. - * @return Bits of double corresponding to remainder of (angle % (PI/2)), - * in [-PI/4,PI/4], with quadrant encoded in exponent bits. - */ - static strictfp long jdkRemainderPiO2(double angle, boolean negateRem) { - final double sin = StrictMath.sin(angle); - final double cos = StrictMath.cos(angle); - - /* - * Computing quadrant first, and then computing - * atan2, to make sure its result ends up in [-PI/4,PI/4], - * i.e. has maximum accuracy. - */ - - final int q; - final double sinForAtan2; - final double cosForAtan2; - if (cos >= (SQRT_2/2)) { - // [-PI/4,PI/4] - q = 0; - sinForAtan2 = sin; - cosForAtan2 = cos; - } else if (cos <= -(SQRT_2/2)) { - // [3*PI/4,5*PI/4] - q = 2; - sinForAtan2 = -sin; - cosForAtan2 = -cos; - } else if (sin > 0.0) { - // [PI/4,3*PI/4] - q = 1; - sinForAtan2 = -cos; - cosForAtan2 = sin; - } else { - // [5*PI/4,7*PI/4] - q = 3; - sinForAtan2 = cos; - cosForAtan2 = -sin; - } - - double fw = StrictMath.atan2(sinForAtan2, cosForAtan2); - - return encodeRemainderAndQuadrant(negateRem ? -fw : fw, q); - } - - /* - * Our remainders implementations. - */ - - /** - * @param angle Angle, in radians. Must not be NaN nor +-Infinity. - * @return Remainder of (angle % (2*PI)), in [-PI,PI]. - */ - static strictfp double heavyRemainderTwoPi(double angle) { - final long remAndQuad = heavyRemainderPiO2(angle, false); - final double rem = decodeRemainder(remAndQuad); - final int q = decodeQuadrant(remAndQuad); - if (q == 0) { - return rem; - } else if (q == 1) { - return (rem + PIO2_LO) + PIO2_HI; - } else if (q == 2) { - if (rem < 0.0) { - return (rem + PI_LO) + PI_HI; - } else { - return (rem - PI_LO) - PI_HI; - } - } else { - return (rem - PIO2_LO) - PIO2_HI; - } - } - - /** - * @param angle Angle, in radians. Must not be NaN nor +-Infinity. - * @return Remainder of (angle % PI), in [-PI/2,PI/2]. - */ - static strictfp double heavyRemainderPi(double angle) { - final long remAndQuad = heavyRemainderPiO2(angle, false); - final double rem = decodeRemainder(remAndQuad); - final int q = decodeQuadrant(remAndQuad); - if ((q&1) != 0) { - // q is 1 or 3 - if (rem < 0.0) { - return (rem + PIO2_LO) + PIO2_HI; - } else { - return (rem - PIO2_LO) - PIO2_HI; - } - } - return rem; - } - - /** - * Remainder using an accurate definition of PI. - * Derived from a fdlibm treatment called __kernel_rem_pio2. - * - * Not defining a non-strictfp version for FastMath, to avoid duplicating - * its long and messy code, and because it's slow anyway, and should be - * rarely used when speed matters. - * - * @param angle Angle, in radians. Must not be NaN nor +-Infinity. - * @param negateRem True if remainder must be negated before encoded into returned long. - * @return Bits of double corresponding to remainder of (angle % (PI/2)), - * in [-PI/4,PI/4], with quadrant encoded in exponent bits. - */ - static strictfp long heavyRemainderPiO2(double angle, boolean negateRem) { - - /* - * fdlibm treatments unrolled, to avoid garbage and be OOME-free, - * corresponding to: - * 1) initial jk = 4 (precision = 3 = 64 bits (extended)), - * which is more accurate than using precision = 2 - * (53 bits, double), even though we work with doubles - * and use strictfp! - * 2) max lengths of 8 for f[], 6 for q[], fq[] and iq[]. - * 3) at most one recomputation (one goto). - * These limitations were experimentally found to - * be sufficient for billions of random doubles - * of random magnitudes. - * For the rare cases that our unrolled treatments can't handle, - * we fall back to a JDK-based implementation. - */ - - int n,i,j,ih; - double fw; - - /* - * Turning angle into 24-bits integer chunks. - * Done outside __kernel_rem_pio2, but we factor it inside our method. - */ - - // Reworking exponent to have a value < 2^24. - final long lx = Double.doubleToRawLongBits(angle); - final long exp = ((lx>>52)&0x7FF) - (1023+23); - double z = Double.longBitsToDouble(lx - (exp<<52)); - - double x0 = (double)(int)z; - z = (z-x0)*TWO_POW_24; - double x1 = (double)(int)z; - z = (z-x1)*TWO_POW_24; - double x2 = (double)(int)z; - - final int e0 = (int)exp; - // in [1,3] - final int nx = (x2 == 0.0) ? ((x1 == 0.0) ? 1 : 2) : 3; - - /* - * - */ - - double f0,f1,f2,f3,f4,f5,f6,f7; - double q0,q1,q2,q3,q4,q5; - int iq0,iq1,iq2,iq3,iq4,iq5; - - int jk = 4; - - int jx = nx-1; - int jv = Math.max(0,(e0-3)/24); - // In fdlibm, this is q0, but we prefer to use q0 for q[0]. - int qZero = e0-24*(jv+1); - - j = jv-jx; - if (jx == 0) { - f6 = 0.0; - f5 = 0.0; - f4 = (j >= -4) ? TWO_OVER_PI_TAB[j+4] : 0.0; - f3 = (j >= -3) ? TWO_OVER_PI_TAB[j+3] : 0.0; - f2 = (j >= -2) ? TWO_OVER_PI_TAB[j+2] : 0.0; - f1 = (j >= -1) ? TWO_OVER_PI_TAB[j+1] : 0.0; - f0 = (j >= 0) ? TWO_OVER_PI_TAB[j] : 0.0; - - q0 = x0*f0; - q1 = x0*f1; - q2 = x0*f2; - q3 = x0*f3; - q4 = x0*f4; - } else if (jx == 1) { - f6 = 0.0; - f5 = (j >= -5) ? TWO_OVER_PI_TAB[j+5] : 0.0; - f4 = (j >= -4) ? TWO_OVER_PI_TAB[j+4] : 0.0; - f3 = (j >= -3) ? TWO_OVER_PI_TAB[j+3] : 0.0; - f2 = (j >= -2) ? TWO_OVER_PI_TAB[j+2] : 0.0; - f1 = (j >= -1) ? TWO_OVER_PI_TAB[j+1] : 0.0; - f0 = (j >= 0) ? TWO_OVER_PI_TAB[j] : 0.0; - - q0 = x0*f1 + x1*f0; - q1 = x0*f2 + x1*f1; - q2 = x0*f3 + x1*f2; - q3 = x0*f4 + x1*f3; - q4 = x0*f5 + x1*f4; - } else { // jx == 2 - f6 = (j >= -6) ? TWO_OVER_PI_TAB[j+6] : 0.0; - f5 = (j >= -5) ? TWO_OVER_PI_TAB[j+5] : 0.0; - f4 = (j >= -4) ? TWO_OVER_PI_TAB[j+4] : 0.0; - f3 = (j >= -3) ? TWO_OVER_PI_TAB[j+3] : 0.0; - f2 = (j >= -2) ? TWO_OVER_PI_TAB[j+2] : 0.0; - f1 = (j >= -1) ? TWO_OVER_PI_TAB[j+1] : 0.0; - f0 = (j >= 0) ? TWO_OVER_PI_TAB[j] : 0.0; - - q0 = x0*f2 + x1*f1 + x2*f0; - q1 = x0*f3 + x1*f2 + x2*f1; - q2 = x0*f4 + x1*f3 + x2*f2; - q3 = x0*f5 + x1*f4 + x2*f3; - q4 = x0*f6 + x1*f5 + x2*f4; - } - - double twoPowQZero = twoPowNormal(qZero); - - int jz = jk; - - /* - * Unrolling of first round. - */ - - z = q4; - fw = (double)(int)(TWO_POW_N24*z); - iq0 = (int)(z-TWO_POW_24*fw); - z = q3+fw; - fw = (double)(int)(TWO_POW_N24*z); - iq1 = (int)(z-TWO_POW_24*fw); - z = q2+fw; - fw = (double)(int)(TWO_POW_N24*z); - iq2 = (int)(z-TWO_POW_24*fw); - z = q1+fw; - fw = (double)(int)(TWO_POW_N24*z); - iq3 = (int)(z-TWO_POW_24*fw); - z = q0+fw; - iq4 = 0; - iq5 = 0; - - z = (z*twoPowQZero) % 8.0; - n = (int)z; - z -= (double)n; - - ih = 0; - if (qZero > 0) { - // Parentheses against code formatter bug. - i = (iq3>>(24-qZero)); - n += i; - iq3 -= i<<(24-qZero); - ih = iq3>>(23-qZero); - } else if (qZero == 0) { - ih = iq3>>23; - } else if (z >= 0.5) { - ih = 2; - } - - if (ih > 0) { - n += 1; - // carry = 1 is common case, - // so using it as initial value. - int carry = 1; - if (iq0 != 0) { - iq0 = 0x1000000 - iq0; - iq1 = 0xFFFFFF - iq1; - iq2 = 0xFFFFFF - iq2; - iq3 = 0xFFFFFF - iq3; - } else if (iq1 != 0) { - iq1 = 0x1000000 - iq1; - iq2 = 0xFFFFFF - iq2; - iq3 = 0xFFFFFF - iq3; - } else if (iq2 != 0) { - iq2 = 0x1000000 - iq2; - iq3 = 0xFFFFFF - iq3; - } else if (iq3 != 0) { - iq3 = 0x1000000 - iq3; - } else { - carry = 0; - } - if (qZero > 0) { - if (qZero == 1) { - iq3 &= 0x7FFFFF; - } else if (qZero == 2) { - iq3 &= 0x3FFFFF; - } - } - if (ih == 2) { - z = 1.0 - z; - if (carry != 0) { - z -= twoPowQZero; - } - } - } - - if (z == 0.0) { - if (iq3 == 0) { - // With random values of random magnitude, - // probability for this to happen seems lower than 1e-6. - // jz would be more than just incremented by one, - // which our unrolling doesn't support. - return jdkRemainderPiO2(angle, negateRem); - } - if (jx == 0) { - f5 = TWO_OVER_PI_TAB[jv+5]; - q5 = x0*f5; - } else if (jx == 1) { - f6 = TWO_OVER_PI_TAB[jv+5]; - q5 = x0*f6 + x1*f5; - } else { // jx == 2 - f7 = TWO_OVER_PI_TAB[jv+5]; - q5 = x0*f7 + x1*f6 + x2*f5; - } - - jz++; - - /* - * Unrolling of second round. - */ - - z = q5; - fw = (double)(int)(TWO_POW_N24*z); - iq0 = (int)(z-TWO_POW_24*fw); - z = q4+fw; - fw = (double)(int)(TWO_POW_N24*z); - iq1 = (int)(z-TWO_POW_24*fw); - z = q3+fw; - fw = (double)(int)(TWO_POW_N24*z); - iq2 = (int)(z-TWO_POW_24*fw); - z = q2+fw; - fw = (double)(int)(TWO_POW_N24*z); - iq3 = (int)(z-TWO_POW_24*fw); - z = q1+fw; - fw = (double)(int)(TWO_POW_N24*z); - iq4 = (int)(z-TWO_POW_24*fw); - z = q0+fw; - iq5 = 0; - - z = (z*twoPowQZero) % 8.0; - n = (int)z; - z -= (double)n; - - ih = 0; - if (qZero > 0) { - // Parentheses against code formatter bug. - i = (iq4>>(24-qZero)); - n += i; - iq4 -= i<<(24-qZero); - ih = iq4>>(23-qZero); - } else if (qZero == 0) { - ih = iq4>>23; - } else if (z >= 0.5) { - ih = 2; - } - - if (ih > 0) { - n += 1; - // carry = 1 is common case, - // so using it as initial value. - int carry = 1; - if (iq0 != 0) { - iq0 = 0x1000000 - iq0; - iq1 = 0xFFFFFF - iq1; - iq2 = 0xFFFFFF - iq2; - iq3 = 0xFFFFFF - iq3; - iq4 = 0xFFFFFF - iq4; - } else if (iq1 != 0) { - iq1 = 0x1000000 - iq1; - iq2 = 0xFFFFFF - iq2; - iq3 = 0xFFFFFF - iq3; - iq4 = 0xFFFFFF - iq4; - } else if (iq2 != 0) { - iq2 = 0x1000000 - iq2; - iq3 = 0xFFFFFF - iq3; - iq4 = 0xFFFFFF - iq4; - } else if (iq3 != 0) { - iq3 = 0x1000000 - iq3; - iq4 = 0xFFFFFF - iq4; - } else if (iq4 != 0) { - iq4 = 0x1000000 - iq4; - } else { - carry = 0; - } - if (qZero > 0) { - if (qZero == 1) { - iq4 &= 0x7FFFFF; - } else if (qZero == 2) { - iq4 &= 0x3FFFFF; - } - } - if (ih == 2) { - z = 1.0 - z; - if (carry != 0) { - z -= twoPowQZero; - } - } - } - - if (z == 0.0) { - if (iq4 == 0) { - // Case not encountered in tests, but still handling it. - // Would require a third loop unrolling. - return jdkRemainderPiO2(angle, negateRem); - } else { - // z == 0.0, and iq4 != 0, - // so we remove 24 from qZero only once, - // but since we no longer use qZero, - // we just bother to multiply its 2-power - // by 2^-24. - jz--; - twoPowQZero *= TWO_POW_N24; - } - } else { - // z != 0.0 at end of second round. - } - } else { - // z != 0.0 at end of first round. - } - - /* - * After loop. - */ - - if (z != 0.0) { - z /= twoPowQZero; - if (z >= TWO_POW_24) { - fw = (double)(int)(TWO_POW_N24*z); - if (jz == jk) { - iq4 = (int)(z-TWO_POW_24*fw); - jz++; // jz to 5 - // Not using qZero anymore so not updating it. - twoPowQZero *= TWO_POW_24; - iq5 = (int)fw; - } else { // jz == jk+1 == 5 - // Case not encountered in tests, but still handling it. - // Would require use of iq6, with jz = 6. - return jdkRemainderPiO2(angle, negateRem); - } - } else { - if (jz == jk) { - iq4 = (int)z; - } else { // jz == jk+1 == 5 - // Case not encountered in tests, but still handling it. - iq5 = (int)z; - } - } - } - - fw = twoPowQZero; - - if (jz == 5) { - q5 = fw*(double)iq5; - fw *= TWO_POW_N24; - } else { - q5 = 0.0; - } - q4 = fw*(double)iq4; - fw *= TWO_POW_N24; - q3 = fw*(double)iq3; - fw *= TWO_POW_N24; - q2 = fw*(double)iq2; - fw *= TWO_POW_N24; - q1 = fw*(double)iq1; - fw *= TWO_POW_N24; - q0 = fw*(double)iq0; - - /* - * We just use HI part of the result. - */ - - fw = PIO2_TAB0*q5; - fw += PIO2_TAB0*q4 + PIO2_TAB1*q5; - fw += PIO2_TAB0*q3 + PIO2_TAB1*q4 + PIO2_TAB2*q5; - fw += PIO2_TAB0*q2 + PIO2_TAB1*q3 + PIO2_TAB2*q4 + PIO2_TAB3*q5; - fw += PIO2_TAB0*q1 + PIO2_TAB1*q2 + PIO2_TAB2*q3 + PIO2_TAB3*q4 + PIO2_TAB4*q5; - fw += PIO2_TAB0*q0 + PIO2_TAB1*q1 + PIO2_TAB2*q2 + PIO2_TAB3*q3 + PIO2_TAB4*q4 + PIO2_TAB5*q5; - - if ((ih != 0) ^ negateRem) { - fw = -fw; - } - - return encodeRemainderAndQuadrant(fw, n&3); - } - - //-------------------------------------------------------------------------- - // PRIVATE METHODS - //-------------------------------------------------------------------------- - - /** - * Redefined here, to avoid cyclic dependency with (Strict)FastMath. - * - * @param value A double value. - * @return -1 if sign bit is 1, 1 if sign bit is 0. - */ - private static long signFromBit_antiCyclic(double value) { - // Returning a long, to avoid useless cast into int. - return ((Double.doubleToRawLongBits(value)>>62)|1); - } - - private static boolean getBooleanProperty( - final String key, - boolean defaultValue) { - final String tmp = System.getProperty(key); - if (tmp != null) { - return Boolean.parseBoolean(tmp); - } else { - return defaultValue; - } - } - - /** - * Use look-up tables size power through this method, - * to make sure is it small in case java.lang.Math - * is directly used. - */ - private static int getTabSizePower(int tabSizePower) { - return (FM_USE_JDK_MATH && SFM_USE_JDK_MATH) ? Math.min(2, tabSizePower) : tabSizePower; - } -} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/DoubleWrapper.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/DoubleWrapper.java deleted file mode 100644 index e7adc8d59..000000000 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/DoubleWrapper.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -package space.kscience.kmath.jafama; - -public class DoubleWrapper { - public double value; - @Override - public String toString() { - return Double.toString(this.value); - } -} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/FastMath.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/FastMath.java deleted file mode 100644 index a83c01f7b..000000000 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/FastMath.java +++ /dev/null @@ -1,2986 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.jafama; - -/** - * Faster (hopefully) versions of java.lang.Math methods, plus additional ones. - * Cf. README.txt for more info. - */ -public final class FastMath extends CmnFastMath { - - //-------------------------------------------------------------------------- - // CONFIGURATION - //-------------------------------------------------------------------------- - - private static final boolean USE_JDK_MATH = FM_USE_JDK_MATH; - - private static final boolean USE_REDEFINED_LOG = FM_USE_REDEFINED_LOG; - - private static final boolean USE_REDEFINED_SQRT = FM_USE_REDEFINED_SQRT; - - private static final boolean USE_POWTABS_FOR_ASIN = FM_USE_POWTABS_FOR_ASIN; - - //-------------------------------------------------------------------------- - // PUBLIC METHODS - //-------------------------------------------------------------------------- - - /* - * trigonometry - */ - - /** - * @param angle Angle in radians. - * @return Angle sine. - */ - public static double sin(double angle) { - if (USE_JDK_MATH) { - return Math.sin(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { - if (false) { - // Can give very bad relative error near PI (mod 2*PI). - angle = remainderTwoPi(angle); - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } else { - final long remAndQuad = remainderPiO2(angle); - angle = decodeRemainder(remAndQuad); - final double sin; - final int q = decodeQuadrant(remAndQuad); - if (q == 0) { - sin = sin(angle); - } else if (q == 1) { - sin = cos(angle); - } else if (q == 2) { - sin = -sin(angle); - } else { - sin = -cos(angle); - } - return (negateResult ? -sin : sin); - } - } - // index: possibly outside tables range. - int index = (int)(angle * SIN_COS_INDEXER + 0.5); - double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; - // Making sure index is within tables range. - // Last value of each table is the same than first, - // so we ignore it (tabs size minus one) for modulo. - index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) - double indexSin = MyTSinCos.sinTab[index]; - double indexCos = MyTSinCos.cosTab[index]; - double result = indexSin + delta * (indexCos + delta * (-indexSin * ONE_DIV_F2 + delta * (-indexCos * ONE_DIV_F3 + delta * indexSin * ONE_DIV_F4))); - return negateResult ? -result : result; - } - - /** - * Quick sin, with accuracy of about 1.6e-3 (PI/) - * for |angle| < 6588395.0 (Integer.MAX_VALUE * (2*PI/) - 2) - * (- 2 due to removing PI/2 before using cosine tab), - * and no accuracy at all for larger values. - * - * @param angle Angle in radians. - * @return Angle sine. - */ - public static double sinQuick(double angle) { - if (USE_JDK_MATH) { - return Math.sin(angle); - } - return MyTSinCos.cosTab[((int)(Math.abs(angle-Math.PI/2) * SIN_COS_INDEXER + 0.5)) & (SIN_COS_TABS_SIZE-2)]; - } - - /** - * @param angle Angle in radians. - * @return Angle cosine. - */ - public static double cos(double angle) { - if (USE_JDK_MATH) { - return Math.cos(angle); - } - angle = Math.abs(angle); - if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { - if (false) { - // Can give very bad relative error near PI (mod 2*PI). - angle = remainderTwoPi(angle); - if (angle < 0.0) { - angle = -angle; - } - } else { - final long remAndQuad = remainderPiO2(angle); - angle = decodeRemainder(remAndQuad); - final double cos; - final int q = decodeQuadrant(remAndQuad); - if (q == 0) { - cos = cos(angle); - } else if (q == 1) { - cos = -sin(angle); - } else if (q == 2) { - cos = -cos(angle); - } else { - cos = sin(angle); - } - return cos; - } - } - // index: possibly outside tables range. - int index = (int)(angle * SIN_COS_INDEXER + 0.5); - double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; - // Making sure index is within tables range. - // Last value of each table is the same than first, - // so we ignore it (tabs size minus one) for modulo. - index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) - double indexCos = MyTSinCos.cosTab[index]; - double indexSin = MyTSinCos.sinTab[index]; - return indexCos + delta * (-indexSin + delta * (-indexCos * ONE_DIV_F2 + delta * (indexSin * ONE_DIV_F3 + delta * indexCos * ONE_DIV_F4))); - } - - /** - * Quick cos, with accuracy of about 1.6e-3 (PI/) - * for |angle| < 6588397.0 (Integer.MAX_VALUE * (2*PI/)), - * and no accuracy at all for larger values. - * - * @param angle Angle in radians. - * @return Angle cosine. - */ - public static double cosQuick(double angle) { - if (USE_JDK_MATH) { - return Math.cos(angle); - } - return MyTSinCos.cosTab[((int)(Math.abs(angle) * SIN_COS_INDEXER + 0.5)) & (SIN_COS_TABS_SIZE-2)]; - } - - /** - * Computes sine and cosine together. - * - * @param angle Angle in radians. - * @param cosine (out) Angle cosine. - * @return Angle sine. - */ - public static double sinAndCos(double angle, DoubleWrapper cosine) { - if (USE_JDK_MATH) { - cosine.value = Math.cos(angle); - return Math.sin(angle); - } - // Using the same algorithm than sin(double) method, - // and computing also cosine at the end. - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { - if (false) { - // Can give very bad relative error near PI (mod 2*PI). - angle = remainderTwoPi(angle); - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } else { - final long remAndQuad = remainderPiO2(angle); - angle = decodeRemainder(remAndQuad); - final double sin; - final int q = decodeQuadrant(remAndQuad); - if (q == 0) { - sin = sin(angle); - cosine.value = cos(angle); - } else if (q == 1) { - sin = cos(angle); - cosine.value = -sin(angle); - } else if (q == 2) { - sin = -sin(angle); - cosine.value = -cos(angle); - } else { - sin = -cos(angle); - cosine.value = sin(angle); - } - return (negateResult ? -sin : sin); - } - } - int index = (int)(angle * SIN_COS_INDEXER + 0.5); - double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; - index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) - double indexSin = MyTSinCos.sinTab[index]; - double indexCos = MyTSinCos.cosTab[index]; - // Could factor some multiplications (delta * factorials), but then is less accurate. - cosine.value = indexCos + delta * (-indexSin + delta * (-indexCos * ONE_DIV_F2 + delta * (indexSin * ONE_DIV_F3 + delta * indexCos * ONE_DIV_F4))); - double result = indexSin + delta * (indexCos + delta * (-indexSin * ONE_DIV_F2 + delta * (-indexCos * ONE_DIV_F3 + delta * indexSin * ONE_DIV_F4))); - return negateResult ? -result : result; - } - - /** - * Can have very bad relative error near +-PI/2, - * but of the same magnitude than the relative delta between - * StrictMath.tan(PI/2) and StrictMath.tan(nextDown(PI/2)). - * - * @param angle Angle in radians. - * @return Angle tangent. - */ - public static double tan(double angle) { - if (USE_JDK_MATH) { - return Math.tan(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle > TAN_MAX_VALUE_FOR_INT_MODULO) { - angle = remainderPi(angle); - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } - // index: possibly outside tables range. - int index = (int)(angle * TAN_INDEXER + 0.5); - double delta = (angle - index * TAN_DELTA_HI) - index * TAN_DELTA_LO; - // Making sure index is within tables range. - // index modulo PI, i.e. 2*(virtual tab size minus one). - index &= (2*(TAN_VIRTUAL_TABS_SIZE-1)-1); // index % (2*(TAN_VIRTUAL_TABS_SIZE-1)) - // Here, index is in [0,2*(TAN_VIRTUAL_TABS_SIZE-1)-1], i.e. indicates an angle in [0,PI[. - if (index > (TAN_VIRTUAL_TABS_SIZE-1)) { - index = (2*(TAN_VIRTUAL_TABS_SIZE-1)) - index; - delta = -delta; - negateResult = !negateResult; - } - double result; - if (index < TAN_TABS_SIZE) { - result = MyTTan.tanTab[index] - + delta * (MyTTan.tanDer1DivF1Tab[index] - + delta * (MyTTan.tanDer2DivF2Tab[index] - + delta * (MyTTan.tanDer3DivF3Tab[index] - + delta * MyTTan.tanDer4DivF4Tab[index]))); - } else { // angle in ]TAN_MAX_VALUE_FOR_TABS,TAN_MAX_VALUE_FOR_INT_MODULO], or angle is NaN - // Using tan(angle) == 1/tan(PI/2-angle) formula: changing angle (index and delta), and inverting. - index = (TAN_VIRTUAL_TABS_SIZE-1) - index; - result = 1/(MyTTan.tanTab[index] - - delta * (MyTTan.tanDer1DivF1Tab[index] - - delta * (MyTTan.tanDer2DivF2Tab[index] - - delta * (MyTTan.tanDer3DivF3Tab[index] - - delta * MyTTan.tanDer4DivF4Tab[index])))); - } - return negateResult ? -result : result; - } - - /** - * @param value Value in [-1,1]. - * @return Value arcsine, in radians, in [-PI/2,PI/2]. - */ - public static double asin(double value) { - if (USE_JDK_MATH) { - return Math.asin(value); - } - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - if (value <= ASIN_MAX_VALUE_FOR_TABS) { - int index = (int)(value * ASIN_INDEXER + 0.5); - double delta = value - index * ASIN_DELTA; - double result = MyTAsin.asinTab[index] - + delta * (MyTAsin.asinDer1DivF1Tab[index] - + delta * (MyTAsin.asinDer2DivF2Tab[index] - + delta * (MyTAsin.asinDer3DivF3Tab[index] - + delta * MyTAsin.asinDer4DivF4Tab[index]))); - return negateResult ? -result : result; - } else if (USE_POWTABS_FOR_ASIN && (value <= ASIN_MAX_VALUE_FOR_POWTABS)) { - int index = (int)(powFast(value * ASIN_POWTABS_ONE_DIV_MAX_VALUE, ASIN_POWTABS_POWER) * ASIN_POWTABS_SIZE_MINUS_ONE + 0.5); - double delta = value - MyTAsinPow.asinParamPowTab[index]; - double result = MyTAsinPow.asinPowTab[index] - + delta * (MyTAsinPow.asinDer1DivF1PowTab[index] - + delta * (MyTAsinPow.asinDer2DivF2PowTab[index] - + delta * (MyTAsinPow.asinDer3DivF3PowTab[index] - + delta * MyTAsinPow.asinDer4DivF4PowTab[index]))); - return negateResult ? -result : result; - } else { // value > ASIN_MAX_VALUE_FOR_TABS, or value is NaN - // This part is derived from fdlibm. - if (value < 1.0) { - double t = (1.0 - value)*0.5; - double p = t*(ASIN_PS0+t*(ASIN_PS1+t*(ASIN_PS2+t*(ASIN_PS3+t*(ASIN_PS4+t*ASIN_PS5))))); - double q = 1.0+t*(ASIN_QS1+t*(ASIN_QS2+t*(ASIN_QS3+t*ASIN_QS4))); - double s = sqrt(t); - double z = s+s*(p/q); - double result = ASIN_PIO2_HI-((z+z)-ASIN_PIO2_LO); - return negateResult ? -result : result; - } else { // value >= 1.0, or value is NaN - if (value == 1.0) { - return negateResult ? -Math.PI/2 : Math.PI/2; - } else { - return Double.NaN; - } - } - } - } - - /** - * If value is not NaN and is outside [-1,1] range, closest value in this range is used. - * - * @param value Value in [-1,1]. - * @return Value arcsine, in radians, in [-PI/2,PI/2]. - */ - public static double asinInRange(double value) { - if (value <= -1.0) { - return -Math.PI/2; - } else if (value >= 1.0) { - return Math.PI/2; - } else { - return asin(value); - } - } - - /** - * @param value Value in [-1,1]. - * @return Value arccosine, in radians, in [0,PI]. - */ - public static double acos(double value) { - if (USE_JDK_MATH) { - return Math.acos(value); - } - return Math.PI/2 - asin(value); - } - - /** - * If value is not NaN and is outside [-1,1] range, - * closest value in this range is used. - * - * @param value Value in [-1,1]. - * @return Value arccosine, in radians, in [0,PI]. - */ - public static double acosInRange(double value) { - if (value <= -1.0) { - return Math.PI; - } else if (value >= 1.0) { - return 0.0; - } else { - return acos(value); - } - } - - /** - * @param value A double value. - * @return Value arctangent, in radians, in [-PI/2,PI/2]. - */ - public static double atan(double value) { - if (USE_JDK_MATH) { - return Math.atan(value); - } - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - if (value == 1.0) { - // We want "exact" result for 1.0. - return negateResult ? -Math.PI/4 : Math.PI/4; - } else if (value <= ATAN_MAX_VALUE_FOR_TABS) { - int index = (int)(value * ATAN_INDEXER + 0.5); - double delta = value - index * ATAN_DELTA; - double result = MyTAtan.atanTab[index] - + delta * (MyTAtan.atanDer1DivF1Tab[index] - + delta * (MyTAtan.atanDer2DivF2Tab[index] - + delta * (MyTAtan.atanDer3DivF3Tab[index] - + delta * MyTAtan.atanDer4DivF4Tab[index]))); - return negateResult ? -result : result; - } else { // value > ATAN_MAX_VALUE_FOR_TABS, or value is NaN - // This part is derived from fdlibm. - if (value < TWO_POW_66) { - double x = -1/value; - double x2 = x*x; - double x4 = x2*x2; - double s1 = x2*(ATAN_AT0+x4*(ATAN_AT2+x4*(ATAN_AT4+x4*(ATAN_AT6+x4*(ATAN_AT8+x4*ATAN_AT10))))); - double s2 = x4*(ATAN_AT1+x4*(ATAN_AT3+x4*(ATAN_AT5+x4*(ATAN_AT7+x4*ATAN_AT9)))); - double result = ATAN_HI3-((x*(s1+s2)-ATAN_LO3)-x); - return negateResult ? -result : result; - } else { // value >= 2^66, or value is NaN - if (value != value) { - return Double.NaN; - } else { - return negateResult ? -Math.PI/2 : Math.PI/2; - } - } - } - } - - /** - * For special values for which multiple conventions could be adopted, - * behaves like Math.atan2(double,double). - * - * @param y Coordinate on y axis. - * @param x Coordinate on x axis. - * @return Angle from x axis positive side to (x,y) position, in radians, in [-PI,PI]. - * Angle measure is positive when going from x axis to y axis (positive sides). - */ - public static double atan2(double y, double x) { - if (USE_JDK_MATH) { - return Math.atan2(y,x); - } - /* - * Using sub-methods, to make method lighter for general case, - * and to avoid JIT-optimization crash on NaN. - */ - if (x > 0.0) { - if (y == 0.0) { - // +-0.0 - return y; - } - if (x == Double.POSITIVE_INFINITY) { - return atan2_pinf_yyy(y); - } else { - return atan(y/x); - } - } else if (x < 0.0) { - if (y == 0.0) { - return signFromBit(y) * Math.PI; - } - if (x == Double.NEGATIVE_INFINITY) { - return atan2_ninf_yyy(y); - } else if (y > 0.0) { - return Math.PI/2 - atan(x/y); - } else if (y < 0.0) { - return -Math.PI/2 - atan(x/y); - } else { - return Double.NaN; - } - } else { - return atan2_yyy_zeroOrNaN(y, x); - } - } - - /** - * Gives same result as Math.toRadians for some particular values - * like 90.0, 180.0 or 360.0, but is faster (no division). - * - * @param angdeg Angle value in degrees. - * @return Angle value in radians. - */ - public static double toRadians(double angdeg) { - if (USE_JDK_MATH) { - return Math.toRadians(angdeg); - } - return angdeg * (Math.PI/180); - } - - /** - * Gives same result as Math.toDegrees for some particular values - * like Math.PI/2, Math.PI or 2*Math.PI, but is faster (no division). - * - * @param angrad Angle value in radians. - * @return Angle value in degrees. - */ - public static double toDegrees(double angrad) { - if (USE_JDK_MATH) { - return Math.toDegrees(angrad); - } - return angrad * (180/Math.PI); - } - - /** - * @param sign Sign of the angle: true for positive, false for negative. - * @param degrees Degrees, in [0,180]. - * @param minutes Minutes, in [0,59]. - * @param seconds Seconds, in [0.0,60.0[. - * @return Angle in radians. - */ - public static double toRadians(boolean sign, int degrees, int minutes, double seconds) { - return toRadians(toDegrees(sign, degrees, minutes, seconds)); - } - - /** - * @param sign Sign of the angle: true for positive, false for negative. - * @param degrees Degrees, in [0,180]. - * @param minutes Minutes, in [0,59]. - * @param seconds Seconds, in [0.0,60.0[. - * @return Angle in degrees. - */ - public static double toDegrees(boolean sign, int degrees, int minutes, double seconds) { - double signFactor = sign ? 1.0 : -1.0; - return signFactor * (degrees + (1.0/60)*(minutes + (1.0/60)*seconds)); - } - - /** - * @param angrad Angle in radians. - * @param degrees (out) Degrees, in [0,180]. - * @param minutes (out) Minutes, in [0,59]. - * @param seconds (out) Seconds, in [0.0,60.0[. - * @return true if the resulting angle in [-180deg,180deg] is positive, false if it is negative. - */ - public static boolean toDMS(double angrad, IntWrapper degrees, IntWrapper minutes, DoubleWrapper seconds) { - // Computing longitude DMS. - double tmp = toDegrees(normalizeMinusPiPi(angrad)); - boolean isNeg = (tmp < 0.0); - if (isNeg) { - tmp = -tmp; - } - degrees.value = (int)tmp; - tmp = (tmp-degrees.value)*60.0; - minutes.value = (int)tmp; - seconds.value = Math.min((tmp-minutes.value)*60.0,DOUBLE_BEFORE_60); - return !isNeg; - } - - /** - * NB: Since 2*Math.PI < 2*PI, a span of 2*Math.PI does not mean full angular range. - * ex.: isInClockwiseDomain(0.0, 2*Math.PI, -1e-20) returns false. - * ---> For full angular range, use a span > 2*Math.PI, like 2*PI_SUP constant of this class. - * - * @param startAngRad An angle, in radians. - * @param angSpanRad An angular span, >= 0.0, in radians. - * @param angRad An angle, in radians. - * @return true if angRad is in the clockwise angular domain going from startAngRad, over angSpanRad, - * extremities included, false otherwise. - */ - public static boolean isInClockwiseDomain(double startAngRad, double angSpanRad, double angRad) { - if (Math.abs(angRad) < -TWO_MATH_PI_IN_MINUS_PI_PI) { - // special case for angular values of small magnitude - if (angSpanRad <= 2*Math.PI) { - if (angSpanRad < 0.0) { - // empty domain - return false; - } - // angSpanRad is in [0,2*PI] - startAngRad = normalizeMinusPiPi(startAngRad); - double endAngRad = normalizeMinusPiPi(startAngRad + angSpanRad); - if (startAngRad <= endAngRad) { - return (angRad >= startAngRad) && (angRad <= endAngRad); - } else { - return (angRad >= startAngRad) || (angRad <= endAngRad); - } - } else { // angSpanRad > 2*Math.PI, or is NaN - return (angSpanRad == angSpanRad); - } - } else { - // general case - return (normalizeZeroTwoPi(angRad - startAngRad) <= angSpanRad); - } - } - - /* - * hyperbolic trigonometry - */ - - /** - * Some properties of sinh(x) = (exp(x)-exp(-x))/2: - * 1) defined on ]-Infinity,+Infinity[ - * 2) result in ]-Infinity,+Infinity[ - * 3) sinh(x) = -sinh(-x) (implies sinh(0) = 0) - * 4) sinh(epsilon) ~= epsilon - * 5) lim(sinh(x),x->+Infinity) = +Infinity - * (y increasing exponentially faster than x) - * 6) reaches +Infinity (double overflow) for x >= 710.475860073944, - * i.e. a bit further than exp(x) - * - * @param value A double value. - * @return Value hyperbolic sine. - */ - public static double sinh(double value) { - if (USE_JDK_MATH) { - return Math.sinh(value); - } - // sinh(x) = (exp(x)-exp(-x))/2 - double h; - if (value < 0.0) { - value = -value; - h = -0.5; - } else { - h = 0.5; - } - if (value < 22.0) { - if (value < TWO_POW_N28) { - return (h < 0.0) ? -value : value; - } else { - // sinh(x) - // = (exp(x)-exp(-x))/2 - // = (exp(x)-1/exp(x))/2 - // = (expm1(x) + 1 - 1/(expm1(x)+1))/2 - // = (expm1(x) + (expm1(x)+1)/(expm1(x)+1) - 1/(expm1(x)+1))/2 - // = (expm1(x) + expm1(x)/(expm1(x)+1))/2 - double t = expm1(value); - // Might be more accurate, if value < 1: return h*((t+t)-t*t/(t+1.0)). - return h * (t + t/(t+1.0)); - } - } else if (value < LOG_DOUBLE_MAX_VALUE) { - return h * exp(value); - } else { - double t = exp(value*0.5); - return (h*t)*t; - } - } - - /** - * Some properties of cosh(x) = (exp(x)+exp(-x))/2: - * 1) defined on ]-Infinity,+Infinity[ - * 2) result in [1,+Infinity[ - * 3) cosh(0) = 1 - * 4) cosh(x) = cosh(-x) - * 5) lim(cosh(x),x->+Infinity) = +Infinity - * (y increasing exponentially faster than x) - * 6) reaches +Infinity (double overflow) for x >= 710.475860073944, - * i.e. a bit further than exp(x) - * - * @param value A double value. - * @return Value hyperbolic cosine. - */ - public static double cosh(double value) { - if (USE_JDK_MATH) { - return Math.cosh(value); - } - // cosh(x) = (exp(x)+exp(-x))/2 - if (value < 0.0) { - value = -value; - } - if (value < LOG_TWO_POW_27) { - if (value < TWO_POW_N27) { - // cosh(x) - // = (exp(x)+exp(-x))/2 - // = ((1+x+x^2/2!+...) + (1-x+x^2/2!-...))/2 - // = 1+x^2/2!+x^4/4!+... - // For value of x small in magnitude, the sum of the terms does not add to 1. - return 1; - } else { - // cosh(x) - // = (exp(x)+exp(-x))/2 - // = (exp(x)+1/exp(x))/2 - double t = exp(value); - return 0.5 * (t+1/t); - } - } else if (value < LOG_DOUBLE_MAX_VALUE) { - return 0.5 * exp(value); - } else { - double t = exp(value*0.5); - return (0.5*t)*t; - } - } - - /** - * Much more accurate than cosh(value)-1, - * for arguments (and results) close to zero. - * - * coshm1(-0.0) = -0.0, for homogeneity with - * acosh1p(-0.0) = -0.0. - * - * @param value A double value. - * @return Value hyperbolic cosine, minus 1. - */ - public static double coshm1(double value) { - // cosh(x)-1 = (exp(x)+exp(-x))/2 - 1 - if (value < 0.0) { - value = -value; - } - if (value < LOG_TWO_POW_27) { - if (value < TWO_POW_N27) { - if (value == 0.0) { - // +-0.0 - return value; - } - // Using (expm1(x)+expm1(-x))/2 - // is not accurate for tiny values, - // for expm1 results are of higher - // magnitude than the result and - // of different signs, such as their - // sum is not accurate. - // cosh(x) - 1 - // = (exp(x)+exp(-x))/2 - 1 - // = ((1+x+x^2/2!+...) + (1-x+x^2/2!-...))/2 - 1 - // = x^2/2!+x^4/4!+... - // ~= x^2 * (1/2 + x^2 * 1/24) - // = x^2 * 0.5 (since x < 2^-27) - return 0.5 * value*value; - } else { - // cosh(x) - 1 - // = (exp(x)+exp(-x))/2 - 1 - // = (exp(x)-1+exp(-x)-1)/2 - // = (expm1(x)+expm1(-x))/2 - return 0.5 * (expm1(value)+expm1(-value)); - } - } else if (value < LOG_DOUBLE_MAX_VALUE) { - return 0.5 * exp(value) - 1.0; - } else { - // No need to subtract 1 from result. - double t = exp(value*0.5); - return (0.5*t)*t; - } - } - - /** - * Computes hyperbolic sine and hyperbolic cosine together. - * - * @param value A double value. - * @param hcosine (out) Value hyperbolic cosine. - * @return Value hyperbolic sine. - */ - public static double sinhAndCosh(double value, DoubleWrapper hcosine) { - if (USE_JDK_MATH) { - hcosine.value = Math.cosh(value); - return Math.sinh(value); - } - // Mixup of sinh and cosh treatments: if you modify them, - // you might want to also modify this. - double h; - if (value < 0.0) { - value = -value; - h = -0.5; - } else { - h = 0.5; - } - final double hsine; - // LOG_TWO_POW_27 = 18.714973875118524 - if (value < LOG_TWO_POW_27) { // test from cosh - // sinh - if (value < TWO_POW_N28) { - hsine = (h < 0.0) ? -value : value; - } else { - double t = expm1(value); - hsine = h * (t + t/(t+1.0)); - } - // cosh - if (value < TWO_POW_N27) { - hcosine.value = 1; - } else { - double t = exp(value); - hcosine.value = 0.5 * (t+1/t); - } - } else if (value < 22.0) { // test from sinh - // Here, value is in [18.714973875118524,22.0[. - double t = expm1(value); - hsine = h * (t + t/(t+1.0)); - hcosine.value = 0.5 * (t+1.0); - } else { - if (value < LOG_DOUBLE_MAX_VALUE) { - hsine = h * exp(value); - } else { - double t = exp(value*0.5); - hsine = (h*t)*t; - } - hcosine.value = Math.abs(hsine); - } - return hsine; - } - - /** - * Some properties of tanh(x) = sinh(x)/cosh(x) = (exp(2*x)-1)/(exp(2*x)+1): - * 1) defined on ]-Infinity,+Infinity[ - * 2) result in ]-1,1[ - * 3) tanh(x) = -tanh(-x) (implies tanh(0) = 0) - * 4) tanh(epsilon) ~= epsilon - * 5) lim(tanh(x),x->+Infinity) = 1 - * 6) reaches 1 (double loss of precision) for x = 19.061547465398498 - * - * @param value A double value. - * @return Value hyperbolic tangent. - */ - public static double tanh(double value) { - if (USE_JDK_MATH) { - return Math.tanh(value); - } - // tanh(x) = sinh(x)/cosh(x) - // = (exp(x)-exp(-x))/(exp(x)+exp(-x)) - // = (exp(2*x)-1)/(exp(2*x)+1) - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - double z; - if (value < TANH_1_THRESHOLD) { - if (value < TWO_POW_N55) { - return negateResult ? -value*(1.0-value) : value*(1.0+value); - } else if (value >= 1) { - z = 1.0-2.0/(expm1(value+value)+2.0); - } else { - double t = expm1(-(value+value)); - z = -t/(t+2.0); - } - } else { - z = (value != value) ? Double.NaN : 1.0; - } - return negateResult ? -z : z; - } - - /** - * Some properties of asinh(x) = log(x + sqrt(x^2 + 1)) - * 1) defined on ]-Infinity,+Infinity[ - * 2) result in ]-Infinity,+Infinity[ - * 3) asinh(x) = -asinh(-x) (implies asinh(0) = 0) - * 4) asinh(epsilon) ~= epsilon - * 5) lim(asinh(x),x->+Infinity) = +Infinity - * (y increasing logarithmically slower than x) - * - * @param value A double value. - * @return Value hyperbolic arcsine. - */ - public static double asinh(double value) { - // asinh(x) = log(x + sqrt(x^2 + 1)) - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - double result; - // (about) smallest possible for - // non-log1p case to be accurate. - if (value < ASINH_LOG1P_THRESHOLD) { - // Around this range, FDLIBM uses - // log1p(value+value*value/(1+sqrt(value*value+1))), - // but it's slower, so we don't use it. - /* - * If x is close to zero, log argument is close to 1, - * so to avoid precision loss we use log1p(double), - * with - * (1+x)^p = 1 + p * x + (p*(p-1))/2! * x^2 + (p*(p-1)*(p-2))/3! * x^3 + ... - * (1+x)^p = 1 + p * x * (1 + (p-1)/2 * x * (1 + (p-2)/3 * x + ...) - * (1+x)^0.5 = 1 + 0.5 * x * (1 + (0.5-1)/2 * x * (1 + (0.5-2)/3 * x + ...) - * (1+x^2)^0.5 = 1 + 0.5 * x^2 * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...) - * x + (1+x^2)^0.5 = 1 + x * (1 + 0.5 * x * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...)) - * so - * asinh(x) = log1p(x * (1 + 0.5 * x * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...))) - */ - final double x = value; - final double x2 = x*x; - // Enough terms for good accuracy, - // given our threshold. - final double argLog1p = (x * - (1 + 0.5 * x - * (1 + (0.5-1)/2 * x2 - * (1 + (0.5-2)/3 * x2 - * (1 + (0.5-3)/4 * x2 - * (1 + (0.5-4)/5 * x2 - )))))); - result = log1p(argLog1p); - } else if (value < ASINH_ACOSH_SQRT_ELISION_THRESHOLD) { - // Around this range, FDLIBM uses - // log(2*value+1/(value+sqrt(value*value+1))), - // but it involves an additional division - // so we don't use it. - result = log(value + sqrt(value*value + 1.0)); - } else { - // log(2*value) would overflow for value > Double.MAX_VALUE/2, - // so we compute otherwise. - result = LOG_2 + log(value); - } - return negateResult ? -result : result; - } - - /** - * Some properties of acosh(x) = log(x + sqrt(x^2 - 1)): - * 1) defined on [1,+Infinity[ - * 2) result in ]0,+Infinity[ (by convention, since cosh(x) = cosh(-x)) - * 3) acosh(1) = 0 - * 4) acosh(1+epsilon) ~= log(1 + sqrt(2*epsilon)) ~= sqrt(2*epsilon) - * 5) lim(acosh(x),x->+Infinity) = +Infinity - * (y increasing logarithmically slower than x) - * - * @param value A double value. - * @return Value hyperbolic arccosine. - */ - public static double acosh(double value) { - if (!(value > 1.0)) { - // NaN, or value <= 1 - if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { - return (value < 1.0) ? Double.NaN : value - 1.0; - } else { - return (value == 1.0) ? 0.0 : Double.NaN; - } - } - double result; - if (value < ASINH_ACOSH_SQRT_ELISION_THRESHOLD) { - // Around this range, FDLIBM uses - // log(2*value-1/(value+sqrt(value*value-1))), - // but it involves an additional division - // so we don't use it. - result = log(value + sqrt(value*value - 1.0)); - } else { - // log(2*value) would overflow for value > Double.MAX_VALUE/2, - // so we compute otherwise. - result = LOG_2 + log(value); - } - return result; - } - - /** - * Much more accurate than acosh(1+value), - * for arguments (and results) close to zero. - * - * acosh1p(-0.0) = -0.0, for homogeneity with - * sqrt(-0.0) = -0.0, which looks about the same - * near 0. - * - * @param value A double value. - * @return Hyperbolic arccosine of (1+value). - */ - public static double acosh1p(double value) { - if (!(value > 0.0)) { - // NaN, or value <= 0. - // If value is -0.0, returning -0.0. - if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { - return (value < 0.0) ? Double.NaN : value; - } else { - return (value == 0.0) ? value : Double.NaN; - } - } - double result; - if (value < (ASINH_ACOSH_SQRT_ELISION_THRESHOLD-1)) { - // acosh(1+x) - // = log((1+x) + sqrt((1+x)^2 - 1)) - // = log(1 + x + sqrt(1 + 2*x + x^2 - 1)) - // = log1p(x + sqrt(2*x + x^2)) - // = log1p(x + sqrt(x * (2 + x)) - result = log1p(value + sqrt(value * (2 + value))); - } else { - result = LOG_2 + log(1+value); - } - return result; - } - - /** - * Some properties of atanh(x) = log((1+x)/(1-x))/2: - * 1) defined on ]-1,1[ - * 2) result in ]-Infinity,+Infinity[ - * 3) atanh(-1) = -Infinity (by continuity) - * 4) atanh(1) = +Infinity (by continuity) - * 5) atanh(epsilon) ~= epsilon - * 6) lim(atanh(x),x->1) = +Infinity - * - * @param value A double value. - * @return Value hyperbolic arctangent. - */ - public static double atanh(double value) { - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - double result; - if (!(value < 1.0)) { - // NaN, or value >= 1 - if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { - result = (value > 1.0) ? Double.NaN : Double.POSITIVE_INFINITY + value; - } else { - result = (value == 1.0) ? Double.POSITIVE_INFINITY : Double.NaN; - } - } else { - // For value < 0.5, FDLIBM uses - // 0.5 * log1p((value+value) + (value+value)*value/(1-value)), - // instead, but this is good enough for us. - // atanh(x) - // = log((1+x)/(1-x))/2 - // = log((1-x+2x)/(1-x))/2 - // = log1p(2x/(1-x))/2 - result = 0.5 * log1p((value+value)/(1.0-value)); - } - return negateResult ? -result : result; - } - - /* - * exponentials - */ - - /** - * @param value A double value. - * @return e^value. - */ - public static double exp(double value) { - if (USE_JDK_MATH) { - return Math.exp(value); - } - // exp(x) = exp([x])*exp(y) - // with [x] the integer part of x, and y = x-[x] - // ===> - // We find an approximation of y, called z. - // ===> - // exp(x) = exp([x])*(exp(z)*exp(epsilon)) - // with epsilon = y - z - // ===> - // We have exp([x]) and exp(z) pre-computed in tables, we "just" have to compute exp(epsilon). - // - // We use the same indexing (cast to int) to compute x integer part and the - // table index corresponding to z, to avoid two int casts. - // Also, to optimize index multiplication and division, we use powers of two, - // so that we can do it with bits shifts. - - if (value > EXP_OVERFLOW_LIMIT) { - return Double.POSITIVE_INFINITY; - } else if (!(value >= EXP_UNDERFLOW_LIMIT)) { - return (value != value) ? Double.NaN : 0.0; - } - - final int indexes = (int)(value*EXP_LO_INDEXING); - - final int valueInt; - if (indexes >= 0) { - valueInt = (indexes>>EXP_LO_INDEXING_DIV_SHIFT); - } else { - valueInt = -((-indexes)>>EXP_LO_INDEXING_DIV_SHIFT); - } - final double hiTerm = MyTExp.expHiTab[valueInt-(int)EXP_UNDERFLOW_LIMIT]; - - final int zIndex = indexes - (valueInt< 0.0) { - if (value == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } - - // For normal values not close to 1.0, we use the following formula: - // log(value) - // = log(2^exponent*1.mantissa) - // = log(2^exponent) + log(1.mantissa) - // = exponent * log(2) + log(1.mantissa) - // = exponent * log(2) + log(1.mantissaApprox) + log(1.mantissa/1.mantissaApprox) - // = exponent * log(2) + log(1.mantissaApprox) + log(1+epsilon) - // = exponent * log(2) + log(1.mantissaApprox) + epsilon-epsilon^2/2+epsilon^3/3-epsilon^4/4+... - // with: - // 1.mantissaApprox <= 1.mantissa, - // log(1.mantissaApprox) in table, - // epsilon = (1.mantissa/1.mantissaApprox)-1 - // - // To avoid bad relative error for small results, - // values close to 1.0 are treated aside, with the formula: - // log(x) = z*(2+z^2*((2.0/3)+z^2*((2.0/5))+z^2*((2.0/7))+...))) - // with z=(x-1)/(x+1) - - double h; - if (value > 0.95) { - if (value < 1.14) { - double z = (value-1.0)/(value+1.0); - double z2 = z*z; - return z*(2+z2*((2.0/3)+z2*((2.0/5)+z2*((2.0/7)+z2*((2.0/9)+z2*((2.0/11))))))); - } - h = 0.0; - } else if (value < DOUBLE_MIN_NORMAL) { - // Ensuring value is normal. - value *= TWO_POW_52; - // log(x*2^52) - // = log(x)-ln(2^52) - // = log(x)-52*ln(2) - h = -52*LOG_2; - } else { - h = 0.0; - } - - int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); - int valueExp = (valueBitsHi>>20)-MAX_DOUBLE_EXPONENT; - // Getting the first LOG_BITS bits of the mantissa. - int xIndex = ((valueBitsHi<<12)>>>(32-LOG_BITS)); - - // 1.mantissa/1.mantissaApprox - 1 - double z = (value * twoPowNormalOrSubnormal(-valueExp)) * MyTLog.logXInvTab[xIndex] - 1; - - z *= (1-z*((1.0/2)-z*((1.0/3)))); - - return h + valueExp * LOG_2 + (MyTLog.logXLogTab[xIndex] + z); - - } else if (value == 0.0) { - return Double.NEGATIVE_INFINITY; - } else { // value < 0.0, or value is NaN - return Double.NaN; - } - } - - /** - * Quick log, with a max relative error of about 1.9e-3 - * for values in ]Double.MIN_NORMAL,+Infinity[, and - * worse accuracy outside this range. - * - * @param value A double value, in ]0,+Infinity[ (strictly positive and finite). - * @return Value logarithm (base e). - */ - public static double logQuick(double value) { - if (USE_JDK_MATH) { - return Math.log(value); - } - /* - * Inverse of Schraudolph's method for exp, is very inaccurate near 1, - * and not that fast (even using floats), especially with added if's - * to deal with values near 1, so we don't use it, and use a simplified - * version of our log's redefined algorithm. - */ - - // Simplified version of log's redefined algorithm: - // log(value) ~= exponent * log(2) + log(1.mantissaApprox) - - double h; - if (value > 0.87) { - if (value < 1.16) { - return 2.0 * (value-1.0)/(value+1.0); - } - h = 0.0; - } else if (value < DOUBLE_MIN_NORMAL) { - value *= TWO_POW_52; - h = -52*LOG_2; - } else { - h = 0.0; - } - - int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); - int valueExp = (valueBitsHi>>20)-MAX_DOUBLE_EXPONENT; - int xIndex = ((valueBitsHi<<12)>>>(32-LOG_BITS)); - - return h + valueExp * LOG_2 + MyTLog.logXLogTab[xIndex]; - } - - /** - * @param value A double value. - * @return Value logarithm (base 10). - */ - public static double log10(double value) { - if (USE_JDK_MATH || (!USE_REDEFINED_LOG)) { - return Math.log10(value); - } - // INV_LOG_10 is < 1, but there is no risk of log(double) - // overflow (positive or negative) while the end result shouldn't, - // since log(Double.MIN_VALUE) and log(Double.MAX_VALUE) have - // magnitudes of just a few hundreds. - return log(value) * INV_LOG_10; - } - - /** - * Much more accurate than log(1+value), - * for arguments (and results) close to zero. - * - * @param value A double value. - * @return Logarithm (base e) of (1+value). - */ - public static double log1p(double value) { - if (USE_JDK_MATH) { - return Math.log1p(value); - } - if (false) { - // This also works. Simpler but a bit slower. - if (value == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } - double valuePlusOne = 1+value; - if (valuePlusOne == 1.0) { - return value; - } else { - return log(valuePlusOne)*(value/(valuePlusOne-1.0)); - } - } - if (value > -1.0) { - if (value == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } - - // ln'(x) = 1/x - // so - // log(x+epsilon) ~= log(x) + epsilon/x - // - // Let u be 1+value rounded: - // 1+value = u+epsilon - // - // log(1+value) - // = log(u+epsilon) - // ~= log(u) + epsilon/value - // We compute log(u) as done in log(double), and then add the corrective term. - - double valuePlusOne = 1.0+value; - if (valuePlusOne == 1.0) { - return value; - } else if (Math.abs(value) < 0.15) { - double z = value/(value+2.0); - double z2 = z*z; - return z*(2+z2*((2.0/3)+z2*((2.0/5)+z2*((2.0/7)+z2*((2.0/9)+z2*((2.0/11))))))); - } - - int valuePlusOneBitsHi = (int)(Double.doubleToRawLongBits(valuePlusOne)>>32) & 0x7FFFFFFF; - int valuePlusOneExp = (valuePlusOneBitsHi>>20)-MAX_DOUBLE_EXPONENT; - // Getting the first LOG_BITS bits of the mantissa. - int xIndex = ((valuePlusOneBitsHi<<12)>>>(32-LOG_BITS)); - - // 1.mantissa/1.mantissaApprox - 1 - double z = (valuePlusOne * twoPowNormalOrSubnormal(-valuePlusOneExp)) * MyTLog.logXInvTab[xIndex] - 1; - - z *= (1-z*((1.0/2)-z*(1.0/3))); - - // Adding epsilon/valuePlusOne to z, - // with - // epsilon = value - (valuePlusOne-1) - // (valuePlusOne + epsilon ~= 1+value (not rounded)) - - return valuePlusOneExp * LOG_2 + MyTLog.logXLogTab[xIndex] + (z + (value - (valuePlusOne-1))/valuePlusOne); - } else if (value == -1.0) { - return Double.NEGATIVE_INFINITY; - } else { // value < -1.0, or value is NaN - return Double.NaN; - } - } - - /* - * powers - */ - - /** - * 1e-13ish accuracy or better on whole double range. - * - * @param value A double value. - * @param power A power. - * @return value^power. - */ - public static double pow(double value, double power) { - if (USE_JDK_MATH) { - return Math.pow(value,power); - } - if (power == 0.0) { - return 1.0; - } else if (power == 1.0) { - return value; - } - if (value <= 0.0) { - // powerInfo: 0 if not integer, 1 if even integer, -1 if odd integer - int powerInfo; - if (Math.abs(power) >= (TWO_POW_52*2)) { - // The binary digit just before comma is outside mantissa, - // thus it is always 0: power is an even integer. - powerInfo = 1; - } else { - // If power's magnitude permits, we cast into int instead of into long, - // as it is faster. - if (Math.abs(power) <= (double)Integer.MAX_VALUE) { - int powerAsInt = (int)power; - if (power == (double)powerAsInt) { - powerInfo = ((powerAsInt & 1) == 0) ? 1 : -1; - } else { // power is not an integer (and not NaN, due to test against Integer.MAX_VALUE) - powerInfo = 0; - } - } else { - long powerAsLong = (long)power; - if (power == (double)powerAsLong) { - powerInfo = ((powerAsLong & 1) == 0) ? 1 : -1; - } else { // power is not an integer, or is NaN - if (power != power) { - return Double.NaN; - } - powerInfo = 0; - } - } - } - - if (value == 0.0) { - if (power < 0.0) { - return (powerInfo < 0) ? 1/value : Double.POSITIVE_INFINITY; - } else { // power > 0.0 (0 and NaN cases already treated) - return (powerInfo < 0) ? value : 0.0; - } - } else { // value < 0.0 - if (value == Double.NEGATIVE_INFINITY) { - if (powerInfo < 0) { // power odd integer - return (power < 0.0) ? -0.0 : Double.NEGATIVE_INFINITY; - } else { // power even integer, or not an integer - return (power < 0.0) ? 0.0 : Double.POSITIVE_INFINITY; - } - } else { - return (powerInfo == 0) ? Double.NaN : powerInfo * exp(power*log(-value)); - } - } - } else { // value > 0.0, or value is NaN - return exp(power*log(value)); - } - } - - /** - * Quick pow, with a max relative error of about 1e-2 - * for value >= Double.MIN_NORMAL and 1e-10 < |value^power| < 1e10, - * of about 6e-2 for value >= Double.MIN_NORMAL and 1e-40 < |value^power| < 1e40, - * and worse accuracy otherwise. - * - * @param value A double value, in ]0,+Infinity[ (strictly positive and finite). - * @param power A double value. - * @return value^power. - */ - public static double powQuick(double value, double power) { - if (USE_JDK_MATH) { - return Math.pow(value,power); - } - return exp(power*logQuick(value)); - } - - /** - * This treatment is somehow accurate for low values of |power|, - * and for |power*getExponent(value)| < 1023 or so (to stay away - * from double extreme magnitudes (large and small)). - * - * @param value A double value. - * @param power A power. - * @return value^power. - */ - public static double powFast(double value, int power) { - if (USE_JDK_MATH) { - return Math.pow(value,power); - } - if (power < 3) { - if (power < 0) { - // Opposite of Integer.MIN_VALUE does not exist as int. - if (power == Integer.MIN_VALUE) { - // Integer.MAX_VALUE = -(power+1) - return 1.0/(powFast(value,Integer.MAX_VALUE) * value); - } else { - return 1.0/powFast(value,-power); - } - } else { - // Here, power is in [0,2]. - if (power == 2) { // Most common case first. - return value * value; - } else if (power == 0) { - return 1.0; - } else { // power == 1 - return value; - } - } - } else { // power >= 4 - double oddRemains = 1.0; - // If power <= 5, faster to finish outside the loop. - while (power > 5) { - // Test if power is odd. - if ((power & 1) != 0) { - oddRemains *= value; - } - value *= value; - power >>= 1; // power = power / 2 - } - // Here, power is in [3,5]. - if (power == 3) { - return oddRemains * value * value * value; - } else { // power in [4,5]. - double v2 = value * value; - if (power == 4) { - return oddRemains * v2 * v2; - } else { // power == 5 - return oddRemains * v2 * v2 * value; - } - } - } - } - - /** - * @param value A float value. - * @return value*value. - */ - public static float pow2(float value) { - return value*value; - } - - /** - * @param value A double value. - * @return value*value. - */ - public static double pow2(double value) { - return value*value; - } - - /** - * @param value A float value. - * @return value*value*value. - */ - public static float pow3(float value) { - return value*value*value; - } - - /** - * @param value A double value. - * @return value*value*value. - */ - public static double pow3(double value) { - return value*value*value; - } - - /* - * roots - */ - - /** - * @param value A double value. - * @return Value square root. - */ - public static double sqrt(double value) { - if (USE_JDK_MATH || (!USE_REDEFINED_SQRT)) { - return Math.sqrt(value); - } - // See cbrt for comments, sqrt uses the same ideas. - - if (!(value > 0.0)) { // value <= 0.0, or value is NaN - if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { - return (value < 0.0) ? Double.NaN : value; - } else { - return (value == 0.0) ? value : Double.NaN; - } - } else if (value == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } - - double h; - if (value < DOUBLE_MIN_NORMAL) { - value *= TWO_POW_52; - h = 2*TWO_POW_N26; - } else { - h = 2.0; - } - - int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); - int valueExponentIndex = (valueBitsHi>>20)+(-MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT); - int xIndex = ((valueBitsHi<<12)>>>(32-SQRT_LO_BITS)); - - double result = MyTSqrt.sqrtXSqrtHiTab[valueExponentIndex] * MyTSqrt.sqrtXSqrtLoTab[xIndex]; - double slope = MyTSqrt.sqrtSlopeHiTab[valueExponentIndex] * MyTSqrt.sqrtSlopeLoTab[xIndex]; - value *= 0.25; - - result += (value - result * result) * slope; - result += (value - result * result) * slope; - return h*(result + (value - result * result) * slope); - } - - /** - * Quick sqrt, with with a max relative error of about 3.41e-2 - * for values in [Double.MIN_NORMAL,Double.MAX_VALUE], and worse - * accuracy outside this range. - * - * @param value A double value. - * @return Value square root. - */ - public static double sqrtQuick(double value) { - if (USE_JDK_MATH) { - return Math.sqrt(value); - } - final long bits = Double.doubleToRawLongBits(value); - /* - * Constant determined empirically, using a random-based metaheuristic. - * Should be possible to find a better one. - */ - return Double.longBitsToDouble((bits+4606859074900000000L)>>>1); - } - - /** - * Quick inverse of square root, with a max relative error of about 3.44e-2 - * for values in [Double.MIN_NORMAL,Double.MAX_VALUE], and worse accuracy - * outside this range. - * - * This implementation uses zero step of Newton's method. - * Here are the max relative errors on [Double.MIN_NORMAL,Double.MAX_VALUE] - * depending on number of steps, if you want to copy-paste this code - * and use your own number: - * n=0: about 3.44e-2 - * n=1: about 1.75e-3 - * n=2: about 4.6e-6 - * n=3: about 3.17e-11 - * n=4: about 3.92e-16 - * n=5: about 3.03e-16 - * - * @param value A double value. - * @return Inverse of value square root. - */ - public static double invSqrtQuick(double value) { - if (USE_JDK_MATH) { - return 1/Math.sqrt(value); - } - /* - * http://en.wikipedia.org/wiki/Fast_inverse_square_root - */ - if (false) { - // With one Newton step (much slower than - // 1/Math.sqrt(double) if not optimized). - final double halfInitial = value * 0.5; - long bits = Double.doubleToRawLongBits(value); - // If n=0, 6910474759270000000L might be better (3.38e-2 max relative error). - bits = 0x5FE6EB50C7B537A9L - (bits>>1); - value = Double.longBitsToDouble(bits); - value = value * (1.5 - halfInitial * value * value); // Newton step, can repeat. - return value; - } else { - return Double.longBitsToDouble(0x5FE6EB50C7B537A9L - (Double.doubleToRawLongBits(value)>>1)); - } - } - - /** - * @param value A double value. - * @return Value cubic root. - */ - public static double cbrt(double value) { - if (USE_JDK_MATH) { - return Math.cbrt(value); - } - double h; - if (value < 0.0) { - if (value == Double.NEGATIVE_INFINITY) { - return Double.NEGATIVE_INFINITY; - } - value = -value; - // Making sure value is normal. - if (value < DOUBLE_MIN_NORMAL) { - value *= (TWO_POW_52*TWO_POW_26); - // h = * / - h = -2*TWO_POW_N26; - } else { - h = -2.0; - } - } else { - if (!(value < Double.POSITIVE_INFINITY)) { // value is +Infinity, or value is NaN - return value; - } - // Making sure value is normal. - if (value < DOUBLE_MIN_NORMAL) { - if (value == 0.0) { - // cbrt(0.0) = 0.0, cbrt(-0.0) = -0.0 - return value; - } - value *= (TWO_POW_52*TWO_POW_26); - h = 2*TWO_POW_N26; - } else { - h = 2.0; - } - } - - // Normal value is (2^ * ). - // First member cubic root is computed, and multiplied with an approximation - // of the cubic root of the second member, to end up with a good guess of - // the result before using Newton's (or Archimedes's) method. - // To compute the cubic root approximation, we use the formula "cbrt(value) = cbrt(x) * cbrt(value/x)", - // choosing x as close to value as possible but inferior to it, so that cbrt(value/x) is close to 1 - // (we could iterate on this method, using value/x as new value for each iteration, - // but finishing with Newton's method is faster). - - // Shift and cast into an int, which overall is faster than working with a long. - int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); - int valueExponentIndex = (valueBitsHi>>20)+(-MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT); - // Getting the first CBRT_LO_BITS bits of the mantissa. - int xIndex = ((valueBitsHi<<12)>>>(32-CBRT_LO_BITS)); - double result = MyTCbrt.cbrtXCbrtHiTab[valueExponentIndex] * MyTCbrt.cbrtXCbrtLoTab[xIndex]; - double slope = MyTCbrt.cbrtSlopeHiTab[valueExponentIndex] * MyTCbrt.cbrtSlopeLoTab[xIndex]; - - // Lowering values to avoid overflows when using Newton's method - // (we will then just have to return twice the result). - // result^3 = value - // (result/2)^3 = value/8 - value *= 0.125; - // No need to divide result here, as division is factorized in result computation tables. - // result *= 0.5; - - // Newton's method, looking for y = x^(1/p): - // y(n) = y(n-1) + (x-y(n-1)^p) * slope(y(n-1)) - // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(x(n-1)^(1/p-1)) - // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(x(n-1)^((1-p)/p)) - // with x(n-1)=y(n-1)^p, i.e.: - // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(y(n-1)^(1-p)) - // - // For p=3: - // y(n) = y(n-1) + (x-y(n-1)^3) * (1/(3*y(n-1)^2)) - - // To save time, we don't recompute the slope between Newton's method steps, - // as initial slope is good enough for a few iterations. - // - // NB: slope = 1/(3*trueResult*trueResult) - // As we have result = trueResult/2 (to avoid overflows), we have: - // slope = 4/(3*result*result) - // = (4/3)*resultInv*resultInv - // with newResultInv = 1/newResult - // = 1/(oldResult+resultDelta) - // = (oldResultInv)*1/(1+resultDelta/oldResult) - // = (oldResultInv)*1/(1+resultDelta*oldResultInv) - // ~= (oldResultInv)*(1-resultDelta*oldResultInv) - // ===> Successive slopes could be computed without division, if needed, - // by computing resultInv (instead of slope right away) and retrieving - // slopes from it. - - result += (value - result * result * result) * slope; - result += (value - result * result * result) * slope; - return h*(result + (value - result * result * result) * slope); - } - - /** - * @return sqrt(x^2+y^2) without intermediate overflow or underflow. - */ - public static double hypot(double x, double y) { - if (USE_JDK_MATH) { - return Math.hypot(x,y); - } - x = Math.abs(x); - y = Math.abs(y); - // Ensuring x <= y. - if (y < x) { - double a = x; - x = y; - y = a; - } else if (!(y >= x)) { // Testing if we have some NaN. - return hypot_NaN(x, y); - } - - if (y-x == y) { - // x too small to subtract from y. - return y; - } else { - double factor; - if (y > HYPOT_MAX_MAG) { - // y is too large: scaling down. - x *= (1/HYPOT_FACTOR); - y *= (1/HYPOT_FACTOR); - factor = HYPOT_FACTOR; - } else if (x < (1/HYPOT_MAX_MAG)) { - // x is too small: scaling up. - x *= HYPOT_FACTOR; - y *= HYPOT_FACTOR; - factor = (1/HYPOT_FACTOR); - } else { - factor = 1.0; - } - return factor * sqrt(x*x+y*y); - } - } - - /** - * @return sqrt(x^2+y^2+z^2) without intermediate overflow or underflow. - */ - public static double hypot(double x, double y, double z) { - if (USE_JDK_MATH) { - // No simple JDK equivalent. - } - x = Math.abs(x); - y = Math.abs(y); - z = Math.abs(z); - /* - * Considering that z magnitude is the most likely to be the smaller, - * hence ensuring z <= y <= x, and not x <= y <= z, for less swaps. - */ - // Ensuring z <= y. - if (z > y) { - // y < z: swapping y and z - double a = z; - z = y; - y = a; - } else if (!(z <= y)) { // Testing if y or z is NaN. - return hypot_NaN(x, y, z); - } - // Ensuring y <= x. - if (z > x) { - // x < z <= y: moving x - double oldZ = z; - z = x; - double oldY = y; - y = oldZ; - x = oldY; - } else if (y > x) { - // z <= x < y: swapping x and y - double a = y; - y = x; - x = a; - } else if (x != x) { // Testing if x is NaN. - return hypot_NaN(x, y, z); - } - - if (x-y == x) { - // y, hence z, too small to subtract from x. - return x; - } else if (y-z == y) { - // z too small to subtract from y, hence x. - double factor; - if (x > HYPOT_MAX_MAG) { - // x is too large: scaling down. - x *= (1/HYPOT_FACTOR); - y *= (1/HYPOT_FACTOR); - factor = HYPOT_FACTOR; - } else if (y < (1/HYPOT_MAX_MAG)) { - // y is too small: scaling up. - x *= HYPOT_FACTOR; - y *= HYPOT_FACTOR; - factor = (1/HYPOT_FACTOR); - } else { - factor = 1.0; - } - return factor * sqrt(x*x+y*y); - } else { - double factor; - if (x > HYPOT_MAX_MAG) { - // x is too large: scaling down. - x *= (1/HYPOT_FACTOR); - y *= (1/HYPOT_FACTOR); - z *= (1/HYPOT_FACTOR); - factor = HYPOT_FACTOR; - } else if (z < (1/HYPOT_MAX_MAG)) { - // z is too small: scaling up. - x *= HYPOT_FACTOR; - y *= HYPOT_FACTOR; - z *= HYPOT_FACTOR; - factor = (1/HYPOT_FACTOR); - } else { - factor = 1.0; - } - // Adding smaller magnitudes together first. - return factor * sqrt(x*x+(y*y+z*z)); - } - } - - /* - * close values - */ - - /** - * @param value A float value. - * @return Floor of value. - */ - public static float floor(float value) { - final int exponent = getExponent(value); - if (exponent < 0) { - // abs(value) < 1. - if (value < 0.0f) { - return -1.0f; - } else { - // 0.0f, or -0.0f if value is -0.0f - return 0.0f * value; - } - } else if (exponent < 23) { - // A bit faster than using casts. - final int bits = Float.floatToRawIntBits(value); - final int anteCommaBits = bits & (0xFF800000>>exponent); - if ((value < 0.0f) && (anteCommaBits != bits)) { - return Float.intBitsToFloat(anteCommaBits) - 1.0f; - } else { - return Float.intBitsToFloat(anteCommaBits); - } - } else { - // +-Infinity, NaN, or a mathematical integer. - return value; - } - } - - /** - * @param value A double value. - * @return Floor of value. - */ - public static double floor(double value) { - if (USE_JDK_MATH) { - return Math.floor(value); - } - if (ANTI_SLOW_CASTS) { - double valueAbs = Math.abs(value); - if (valueAbs <= (double)Integer.MAX_VALUE) { - if (value > 0.0) { - return (double)(int)value; - } else if (value < 0.0) { - double anteCommaDigits = (double)(int)value; - if (value != anteCommaDigits) { - return anteCommaDigits - 1.0; - } else { - return anteCommaDigits; - } - } else { // value is +-0.0 (not NaN due to test against Integer.MAX_VALUE) - return value; - } - } else if (valueAbs < TWO_POW_52) { - // We split the value in two: - // high part, which is a mathematical integer, - // and the rest, for which we can get rid of the - // post comma digits by casting into an int. - double highPart = ((int)(value * TWO_POW_N26)) * TWO_POW_26; - if (value > 0.0) { - return highPart + (double)((int)(value - highPart)); - } else { - double anteCommaDigits = highPart + (double)((int)(value - highPart)); - if (value != anteCommaDigits) { - return anteCommaDigits - 1.0; - } else { - return anteCommaDigits; - } - } - } else { // abs(value) >= 2^52, or value is NaN - return value; - } - } else { - final int exponent = getExponent(value); - if (exponent < 0) { - // abs(value) < 1. - if (value < 0.0) { - return -1.0; - } else { - // 0.0, or -0.0 if value is -0.0 - return 0.0 * value; - } - } else if (exponent < 52) { - // A bit faster than working on bits. - final long matIntPart = (long)value; - final double matIntToValue = value-(double)matIntPart; - if (matIntToValue >= 0.0) { - return (double)matIntPart; - } else { - return (double)(matIntPart - 1); - } - } else { - // +-Infinity, NaN, or a mathematical integer. - return value; - } - } - } - - /** - * @param value A float value. - * @return Ceiling of value. - */ - public static float ceil(float value) { - return -floor(-value); - } - - /** - * @param value A double value. - * @return Ceiling of value. - */ - public static double ceil(double value) { - if (USE_JDK_MATH) { - return Math.ceil(value); - } - return -floor(-value); - } - - /** - * Might have different semantics than Math.round(float), - * see bugs 6430675 and 8010430. - * - * @param value A double value. - * @return Value rounded to nearest int, choosing superior int in case two - * are equally close (i.e. rounding-up). - */ - public static int round(float value) { - /* - * Not delegating to JDK, because we want delegation to provide - * at least as good results, and some supported JDK versions - * have bugged round() methods. - */ - // Algorithm by Dmitry Nadezhin (but replaced an if by a multiply) - // (http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-August/020247.html). - final int bits = Float.floatToRawIntBits(value); - final int biasedExp = ((bits>>23)&0xFF); - // Shift to get rid of bits past comma except first one: will need to - // 1-shift to the right to end up with correct magnitude. - final int shift = (23 - 1 + MAX_FLOAT_EXPONENT) - biasedExp; - if ((shift & -32) == 0) { - int bitsSignum = (((bits >> 31) << 1) + 1); - // shift in [0,31], so unbiased exp in [-9,22]. - int extendedMantissa = (0x00800000 | (bits & 0x007FFFFF)) * bitsSignum; - // If value is positive and first bit past comma is 0, rounding - // to lower integer, else to upper one, which is what "+1" and - // then ">>1" do. - return ((extendedMantissa >> shift) + 1) >> 1; - } else { - // +-Infinity, NaN, or a mathematical integer, or tiny. - if (false && ANTI_SLOW_CASTS) { // not worth it - if (Math.abs(value) >= -(float)Integer.MIN_VALUE) { - // +-Infinity or a mathematical integer (mostly) out of int range. - return (value < 0.0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; - } - // NaN or a mathematical integer (mostly) in int range. - } - return (int)value; - } - } - - /** - * Might have different semantics than Math.round(double), - * see bugs 6430675 and 8010430. - * - * @param value A double value. - * @return Value rounded to nearest long, choosing superior long in case two - * are equally close (i.e. rounding-up). - */ - public static long round(double value) { - /* - * Not delegating to JDK, because we want delegation to provide - * at least as good results, and some supported JDK versions - * have bugged round() methods. - */ - final long bits = Double.doubleToRawLongBits(value); - final int biasedExp = (((int)(bits>>52))&0x7FF); - // Shift to get rid of bits past comma except first one: will need to - // 1-shift to the right to end up with correct magnitude. - final int shift = (52 - 1 + MAX_DOUBLE_EXPONENT) - biasedExp; - if ((shift & -64) == 0) { - long bitsSignum = (((bits >> 63) << 1) + 1); - // shift in [0,63], so unbiased exp in [-12,51]. - long extendedMantissa = (0x0010000000000000L | (bits & 0x000FFFFFFFFFFFFFL)) * bitsSignum; - // If value is positive and first bit past comma is 0, rounding - // to lower integer, else to upper one, which is what "+1" and - // then ">>1" do. - return ((extendedMantissa >> shift) + 1L) >> 1; - } else { - // +-Infinity, NaN, or a mathematical integer, or tiny. - if (ANTI_SLOW_CASTS) { - if (Math.abs(value) >= -(double)Long.MIN_VALUE) { - // +-Infinity or a mathematical integer (mostly) out of long range. - return (value < 0.0) ? Long.MIN_VALUE : Long.MAX_VALUE; - } - // NaN or a mathematical integer (mostly) in long range. - } - return (long)value; - } - } - - /** - * @param value A float value. - * @return Value rounded to nearest int, choosing even int in case two - * are equally close. - */ - public static int roundEven(float value) { - final int sign = signFromBit(value); - value = Math.abs(value); - if (ANTI_SLOW_CASTS) { - if (value < TWO_POW_23_F) { - // Getting rid of post-comma bits. - value = ((value + TWO_POW_23_F) - TWO_POW_23_F); - return sign * (int)value; - } else if (value < (float)Integer.MAX_VALUE) { // "<=" doesn't work, because of float precision - // value is in [-Integer.MAX_VALUE,Integer.MAX_VALUE] - return sign * (int)value; - } - } else { - if (value < TWO_POW_23_F) { - // Getting rid of post-comma bits. - value = ((value + TWO_POW_23_F) - TWO_POW_23_F); - } - } - return (int)(sign * value); - } - - /** - * @param value A double value. - * @return Value rounded to nearest long, choosing even long in case two - * are equally close. - */ - public static long roundEven(double value) { - final int sign = (int)signFromBit(value); - value = Math.abs(value); - if (value < TWO_POW_52) { - // Getting rid of post-comma bits. - value = ((value + TWO_POW_52) - TWO_POW_52); - } - if (ANTI_SLOW_CASTS) { - if (value <= (double)Integer.MAX_VALUE) { - // value is in [-Integer.MAX_VALUE,Integer.MAX_VALUE] - return sign * (int)value; - } - } - return (long)(sign * value); - } - - /** - * @param value A float value. - * @return The float mathematical integer closest to the specified value, - * choosing even one if two are equally close, or respectively - * NaN, +-Infinity or +-0.0f if the value is any of these. - */ - public static float rint(float value) { - final int sign = signFromBit(value); - value = Math.abs(value); - if (value < TWO_POW_23_F) { - // Getting rid of post-comma bits. - value = ((TWO_POW_23_F + value ) - TWO_POW_23_F); - } - // Restoring original sign. - return sign * value; - } - - /** - * @param value A double value. - * @return The double mathematical integer closest to the specified value, - * choosing even one if two are equally close, or respectively - * NaN, +-Infinity or +-0.0 if the value is any of these. - */ - public static double rint(double value) { - if (USE_JDK_MATH) { - return Math.rint(value); - } - final int sign = (int)signFromBit(value); - value = Math.abs(value); - if (value < TWO_POW_52) { - // Getting rid of post-comma bits. - value = ((TWO_POW_52 + value ) - TWO_POW_52); - } - // Restoring original sign. - return sign * value; - } - - /* - * close int values - * - * Never delegating to JDK for these methods, for we should always - * be faster and exact, and JDK doesn't exactly have such methods. - */ - - /** - * @param value A double value. - * @return Floor of value as int, or closest int if floor is out - * of int range, or 0 if value is NaN. - */ - public static int floorToInt(double value) { - int valueInt = (int) value; - if (value < 0.0) { - if (value == (double) valueInt) { - return valueInt; - } else { - if (valueInt == Integer.MIN_VALUE) { - return valueInt; - } else { - return valueInt - 1; - } - } - } else { // >= 0 or NaN. - return valueInt; - } - } - - /** - * @param value A double value. - * @return Ceiling of value as int, or closest int if ceiling is out - * of int range, or 0 if value is NaN. - */ - public static int ceilToInt(double value) { - int valueInt = (int) value; - if (value > 0.0) { - if (value == (double) valueInt) { - return valueInt; - } else { - if (valueInt == Integer.MAX_VALUE) { - return valueInt; - } else { - return valueInt + 1; - } - } - } else { // <= 0 or NaN. - return valueInt; - } - } - - /** - * @param value A double value. - * @return Value rounded to nearest int, choosing superior int in case two - * are equally close (i.e. rounding-up). - */ - public static int roundToInt(double value) { - /* - * We don't gain much by reimplementing rounding, except for - * pathologically large values, which should not be a common case - * when dealing with ints, so we just use round(double). - */ - return NumbersUtils.toInt(round(value)); - } - - /** - * @param value A double value. - * @return Value rounded to nearest int, choosing even int in case two - * are equally close. - */ - public static int roundEvenToInt(double value) { - final int sign = (int)signFromBit(value); - value = Math.abs(value); - /* - * Applying the post-comma bits removal logic even if value is out - * of int range, to avoid a test, for it doesn't mess up the result, - * and we want to optimize for the case of values in int range. - */ - value = ((value + TWO_POW_52) - TWO_POW_52); - return (int)(sign * value); - } - - /* - * ranges - */ - - /** - * @param min A float value. - * @param max A float value. - * @param value A float value. - * @return min if value < min, max if value > max, value otherwise. - */ - public static float toRange(float min, float max, float value) { - return NumbersUtils.toRange(min, max, value); - } - - /** - * @param min A double value. - * @param max A double value. - * @param value A double value. - * @return min if value < min, max if value > max, value otherwise. - */ - public static double toRange(double min, double max, double value) { - return NumbersUtils.toRange(min, max, value); - } - - /* - * binary operators (/,%) - */ - - /** - * Returns dividend - divisor * n, where n is the mathematical integer - * closest to dividend/divisor. - * If dividend/divisor is equally close to surrounding integers, - * we choose n to be the integer of smallest magnitude, which makes - * this treatment differ from Math.IEEEremainder(double,double), - * where n is chosen to be the even integer. - * Note that the choice of n is not done considering the double - * approximation of dividend/divisor, because it could cause - * result to be outside [-|divisor|/2,|divisor|/2] range. - * The practical effect is that if multiple results would be possible, - * we always choose the result that is the closest to (and has the same - * sign as) the dividend. - * Ex. : - * - for (-3.0,2.0), this method returns -1.0, - * whereas Math.IEEEremainder returns 1.0. - * - for (-5.0,2.0), both this method and Math.IEEEremainder return -1.0. - * - * If the remainder is zero, its sign is the same as the sign of the first argument. - * If either argument is NaN, or the first argument is infinite, - * or the second argument is positive zero or negative zero, - * then the result is NaN. - * If the first argument is finite and the second argument is - * infinite, then the result is the same as the first argument. - * - * NB: - * - Modulo operator (%) returns a value in ]-|divisor|,|divisor|[, - * which sign is the same as dividend. - * - As for modulo operator, the sign of the divisor has no effect on the result. - * - On some architecture, % operator has been observed to return NaN - * for some subnormal values of divisor, when dividend exponent is 1023, - * which impacts the correctness of this method. - * - * @param dividend Dividend. - * @param divisor Divisor. - * @return Remainder of dividend/divisor, i.e. a value in [-|divisor|/2,|divisor|/2]. - */ - public static double remainder(double dividend, double divisor) { - if (Double.isInfinite(divisor)) { - if (Double.isInfinite(dividend)) { - return Double.NaN; - } else { - return dividend; - } - } - double value = dividend % divisor; - if (Math.abs(value+value) > Math.abs(divisor)) { - return value + ((value > 0.0) ? -Math.abs(divisor) : Math.abs(divisor)); - } else { - return value; - } - } - - /** - * @param angle Angle in radians. - * @return The same angle, in radians, but in [-PI,PI]. - */ - public static double normalizeMinusPiPi(double angle) { - // Not modifying values in output range. - if ((angle >= -Math.PI) && (angle <= Math.PI)) { - return angle; - } - return remainderTwoPi(angle); - } - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return The same angle, in radians, but in [-PI,PI]. - */ - public static double normalizeMinusPiPiFast(double angle) { - // Not modifying values in output range. - if ((angle >= -Math.PI) && (angle <= Math.PI)) { - return angle; - } - return remainderTwoPiFast(angle); - } - - /** - * @param angle Angle in radians. - * @return The same angle, in radians, but in [0,2*PI]. - */ - public static double normalizeZeroTwoPi(double angle) { - // Not modifying values in output range. - if ((angle >= 0.0) && (angle <= 2*Math.PI)) { - return angle; - } - angle = remainderTwoPi(angle); - if (angle < 0.0) { - // LO then HI is theoretically better (when starting near 0). - return (angle + TWOPI_LO) + TWOPI_HI; - } else { - return angle; - } - } - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return The same angle, in radians, but in [0,2*PI]. - */ - public static double normalizeZeroTwoPiFast(double angle) { - // Not modifying values in output range. - if ((angle >= 0.0) && (angle <= 2*Math.PI)) { - return angle; - } - angle = remainderTwoPiFast(angle); - if (angle < 0.0) { - // LO then HI is theoretically better (when starting near 0). - return (angle + TWOPI_LO) + TWOPI_HI; - } else { - return angle; - } - } - - /** - * @param angle Angle in radians. - * @return Angle value modulo PI, in radians, in [-PI/2,PI/2]. - */ - public static double normalizeMinusHalfPiHalfPi(double angle) { - // Not modifying values in output range. - if ((angle >= -Math.PI/2) && (angle <= Math.PI/2)) { - return angle; - } - return remainderPi(angle); - } - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return Angle value modulo PI, in radians, in [-PI/2,PI/2]. - */ - public static double normalizeMinusHalfPiHalfPiFast(double angle) { - // Not modifying values in output range. - if ((angle >= -Math.PI/2) && (angle <= Math.PI/2)) { - return angle; - } - return remainderPiFast(angle); - } - - /* - * floating points utils - */ - - /** - * @param value A float value. - * @return true if the specified value is NaN or +-Infinity, false otherwise. - */ - public static boolean isNaNOrInfinite(float value) { - return NumbersUtils.isNaNOrInfinite(value); - } - - /** - * @param value A double value. - * @return true if the specified value is NaN or +-Infinity, false otherwise. - */ - public static boolean isNaNOrInfinite(double value) { - return NumbersUtils.isNaNOrInfinite(value); - } - - /** - * @param value A float value. - * @return Value unbiased exponent. - */ - public static int getExponent(float value) { - return ((Float.floatToRawIntBits(value)>>23)&0xFF)-MAX_FLOAT_EXPONENT; - } - - /** - * @param value A double value. - * @return Value unbiased exponent. - */ - public static int getExponent(double value) { - return (((int)(Double.doubleToRawLongBits(value)>>52))&0x7FF)-MAX_DOUBLE_EXPONENT; - } - - /** - * @param value A float value. - * @return -1.0f if the specified value is < 0, 1.0f if it is > 0, - * and the value itself if it is NaN or +-0.0f. - */ - public static float signum(float value) { - if (USE_JDK_MATH) { - return Math.signum(value); - } - if ((value == 0.0f) || (value != value)) { - return value; - } - return (float)signFromBit(value); - } - - /** - * @param value A double value. - * @return -1.0 if the specified value is < 0, 1.0 if it is > 0, - * and the value itself if it is NaN or +-0.0. - */ - public static double signum(double value) { - if (USE_JDK_MATH) { - return Math.signum(value); - } - if ((value == 0.0) || (value != value)) { - return value; - } - if (ANTI_SLOW_CASTS) { - return (double)(int)signFromBit(value); - } else { - return (double)signFromBit(value); - } - } - - /** - * @param value A float value. - * @return -1 if sign bit is 1, 1 if sign bit is 0. - */ - public static int signFromBit(float value) { - return ((Float.floatToRawIntBits(value)>>30)|1); - } - - /** - * @param value A double value. - * @return -1 if sign bit is 1, 1 if sign bit is 0. - */ - public static long signFromBit(double value) { - // Returning a long, to avoid useless cast into int. - return ((Double.doubleToRawLongBits(value)>>62)|1); - } - - /** - * A sign of NaN can be interpreted as positive or negative. - * - * @param magnitude A float value. - * @param sign A float value. - * @return A value with the magnitude of the first argument, and the sign - * of the second argument. - */ - public static float copySign(float magnitude, float sign) { - return Float.intBitsToFloat( - (Float.floatToRawIntBits(sign) & Integer.MIN_VALUE) - | (Float.floatToRawIntBits(magnitude) & Integer.MAX_VALUE)); - } - - /** - * A sign of NaN can be interpreted as positive or negative. - * - * @param magnitude A double value. - * @param sign A double value. - * @return A value with the magnitude of the first argument, and the sign - * of the second argument. - */ - public static double copySign(double magnitude, double sign) { - return Double.longBitsToDouble( - (Double.doubleToRawLongBits(sign) & Long.MIN_VALUE) - | (Double.doubleToRawLongBits(magnitude) & Long.MAX_VALUE)); - } - - /** - * The ULP (Unit in the Last Place) is the distance to the next value larger - * in magnitude. - * - * @param value A float value. - * @return The size of an ulp of the specified value, or Float.MIN_VALUE - * if it is +-0.0f, or +Infinity if it is +-Infinity, or NaN - * if it is NaN. - */ - public static float ulp(float value) { - if (USE_JDK_MATH) { - return Math.ulp(value); - } - /* - * Look-up table not really worth it in micro-benchmark, - * so should be worse with cache-misses. - */ - final int exponent = getExponent(value); - if (exponent >= (MIN_FLOAT_NORMAL_EXPONENT+23)) { - if (exponent == MAX_FLOAT_EXPONENT+1) { - // NaN or +-Infinity - return Math.abs(value); - } - // normal: returning 2^(exponent-23) - return Float.intBitsToFloat((exponent+(MAX_FLOAT_EXPONENT-23))<<23); - } else { - if (exponent == MIN_FLOAT_NORMAL_EXPONENT-1) { - // +-0.0f or subnormal - return Float.MIN_VALUE; - } - // subnormal result - return Float.intBitsToFloat(1<<(exponent-MIN_FLOAT_NORMAL_EXPONENT)); - } - } - - /** - * The ULP (Unit in the Last Place) is the distance to the next value larger - * in magnitude. - * - * @param value A double value. - * @return The size of an ulp of the specified value, or Double.MIN_VALUE - * if it is +-0.0, or +Infinity if it is +-Infinity, or NaN - * if it is NaN. - */ - public static double ulp(double value) { - if (USE_JDK_MATH) { - return Math.ulp(value); - } - /* - * Look-up table not really worth it in micro-benchmark, - * so should be worse with cache-misses. - */ - final int exponent = getExponent(value); - if (exponent >= (MIN_DOUBLE_NORMAL_EXPONENT+52)) { - if (exponent == MAX_DOUBLE_EXPONENT+1) { - // NaN or +-Infinity - return Math.abs(value); - } - // normal: returning 2^(exponent-52) - return Double.longBitsToDouble((exponent+(MAX_DOUBLE_EXPONENT-52L))<<52); - } else { - if (exponent == MIN_DOUBLE_NORMAL_EXPONENT-1) { - // +-0.0f or subnormal - return Double.MIN_VALUE; - } - // subnormal result - return Double.longBitsToDouble(1L<<(exponent-MIN_DOUBLE_NORMAL_EXPONENT)); - } - } - - /** - * If both arguments are +-0.0(f), (float)direction is returned. - * - * If both arguments are +Infinity or -Infinity, - * respectively +Infinity or -Infinity is returned. - * - * @param start A float value. - * @param direction A double value. - * @return The float adjacent to start towards direction, considering that - * +(-)Float.MIN_VALUE is adjacent to +(-)0.0f, and that - * +(-)Float.MAX_VALUE is adjacent to +(-)Infinity, - * or NaN if any argument is NaN. - */ - public static float nextAfter(float start, double direction) { - if (direction < start) { - // Going towards -Infinity. - if (start == 0.0f) { - // +-0.0f - return -Float.MIN_VALUE; - } - final int bits = Float.floatToRawIntBits(start); - return Float.intBitsToFloat(bits + ((bits > 0) ? -1 : 1)); - } else if (direction > start) { - // Going towards +Infinity. - // +0.0f to get rid of eventual -0.0f - final int bits = Float.floatToRawIntBits(start + 0.0f); - return Float.intBitsToFloat(bits + (bits >= 0 ? 1 : -1)); - } else if (start == direction) { - return (float)direction; - } else { - // Returning a NaN derived from the input NaN(s). - return start + (float)direction; - } - } - - /** - * If both arguments are +-0.0, direction is returned. - * - * If both arguments are +Infinity or -Infinity, - * respectively +Infinity or -Infinity is returned. - * - * @param start A double value. - * @param direction A double value. - * @return The double adjacent to start towards direction, considering that - * +(-)Double.MIN_VALUE is adjacent to +(-)0.0, and that - * +(-)Double.MAX_VALUE is adjacent to +(-)Infinity, - * or NaN if any argument is NaN. - */ - public static double nextAfter(double start, double direction) { - if (direction < start) { - // Going towards -Infinity. - if (start == 0.0) { - // +-0.0 - return -Double.MIN_VALUE; - } - final long bits = Double.doubleToRawLongBits(start); - return Double.longBitsToDouble(bits + ((bits > 0) ? -1 : 1)); - } else if (direction > start) { - // Going towards +Infinity. - // +0.0 to get rid of eventual -0.0 - final long bits = Double.doubleToRawLongBits(start + 0.0f); - return Double.longBitsToDouble(bits + (bits >= 0 ? 1 : -1)); - } else if (start == direction) { - return direction; - } else { - // Returning a NaN derived from the input NaN(s). - return start + direction; - } - } - - /** - * Semantically equivalent to nextAfter(start,Double.NEGATIVE_INFINITY). - */ - public static float nextDown(float start) { - if (start > Float.NEGATIVE_INFINITY) { - if (start == 0.0f) { - // +-0.0f - return -Float.MIN_VALUE; - } - final int bits = Float.floatToRawIntBits(start); - return Float.intBitsToFloat(bits + ((bits > 0) ? -1 : 1)); - } else if (start == Float.NEGATIVE_INFINITY) { - return Float.NEGATIVE_INFINITY; - } else { - // NaN - return start; - } - } - - /** - * Semantically equivalent to nextAfter(start,Double.NEGATIVE_INFINITY). - */ - public static double nextDown(double start) { - if (start > Double.NEGATIVE_INFINITY) { - if (start == 0.0) { - // +-0.0 - return -Double.MIN_VALUE; - } - final long bits = Double.doubleToRawLongBits(start); - return Double.longBitsToDouble(bits + ((bits > 0) ? -1 : 1)); - } else if (start == Double.NEGATIVE_INFINITY) { - return Double.NEGATIVE_INFINITY; - } else { - // NaN - return start; - } - } - - /** - * Semantically equivalent to nextAfter(start,Double.POSITIVE_INFINITY). - */ - public static float nextUp(float start) { - if (start < Float.POSITIVE_INFINITY) { - // +0.0f to get rid of eventual -0.0f - final int bits = Float.floatToRawIntBits(start + 0.0f); - return Float.intBitsToFloat(bits + (bits >= 0 ? 1 : -1)); - } else if (start == Float.POSITIVE_INFINITY) { - return Float.POSITIVE_INFINITY; - } else { - // NaN - return start; - } - } - - /** - * Semantically equivalent to nextAfter(start,Double.POSITIVE_INFINITY). - */ - public static double nextUp(double start) { - if (start < Double.POSITIVE_INFINITY) { - // +0.0 to get rid of eventual -0.0 - final long bits = Double.doubleToRawLongBits(start + 0.0); - return Double.longBitsToDouble(bits + (bits >= 0 ? 1 : -1)); - } else if (start == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } else { - // NaN - return start; - } - } - - /** - * Precision may be lost if the result is subnormal. - * - * @param value A float value. - * @param scaleFactor An int value. - * @return value * 2^scaleFactor, or a value equivalent to the specified - * one if it is NaN, +-Infinity or +-0.0f. - */ - public static float scalb(float value, int scaleFactor) { - // Large enough to imply overflow or underflow for - // a finite non-zero value. - final int MAX_SCALE = 2*MAX_FLOAT_EXPONENT+23+1; - - // Making sure scaling factor is in a reasonable range. - scaleFactor = Math.max(Math.min(scaleFactor, MAX_SCALE), -MAX_SCALE); - - return (float)(((double)value) * twoPowNormal(scaleFactor)); - } - - /** - * Precision may be lost if the result is subnormal. - * - * @param value A double value. - * @param scaleFactor An int value. - * @return value * 2^scaleFactor, or a value equivalent to the specified - * one if it is NaN, +-Infinity or +-0.0. - */ - public static double scalb(double value, int scaleFactor) { - if ((scaleFactor > -MAX_DOUBLE_EXPONENT) && (scaleFactor <= MAX_DOUBLE_EXPONENT)) { - // Quick case (as done in apache FastMath). - return value * twoPowNormal(scaleFactor); - } - - // Large enough to imply overflow or underflow for - // a finite non-zero value. - final int MAX_SCALE = 2*MAX_DOUBLE_EXPONENT+52+1; - - // Making sure scaling factor is in a reasonable range. - final int exponentAdjust; - final int scaleIncrement; - final double exponentDelta; - if (scaleFactor < 0) { - scaleFactor = Math.max(scaleFactor, -MAX_SCALE); - scaleIncrement = -512; - exponentDelta = TWO_POW_N512; - } else { - scaleFactor = Math.min(scaleFactor, MAX_SCALE); - scaleIncrement = 512; - exponentDelta = TWO_POW_512; - } - - // Calculating (scaleFactor % +-512), 512 = 2^9, using - // technique from "Hacker's Delight" section 10-2. - final int t = ((scaleFactor >> (9-1)) >>> (32-9)); - exponentAdjust = ((scaleFactor + t) & (512-1)) - t; - - value *= twoPowNormal(exponentAdjust); - scaleFactor -= exponentAdjust; - - while (scaleFactor != 0) { - value *= exponentDelta; - scaleFactor -= scaleIncrement; - } - - return value; - } - - /* - * Non-redefined Math public values and treatments. - */ - - public static float abs(float a) { - return Math.abs(a); - } - - public static double abs(double a) { - return Math.abs(a); - } - - public static float min(float a, float b) { - return Math.min(a,b); - } - - public static double min(double a, double b) { - return Math.min(a,b); - } - - public static float max(float a, float b) { - return Math.max(a,b); - } - - public static double max(double a, double b) { - return Math.max(a,b); - } - - public static double IEEEremainder(double f1, double f2) { - return Math.IEEEremainder(f1,f2); - } - - public static double random() { - return Math.random(); - } - - //-------------------------------------------------------------------------- - // PRIVATE METHODS - //-------------------------------------------------------------------------- - - /** - * Non-instantiable. - */ - private FastMath() { - } - - /* - * Remainders (accurate). - */ - - /** - * @param angle Angle in radians. - * @return Remainder of (angle % (2*PI)), in [-PI,PI]. - */ - private static double remainderTwoPi(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderTwoPi(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle <= (4*NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2)) { - double fn = (double)(int)(angle*TWOPI_INV+0.5); - angle = (angle - fn*TWOPI_HI) - fn*TWOPI_LO; - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI) { - angle = (angle + TWOPI_HI) + TWOPI_LO; - } else if (angle > Math.PI) { - angle = (angle - TWOPI_HI) - TWOPI_LO; - } - return negateResult ? -angle : angle; - } else if (angle < Double.POSITIVE_INFINITY) { - angle = heavyRemainderTwoPi(angle); - return negateResult ? -angle : angle; - } else { // angle is +Infinity or NaN - return Double.NaN; - } - } - - /** - * @param angle Angle in radians. - * @return Remainder of (angle % PI), in [-PI/2,PI/2]. - */ - private static double remainderPi(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderPi(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle <= (2*NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2)) { - double fn = (double)(int)(angle*PI_INV+0.5); - angle = (angle - fn*PI_HI) - fn*PI_LO; - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI/2) { - angle = (angle + PI_HI) + PI_LO; - } else if (angle > Math.PI/2) { - angle = (angle - PI_HI) - PI_LO; - } - return negateResult ? -angle : angle; - } else if (angle < Double.POSITIVE_INFINITY) { - angle = heavyRemainderPi(angle); - return negateResult ? -angle : angle; - } else { // angle is +Infinity or NaN - return Double.NaN; - } - } - - /** - * @param angle Angle in radians. - * @return Bits of double corresponding to remainder of (angle % (PI/2)), - * in [-PI/4,PI/4], with quadrant encoded in exponent bits. - */ - private static long remainderPiO2(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderPiO2(angle, false); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle <= NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2) { - int n = (int)(angle*PIO2_INV+0.5); - double fn = (double)n; - angle = (angle - fn*PIO2_HI) - fn*PIO2_LO; - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI/4) { - angle = (angle + PIO2_HI) + PIO2_LO; - n--; - } else if (angle > Math.PI/4) { - angle = (angle - PIO2_HI) - PIO2_LO; - n++; - } - if (negateResult) { - angle = -angle; - } - return encodeRemainderAndQuadrant(angle, n&3); - } else if (angle < Double.POSITIVE_INFINITY) { - return heavyRemainderPiO2(angle, negateResult); - } else { // angle is +Infinity or NaN - return encodeRemainderAndQuadrant(Double.NaN, 0); - } - } - - /* - * Remainders (fast). - */ - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return Remainder of (angle % (2*PI)), in [-PI,PI]. - */ - private static double remainderTwoPiFast(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderTwoPi(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - // - We don't bother with values higher than (2*PI*(2^52)), - // since they are spaced by 2*PI or more from each other. - // - For large values, we don't use % because it might be very slow, - // and we split computation in two, because cast from double to int - // with large numbers might be very slow also. - if (angle <= TWO_POW_26*(2*Math.PI)) { - // ok - } else if (angle <= TWO_POW_52*(2*Math.PI)) { - // Computing remainder of angle modulo TWO_POW_26*(2*PI). - double fn = (double)(int)(angle*(TWOPI_INV/TWO_POW_26)+0.5); - angle = (angle - fn*(TWOPI_HI*TWO_POW_26)) - fn*(TWOPI_LO*TWO_POW_26); - // Here, angle is in [-TWO_POW_26*PI,TWO_POW_26*PI], or so. - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } else if (angle < Double.POSITIVE_INFINITY) { - return 0.0; - } else { // angle is +Infinity or NaN - return Double.NaN; - } - - // Computing remainder of angle modulo 2*PI. - double fn = (double)(int)(angle*TWOPI_INV+0.5); - angle = (angle - fn*TWOPI_HI) - fn*TWOPI_LO; - - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI) { - angle = (angle + TWOPI_HI) + TWOPI_LO; - } else if (angle > Math.PI) { - angle = (angle - TWOPI_HI) - TWOPI_LO; - } - return negateResult ? -angle : angle; - } - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return Remainder of (angle % PI), in [-PI/2,PI/2]. - */ - private static double remainderPiFast(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderPi(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - // - We don't bother with values higher than (PI*(2^52)), - // since they are spaced by PI or more from each other. - // - For large values, we don't use % because it might be very slow, - // and we split computation in two, because cast from double to int - // with large numbers might be very slow also. - if (angle <= TWO_POW_26*Math.PI) { - // ok - } else if (angle <= TWO_POW_52*Math.PI) { - // Computing remainder of angle modulo TWO_POW_26*PI. - double fn = (double)(int)(angle*(PI_INV/TWO_POW_26)+0.5); - angle = (angle - fn*(PI_HI*TWO_POW_26)) - fn*(PI_LO*TWO_POW_26); - // Here, angle is in [-TWO_POW_26*PI/2,TWO_POW_26*PI/2], or so. - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } else if (angle < Double.POSITIVE_INFINITY) { - return 0.0; - } else { // angle is +Infinity or NaN - return Double.NaN; - } - - // Computing remainder of angle modulo PI. - double fn = (double)(int)(angle*PI_INV+0.5); - angle = (angle - fn*PI_HI) - fn*PI_LO; - - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI/2) { - angle = (angle + PI_HI) + PI_LO; - } else if (angle > Math.PI/2) { - angle = (angle - PI_HI) - PI_LO; - } - return negateResult ? -angle : angle; - } -} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/IntWrapper.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/IntWrapper.java deleted file mode 100644 index 812e5a22d..000000000 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/IntWrapper.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -package space.kscience.kmath.jafama; - -public class IntWrapper { - public int value; - @Override - public String toString() { - return Integer.toString(this.value); - } -} 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 2b6cc3a5a..2557004e9 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 @@ -1,6 +1,7 @@ package space.kscience.kmath.jafama import space.kscience.kmath.operations.* +import net.jafama.* /** * Advanced Number-like semifield that implements basic operations. @@ -55,7 +56,7 @@ public interface ExtendedField : ExtendedFieldOperations, Field, Numeri * A field for [Double] without boxing. Does not produce appropriate field element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object DoubleField : ExtendedField, Norm, ScaleOperations { +public object JafamaDoubleField : ExtendedField, Norm, ScaleOperations { public override inline val zero: Double get() = 0.0 public override inline val one: Double get() = 1.0 diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/NumbersUtils.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/NumbersUtils.java deleted file mode 100644 index 6fdd9dea5..000000000 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/NumbersUtils.java +++ /dev/null @@ -1,2647 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -package space.kscience.kmath.jafama; - -/** - * Class containing various basic utility methods to deal with numbers. - * This class is meant to be light (no big look-up tables or such). - * - * Check methods return boolean if success, - * for it allows to use them in assertions. - * - * toString methods use capital letters, unlike JDK's toStrings, for it is more - * readable (especially, "l" and "1" can easily be confused with one another). - * - * Some methods have an int version additionally to the long version, - * even though long version could be used instead, for performance reasons, - * either for the methods themselves (if they do computations with ints - * instead of longs), or to be used in an int use case (like methods - * checking whether or not a signed int can fit in such number of bits). - */ -public final class NumbersUtils { - - //-------------------------------------------------------------------------- - // MEMBERS - //-------------------------------------------------------------------------- - - /** - * Double.MIN_NORMAL since Java 6. - */ - public static final double DOUBLE_MIN_NORMAL = Double.longBitsToDouble(0x0010000000000000L); // 2.2250738585072014E-308 - - /** - * Float.MIN_NORMAL since Java 6. - */ - public static final float FLOAT_MIN_NORMAL = Float.intBitsToFloat(0x00800000); // 1.17549435E-38f - - private static final int MIN_DOUBLE_EXPONENT = -1074; - private static final int MAX_DOUBLE_EXPONENT = 1023; - - /** - * All possible upper case chars for representing a number as a String. - */ - private final static char[] CHAR_BY_DIGIT; - static { - final char minDecimal = '0'; - final char maxDecimal = '9'; - final int n1 = maxDecimal - minDecimal + 1; - final char minLetter = 'A'; - final char maxLetter = 'Z'; - final int n2 = maxLetter - minLetter + 1; - CHAR_BY_DIGIT = new char[n1+n2]; - int i=0; - for (char c=minDecimal;c<=maxDecimal;c++) { - CHAR_BY_DIGIT[i++] = c; - } - for (char c=minLetter;c<=maxLetter;c++) { - CHAR_BY_DIGIT[i++] = c; - } - } - - /** - * For power-of-two radixes only. - */ - private static final int[] DIV_SHIFT_BY_RADIX; - static { - DIV_SHIFT_BY_RADIX = new int[32+1]; - int shift=1; - for (int radix=2;radix<=32;radix*=2) { - DIV_SHIFT_BY_RADIX[radix] = shift++; - } - } - - private final static int[] MAX_NBR_OF_NEG_INT_DIGITS_BY_RADIX = new int[Character.MAX_RADIX+1]; - private final static int[] MAX_NBR_OF_NEG_LONG_DIGITS_BY_RADIX = new int[Character.MAX_RADIX+1]; - static { - for (int radix=Character.MIN_RADIX;radix<=Character.MAX_RADIX;radix++) { - /* - * Brutal but works. - * -1 for the sign. - */ - MAX_NBR_OF_NEG_INT_DIGITS_BY_RADIX[radix] = Integer.toString(Integer.MIN_VALUE, radix).length()-1; - MAX_NBR_OF_NEG_LONG_DIGITS_BY_RADIX[radix] = Long.toString(Long.MIN_VALUE, radix).length()-1; - } - } - - static final double NO_CSN_MIN_BOUND_INCL = 1e-3; - static final double NO_CSN_MAX_BOUND_EXCL = 1e7; - - private static final double PIO2_HI = Double.longBitsToDouble(0x3FF921FB54400000L); // 1.57079632673412561417e+00 first 33 bits of pi/2 - private static final double PIO2_LO = Double.longBitsToDouble(0x3DD0B4611A626331L); // 6.07710050650619224932e-11 pi/2 - PIO2_HI - private static final double PI_HI = 2*PIO2_HI; - private static final double PI_LO = 2*PIO2_LO; - private static final double TWOPI_HI = 4*PIO2_HI; - private static final double TWOPI_LO = 4*PIO2_LO; - - //-------------------------------------------------------------------------- - // PUBLIC METHODS - //-------------------------------------------------------------------------- - - /** - * @return True if the specified values are equal or both NaN, false otherwise. - */ - public static boolean equal(float a, float b) { - // Only does one test if a == b. - return (a == b) ? true : ((a != a) && (b != b)); - } - - /** - * @return True if the specified values are equal or both NaN, false otherwise. - */ - public static boolean equal(double a, double b) { - // Only does one test if a == b. - return (a == b) ? true : ((a != a) && (b != b)); - } - - /** - * @return True if the specified value is a mathematical integer, - * false otherwise (which includes NaN and +-Infinity). - */ - public static boolean isMathematicalInteger(float value) { - // Doing magnitude test first, for cast - // might be very slow for huge values. - // It also helps be faster for huge values, - // for which the test with cast always fail. - value = Math.abs(value); - return ((value >= (float)(1<<23) - && (value != Float.POSITIVE_INFINITY))) - || (value == (float)(int)value); - } - - /** - * @return True if the specified value is a mathematical integer, - * false otherwise (which includes NaN and +-Infinity). - */ - public static boolean isMathematicalInteger(double value) { - // Doing magnitude test first, for cast - // might be very slow for huge values. - // It also helps be faster for huge values, - // for which the test with cast always fail. - value = Math.abs(value); - return ((value >= (double)(1L<<52)) - && (value != Double.POSITIVE_INFINITY)) - || (value == (double)(long)value); - } - - /** - * @param value A float value. - * @return True if the specified value is equidistant from two adjacent - * mathematical integers, false otherwise (which includes NaN - * and +-Infinity). - */ - public static boolean isEquidistant(float value) { - if (false) { - // Also works, but slower. - final int bits = Float.floatToRawIntBits(value); - final int exponent = ((bits>>23)&0xFF)-127; - final int nbrOfPostCommaBits = 23 - exponent; - if ((nbrOfPostCommaBits <= 0) || (nbrOfPostCommaBits >= 25)) { - // No mantissa bit after comma, or all mantissa bits - // (including implicit 1) are at least one bit away from it. - //System.out.println("can't be"); - return false; - } - final int mantissa = 0x00800000|(bits&0x007FFFFF); - final int postCommaMask = ~((-1)<>52))&0x7FF)-1023; - final int nbrOfPostCommaBits = 52 - exponent; - if ((nbrOfPostCommaBits <= 0) || (nbrOfPostCommaBits >= 54)) { - // No mantissa bit after comma, or all mantissa bits - // (including implicit 1) are at least one bit away from it. - return false; - } - final long mantissa = 0x0010000000000000L|(bits&0x000FFFFFFFFFFFFFL); - final long postCommaMask = ~((-1L)< value is NaN or +-Infinity - return !(value-value == 0.0f); - } - - /** - * @param value A double value. - * @return True if the specified value is NaN or +-Infinity, false otherwise. - */ - public static boolean isNaNOrInfinite(double value) { - // value-value is not equal to 0.0 (and is NaN) <-> value is NaN or +-Infinity - return !(value-value == 0.0); - } - - /** - * @param value A float value. - * @return -1 if sign bit is 1, 1 if sign bit is 0. - */ - public static int signFromBit(float value) { - return ((Float.floatToRawIntBits(value)>>30)|1); - } - - /** - * @param value A double value. - * @return -1 if sign bit is 1, 1 if sign bit is 0. - */ - public static long signFromBit(double value) { - // Returning a long, to avoid useless cast into int. - return ((Double.doubleToRawLongBits(value)>>62)|1); - } - - /* - * min/max ranges - */ - - /** - * @return True if the specified value is in the specified range (inclusive), false otherwise. - */ - public static boolean isInRange(int min, int max, int a) { - return (min <= a) && (a <= max); - } - - /** - * @return True if the specified value is in the specified range (inclusive), false otherwise. - */ - public static boolean isInRange(long min, long max, long a) { - return (min <= a) && (a <= max); - } - - /** - * Returns false if any value is NaN. - * - * @return True if the specified value is in the specified range (inclusive), false otherwise. - */ - public static boolean isInRange(float min, float max, float a) { - return (min <= a) && (a <= max); - } - - /** - * Returns false if any value is NaN. - * - * @return True if the specified value is in the specified range (inclusive), false otherwise. - */ - public static boolean isInRange(double min, double max, double a) { - return (min <= a) && (a <= max); - } - - /* - * - */ - - /** - * @return True if does not throw. - * @throws IllegalArgumentException if the specified value is not in the specified range (inclusive). - */ - public static boolean checkIsInRange(int min, int max, int a) { - if (!isInRange(min, max, a)) { - throw new IllegalArgumentException(a+" not in ["+min+","+max+"]"); - } - return true; - } - - /** - * @return True if does not throw. - * @throws IllegalArgumentException if the specified value is not in the specified range (inclusive). - */ - public static boolean checkIsInRange(long min, long max, long a) { - if (!isInRange(min, max, a)) { - throw new IllegalArgumentException(a+" not in ["+min+","+max+"]"); - } - return true; - } - - /** - * @return True if does not throw. - * @throws IllegalArgumentException if the specified value is not in the specified range (inclusive) - * or any parameter is NaN. - */ - public static boolean checkIsInRange(float min, float max, float a) { - if (!isInRange(min, max, a)) { - throw new IllegalArgumentException(a+" not in ["+min+","+max+"]"); - } - return true; - } - - /** - * @return True if does not throw. - * @throws IllegalArgumentException if the specified value is not in the specified range (inclusive) - * or any parameter is NaN. - */ - public static boolean checkIsInRange(double min, double max, double a) { - if (!isInRange(min, max, a)) { - throw new IllegalArgumentException(a+" not in ["+min+","+max+"]"); - } - return true; - } - - /* - * - */ - - /** - * @param min A value. - * @param max A value. - * @param a A value. - * @return min if a <= min, else max if a >= max, else a. - */ - public static int toRange(int min, int max, int a) { - if (a <= min) { - return min; - } else if (a >= max) { - return max; - } else { - return a; - } - } - - /** - * @param min A value. - * @param max A value. - * @param a A value. - * @return min if a <= min, else max if a >= max, else a. - */ - public static long toRange(long min, long max, long a) { - if (a <= min) { - return min; - } else if (a >= max) { - return max; - } else { - return a; - } - } - - /** - * @param min A value. - * @param max A value. - * @param a A value. - * @return min if a <= min, else max if a >= max, else a. - */ - public static float toRange(float min, float max, float a) { - if (a <= min) { - return min; - } else if (a >= max) { - return max; - } else { - return a; - } - } - - /** - * @param min A value. - * @param max A value. - * @param a A value. - * @return min if a <= min, else max if a >= max, else a. - */ - public static double toRange(double min, double max, double a) { - if (a <= min) { - return min; - } else if (a >= max) { - return max; - } else { - return a; - } - } - - /* - * bitwise ranges - */ - - /** - * @param bitSize A number of bits, in [1,32]. - * @return True if the specified value fits as a signed integer - * over the specified number of bits, false otherwise. - * @throws IllegalArgumentException if the specified number of bits is not in [1,32]. - */ - public static boolean isInRangeSigned(int a, int bitSize) { - checkBitSizeForSignedInt(bitSize); - return (minSignedIntForBitSize_noCheck(bitSize) <= a) && (a <= maxSignedIntForBitSize_noCheck(bitSize)); - } - - /** - * @param bitSize A number of bits, in [1,64]. - * @return True if the specified value fits as a signed integer - * over the specified number of bits, false otherwise. - * @throws IllegalArgumentException if the specified number of bits is not in [1,64]. - */ - public static boolean isInRangeSigned(long a, int bitSize) { - checkBitSizeForSignedLong(bitSize); - return (minSignedLongForBitSize_noCheck(bitSize) <= a) && (a <= maxSignedLongForBitSize_noCheck(bitSize)); - } - - /** - * @param bitSize A number of bits, in [1,31]. - * @return True if the specified value fits as an unsigned integer - * over the specified number of bits, false otherwise. - * @throws IllegalArgumentException if the specified number of bits is not in [1,31]. - */ - public static boolean isInRangeUnsigned(int a, int bitSize) { - return isInRange(0, maxUnsignedIntForBitSize(bitSize), a); - } - - /** - * @param bitSize A number of bits, in [1,63]. - * @return True if the specified value fits as an unsigned integer - * over the specified number of bits, false otherwise. - * @throws IllegalArgumentException if the specified number of bits is not in [1,63]. - */ - public static boolean isInRangeUnsigned(long a, int bitSize) { - return isInRange(0, maxUnsignedLongForBitSize(bitSize), a); - } - - /* - * - */ - - /** - * @param bitSize A number of bits, in [1,32]. - * @return True if does not throw. - * @throws IllegalArgumentException if the specified value does not fit - * as a signed integer over the specified number of bits. - */ - public static boolean checkIsInRangeSigned(int a, int bitSize) { - if (!isInRangeSigned(a, bitSize)) { - throw new IllegalArgumentException(a+" does not fit as a signed value over "+bitSize+" bits"); - } - return true; - } - - /** - * @param bitSize A number of bits, in [1,64]. - * @return True if does not throw. - * @throws IllegalArgumentException if the specified value does not fit - * as a signed integer over the specified number of bits. - */ - public static boolean checkIsInRangeSigned(long a, int bitSize) { - if (!isInRangeSigned(a, bitSize)) { - throw new IllegalArgumentException(a+" does not fit as a signed value over "+bitSize+" bits"); - } - return true; - } - - /** - * @param bitSize A number of bits, in [1,31]. - * @return True if does not throw. - * @throws IllegalArgumentException if the specified value does not fit - * as an unsigned integer over the specified number of bits. - */ - public static boolean checkIsInRangeUnsigned(int a, int bitSize) { - if (!isInRangeUnsigned(a, bitSize)) { - throw new IllegalArgumentException(a+" does not fit as an unsigned value over "+bitSize+" bits"); - } - return true; - } - - /** - * @param bitSize A number of bits, in [1,63]. - * @return True if does not throw. - * @throws IllegalArgumentException if the specified value does not fit - * as an unsigned integer over the specified number of bits. - */ - public static boolean checkIsInRangeUnsigned(long a, int bitSize) { - if (!isInRangeUnsigned(a, bitSize)) { - throw new IllegalArgumentException(a+" does not fit as an unsigned value over "+bitSize+" bits"); - } - return true; - } - - /* - * masks (int) - */ - - /** - * @param bitSize A number of bits, in [0,32]. - * @return Mask with the specified number of left bits set with 0, - * and other bits set with 1. - */ - public static int intMaskMSBits0(int bitSize) { - checkIsInRange(0, 32, bitSize); - // Shifting in two times, for >>> doesn't work for full bit size (<< as well). - final int halfish = (bitSize>>1); - return ((-1)>>>halfish)>>>(bitSize-halfish); - } - - /** - * @param bitSize A number of bits, in [0,32]. - * @return Mask with the specified number of left bits set with 1, - * and other bits set with 0. - */ - public static int intMaskMSBits1(int bitSize) { - return ~intMaskMSBits0(bitSize); - } - - /** - * @param bitSize A number of bits, in [0,32]. - * @return Mask with the specified number of right bits set with 0, - * and other bits set with 1. - */ - public static int intMaskLSBits0(int bitSize) { - return ~intMaskMSBits0(32-bitSize); - } - - /** - * @param bitSize A number of bits, in [0,32]. - * @return Mask with the specified number of right bits set with 1, - * and other bits set with 0. - */ - public static int intMaskLSBits1(int bitSize) { - return intMaskMSBits0(32-bitSize); - } - - /* - * masks (long) - */ - - /** - * @param bitSize A number of bits, in [0,64]. - * @return Mask with the specified number of left bits set with 0, - * and other bits set with 1. - */ - public static long longMaskMSBits0(int bitSize) { - checkIsInRange(0, 64, bitSize); - // Shifting in two times, for >>> doesn't work for full bit size (<< as well). - final int halfish = (bitSize>>1); - return ((-1L)>>>halfish)>>>(bitSize-halfish); - } - - /** - * @param bitSize A number of bits, in [0,64]. - * @return Mask with the specified number of left bits set with 1, - * and other bits set with 0. - */ - public static long longMaskMSBits1(int bitSize) { - return ~longMaskMSBits0(bitSize); - } - - /** - * @param bitSize A number of bits, in [0,64]. - * @return Mask with the specified number of right bits set with 0, - * and other bits set with 1. - */ - public static long longMaskLSBits0(int bitSize) { - return ~longMaskMSBits0(64-bitSize); - } - - /** - * @param bitSize A number of bits, in [0,64]. - * @return Mask with the specified number of right bits set with 1, - * and other bits set with 0. - */ - public static long longMaskLSBits1(int bitSize) { - return longMaskMSBits0(64-bitSize); - } - - /* - * signed/unsigned - */ - - /** - * @return Unsigned value corresponding to bits of the specified byte. - */ - public static short byteAsUnsigned(byte value) { - return (short)(((short)value) & 0xFF); - } - - /** - * @return Unsigned value corresponding to bits of the specified short. - */ - public static int shortAsUnsigned(short value) { - return ((int)value) & 0xFFFF; - } - - /** - * @return Unsigned value corresponding to bits of the specified int. - */ - public static long intAsUnsigned(int value) { - return ((long)value) & 0xFFFFFFFF; - } - - /* - * bitwise ranges - */ - - /** - * @return True if a signed int value can be read over the specified number of bits, - * i.e. if it is in [1,32], false otherwise. - */ - public static boolean isValidBitSizeForSignedInt(int bitSize) { - return (bitSize > 0) && (bitSize <= 32); - } - - /** - * @return True if a signed long value can be read over the specified number of bits, - * i.e. if it is in [1,64], false otherwise. - */ - public static boolean isValidBitSizeForSignedLong(int bitSize) { - return (bitSize > 0) && (bitSize <= 64); - } - - /** - * @return True if an unsigned int value can be read over the specified number of bits, - * i.e. if it is in [1,31], false otherwise. - */ - public static boolean isValidBitSizeForUnsignedInt(int bitSize) { - return (bitSize > 0) && (bitSize < 32); - } - - /** - * @return True if an unsigned long value can be read over the specified number of bits, - * i.e. if it is in [1,63], false otherwise. - */ - public static boolean isValidBitSizeForUnsignedLong(int bitSize) { - return (bitSize > 0) && (bitSize < 64); - } - - /* - * - */ - - /** - * @return True if does not throw. - * @throws IllegalArgumentException if a signed int value can't be read over the - * specified number of bits, i.e. if it is not in [1,32]. - */ - public static boolean checkBitSizeForSignedInt(int bitSize) { - if (!isValidBitSizeForSignedInt(bitSize)) { - throw new IllegalArgumentException("bit size ["+bitSize+"] must be in [1,32] for signed int values"); - } - return true; - } - - /** - * @return True if does not throw. - * @throws IllegalArgumentException if a signed long value can't be read over the - * specified number of bits, i.e. if it is not in [1,64]. - */ - public static boolean checkBitSizeForSignedLong(int bitSize) { - if (!isValidBitSizeForSignedLong(bitSize)) { - throw new IllegalArgumentException("bit size ["+bitSize+"] must be in [1,64] for signed long values"); - } - return true; - } - - /** - * @return True if does not throw. - * @throws IllegalArgumentException if an unsigned int value can't be read over the - * specified number of bits, i.e. if it is not in [1,31]. - */ - public static boolean checkBitSizeForUnsignedInt(int bitSize) { - if (!isValidBitSizeForUnsignedInt(bitSize)) { - throw new IllegalArgumentException("bit size ["+bitSize+"] must be in [1,31] for unsigned int values"); - } - return true; - } - - /** - * @return True if does not throw. - * @throws IllegalArgumentException if an unsigned long value can't be read over the - * specified number of bits, i.e. if it is not in [1,63]. - */ - public static boolean checkBitSizeForUnsignedLong(int bitSize) { - if (!isValidBitSizeForUnsignedLong(bitSize)) { - throw new IllegalArgumentException("bit size ["+bitSize+"] must be in [1,63] for unsigned long values"); - } - return true; - } - - /* - * - */ - - /** - * @param bitSize A number of bits in [1,32]. - * @return The min signed int value that can be stored over the specified number of bits. - * @throws IllegalArgumentException if the specified number of bits is out of range. - */ - public static int minSignedIntForBitSize(int bitSize) { - checkBitSizeForSignedInt(bitSize); - return minSignedIntForBitSize_noCheck(bitSize); - } - - /** - * @param bitSize A number of bits in [1,64]. - * @return The min signed long value that can be stored over the specified number of bits. - * @throws IllegalArgumentException if the specified number of bits is out of range. - */ - public static long minSignedLongForBitSize(int bitSize) { - checkBitSizeForSignedLong(bitSize); - return minSignedLongForBitSize_noCheck(bitSize); - } - - /** - * @param bitSize A number of bits in [1,32]. - * @return The max signed int value that can be stored over the specified number of bits. - * @throws IllegalArgumentException if the specified number of bits is out of range. - */ - public static int maxSignedIntForBitSize(int bitSize) { - checkBitSizeForSignedInt(bitSize); - return maxSignedIntForBitSize_noCheck(bitSize); - } - - /** - * @param bitSize A number of bits in [1,64]. - * @return The max signed long value that can be stored over the specified number of bits. - * @throws IllegalArgumentException if the specified number of bits is out of range. - */ - public static long maxSignedLongForBitSize(int bitSize) { - checkBitSizeForSignedLong(bitSize); - return maxSignedLongForBitSize_noCheck(bitSize); - } - - /** - * @param bitSize A number of bits in [1,31]. - * @return The max unsigned int value that can be stored over the specified number of bits. - * @throws IllegalArgumentException if the specified number of bits is out of range. - */ - public static int maxUnsignedIntForBitSize(int bitSize) { - checkBitSizeForUnsignedInt(bitSize); - // i.e. (1<>(31-bitSize)); - } - - /** - * @param bitSize A number of bits in [1,63]. - * @return The max unsigned long value that can be stored over the specified number of bits. - * @throws IllegalArgumentException if the specified number of bits is out of range. - */ - public static long maxUnsignedLongForBitSize(int bitSize) { - checkBitSizeForUnsignedLong(bitSize); - // i.e. (1L<>(63-bitSize)); - } - - /* - * - */ - - /** - * @return The number of bits required to store the specified value as a signed integer, - * i.e. a result in [1,32]. - */ - public static int bitSizeForSignedValue(int value) { - if (value > 0) { - return 33-Integer.numberOfLeadingZeros(value); - } else if (value == 0) { - return 1; - } else { - // Works for Integer.MIN_VALUE as well. - return 33-Integer.numberOfLeadingZeros(-value-1); - } - } - - /** - * @return The number of bits required to store the specified value as a signed integer, - * i.e. a result in [1,64]. - */ - public static int bitSizeForSignedValue(long value) { - if (value > 0) { - return 65-Long.numberOfLeadingZeros(value); - } else if (value == 0) { - return 1; - } else { - // Works for Long.MIN_VALUE as well. - return 65-Long.numberOfLeadingZeros(-value-1); - } - } - - /** - * @param value An integer value in [0,Integer.MAX_VALUE]. - * @return The number of bits required to store the specified value as an unsigned integer, - * i.e. a result in [1,31]. - * @throws IllegalArgumentException if the specified value is < 0. - */ - public static int bitSizeForUnsignedValue(int value) { - if (value > 0) { - return 32-Integer.numberOfLeadingZeros(value); - } else { - if (value == 0) { - return 1; - } else { - throw new IllegalArgumentException("unsigned value ["+value+"] must be >= 0"); - } - } - } - - /** - * @param value An integer value in [0,Long.MAX_VALUE]. - * @return The number of bits required to store the specified value as an unsigned integer, - * i.e. a result in [1,63]. - * @throws IllegalArgumentException if the specified value is < 0. - */ - public static int bitSizeForUnsignedValue(long value) { - if (value > 0) { - return 64-Long.numberOfLeadingZeros(value); - } else { - if (value == 0) { - return 1; - } else { - throw new IllegalArgumentException("unsigned value ["+value+"] must be >= 0"); - } - } - } - - /* - * integer functions - */ - - /** - * @return 1 if the specified value is > 0, 0 if it is 0, -1 otherwise. - */ - public static int signum(int a) { - return (a < 0) ? -1 : ((a == 0) ? 0 : 1); - } - - /** - * @return 1 if the specified value is > 0, 0 if it is 0, -1 otherwise. - */ - public static int signum(long a) { - return (a < 0) ? -1 : ((a == 0) ? 0 : 1); - } - - /** - * @return True if the specified value is even, false otherwise. - */ - public static boolean isEven(int a) { - return ((a&1) == 0); - } - - /** - * @return True if the specified value is even, false otherwise. - */ - public static boolean isEven(long a) { - // faster to work on ints - return isEven((int)a); - } - - /** - * @return True if the specified value is odd, false otherwise. - */ - public static boolean isOdd(int a) { - return ((a&1) != 0); - } - - /** - * @return True if the specified value is odd, false otherwise. - */ - public static boolean isOdd(long a) { - // faster to work on ints - return isOdd((int)a); - } - - /** - * @return True if the specified values are both even or both odd, false otherwise. - */ - public static boolean haveSameEvenness(int a, int b) { - return (((a^b)&1) == 0); - } - - /** - * @return True if the specified values are both even or both odd, false otherwise. - */ - public static boolean haveSameEvenness(long a, long b) { - // faster to work on ints - return haveSameEvenness((int)a, (int)b); - } - - /** - * @return True if the specified values are both >= 0 or both < 0, false otherwise. - */ - public static boolean haveSameSign(int a, int b) { - return ((a^b) >= 0); - } - - /** - * @return True if the specified values are both >= 0 or both < 0, false otherwise. - */ - public static boolean haveSameSign(long a, long b) { - return ((a^b) >= 0); - } - - /** - * @return True if the specified value is a power of two, - * i.e. a value of the form 2^k, with k >= 0. - */ - public static boolean isPowerOfTwo(int a) { - if (a <= 0) { - return false; - } - if (false) { - // also works - return (a & -a) == a; - } - return (a & (a-1)) == 0; - } - - /** - * @return True if the specified value is a power of two, - * i.e. a value of the form 2^k, with k >= 0. - */ - public static boolean isPowerOfTwo(long a) { - if (a <= 0) { - return false; - } - if (false) { - // also works - return (a & -a) == a; - } - return (a & (a-1)) == 0; - } - - /** - * @return True if the specified value is a signed power of two, - * i.e. a value of the form +-2^k, with k >= 0. - */ - public static boolean isSignedPowerOfTwo(int a) { - if (a > 0) { - return (a & (a-1)) == 0; - } else { - if (a == -a) { - // a is 0 or Integer.MIN_VALUE - return (a != 0); - } - return ((-a) & (-a-1)) == 0; - } - } - - /** - * @return True if the specified value is a signed power of two, - * i.e. a value of the form +-2^k, with k >= 0. - */ - public static boolean isSignedPowerOfTwo(long a) { - if (a > 0) { - return (a & (a-1)) == 0; - } else { - if (a == -a) { - // a is 0 or Long.MIN_VALUE - return (a != 0); - } - return ((-a) & (-a-1)) == 0; - } - } - - /** - * @param a A value in [1,Integer.MAX_VALUE]. - * @return The highest power of two <= a. - */ - public static int floorPowerOfTwo(int a) { - if (a <= 0) { - throw new IllegalArgumentException("a ["+a+"] must be > 0"); - } - return Integer.highestOneBit(a); - } - - /** - * @param a A value in [1,Long.MAX_VALUE]. - * @return The highest power of two <= a. - */ - public static long floorPowerOfTwo(long a) { - if (a <= 0) { - throw new IllegalArgumentException("a ["+a+"] must be > 0"); - } - // Faster than copying int method - // (less computations on long). - return 1L << (63 - Long.numberOfLeadingZeros(a)); - } - - /** - * @param a A value in [0,2^30]. - * @return The lowest power of two >= a. - */ - public static int ceilingPowerOfTwo(int a) { - checkIsInRange(0, (1<<30), a); - return (a >= 2) ? Integer.highestOneBit((a-1)<<1) : 1; - } - - /** - * @param a A value in [0,2^62]. - * @return The lowest power of two >= a. - */ - public static long ceilingPowerOfTwo(long a) { - checkIsInRange(0L, (1L<<62), a); - // Faster than copying int method - // (less computations on long). - return 1L << (64 - Long.numberOfLeadingZeros(a - 1)); - } - - /** - * @return Mean without overflow, rounded to the lowest value (i.e. mathematical floor((a+b)/2), using floating point division). - */ - public static int meanLow(int a, int b) { - return (a & b) + ((a ^ b) >> 1); - } - - /** - * @return Mean without overflow, rounded to the lowest value (i.e. mathematical floor((a+b)/2), using floating point division). - */ - public static long meanLow(long a, long b) { - return (a & b) + ((a ^ b) >> 1); - } - - /** - * @return Mean without overflow, rounded to the value of smallest magnitude (i.e. mathematical (a+b)/2, using integer division). - */ - public static int meanSml(int a, int b) { - int result = meanLow(a,b); - if (!haveSameEvenness(a, b)) { - // inexact - if (((a&b) < 0) || (((a|b) < 0) && (a+b < 0))) { - // both < 0, or only one is < 0 and it has the largest magnitude - result++; - } - } - return result; - } - - /** - * @return Mean without overflow, rounded to the value of smallest magnitude (i.e. mathematical (a+b)/2, using integer division). - */ - public static long meanSml(long a, long b) { - long result = meanLow(a,b); - if (!haveSameEvenness(a, b)) { - // inexact - if (((a&b) < 0) || (((a|b) < 0) && (a+b < 0))) { - // both < 0, or only one is < 0 and it has the largest magnitude - result++; - } - } - return result; - } - - /** - * Useful because a positive int value could not represent half the width - * of full int range width, which is mathematically Integer.MAX_VALUE+1. - * - * @return Minus half the range width (inclusive, and rounded to the value of smaller magnitude) - * between the specified bounds. - * @throws IllegalArgumentException if min > max. - */ - public static int negHalfWidth(int min, int max) { - if (min > max) { - throw new IllegalArgumentException("min ["+min+"] must be <= max ["+max+"]"); - } - int mean = meanLow(min, max); - return min - mean - ((min^max)&1); - } - - /** - * Useful because a positive long value could not represent half the width - * of full long range width, which is mathematically Long.MAX_VALUE+1. - * - * @return Minus half the range width (inclusive, and rounded to the value of smaller magnitude) - * between the specified bounds. - * @throws IllegalArgumentException if min > max. - */ - public static long negHalfWidth(long min, long max) { - if (min > max) { - throw new IllegalArgumentException("min ["+min+"] must be <= max ["+max+"]"); - } - long mean = meanLow(min, max); - return min - mean - ((min^max)&1); - } - - /** - * This treatment being designed for optimization, the fact that spot - * is a signed power of two is not checked. - * - * @param value A value. - * @param spot A signed power of two (i.e. a value of the form +-2^k, k >= 0). - * @return value % spot, i.e. a value in ]-|spot|,|spot|[. - */ - public static int moduloSignedPowerOfTwo(int value, int spot) { - if (spot == Integer.MIN_VALUE) { - return (value != Integer.MIN_VALUE) ? value : 0; - } else { - int s = (value>>31); - return ((((value+s) ^ s) & (abs(spot)-1)) + s) ^ s; - } - } - - /** - * This treatment being designed for optimization, the fact that spot - * is a signed power of two is not checked. - * - * @param value A value. - * @param spot A signed power of two (i.e. a value of the form +-2^k, k >= 0). - * @return value % spot, i.e. a value in ]-|spot|,|spot|[. - */ - public static long moduloSignedPowerOfTwo(long value, long spot) { - if (spot == Long.MIN_VALUE) { - return (value != Long.MIN_VALUE) ? value : 0; - } else { - long s = (value>>63); - return ((((value+s) ^ s) & (abs(spot)-1)) + s) ^ s; - } - } - - /** - * @param value An integer value > 0. - * @return The integer part of the logarithm, in base 2, of the specified value, - * i.e. a result in [0,30] - * @throws IllegalArgumentException if the specified value is <= 0. - */ - public static int log2(int value) { - if (value <= 0) { - throw new IllegalArgumentException("value ["+value+"] must be > 0"); - } - return 31-Integer.numberOfLeadingZeros(value); - } - - /** - * @param value An integer value > 0. - * @return The integer part of the logarithm, in base 2, of the specified value, - * i.e. a result in [0,62] - * @throws IllegalArgumentException if the specified value is <= 0. - */ - public static int log2(long value) { - if (value <= 0) { - throw new IllegalArgumentException("value ["+value+"] must be > 0"); - } - return 63-Long.numberOfLeadingZeros(value); - } - - /** - * Possibly faster than java.lang.Math.abs(int). - * - * @return The absolute value, except if value is Integer.MIN_VALUE, for which it returns Integer.MIN_VALUE. - */ - public static int abs(int a) { - return (a^(a>>31))-(a>>31); - } - - /** - * Possibly faster than java.lang.Math.abs(long). - * - * @return The absolute value, except if value is Long.MIN_VALUE, for which it returns Long.MIN_VALUE. - */ - public static long abs(long a) { - return (a^(a>>63))-(a>>63); - } - - /** - * @return The negative of the absolute value (always exact). - */ - public static int absNeg(int a) { - return (a>>31)-(a^(a>>31)); - } - - /** - * @return The negative of the absolute value (always exact). - */ - public static long absNeg(long a) { - return (a>>63)-(a^(a>>63)); - } - - /** - * If the specified value is in int range, the returned value is identical. - * - * @return An int hash of the specified value. - */ - public static int intHash(long a) { - if (false) { - // also works - int hash = ((int)(a>>32)) ^ ((int)a); - if (a < 0) { - hash = -hash-1; - } - return hash; - } - int hash = ((int)(a>>32)) + ((int)a); - if (a < 0) { - hash++; - } - return hash; - } - - /** - * @param a An int value. - * @return The specified value as byte. - * @throws ArithmeticException if the specified value is not in [Byte.MIN_VALUE,Byte.MAX_VALUE] range. - */ - public static byte asByte(int a) { - if (a != (byte)a) { - throw new ArithmeticException("overflow: "+a); - } - return (byte)a; - } - - /** - * @param a A long value. - * @return The specified value as int. - * @throws ArithmeticException if the specified value is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int asInt(long a) { - if (a != (int)a) { - throw new ArithmeticException("overflow: "+a); - } - return (int)a; - } - - /** - * @param a A long value. - * @return The closest int value in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int toInt(long a) { - if (a != (int)a) { - return (a < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; - } - return (int)a; - } - - /** - * @param a An int value. - * @param b An int value. - * @return The mathematical result of a+b. - * @throws ArithmeticException if the mathematical result of a+b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int plusExact(int a, int b) { - final int sum = a + b; - // HD 2-12 Overflow iff both arguments - // have the opposite sign of the result. - if (((a ^ sum) & (b ^ sum)) < 0) { - throw new ArithmeticException("overflow: "+a+"+"+b); - } - return sum; - } - - /** - * @param a A long value. - * @param b A long value. - * @return The mathematical result of a+b. - * @throws ArithmeticException if the mathematical result of a+b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. - */ - public static long plusExact(long a, long b) { - final long sum = a + b; - // HD 2-12 Overflow iff both arguments - // have the opposite sign of the result. - if (((a ^ sum) & (b ^ sum)) < 0) { - throw new ArithmeticException("overflow: "+a+"+"+b); - } - return sum; - } - - /** - * @param a An int value. - * @param b An int value. - * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a+b. - */ - public static int plusBounded(int a, int b) { - return toInt(((long)a) + ((long)b)); - } - - /** - * @param a A long value. - * @param b A long value. - * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a+b. - */ - public static long plusBounded(long a, long b) { - final long sum = a + b; - if (((a ^ sum) & (b ^ sum)) < 0) { - return (sum >= 0) ? Long.MIN_VALUE : Long.MAX_VALUE; - } - return sum; - } - - /** - * @param a An int value. - * @param b An int value. - * @return The mathematical result of a-b. - * @throws ArithmeticException if the mathematical result of a-b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int minusExact(int a, int b) { - final int diff = a - b; - // HD 2-12 Overflow iff the arguments have different signs and - // the sign of the result is different than the sign of "a". - if (((a ^ b) & (a ^ diff)) < 0) { - throw new ArithmeticException("integer overflow"); - } - return diff; - } - - /** - * @param a A long value. - * @param b A long value. - * @return The mathematical result of a-b. - * @throws ArithmeticException if the mathematical result of a-b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. - */ - public static long minusExact(long a, long b) { - final long diff = a - b; - // HD 2-12 Overflow iff the arguments have different signs and - // the sign of the result is different than the sign of "a". - if (((a ^ b) & (a ^ diff)) < 0) { - throw new ArithmeticException("integer overflow"); - } - return diff; - } - - /** - * @param a An int value. - * @param b An int value. - * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a-b. - */ - public static int minusBounded(int a, int b) { - return toInt(((long)a) - ((long)b)); - } - - /** - * @param a A long value. - * @param b A long value. - * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a-b. - */ - public static long minusBounded(long a, long b) { - final long diff = a - b; - if (((a ^ b) & (a ^ diff)) < 0) { - return (diff >= 0) ? Long.MIN_VALUE : Long.MAX_VALUE; - } - return diff; - } - - /** - * @param a An int value. - * @param b An int value. - * @return The mathematical result of a*b. - * @throws ArithmeticException if the mathematical result of a*b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range. - */ - public static int timesExact(int a, int b) { - final long prod = a * (long)b; - if (prod != (int)prod) { - throw new ArithmeticException("overflow: "+a+"*"+b); - } - return (int)prod; - } - - /** - * @param a A long value. - * @param b A long value. - * @return The mathematical result of a*b. - * @throws ArithmeticException if the mathematical result of a*b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range. - */ - public static long timesExact(long a, long b) { - final long prod = a * b; - final long absA = abs(a); - final long absB = abs(b); - if (((absA|absB)>>>31) != 0) { - // Some bits greater than 2^31 that might cause overflow - // Check the result using the divide operator - // and check for the special case of Long.MIN_VALUE * -1 - if (((b != 0) && (prod/b != a)) || - ((a == Long.MIN_VALUE) && (b == -1))) { - throw new ArithmeticException("overflow: "+a+"*"+b); - } - } - return prod; - } - - /** - * @param a An int value. - * @param b An int value. - * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a*b. - */ - public static int timesBounded(int a, int b) { - return (int)(a * (double)b); - } - - /** - * @param a A long value. - * @param b A long value. - * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a*b. - */ - public static long timesBounded(long a, long b) { - final long prod = a * b; - final long absA = abs(a); - final long absB = abs(b); - if (((absA|absB)>>>31) != 0) { - // Some bits greater than 2^31 that might cause overflow - // Check the result using the divide operator - // and check for the special case of Long.MIN_VALUE * -1 - if (((b != 0) && (prod/b != a)) || - ((a == Long.MIN_VALUE) && (b == -1))) { - return ((a^b) >= 0) ? Long.MAX_VALUE : Long.MIN_VALUE; - } - } - return prod; - } - - /* - * powers - */ - - /** - * Returns the exact result, provided it's in double range, - * i.e. if power is in [-1074,1023]. - * - * @param power An int power. - * @return 2^power as a double, or +-Infinity in case of overflow. - */ - public static double twoPow(int power) { - if (power <= -MAX_DOUBLE_EXPONENT) { // Not normal. - if (power >= MIN_DOUBLE_EXPONENT) { // Subnormal. - return Double.longBitsToDouble(0x0008000000000000L>>(-(power+MAX_DOUBLE_EXPONENT))); - } else { // Underflow. - return 0.0; - } - } else if (power > MAX_DOUBLE_EXPONENT) { // Overflow. - return Double.POSITIVE_INFINITY; - } else { // Normal. - return Double.longBitsToDouble(((long)(power+MAX_DOUBLE_EXPONENT))<<52); - } - } - - /** - * @param power An int power. - * @return 2^power as an int. - * @throws ArithmeticException if the mathematical result - * is not in int range, i.e. if power is not in [0,30]. - */ - public static int twoPowAsIntExact(int power) { - if ((power < 0) || (power > 30)) { - throw new ArithmeticException("integer overflow"); - } - return 1 << power; - } - - /** - * @param power An int power. - * @return 2^power as an int, or the closest power of two in int range - * in case of overflow, i.e. if power is not in [0,30]. - */ - public static int twoPowAsIntBounded(int power) { - power = toRange(0, 30, power); - return 1 << power; - } - - /** - * @param power An int power. - * @return 2^power as a long. - * @throws ArithmeticException if the mathematical result - * is not in long range, i.e. if power is not in [0,62]. - */ - public static long twoPowAsLongExact(int power) { - if ((power < 0) || (power > 62)) { - throw new ArithmeticException("long overflow"); - } - return 1L << power; - } - - /** - * @param power An int power. - * @return 2^power as a long, or the closest power of two in long range - * in case of overflow, i.e. if power is not in [0,62]. - */ - public static long twoPowAsLongBounded(int power) { - power = toRange(0, 62, power); - return 1L << power; - } - - /** - * @param a A value. - * @return a*a. - */ - public static int pow2(int a) { - return a*a; - } - - /** - * @param a A value. - * @return a*a. - */ - public static long pow2(long a) { - return a*a; - } - - /** - * @param a A value. - * @return a*a. - */ - public static float pow2(float a) { - return a*a; - } - - /** - * Strict version. - * - * @param a A value. - * @return a*a. - */ - public static strictfp float pow2_strict(float a) { - return a*a; - } - - /** - * @param a A value. - * @return a*a. - */ - public static double pow2(double a) { - return a*a; - } - - /** - * Strict version. - * - * @param a A value. - * @return a*a. - */ - public static strictfp double pow2_strict(double a) { - return a*a; - } - - /** - * @param a A value. - * @return a*a*a. - */ - public static int pow3(int a) { - return a*a*a; - } - - /** - * @param a A value. - * @return a*a*a. - */ - public static long pow3(long a) { - return a*a*a; - } - - /** - * @param a A value. - * @return a*a*a. - */ - public static float pow3(float a) { - return a*a*a; - } - - /** - * Strict version. - * - * @param a A value. - * @return a*a*a. - */ - public static strictfp float pow3_strict(float a) { - return a*a*a; - } - - /** - * @param a A value. - * @return a*a*a. - */ - public static double pow3(double a) { - return a*a*a; - } - - /** - * Strict version. - * - * @param a A value. - * @return a*a*a. - */ - public static strictfp double pow3_strict(double a) { - return a*a*a; - } - - /* - * Accurate +-m*PI/n. - */ - - /** - * @param angRad An angle, in radians. - * @return angRad + 2*PI, accurately computed. - */ - public static double plus2PI(double angRad) { - if (angRad > -Math.PI) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad + TWOPI_LO) + TWOPI_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad + TWOPI_HI) + TWOPI_LO; - } - } - - /** - * Strict version. - * - * @param angRad An angle, in radians. - * @return angRad + 2*PI, accurately computed. - */ - public static strictfp double plus2PI_strict(double angRad) { - if (angRad > -Math.PI) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad + TWOPI_LO) + TWOPI_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad + TWOPI_HI) + TWOPI_LO; - } - } - - /** - * @param angRad An angle, in radians. - * @return angRad - 2*PI, accurately computed. - */ - public static double minus2PI(double angRad) { - if (angRad < Math.PI) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad - TWOPI_LO) - TWOPI_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad - TWOPI_HI) - TWOPI_LO; - } - } - - /** - * Strict version. - * - * @param angRad An angle, in radians. - * @return angRad - 2*PI, accurately computed. - */ - public static strictfp double minus2PI_strict(double angRad) { - if (angRad < Math.PI) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad - TWOPI_LO) - TWOPI_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad - TWOPI_HI) - TWOPI_LO; - } - } - - /** - * @param angRad An angle, in radians. - * @return angRad + PI, accurately computed. - */ - public static double plusPI(double angRad) { - if (angRad > -Math.PI/2) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad + PI_LO) + PI_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad + PI_HI) + PI_LO; - } - } - - /** - * Strict version. - * - * @param angRad An angle, in radians. - * @return angRad + PI, accurately computed. - */ - public static strictfp double plusPI_strict(double angRad) { - if (angRad > -Math.PI/2) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad + PI_LO) + PI_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad + PI_HI) + PI_LO; - } - } - - /** - * @param angRad An angle, in radians. - * @return angRad - PI, accurately computed. - */ - public static double minusPI(double angRad) { - if (angRad < Math.PI/2) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad - PI_LO) - PI_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad - PI_HI) - PI_LO; - } - } - - /** - * Strict version. - * - * @param angRad An angle, in radians. - * @return angRad - PI, accurately computed. - */ - public static strictfp double minusPI_strict(double angRad) { - if (angRad < Math.PI/2) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad - PI_LO) - PI_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad - PI_HI) - PI_LO; - } - } - - /** - * @param angRad An angle, in radians. - * @return angRad + PI/2, accurately computed. - */ - public static double plusPIO2(double angRad) { - if (angRad > -Math.PI/4) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad + PIO2_LO) + PIO2_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad + PIO2_HI) + PIO2_LO; - } - } - - /** - * Strict version. - * - * @param angRad An angle, in radians. - * @return angRad + PI/2, accurately computed. - */ - public static strictfp double plusPIO2_strict(double angRad) { - if (angRad > -Math.PI/4) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad + PIO2_LO) + PIO2_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad + PIO2_HI) + PIO2_LO; - } - } - - /** - * @param angRad An angle, in radians. - * @return angRad - PI/2, accurately computed. - */ - public static double minusPIO2(double angRad) { - if (angRad < Math.PI/4) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad - PIO2_LO) - PIO2_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad - PIO2_HI) - PIO2_LO; - } - } - - /** - * Strict version. - * - * @param angRad An angle, in radians. - * @return angRad - PI/2, accurately computed. - */ - public static strictfp double minusPIO2_strict(double angRad) { - if (angRad < Math.PI/4) { - // LO then HI, for better accuracy (if starting near 0). - return (angRad - PIO2_LO) - PIO2_HI; - } else { - // HI then LO, for better accuracy (if ending near 0). - return (angRad - PIO2_HI) - PIO2_LO; - } - } - - /* - * toString (radix) - */ - - /** - * @param radix Radix to be checked. - * @return True if does not throw. - * @throws IllegalArgumentException if the specified radix is not in [2,36]. - */ - public static boolean checkRadix(int radix) { - if (!isInRange(Character.MIN_RADIX, Character.MAX_RADIX, radix)) { - throw new IllegalArgumentException("radix ["+radix+"] must be in ["+Character.MIN_RADIX+","+Character.MAX_RADIX+"]"); - } - return true; - } - - /** - * @param radix A radix in [2,36]. - * @return Number of characters (minus sign included) - * to represent the specified value in the specified radix. - */ - public static int computeNbrOfChars(int value, int radix) { - if (value < 0) { - // 1 for sign - return 1 + computeNbrOfDigits_negValue(value, radix); - } else { - return computeNbrOfDigits_negValue(-value, radix); - } - } - - /** - * @param radix A radix in [2,36]. - * @return Number of characters (minus sign included) - * to represent the specified value in the specified radix. - */ - public static int computeNbrOfChars(long value, int radix) { - if (value < 0) { - // 1 for sign - return 1 + computeNbrOfDigits_negValue(value, radix); - } else { - return computeNbrOfDigits_negValue(-value, radix); - } - } - - /** - * @param radix A radix in [2,36]. - * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. - * @return Number of characters (minus sign included) - * to represent the specified value in the specified radix. - */ - public static int computeNbrOfChars(int value, int radix, int paddingUpTo) { - if (value < 0) { - // 1 for sign - return 1 + Math.max(paddingUpTo, computeNbrOfDigits_negValue(value, radix)); - } else { - return Math.max(paddingUpTo, computeNbrOfDigits_negValue(-value, radix)); - } - } - - /** - * @param radix A radix in [2,36]. - * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. - * @return Number of characters (minus sign included) - * to represent the specified value in the specified radix. - */ - public static int computeNbrOfChars(long value, int radix, int paddingUpTo) { - if (value < 0) { - // 1 for sign - return 1 + Math.max(paddingUpTo, computeNbrOfDigits_negValue(value, radix)); - } else { - return Math.max(paddingUpTo, computeNbrOfDigits_negValue(-value, radix)); - } - } - - /** - * @param radix A radix in [2,36]. - * @return Number of digits of the specified value in the specified radix. - */ - public static int computeNbrOfDigits(int value, int radix) { - return computeNbrOfDigits_negValue(-abs(value), radix); - } - - /** - * @param radix A radix in [2,36]. - * @return Number of digits of the specified value in the specified radix. - */ - public static int computeNbrOfDigits(long value, int radix) { - return computeNbrOfDigits_negValue(-abs(value), radix); - } - - /** - * @param radix A radix in [2,36]. - * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. - * @return Number of digits of the specified value in the specified radix, - * including the specified padding. - */ - public static int computeNbrOfDigits(int value, int radix, int paddingUpTo) { - return Math.max(paddingUpTo,computeNbrOfDigits(value, radix)); - } - - /** - * @param radix A radix in [2,36]. - * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. - * @return Number of digits of the specified value in the specified radix, - * including the specified padding. - */ - public static int computeNbrOfDigits(long value, int radix, int paddingUpTo) { - return Math.max(paddingUpTo,computeNbrOfDigits(value, radix)); - } - - /** - * This method just delegates to Integer.toString(int), - * but is defined here to complete the API. - * - * @return String representation of the specified value in base 10. - */ - public static String toString(int value) { - return Integer.toString(value); - } - - /** - * This method just delegates to Long.toString(long), - * but is defined here to complete the API. - * - * @return String representation of the specified value in base 10. - */ - public static String toString(long value) { - return Long.toString(value); - } - - /** - * @param radix A radix in [2,36]. - * @return String representation of the specified value in the specified radix. - * @throws IllegalArgumentException if the specified radix is out of range. - */ - public static String toString(int value, int radix) { - return toString(value, radix, 0); - } - - /** - * @param radix A radix in [2,36]. - * @return String representation of the specified value in the specified radix. - * @throws IllegalArgumentException if the specified radix is out of range. - */ - public static String toString(long value, int radix) { - return toString(value, radix, 0); - } - - /** - * @param radix A radix in [2,36]. - * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. - * @return String representation of the specified value in the specified radix. - * @throws IllegalArgumentException if the specified radix is out of range. - */ - public static String toString(int value, int radix, int paddingUpTo) { - // Only one test if radix+paddingUpTo != 10. - if ((radix+paddingUpTo == 10) && (paddingUpTo == 0)) { - // Using JDK's optimized algorithm. - return Integer.toString(value); - } - - int negValue; - final int signSize; - final boolean negative = (value < 0); - if (negative) { - negValue = value; - signSize = 1; - } else { - negValue = -value; - signSize = 0; - } - // Faster if we just use max possible number of characters (33), - // but we prefer to take care of garbage's memory footprint. - // Checks radix. - final int nbrOfChars = signSize + Math.max(paddingUpTo, computeNbrOfDigits_negValue(negValue, radix)); - - final char[] chars = new char[nbrOfChars]; - - int charPos = nbrOfChars; - - final boolean radixIsPowerOfTwo = ((radix & (radix-1)) == 0); - // Not allowing Integer.MIN_VALUE so it can be negated. - if (radixIsPowerOfTwo && (negValue != Integer.MIN_VALUE)) { - final int mask = radix-1; - final int divShift = DIV_SHIFT_BY_RADIX[radix]; - while (negValue <= -radix) { - chars[--charPos] = CHAR_BY_DIGIT[(int)((-negValue) & mask)]; - negValue = -((-negValue) >> divShift); - } - } else { - while (negValue <= -radix) { - chars[--charPos] = CHAR_BY_DIGIT[(int)(-(negValue % radix))]; - negValue /= radix; - } - } - chars[--charPos] = CHAR_BY_DIGIT[(int)(-negValue)]; - - while (charPos > signSize) { - chars[--charPos] = '0'; - } - - if (negative) { - chars[0] = '-'; - } - - return new String(chars); - } - - /** - * @param radix A radix in [2,36]. - * @param paddingUpTo Number of digits (sign excluded) up to which left-padding with zeros is done. - * @return String representation of the specified value in the specified radix. - * @throws IllegalArgumentException if the specified radix is out of range. - */ - public static String toString(long value, int radix, int paddingUpTo) { - // Only one test if radix+paddingUpTo != 10. - if ((radix+paddingUpTo == 10) && (paddingUpTo == 0)) { - // Using JDK's optimized algorithm. - return Long.toString(value); - } - - long negValue; - final int signSize; - final boolean negative = (value < 0); - if (negative) { - negValue = value; - signSize = 1; - } else { - negValue = -value; - signSize = 0; - } - // Checks radix. - final int nbrOfChars = signSize + Math.max(paddingUpTo, computeNbrOfDigits_negValue(negValue, radix)); - - final char[] chars = new char[nbrOfChars]; - - int charPos = nbrOfChars; - - final boolean radixIsPowerOfTwo = ((radix & (radix-1)) == 0); - // Not allowing Long.MIN_VALUE so it can be negated. - if (radixIsPowerOfTwo && (negValue != Long.MIN_VALUE)) { - final int mask = radix-1; - final int divShift = DIV_SHIFT_BY_RADIX[radix]; - while (negValue <= -radix) { - chars[--charPos] = CHAR_BY_DIGIT[(int)((-negValue) & mask)]; - negValue = -((-negValue) >> divShift); - } - } else { - while (negValue <= -radix) { - chars[--charPos] = CHAR_BY_DIGIT[(int)(-(negValue % radix))]; - negValue /= radix; - } - } - chars[--charPos] = CHAR_BY_DIGIT[(int)(-negValue)]; - - while (charPos > signSize) { - chars[--charPos] = '0'; - } - - if (negative) { - chars[0] = '-'; - } - - return new String(chars); - } - - /* - * toString (bits) - */ - - /** - * @param firstBitPos First bit position (inclusive). - * @param lastBitPosExcl Last bit position (exclusive). - * @return True if does not throw. - * @throws IllegalArgumentException if the specified bit range does not fit in a byte. - */ - public static boolean checkBitPositionsByte(int firstBitPos, int lastBitPosExcl) { - return checkBitPositions(firstBitPos, lastBitPosExcl, 8); - } - - /** - * @param firstBitPos First bit position (inclusive). - * @param lastBitPosExcl Last bit position (exclusive). - * @return True if does not throw. - * @throws IllegalArgumentException if the specified bit range does not fit in a short. - */ - public static boolean checkBitPositionsShort(int firstBitPos, int lastBitPosExcl) { - return checkBitPositions(firstBitPos, lastBitPosExcl, 16); - } - - /** - * @param firstBitPos First bit position (inclusive). - * @param lastBitPosExcl Last bit position (exclusive). - * @return True if does not throw. - * @throws IllegalArgumentException if the specified bit range does not fit in an int. - */ - public static boolean checkBitPositionsInt(int firstBitPos, int lastBitPosExcl) { - return checkBitPositions(firstBitPos, lastBitPosExcl, 32); - } - - /** - * @param firstBitPos First bit position (inclusive). - * @param lastBitPosExcl Last bit position (exclusive). - * @return True if does not throw. - * @throws IllegalArgumentException if the specified bit range does not fit in a long. - */ - public static boolean checkBitPositionsLong(int firstBitPos, int lastBitPosExcl) { - return checkBitPositions(firstBitPos, lastBitPosExcl, 64); - } - - /** - * @return String representation of specified bits, in big endian. - */ - public static String toStringBits(byte bits) { - final char[] chars = new char[8]; - int bitIndex = 8; - while (--bitIndex >= 0) { - chars[7-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - } - return new String(chars); - } - - /** - * @return String representation of specified bits, in big endian. - */ - public static String toStringBits(short bits) { - final char[] chars = new char[16]; - int bitIndex = 16; - while (--bitIndex >= 0) { - chars[15-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - } - return new String(chars); - } - - /** - * @return String representation of specified bits, in big endian. - */ - public static String toStringBits(int bits) { - final char[] chars = new char[32]; - int bitIndex = 32; - while (--bitIndex >= 0) { - chars[31-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - } - return new String(chars); - } - - /** - * @return String representation of specified bits, in big endian. - */ - public static String toStringBits(long bits) { - final char[] chars = new char[64]; - int bitIndex = 64; - while (--bitIndex >= 0) { - chars[63-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - } - return new String(chars); - } - - /** - * @param firstBitPos First bit position (inclusive). - * @param lastBitPosExcl Last bit position (exclusive). - * @param bigEndian True for bits to be added in big endian order (MSBit to LSBit) - * false for little endian order. - * @param padding True if underscores must be added instead of out-of-range bits, - * false to just add characters corresponding to in-range bits. - * @return String representation of specified bits. - */ - public static String toStringBits( - byte bits, - int firstBitPos, - int lastBitPosExcl, - boolean bigEndian, - boolean padding) { - checkBitPositionsByte(firstBitPos, lastBitPosExcl); - return toStringBits_0_32_bitPosAlreadyChecked(8,bits, firstBitPos, lastBitPosExcl, bigEndian, padding); - } - - /** - * @param firstBitPos First bit position (inclusive). - * @param lastBitPosExcl Last bit position (exclusive). - * @param bigEndian True for bits to be added in big endian order (MSBit to LSBit) - * false for little endian order. - * @param padding True if underscores must be added instead of out-of-range bits, - * false to just add characters corresponding to in-range bits. - * @return String representation of specified bits. - */ - public static String toStringBits( - short bits, - int firstBitPos, - int lastBitPosExcl, - boolean bigEndian, - boolean padding) { - checkBitPositionsShort(firstBitPos, lastBitPosExcl); - return toStringBits_0_32_bitPosAlreadyChecked(16,bits, firstBitPos, lastBitPosExcl, bigEndian, padding); - } - - /** - * @param firstBitPos First bit position (inclusive). - * @param lastBitPosExcl Last bit position (exclusive). - * @param bigEndian True for bits to be added in big endian order (MSBit to LSBit) - * false for little endian order. - * @param padding True if underscores must be added instead of out-of-range bits, - * false to just add characters corresponding to in-range bits. - * @return String representation of specified bits. - */ - public static String toStringBits( - int bits, - int firstBitPos, - int lastBitPosExcl, - boolean bigEndian, - boolean padding) { - checkBitPositionsInt(firstBitPos, lastBitPosExcl); - return toStringBits_0_32_bitPosAlreadyChecked(32,bits, firstBitPos, lastBitPosExcl, bigEndian, padding); - } - - /** - * @param firstBitPos First bit position (inclusive). - * @param lastBitPosExcl Last bit position (exclusive). - * @param bigEndian True for bits to be added in big endian order (MSBit to LSBit) - * false for little endian order. - * @param padding True if underscores must be added instead of out-of-range bits, - * false to just add characters corresponding to in-range bits. - * @return String representation of specified bits. - */ - public static String toStringBits( - long bits, - int firstBitPos, - int lastBitPosExcl, - boolean bigEndian, - boolean padding) { - checkBitPositionsLong(firstBitPos, lastBitPosExcl); - final int bitSize = 64; - final int bitSizeM1 = bitSize-1; - final int lastBitPos = lastBitPosExcl-1; - if (padding) { - final int nbrOfChars = bitSize; - final char[] chars = new char[nbrOfChars]; - int bitIndex = bitSizeM1; - if (bigEndian) { - final int firstBitIndex = bitSizeM1-lastBitPos; - final int lastBitIndex = bitSizeM1-firstBitPos; - while (bitIndex > lastBitIndex) { - chars[bitSizeM1-bitIndex] = '_'; - --bitIndex; - } - while (bitIndex >= firstBitIndex) { - chars[bitSizeM1-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - --bitIndex; - } - while (bitIndex >= 0) { - chars[bitSizeM1-bitIndex] = '_'; - --bitIndex; - } - } else { - while (bitIndex > lastBitPos) { - chars[bitIndex] = '_'; - --bitIndex; - } - while (bitIndex >= firstBitPos) { - chars[bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - --bitIndex; - } - while (bitIndex >= 0) { - chars[bitIndex] = '_'; - --bitIndex; - } - } - return new String(chars); - } else { - final int nbrOfChars = (lastBitPosExcl - firstBitPos); - final char[] chars = new char[nbrOfChars]; - if (bigEndian) { - final int firstBitIndex = bitSizeM1-lastBitPos; - final int lastBitIndex = bitSizeM1-firstBitPos; - int bitIndex = lastBitIndex; - while (bitIndex >= firstBitIndex) { - chars[lastBitIndex-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - --bitIndex; - } - } else { - int bitIndex = lastBitPos; - while (bitIndex >= firstBitPos) { - chars[bitIndex-firstBitPos] = (char)('0'+((bits>>bitIndex)&1)); - --bitIndex; - } - } - return new String(chars); - } - } - - /* - * toString (floating points) - * - * toStringCSN(double) and toStringNoCSN(double) - * could be made faster, by using directly internals - * of Double.toString(double), but this would require - * copy-paste of much tricky code from JDK, and - * the overhead of our little rework is relatively - * negligible. - */ - - /** - * @param value A double value. - * @return String representing the specified value, - * using "computerized scientific notation", - * which Double.toString(double) uses for non-infinite - * values, when |value| < 1e-3 or |value| >= 1e7. - */ - public static String toStringCSN(double value) { - // Quick case (also to get rid of +-0.0, - // for which Double.toString(double) doesn't use CSN). - if (value == 0.0) { - if (Double.doubleToRawLongBits(value) < 0) { - return "-0.0E0"; - } else { - return "0.0E0"; - } - } - - final double abs = Math.abs(value); - if ((abs >= NO_CSN_MIN_BOUND_INCL) && (abs < NO_CSN_MAX_BOUND_EXCL)) { - final boolean neg = (value < 0.0); - - final String rawAbs = Double.toString(abs); - if (abs >= 1.0) { - /* - * 0123456 - * 12.3456 ===> 1.23456E1 - * 123.0 ===> 1.23E2 - */ - final int dotIndex = rawAbs.indexOf((int)'.'); - final int powerOfTen = dotIndex-1; - final StringBuilder sb = new StringBuilder(); - if (neg) { - sb.append('-'); - } - // Adding unit-or-above digits, with dot after first one. - sb.append(rawAbs.charAt(0)); - sb.append('.'); - sb.append(rawAbs,1,dotIndex); - if ((value != (int)value) || (abs < 10.0)) { - // Adding below-unit digits (possibly just 0 if abs < 10.0, - // to end up for example with "3.0E0" instead of "3.E0"). - sb.append(rawAbs,dotIndex+1,rawAbs.length()); - } - sb.append('E'); - sb.append(CHAR_BY_DIGIT[powerOfTen]); - return sb.toString(); - } else { - /* - * 012345678 - * 0.0123456 ===> 1.23456E-2 - * 0.01 ===> 1.0E-2 - */ - int nonZeroIndex = 1; - while (rawAbs.charAt(++nonZeroIndex) == '0') { - } - // Negative. - final int powerOfTen = 1-nonZeroIndex; - final int nbrOfSignificantDigitsPastDot = (rawAbs.length() - (nonZeroIndex+1)); - final StringBuilder sb = new StringBuilder(); - if (neg) { - sb.append('-'); - } - sb.append(rawAbs.charAt(nonZeroIndex)); - sb.append('.'); - if (nbrOfSignificantDigitsPastDot > 0) { - // If bug 4428022 make rawAbs being something like "0.0010", - // we add the last '0' here after the dot, which is fine. - sb.append(rawAbs,nonZeroIndex+1,rawAbs.length()); - } else { - sb.append('0'); - } - sb.append("E-"); - sb.append(CHAR_BY_DIGIT[-powerOfTen]); - return sb.toString(); - } - } else { - return Double.toString(value); - } - } - - /** - * @param value A double value. - * @return String representing the specified value, - * not in "computerized scientific notation", - * which Double.toString(double) uses for non-infinite - * values, when |value| < 1e-3 or |value| >= 1e7. - */ - public static String toStringNoCSN(double value) { - // Quick case. - // Should also work with long instead of int, - // but less obvious (due to roundings...), - // and we just want to speed up the more common - // case of "small" integer values. - final int intValue = (int)value; - if (value == intValue) { - if (value == 0.0) { - if (Double.doubleToRawLongBits(value) < 0) { - return "-0.0"; - } else { - return "0.0"; - } - } else { - return Integer.toString(intValue)+".0"; - } - } - - final String raw = Double.toString(value); - final double abs = Math.abs(value); - if (abs >= NO_CSN_MAX_BOUND_EXCL) { - if (abs == Double.POSITIVE_INFINITY) { - return raw; - } - /* - * 0123456789 - * 1.234567E5 ===> 123456.7 - * 1.23456E5 ===> 123456.0 (adding 0) - * 1.23E5 ===> 123000.0 - * 1.0E5 ===> 100000.0 - */ - // "." close to start, so using indexOf. - final int dotIndex = raw.indexOf((int)'.'); - // "E" close to end, so using lastIndexOf. - final int eIndex = raw.lastIndexOf((int)'E'); - final int powerOfTen = Integer.parseInt(raw.substring(eIndex+1)); - final int nbrOfSignificantLoDigits = (eIndex - dotIndex - 1); - final int nbrOfZerosToAddBeforeDot = (powerOfTen - nbrOfSignificantLoDigits); - - int start; - int end; - - final StringBuilder sb = new StringBuilder(); - sb.append(raw,0,dotIndex); - if (nbrOfZerosToAddBeforeDot >= 0) { - // Can copy all digits that were between '.' and 'E'. - sb.append(raw,dotIndex+1,eIndex); - for (int i=0;i 0.0001234 - * 1.0E-4 ===> 0.0001 - */ - // "." close to start, so using indexOf. - final int dotIndex = raw.indexOf((int)'.'); - // "E" close to end, so using lastIndexOf. - final int eIndex = raw.lastIndexOf((int)'E'); - // Negative. - final int powerOfTen = Integer.parseInt(raw.substring(eIndex+1)); - final int nbrOfZerosToAddAfterDot = (-powerOfTen-1); - - final StringBuilder sb = new StringBuilder(); - if (value < 0.0) { - sb.append("-0."); - } else { - sb.append("0."); - } - for (int i=0;i>(32-bitSize)); - } - - private static long minSignedLongForBitSize_noCheck(int bitSize) { - // i.e. (-1L<<(bitSize-1)) - return (Long.MIN_VALUE>>(64-bitSize)); - } - - private static int maxSignedIntForBitSize_noCheck(int bitSize) { - // i.e. (1<<(bitSize-1))-1 - return (Integer.MAX_VALUE>>(32-bitSize)); - } - - private static long maxSignedLongForBitSize_noCheck(int bitSize) { - // i.e. (1L<<(bitSize-1))-1 - return (Long.MAX_VALUE>>(64-bitSize)); - } - - /* - * - */ - - /** - * @throws IllegalArgumentException if the specified radix is out of range. - */ - private static int computeNbrOfDigits_negValue(int negValue, int radix) { - checkRadix(radix); - final int maxNbrOfDigits = MAX_NBR_OF_NEG_INT_DIGITS_BY_RADIX[radix]; - int p = radix; - for (int i=1;i -p) { - return i; - } - p *= radix; - } - return maxNbrOfDigits; - } - - /** - * @throws IllegalArgumentException if the specified radix is out of range. - */ - private static int computeNbrOfDigits_negValue(long negValue, int radix) { - checkRadix(radix); - final int maxNbrOfDigits = MAX_NBR_OF_NEG_LONG_DIGITS_BY_RADIX[radix]; - long p = radix; - for (int i=1;i -p) { - return i; - } - p *= radix; - } - return maxNbrOfDigits; - } - - /* - * - */ - - private static boolean checkBitPositions(int firstBitPos, int lastBitPosExcl, int bitSize) { - if ((firstBitPos < 0) || (firstBitPos > lastBitPosExcl) || (lastBitPosExcl > bitSize)) { - throw new IllegalArgumentException( - "bit positions (first="+firstBitPos+",lastExcl="+lastBitPosExcl - +") must verify 0 <= first <= lastExcl <= "+bitSize); - } - return true; - } - - /** - * Common method for byte, short and int. - * Could be a bit faster to have specific methods for byte and short, - * but not much, and that would also make more messy (byte-)code. - * - * @param bitSize Must be in [0,32]. - */ - private static String toStringBits_0_32_bitPosAlreadyChecked( - int bitSize, - int bits, - int firstBitPos, - int lastBitPosExcl, - boolean bigEndian, - boolean padding) { - final int bitSizeM1 = bitSize-1; - final int lastBitPos = lastBitPosExcl-1; - if (padding) { - final int nbrOfChars = bitSize; - final char[] chars = new char[nbrOfChars]; - int bitIndex = bitSizeM1; - if (bigEndian) { - final int firstBitIndex = bitSizeM1-lastBitPos; - final int lastBitIndex = bitSizeM1-firstBitPos; - while (bitIndex > lastBitIndex) { - chars[bitSizeM1-bitIndex] = '_'; - --bitIndex; - } - while (bitIndex >= firstBitIndex) { - chars[bitSizeM1-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - --bitIndex; - } - while (bitIndex >= 0) { - chars[bitSizeM1-bitIndex] = '_'; - --bitIndex; - } - } else { - while (bitIndex > lastBitPos) { - chars[bitIndex] = '_'; - --bitIndex; - } - while (bitIndex >= firstBitPos) { - chars[bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - --bitIndex; - } - while (bitIndex >= 0) { - chars[bitIndex] = '_'; - --bitIndex; - } - } - return new String(chars); - } else { - final int nbrOfChars = (lastBitPosExcl - firstBitPos); - final char[] chars = new char[nbrOfChars]; - if (bigEndian) { - final int firstBitIndex = bitSizeM1-lastBitPos; - final int lastBitIndex = bitSizeM1-firstBitPos; - int bitIndex = lastBitIndex; - while (bitIndex >= firstBitIndex) { - chars[lastBitIndex-bitIndex] = (char)('0'+((bits>>bitIndex)&1)); - --bitIndex; - } - } else { - int bitIndex = lastBitPos; - while (bitIndex >= firstBitPos) { - chars[bitIndex-firstBitPos] = (char)('0'+((bits>>bitIndex)&1)); - --bitIndex; - } - } - return new String(chars); - } - } -} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/StrictFastMath.java b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/StrictFastMath.java deleted file mode 100644 index a61ac9772..000000000 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/StrictFastMath.java +++ /dev/null @@ -1,2998 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.jafama; - -/** - * Strict versions of FastMath methods. - * Cf. README.txt for more info. - */ -public final strictfp class StrictFastMath extends CmnFastMath { - - /* - * We use strictfp for the whole class: - * - for simplicity, - * - to reduce strictfp/non-strictfp switching, which can add overhead, - * when these treatments are used from within strictfp code, - * - to make sure that we only use and return non-extended values, - * else if strictfp gets added later to some treatments they might then - * behave differently due to no longer being inlinable into FP-wide - * expressions, - * - to make sure we don't mistakenly not use it. - */ - - //-------------------------------------------------------------------------- - // CONFIGURATION - //-------------------------------------------------------------------------- - - private static final boolean USE_JDK_MATH = SFM_USE_JDK_MATH; - - private static final boolean USE_REDEFINED_LOG = SFM_USE_REDEFINED_LOG; - - private static final boolean USE_REDEFINED_SQRT = SFM_USE_REDEFINED_SQRT; - - private static final boolean USE_POWTABS_FOR_ASIN = SFM_USE_POWTABS_FOR_ASIN; - - //-------------------------------------------------------------------------- - // PUBLIC METHODS - //-------------------------------------------------------------------------- - - /* - * trigonometry - */ - - /** - * @param angle Angle in radians. - * @return Angle sine. - */ - public static double sin(double angle) { - if (USE_JDK_MATH) { - return StrictMath.sin(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { - if (false) { - // Can give very bad relative error near PI (mod 2*PI). - angle = remainderTwoPi(angle); - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } else { - final long remAndQuad = remainderPiO2(angle); - angle = decodeRemainder(remAndQuad); - final double sin; - final int q = decodeQuadrant(remAndQuad); - if (q == 0) { - sin = sin(angle); - } else if (q == 1) { - sin = cos(angle); - } else if (q == 2) { - sin = -sin(angle); - } else { - sin = -cos(angle); - } - return (negateResult ? -sin : sin); - } - } - // index: possibly outside tables range. - int index = (int)(angle * SIN_COS_INDEXER + 0.5); - double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; - // Making sure index is within tables range. - // Last value of each table is the same than first, - // so we ignore it (tabs size minus one) for modulo. - index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) - double indexSin = MyTSinCos.sinTab[index]; - double indexCos = MyTSinCos.cosTab[index]; - double result = indexSin + delta * (indexCos + delta * (-indexSin * ONE_DIV_F2 + delta * (-indexCos * ONE_DIV_F3 + delta * indexSin * ONE_DIV_F4))); - return negateResult ? -result : result; - } - - /** - * Quick sin, with accuracy of about 1.6e-3 (PI/) - * for |angle| < 6588395.0 (Integer.MAX_VALUE * (2*PI/) - 2) - * (- 2 due to removing PI/2 before using cosine tab), - * and no accuracy at all for larger values. - * - * @param angle Angle in radians. - * @return Angle sine. - */ - public static double sinQuick(double angle) { - if (USE_JDK_MATH) { - return StrictMath.sin(angle); - } - return MyTSinCos.cosTab[((int)(Math.abs(angle-Math.PI/2) * SIN_COS_INDEXER + 0.5)) & (SIN_COS_TABS_SIZE-2)]; - } - - /** - * @param angle Angle in radians. - * @return Angle cosine. - */ - public static double cos(double angle) { - if (USE_JDK_MATH) { - return StrictMath.cos(angle); - } - angle = Math.abs(angle); - if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { - if (false) { - // Can give very bad relative error near PI (mod 2*PI). - angle = remainderTwoPi(angle); - if (angle < 0.0) { - angle = -angle; - } - } else { - final long remAndQuad = remainderPiO2(angle); - angle = decodeRemainder(remAndQuad); - final double cos; - final int q = decodeQuadrant(remAndQuad); - if (q == 0) { - cos = cos(angle); - } else if (q == 1) { - cos = -sin(angle); - } else if (q == 2) { - cos = -cos(angle); - } else { - cos = sin(angle); - } - return cos; - } - } - // index: possibly outside tables range. - int index = (int)(angle * SIN_COS_INDEXER + 0.5); - double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; - // Making sure index is within tables range. - // Last value of each table is the same than first, - // so we ignore it (tabs size minus one) for modulo. - index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) - double indexCos = MyTSinCos.cosTab[index]; - double indexSin = MyTSinCos.sinTab[index]; - return indexCos + delta * (-indexSin + delta * (-indexCos * ONE_DIV_F2 + delta * (indexSin * ONE_DIV_F3 + delta * indexCos * ONE_DIV_F4))); - } - - /** - * Quick cos, with accuracy of about 1.6e-3 (PI/) - * for |angle| < 6588397.0 (Integer.MAX_VALUE * (2*PI/)), - * and no accuracy at all for larger values. - * - * @param angle Angle in radians. - * @return Angle cosine. - */ - public static double cosQuick(double angle) { - if (USE_JDK_MATH) { - return StrictMath.cos(angle); - } - return MyTSinCos.cosTab[((int)(Math.abs(angle) * SIN_COS_INDEXER + 0.5)) & (SIN_COS_TABS_SIZE-2)]; - } - - /** - * Computes sine and cosine together. - * - * @param angle Angle in radians. - * @param cosine (out) Angle cosine. - * @return Angle sine. - */ - public static double sinAndCos(double angle, DoubleWrapper cosine) { - if (USE_JDK_MATH) { - cosine.value = StrictMath.cos(angle); - return StrictMath.sin(angle); - } - // Using the same algorithm than sin(double) method, - // and computing also cosine at the end. - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle > SIN_COS_MAX_VALUE_FOR_INT_MODULO) { - if (false) { - // Can give very bad relative error near PI (mod 2*PI). - angle = remainderTwoPi(angle); - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } else { - final long remAndQuad = remainderPiO2(angle); - angle = decodeRemainder(remAndQuad); - final double sin; - final int q = decodeQuadrant(remAndQuad); - if (q == 0) { - sin = sin(angle); - cosine.value = cos(angle); - } else if (q == 1) { - sin = cos(angle); - cosine.value = -sin(angle); - } else if (q == 2) { - sin = -sin(angle); - cosine.value = -cos(angle); - } else { - sin = -cos(angle); - cosine.value = sin(angle); - } - return (negateResult ? -sin : sin); - } - } - int index = (int)(angle * SIN_COS_INDEXER + 0.5); - double delta = (angle - index * SIN_COS_DELTA_HI) - index * SIN_COS_DELTA_LO; - index &= (SIN_COS_TABS_SIZE-2); // index % (SIN_COS_TABS_SIZE-1) - double indexSin = MyTSinCos.sinTab[index]; - double indexCos = MyTSinCos.cosTab[index]; - // Could factor some multiplications (delta * factorials), but then is less accurate. - cosine.value = indexCos + delta * (-indexSin + delta * (-indexCos * ONE_DIV_F2 + delta * (indexSin * ONE_DIV_F3 + delta * indexCos * ONE_DIV_F4))); - double result = indexSin + delta * (indexCos + delta * (-indexSin * ONE_DIV_F2 + delta * (-indexCos * ONE_DIV_F3 + delta * indexSin * ONE_DIV_F4))); - return negateResult ? -result : result; - } - - /** - * Can have very bad relative error near +-PI/2, - * but of the same magnitude than the relative delta between - * StrictMath.tan(PI/2) and StrictMath.tan(nextDown(PI/2)). - * - * @param angle Angle in radians. - * @return Angle tangent. - */ - public static double tan(double angle) { - if (USE_JDK_MATH) { - return StrictMath.tan(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle > TAN_MAX_VALUE_FOR_INT_MODULO) { - angle = remainderPi(angle); - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } - // index: possibly outside tables range. - int index = (int)(angle * TAN_INDEXER + 0.5); - double delta = (angle - index * TAN_DELTA_HI) - index * TAN_DELTA_LO; - // Making sure index is within tables range. - // index modulo PI, i.e. 2*(virtual tab size minus one). - index &= (2*(TAN_VIRTUAL_TABS_SIZE-1)-1); // index % (2*(TAN_VIRTUAL_TABS_SIZE-1)) - // Here, index is in [0,2*(TAN_VIRTUAL_TABS_SIZE-1)-1], i.e. indicates an angle in [0,PI[. - if (index > (TAN_VIRTUAL_TABS_SIZE-1)) { - index = (2*(TAN_VIRTUAL_TABS_SIZE-1)) - index; - delta = -delta; - negateResult = !negateResult; - } - double result; - if (index < TAN_TABS_SIZE) { - result = MyTTan.tanTab[index] - + delta * (MyTTan.tanDer1DivF1Tab[index] - + delta * (MyTTan.tanDer2DivF2Tab[index] - + delta * (MyTTan.tanDer3DivF3Tab[index] - + delta * MyTTan.tanDer4DivF4Tab[index]))); - } else { // angle in ]TAN_MAX_VALUE_FOR_TABS,TAN_MAX_VALUE_FOR_INT_MODULO], or angle is NaN - // Using tan(angle) == 1/tan(PI/2-angle) formula: changing angle (index and delta), and inverting. - index = (TAN_VIRTUAL_TABS_SIZE-1) - index; - result = 1/(MyTTan.tanTab[index] - - delta * (MyTTan.tanDer1DivF1Tab[index] - - delta * (MyTTan.tanDer2DivF2Tab[index] - - delta * (MyTTan.tanDer3DivF3Tab[index] - - delta * MyTTan.tanDer4DivF4Tab[index])))); - } - return negateResult ? -result : result; - } - - /** - * @param value Value in [-1,1]. - * @return Value arcsine, in radians, in [-PI/2,PI/2]. - */ - public static double asin(double value) { - if (USE_JDK_MATH) { - return StrictMath.asin(value); - } - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - if (value <= ASIN_MAX_VALUE_FOR_TABS) { - int index = (int)(value * ASIN_INDEXER + 0.5); - double delta = value - index * ASIN_DELTA; - double result = MyTAsin.asinTab[index] - + delta * (MyTAsin.asinDer1DivF1Tab[index] - + delta * (MyTAsin.asinDer2DivF2Tab[index] - + delta * (MyTAsin.asinDer3DivF3Tab[index] - + delta * MyTAsin.asinDer4DivF4Tab[index]))); - return negateResult ? -result : result; - } else if (USE_POWTABS_FOR_ASIN && (value <= ASIN_MAX_VALUE_FOR_POWTABS)) { - int index = (int)(powFast(value * ASIN_POWTABS_ONE_DIV_MAX_VALUE, ASIN_POWTABS_POWER) * ASIN_POWTABS_SIZE_MINUS_ONE + 0.5); - double delta = value - MyTAsinPow.asinParamPowTab[index]; - double result = MyTAsinPow.asinPowTab[index] - + delta * (MyTAsinPow.asinDer1DivF1PowTab[index] - + delta * (MyTAsinPow.asinDer2DivF2PowTab[index] - + delta * (MyTAsinPow.asinDer3DivF3PowTab[index] - + delta * MyTAsinPow.asinDer4DivF4PowTab[index]))); - return negateResult ? -result : result; - } else { // value > ASIN_MAX_VALUE_FOR_TABS, or value is NaN - // This part is derived from fdlibm. - if (value < 1.0) { - double t = (1.0 - value)*0.5; - double p = t*(ASIN_PS0+t*(ASIN_PS1+t*(ASIN_PS2+t*(ASIN_PS3+t*(ASIN_PS4+t*ASIN_PS5))))); - double q = 1.0+t*(ASIN_QS1+t*(ASIN_QS2+t*(ASIN_QS3+t*ASIN_QS4))); - double s = sqrt(t); - double z = s+s*(p/q); - double result = ASIN_PIO2_HI-((z+z)-ASIN_PIO2_LO); - return negateResult ? -result : result; - } else { // value >= 1.0, or value is NaN - if (value == 1.0) { - return negateResult ? -Math.PI/2 : Math.PI/2; - } else { - return Double.NaN; - } - } - } - } - - /** - * If value is not NaN and is outside [-1,1] range, closest value in this range is used. - * - * @param value Value in [-1,1]. - * @return Value arcsine, in radians, in [-PI/2,PI/2]. - */ - public static double asinInRange(double value) { - if (value <= -1.0) { - return -Math.PI/2; - } else if (value >= 1.0) { - return Math.PI/2; - } else { - return asin(value); - } - } - - /** - * @param value Value in [-1,1]. - * @return Value arccosine, in radians, in [0,PI]. - */ - public static double acos(double value) { - if (USE_JDK_MATH) { - return StrictMath.acos(value); - } - return Math.PI/2 - asin(value); - } - - /** - * If value is not NaN and is outside [-1,1] range, - * closest value in this range is used. - * - * @param value Value in [-1,1]. - * @return Value arccosine, in radians, in [0,PI]. - */ - public static double acosInRange(double value) { - if (value <= -1.0) { - return Math.PI; - } else if (value >= 1.0) { - return 0.0; - } else { - return acos(value); - } - } - - /** - * @param value A double value. - * @return Value arctangent, in radians, in [-PI/2,PI/2]. - */ - public static double atan(double value) { - if (USE_JDK_MATH) { - return StrictMath.atan(value); - } - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - if (value == 1.0) { - // We want "exact" result for 1.0. - return negateResult ? -Math.PI/4 : Math.PI/4; - } else if (value <= ATAN_MAX_VALUE_FOR_TABS) { - int index = (int)(value * ATAN_INDEXER + 0.5); - double delta = value - index * ATAN_DELTA; - double result = MyTAtan.atanTab[index] - + delta * (MyTAtan.atanDer1DivF1Tab[index] - + delta * (MyTAtan.atanDer2DivF2Tab[index] - + delta * (MyTAtan.atanDer3DivF3Tab[index] - + delta * MyTAtan.atanDer4DivF4Tab[index]))); - return negateResult ? -result : result; - } else { // value > ATAN_MAX_VALUE_FOR_TABS, or value is NaN - // This part is derived from fdlibm. - if (value < TWO_POW_66) { - double x = -1/value; - double x2 = x*x; - double x4 = x2*x2; - double s1 = x2*(ATAN_AT0+x4*(ATAN_AT2+x4*(ATAN_AT4+x4*(ATAN_AT6+x4*(ATAN_AT8+x4*ATAN_AT10))))); - double s2 = x4*(ATAN_AT1+x4*(ATAN_AT3+x4*(ATAN_AT5+x4*(ATAN_AT7+x4*ATAN_AT9)))); - double result = ATAN_HI3-((x*(s1+s2)-ATAN_LO3)-x); - return negateResult ? -result : result; - } else { // value >= 2^66, or value is NaN - if (value != value) { - return Double.NaN; - } else { - return negateResult ? -Math.PI/2 : Math.PI/2; - } - } - } - } - - /** - * For special values for which multiple conventions could be adopted, - * behaves like StrictMath.atan2(double,double). - * - * @param y Coordinate on y axis. - * @param x Coordinate on x axis. - * @return Angle from x axis positive side to (x,y) position, in radians, in [-PI,PI]. - * Angle measure is positive when going from x axis to y axis (positive sides). - */ - public static double atan2(double y, double x) { - if (USE_JDK_MATH) { - return StrictMath.atan2(y,x); - } - /* - * Using sub-methods, to make method lighter for general case, - * and to avoid JIT-optimization crash on NaN. - */ - if (x > 0.0) { - if (y == 0.0) { - // +-0.0 - return y; - } - if (x == Double.POSITIVE_INFINITY) { - return atan2_pinf_yyy(y); - } else { - return atan(y/x); - } - } else if (x < 0.0) { - if (y == 0.0) { - return signFromBit(y) * Math.PI; - } - if (x == Double.NEGATIVE_INFINITY) { - return atan2_ninf_yyy(y); - } else if (y > 0.0) { - return Math.PI/2 - atan(x/y); - } else if (y < 0.0) { - return -Math.PI/2 - atan(x/y); - } else { - return Double.NaN; - } - } else { - return atan2_yyy_zeroOrNaN(y, x); - } - } - - /** - * Gives same result as StrictMath.toRadians for some particular values - * like 90.0, 180.0 or 360.0, but is faster (no division). - * - * @param angdeg Angle value in degrees. - * @return Angle value in radians. - */ - public static double toRadians(double angdeg) { - if (USE_JDK_MATH) { - return StrictMath.toRadians(angdeg); - } - return angdeg * (Math.PI/180); - } - - /** - * Gives same result as StrictMath.toDegrees for some particular values - * like Math.PI/2, Math.PI or 2*Math.PI, but is faster (no division). - * - * @param angrad Angle value in radians. - * @return Angle value in degrees. - */ - public static double toDegrees(double angrad) { - if (USE_JDK_MATH) { - return StrictMath.toDegrees(angrad); - } - return angrad * (180/Math.PI); - } - - /** - * @param sign Sign of the angle: true for positive, false for negative. - * @param degrees Degrees, in [0,180]. - * @param minutes Minutes, in [0,59]. - * @param seconds Seconds, in [0.0,60.0[. - * @return Angle in radians. - */ - public static double toRadians(boolean sign, int degrees, int minutes, double seconds) { - return toRadians(toDegrees(sign, degrees, minutes, seconds)); - } - - /** - * @param sign Sign of the angle: true for positive, false for negative. - * @param degrees Degrees, in [0,180]. - * @param minutes Minutes, in [0,59]. - * @param seconds Seconds, in [0.0,60.0[. - * @return Angle in degrees. - */ - public static double toDegrees(boolean sign, int degrees, int minutes, double seconds) { - double signFactor = sign ? 1.0 : -1.0; - return signFactor * (degrees + (1.0/60)*(minutes + (1.0/60)*seconds)); - } - - /** - * @param angrad Angle in radians. - * @param degrees (out) Degrees, in [0,180]. - * @param minutes (out) Minutes, in [0,59]. - * @param seconds (out) Seconds, in [0.0,60.0[. - * @return true if the resulting angle in [-180deg,180deg] is positive, false if it is negative. - */ - public static boolean toDMS(double angrad, IntWrapper degrees, IntWrapper minutes, DoubleWrapper seconds) { - // Computing longitude DMS. - double tmp = toDegrees(normalizeMinusPiPi(angrad)); - boolean isNeg = (tmp < 0.0); - if (isNeg) { - tmp = -tmp; - } - degrees.value = (int)tmp; - tmp = (tmp-degrees.value)*60.0; - minutes.value = (int)tmp; - seconds.value = Math.min((tmp-minutes.value)*60.0,DOUBLE_BEFORE_60); - return !isNeg; - } - - /** - * NB: Since 2*Math.PI < 2*PI, a span of 2*Math.PI does not mean full angular range. - * ex.: isInClockwiseDomain(0.0, 2*Math.PI, -1e-20) returns false. - * ---> For full angular range, use a span > 2*Math.PI, like 2*PI_SUP constant of this class. - * - * @param startAngRad An angle, in radians. - * @param angSpanRad An angular span, >= 0.0, in radians. - * @param angRad An angle, in radians. - * @return true if angRad is in the clockwise angular domain going from startAngRad, over angSpanRad, - * extremities included, false otherwise. - */ - public static boolean isInClockwiseDomain(double startAngRad, double angSpanRad, double angRad) { - if (Math.abs(angRad) < -TWO_MATH_PI_IN_MINUS_PI_PI) { - // special case for angular values of small magnitude - if (angSpanRad <= 2*Math.PI) { - if (angSpanRad < 0.0) { - // empty domain - return false; - } - // angSpanRad is in [0,2*PI] - startAngRad = normalizeMinusPiPi(startAngRad); - double endAngRad = normalizeMinusPiPi(startAngRad + angSpanRad); - if (startAngRad <= endAngRad) { - return (angRad >= startAngRad) && (angRad <= endAngRad); - } else { - return (angRad >= startAngRad) || (angRad <= endAngRad); - } - } else { // angSpanRad > 2*Math.PI, or is NaN - return (angSpanRad == angSpanRad); - } - } else { - // general case - return (normalizeZeroTwoPi(angRad - startAngRad) <= angSpanRad); - } - } - - /* - * hyperbolic trigonometry - */ - - /** - * Some properties of sinh(x) = (exp(x)-exp(-x))/2: - * 1) defined on ]-Infinity,+Infinity[ - * 2) result in ]-Infinity,+Infinity[ - * 3) sinh(x) = -sinh(-x) (implies sinh(0) = 0) - * 4) sinh(epsilon) ~= epsilon - * 5) lim(sinh(x),x->+Infinity) = +Infinity - * (y increasing exponentially faster than x) - * 6) reaches +Infinity (double overflow) for x >= 710.475860073944, - * i.e. a bit further than exp(x) - * - * @param value A double value. - * @return Value hyperbolic sine. - */ - public static double sinh(double value) { - if (USE_JDK_MATH) { - return StrictMath.sinh(value); - } - // sinh(x) = (exp(x)-exp(-x))/2 - double h; - if (value < 0.0) { - value = -value; - h = -0.5; - } else { - h = 0.5; - } - if (value < 22.0) { - if (value < TWO_POW_N28) { - return (h < 0.0) ? -value : value; - } else { - // sinh(x) - // = (exp(x)-exp(-x))/2 - // = (exp(x)-1/exp(x))/2 - // = (expm1(x) + 1 - 1/(expm1(x)+1))/2 - // = (expm1(x) + (expm1(x)+1)/(expm1(x)+1) - 1/(expm1(x)+1))/2 - // = (expm1(x) + expm1(x)/(expm1(x)+1))/2 - double t = expm1(value); - // Might be more accurate, if value < 1: return h*((t+t)-t*t/(t+1.0)). - return h * (t + t/(t+1.0)); - } - } else if (value < LOG_DOUBLE_MAX_VALUE) { - return h * exp(value); - } else { - double t = exp(value*0.5); - return (h*t)*t; - } - } - - /** - * Some properties of cosh(x) = (exp(x)+exp(-x))/2: - * 1) defined on ]-Infinity,+Infinity[ - * 2) result in [1,+Infinity[ - * 3) cosh(0) = 1 - * 4) cosh(x) = cosh(-x) - * 5) lim(cosh(x),x->+Infinity) = +Infinity - * (y increasing exponentially faster than x) - * 6) reaches +Infinity (double overflow) for x >= 710.475860073944, - * i.e. a bit further than exp(x) - * - * @param value A double value. - * @return Value hyperbolic cosine. - */ - public static double cosh(double value) { - if (USE_JDK_MATH) { - return StrictMath.cosh(value); - } - // cosh(x) = (exp(x)+exp(-x))/2 - if (value < 0.0) { - value = -value; - } - if (value < LOG_TWO_POW_27) { - if (value < TWO_POW_N27) { - // cosh(x) - // = (exp(x)+exp(-x))/2 - // = ((1+x+x^2/2!+...) + (1-x+x^2/2!-...))/2 - // = 1+x^2/2!+x^4/4!+... - // For value of x small in magnitude, the sum of the terms does not add to 1. - return 1; - } else { - // cosh(x) - // = (exp(x)+exp(-x))/2 - // = (exp(x)+1/exp(x))/2 - double t = exp(value); - return 0.5 * (t+1/t); - } - } else if (value < LOG_DOUBLE_MAX_VALUE) { - return 0.5 * exp(value); - } else { - double t = exp(value*0.5); - return (0.5*t)*t; - } - } - - /** - * Much more accurate than cosh(value)-1, - * for arguments (and results) close to zero. - * - * coshm1(-0.0) = -0.0, for homogeneity with - * acosh1p(-0.0) = -0.0. - * - * @param value A double value. - * @return Value hyperbolic cosine, minus 1. - */ - public static double coshm1(double value) { - // cosh(x)-1 = (exp(x)+exp(-x))/2 - 1 - if (value < 0.0) { - value = -value; - } - if (value < LOG_TWO_POW_27) { - if (value < TWO_POW_N27) { - if (value == 0.0) { - // +-0.0 - return value; - } - // Using (expm1(x)+expm1(-x))/2 - // is not accurate for tiny values, - // for expm1 results are of higher - // magnitude than the result and - // of different signs, such as their - // sum is not accurate. - // cosh(x) - 1 - // = (exp(x)+exp(-x))/2 - 1 - // = ((1+x+x^2/2!+...) + (1-x+x^2/2!-...))/2 - 1 - // = x^2/2!+x^4/4!+... - // ~= x^2 * (1/2 + x^2 * 1/24) - // = x^2 * 0.5 (since x < 2^-27) - return 0.5 * value*value; - } else { - // cosh(x) - 1 - // = (exp(x)+exp(-x))/2 - 1 - // = (exp(x)-1+exp(-x)-1)/2 - // = (expm1(x)+expm1(-x))/2 - return 0.5 * (expm1(value)+expm1(-value)); - } - } else if (value < LOG_DOUBLE_MAX_VALUE) { - return 0.5 * exp(value) - 1.0; - } else { - // No need to subtract 1 from result. - double t = exp(value*0.5); - return (0.5*t)*t; - } - } - - /** - * Computes hyperbolic sine and hyperbolic cosine together. - * - * @param value A double value. - * @param hcosine (out) Value hyperbolic cosine. - * @return Value hyperbolic sine. - */ - public static double sinhAndCosh(double value, DoubleWrapper hcosine) { - if (USE_JDK_MATH) { - hcosine.value = StrictMath.cosh(value); - return StrictMath.sinh(value); - } - // Mixup of sinh and cosh treatments: if you modify them, - // you might want to also modify this. - double h; - if (value < 0.0) { - value = -value; - h = -0.5; - } else { - h = 0.5; - } - final double hsine; - // LOG_TWO_POW_27 = 18.714973875118524 - if (value < LOG_TWO_POW_27) { // test from cosh - // sinh - if (value < TWO_POW_N28) { - hsine = (h < 0.0) ? -value : value; - } else { - double t = expm1(value); - hsine = h * (t + t/(t+1.0)); - } - // cosh - if (value < TWO_POW_N27) { - hcosine.value = 1; - } else { - double t = exp(value); - hcosine.value = 0.5 * (t+1/t); - } - } else if (value < 22.0) { // test from sinh - // Here, value is in [18.714973875118524,22.0[. - double t = expm1(value); - hsine = h * (t + t/(t+1.0)); - hcosine.value = 0.5 * (t+1.0); - } else { - if (value < LOG_DOUBLE_MAX_VALUE) { - hsine = h * exp(value); - } else { - double t = exp(value*0.5); - hsine = (h*t)*t; - } - hcosine.value = Math.abs(hsine); - } - return hsine; - } - - /** - * Some properties of tanh(x) = sinh(x)/cosh(x) = (exp(2*x)-1)/(exp(2*x)+1): - * 1) defined on ]-Infinity,+Infinity[ - * 2) result in ]-1,1[ - * 3) tanh(x) = -tanh(-x) (implies tanh(0) = 0) - * 4) tanh(epsilon) ~= epsilon - * 5) lim(tanh(x),x->+Infinity) = 1 - * 6) reaches 1 (double loss of precision) for x = 19.061547465398498 - * - * @param value A double value. - * @return Value hyperbolic tangent. - */ - public static double tanh(double value) { - if (USE_JDK_MATH) { - return StrictMath.tanh(value); - } - // tanh(x) = sinh(x)/cosh(x) - // = (exp(x)-exp(-x))/(exp(x)+exp(-x)) - // = (exp(2*x)-1)/(exp(2*x)+1) - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - double z; - if (value < TANH_1_THRESHOLD) { - if (value < TWO_POW_N55) { - return negateResult ? -value*(1.0-value) : value*(1.0+value); - } else if (value >= 1) { - z = 1.0-2.0/(expm1(value+value)+2.0); - } else { - double t = expm1(-(value+value)); - z = -t/(t+2.0); - } - } else { - z = (value != value) ? Double.NaN : 1.0; - } - return negateResult ? -z : z; - } - - /** - * Some properties of asinh(x) = log(x + sqrt(x^2 + 1)) - * 1) defined on ]-Infinity,+Infinity[ - * 2) result in ]-Infinity,+Infinity[ - * 3) asinh(x) = -asinh(-x) (implies asinh(0) = 0) - * 4) asinh(epsilon) ~= epsilon - * 5) lim(asinh(x),x->+Infinity) = +Infinity - * (y increasing logarithmically slower than x) - * - * @param value A double value. - * @return Value hyperbolic arcsine. - */ - public static double asinh(double value) { - // asinh(x) = log(x + sqrt(x^2 + 1)) - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - double result; - // (about) smallest possible for - // non-log1p case to be accurate. - if (value < ASINH_LOG1P_THRESHOLD) { - // Around this range, FDLIBM uses - // log1p(value+value*value/(1+sqrt(value*value+1))), - // but it's slower, so we don't use it. - /* - * If x is close to zero, log argument is close to 1, - * so to avoid precision loss we use log1p(double), - * with - * (1+x)^p = 1 + p * x + (p*(p-1))/2! * x^2 + (p*(p-1)*(p-2))/3! * x^3 + ... - * (1+x)^p = 1 + p * x * (1 + (p-1)/2 * x * (1 + (p-2)/3 * x + ...) - * (1+x)^0.5 = 1 + 0.5 * x * (1 + (0.5-1)/2 * x * (1 + (0.5-2)/3 * x + ...) - * (1+x^2)^0.5 = 1 + 0.5 * x^2 * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...) - * x + (1+x^2)^0.5 = 1 + x * (1 + 0.5 * x * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...)) - * so - * asinh(x) = log1p(x * (1 + 0.5 * x * (1 + (0.5-1)/2 * x^2 * (1 + (0.5-2)/3 * x^2 + ...))) - */ - final double x = value; - final double x2 = x*x; - // Enough terms for good accuracy, - // given our threshold. - final double argLog1p = (x * - (1 + 0.5 * x - * (1 + (0.5-1)/2 * x2 - * (1 + (0.5-2)/3 * x2 - * (1 + (0.5-3)/4 * x2 - * (1 + (0.5-4)/5 * x2 - )))))); - result = log1p(argLog1p); - } else if (value < ASINH_ACOSH_SQRT_ELISION_THRESHOLD) { - // Around this range, FDLIBM uses - // log(2*value+1/(value+sqrt(value*value+1))), - // but it involves an additional division - // so we don't use it. - result = log(value + sqrt(value*value + 1.0)); - } else { - // log(2*value) would overflow for value > Double.MAX_VALUE/2, - // so we compute otherwise. - result = LOG_2 + log(value); - } - return negateResult ? -result : result; - } - - /** - * Some properties of acosh(x) = log(x + sqrt(x^2 - 1)): - * 1) defined on [1,+Infinity[ - * 2) result in ]0,+Infinity[ (by convention, since cosh(x) = cosh(-x)) - * 3) acosh(1) = 0 - * 4) acosh(1+epsilon) ~= log(1 + sqrt(2*epsilon)) ~= sqrt(2*epsilon) - * 5) lim(acosh(x),x->+Infinity) = +Infinity - * (y increasing logarithmically slower than x) - * - * @param value A double value. - * @return Value hyperbolic arccosine. - */ - public static double acosh(double value) { - if (!(value > 1.0)) { - // NaN, or value <= 1 - if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { - return (value < 1.0) ? Double.NaN : value - 1.0; - } else { - return (value == 1.0) ? 0.0 : Double.NaN; - } - } - double result; - if (value < ASINH_ACOSH_SQRT_ELISION_THRESHOLD) { - // Around this range, FDLIBM uses - // log(2*value-1/(value+sqrt(value*value-1))), - // but it involves an additional division - // so we don't use it. - result = log(value + sqrt(value*value - 1.0)); - } else { - // log(2*value) would overflow for value > Double.MAX_VALUE/2, - // so we compute otherwise. - result = LOG_2 + log(value); - } - return result; - } - - /** - * Much more accurate than acosh(1+value), - * for arguments (and results) close to zero. - * - * acosh1p(-0.0) = -0.0, for homogeneity with - * sqrt(-0.0) = -0.0, which looks about the same - * near 0. - * - * @param value A double value. - * @return Hyperbolic arccosine of (1+value). - */ - public static double acosh1p(double value) { - if (!(value > 0.0)) { - // NaN, or value <= 0. - // If value is -0.0, returning -0.0. - if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { - return (value < 0.0) ? Double.NaN : value; - } else { - return (value == 0.0) ? value : Double.NaN; - } - } - double result; - if (value < (ASINH_ACOSH_SQRT_ELISION_THRESHOLD-1)) { - // acosh(1+x) - // = log((1+x) + sqrt((1+x)^2 - 1)) - // = log(1 + x + sqrt(1 + 2*x + x^2 - 1)) - // = log1p(x + sqrt(2*x + x^2)) - // = log1p(x + sqrt(x * (2 + x)) - result = log1p(value + sqrt(value * (2 + value))); - } else { - result = LOG_2 + log(1+value); - } - return result; - } - - /** - * Some properties of atanh(x) = log((1+x)/(1-x))/2: - * 1) defined on ]-1,1[ - * 2) result in ]-Infinity,+Infinity[ - * 3) atanh(-1) = -Infinity (by continuity) - * 4) atanh(1) = +Infinity (by continuity) - * 5) atanh(epsilon) ~= epsilon - * 6) lim(atanh(x),x->1) = +Infinity - * - * @param value A double value. - * @return Value hyperbolic arctangent. - */ - public static double atanh(double value) { - boolean negateResult = false; - if (value < 0.0) { - value = -value; - negateResult = true; - } - double result; - if (!(value < 1.0)) { - // NaN, or value >= 1 - if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { - result = (value > 1.0) ? Double.NaN : Double.POSITIVE_INFINITY + value; - } else { - result = (value == 1.0) ? Double.POSITIVE_INFINITY : Double.NaN; - } - } else { - // For value < 0.5, FDLIBM uses - // 0.5 * log1p((value+value) + (value+value)*value/(1-value)), - // instead, but this is good enough for us. - // atanh(x) - // = log((1+x)/(1-x))/2 - // = log((1-x+2x)/(1-x))/2 - // = log1p(2x/(1-x))/2 - result = 0.5 * log1p((value+value)/(1.0-value)); - } - return negateResult ? -result : result; - } - - /* - * exponentials - */ - - /** - * @param value A double value. - * @return e^value. - */ - public static double exp(double value) { - if (USE_JDK_MATH) { - return StrictMath.exp(value); - } - // exp(x) = exp([x])*exp(y) - // with [x] the integer part of x, and y = x-[x] - // ===> - // We find an approximation of y, called z. - // ===> - // exp(x) = exp([x])*(exp(z)*exp(epsilon)) - // with epsilon = y - z - // ===> - // We have exp([x]) and exp(z) pre-computed in tables, we "just" have to compute exp(epsilon). - // - // We use the same indexing (cast to int) to compute x integer part and the - // table index corresponding to z, to avoid two int casts. - // Also, to optimize index multiplication and division, we use powers of two, - // so that we can do it with bits shifts. - - if (value > EXP_OVERFLOW_LIMIT) { - return Double.POSITIVE_INFINITY; - } else if (!(value >= EXP_UNDERFLOW_LIMIT)) { - return (value != value) ? Double.NaN : 0.0; - } - - final int indexes = (int)(value*EXP_LO_INDEXING); - - final int valueInt; - if (indexes >= 0) { - valueInt = (indexes>>EXP_LO_INDEXING_DIV_SHIFT); - } else { - valueInt = -((-indexes)>>EXP_LO_INDEXING_DIV_SHIFT); - } - final double hiTerm = MyTExp.expHiTab[valueInt-(int)EXP_UNDERFLOW_LIMIT]; - - final int zIndex = indexes - (valueInt< 0.0) { - if (value == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } - - // For normal values not close to 1.0, we use the following formula: - // log(value) - // = log(2^exponent*1.mantissa) - // = log(2^exponent) + log(1.mantissa) - // = exponent * log(2) + log(1.mantissa) - // = exponent * log(2) + log(1.mantissaApprox) + log(1.mantissa/1.mantissaApprox) - // = exponent * log(2) + log(1.mantissaApprox) + log(1+epsilon) - // = exponent * log(2) + log(1.mantissaApprox) + epsilon-epsilon^2/2+epsilon^3/3-epsilon^4/4+... - // with: - // 1.mantissaApprox <= 1.mantissa, - // log(1.mantissaApprox) in table, - // epsilon = (1.mantissa/1.mantissaApprox)-1 - // - // To avoid bad relative error for small results, - // values close to 1.0 are treated aside, with the formula: - // log(x) = z*(2+z^2*((2.0/3)+z^2*((2.0/5))+z^2*((2.0/7))+...))) - // with z=(x-1)/(x+1) - - double h; - if (value > 0.95) { - if (value < 1.14) { - double z = (value-1.0)/(value+1.0); - double z2 = z*z; - return z*(2+z2*((2.0/3)+z2*((2.0/5)+z2*((2.0/7)+z2*((2.0/9)+z2*((2.0/11))))))); - } - h = 0.0; - } else if (value < DOUBLE_MIN_NORMAL) { - // Ensuring value is normal. - value *= TWO_POW_52; - // log(x*2^52) - // = log(x)-ln(2^52) - // = log(x)-52*ln(2) - h = -52*LOG_2; - } else { - h = 0.0; - } - - int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); - int valueExp = (valueBitsHi>>20)-MAX_DOUBLE_EXPONENT; - // Getting the first LOG_BITS bits of the mantissa. - int xIndex = ((valueBitsHi<<12)>>>(32-LOG_BITS)); - - // 1.mantissa/1.mantissaApprox - 1 - double z = (value * twoPowNormalOrSubnormal(-valueExp)) * MyTLog.logXInvTab[xIndex] - 1; - - z *= (1-z*((1.0/2)-z*((1.0/3)))); - - return h + valueExp * LOG_2 + (MyTLog.logXLogTab[xIndex] + z); - - } else if (value == 0.0) { - return Double.NEGATIVE_INFINITY; - } else { // value < 0.0, or value is NaN - return Double.NaN; - } - } - - /** - * Quick log, with a max relative error of about 1.9e-3 - * for values in ]Double.MIN_NORMAL,+Infinity[, and - * worse accuracy outside this range. - * - * @param value A double value, in ]0,+Infinity[ (strictly positive and finite). - * @return Value logarithm (base e). - */ - public static double logQuick(double value) { - if (USE_JDK_MATH) { - return StrictMath.log(value); - } - /* - * Inverse of Schraudolph's method for exp, is very inaccurate near 1, - * and not that fast (even using floats), especially with added if's - * to deal with values near 1, so we don't use it, and use a simplified - * version of our log's redefined algorithm. - */ - - // Simplified version of log's redefined algorithm: - // log(value) ~= exponent * log(2) + log(1.mantissaApprox) - - double h; - if (value > 0.87) { - if (value < 1.16) { - return 2.0 * (value-1.0)/(value+1.0); - } - h = 0.0; - } else if (value < DOUBLE_MIN_NORMAL) { - value *= TWO_POW_52; - h = -52*LOG_2; - } else { - h = 0.0; - } - - int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); - int valueExp = (valueBitsHi>>20)-MAX_DOUBLE_EXPONENT; - int xIndex = ((valueBitsHi<<12)>>>(32-LOG_BITS)); - - return h + valueExp * LOG_2 + MyTLog.logXLogTab[xIndex]; - } - - /** - * @param value A double value. - * @return Value logarithm (base 10). - */ - public static double log10(double value) { - if (USE_JDK_MATH || (!USE_REDEFINED_LOG)) { - return StrictMath.log10(value); - } - // INV_LOG_10 is < 1, but there is no risk of log(double) - // overflow (positive or negative) while the end result shouldn't, - // since log(Double.MIN_VALUE) and log(Double.MAX_VALUE) have - // magnitudes of just a few hundreds. - return log(value) * INV_LOG_10; - } - - /** - * Much more accurate than log(1+value), - * for arguments (and results) close to zero. - * - * @param value A double value. - * @return Logarithm (base e) of (1+value). - */ - public static double log1p(double value) { - if (USE_JDK_MATH) { - return StrictMath.log1p(value); - } - if (false) { - // This also works. Simpler but a bit slower. - if (value == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } - double valuePlusOne = 1+value; - if (valuePlusOne == 1.0) { - return value; - } else { - return log(valuePlusOne)*(value/(valuePlusOne-1.0)); - } - } - if (value > -1.0) { - if (value == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } - - // ln'(x) = 1/x - // so - // log(x+epsilon) ~= log(x) + epsilon/x - // - // Let u be 1+value rounded: - // 1+value = u+epsilon - // - // log(1+value) - // = log(u+epsilon) - // ~= log(u) + epsilon/value - // We compute log(u) as done in log(double), and then add the corrective term. - - double valuePlusOne = 1.0+value; - if (valuePlusOne == 1.0) { - return value; - } else if (Math.abs(value) < 0.15) { - double z = value/(value+2.0); - double z2 = z*z; - return z*(2+z2*((2.0/3)+z2*((2.0/5)+z2*((2.0/7)+z2*((2.0/9)+z2*((2.0/11))))))); - } - - int valuePlusOneBitsHi = (int)(Double.doubleToRawLongBits(valuePlusOne)>>32) & 0x7FFFFFFF; - int valuePlusOneExp = (valuePlusOneBitsHi>>20)-MAX_DOUBLE_EXPONENT; - // Getting the first LOG_BITS bits of the mantissa. - int xIndex = ((valuePlusOneBitsHi<<12)>>>(32-LOG_BITS)); - - // 1.mantissa/1.mantissaApprox - 1 - double z = (valuePlusOne * twoPowNormalOrSubnormal(-valuePlusOneExp)) * MyTLog.logXInvTab[xIndex] - 1; - - z *= (1-z*((1.0/2)-z*(1.0/3))); - - // Adding epsilon/valuePlusOne to z, - // with - // epsilon = value - (valuePlusOne-1) - // (valuePlusOne + epsilon ~= 1+value (not rounded)) - - return valuePlusOneExp * LOG_2 + MyTLog.logXLogTab[xIndex] + (z + (value - (valuePlusOne-1))/valuePlusOne); - } else if (value == -1.0) { - return Double.NEGATIVE_INFINITY; - } else { // value < -1.0, or value is NaN - return Double.NaN; - } - } - - /* - * powers - */ - - /** - * 1e-13ish accuracy or better on whole double range. - * - * @param value A double value. - * @param power A power. - * @return value^power. - */ - public static double pow(double value, double power) { - if (USE_JDK_MATH) { - return StrictMath.pow(value,power); - } - if (power == 0.0) { - return 1.0; - } else if (power == 1.0) { - return value; - } - if (value <= 0.0) { - // powerInfo: 0 if not integer, 1 if even integer, -1 if odd integer - int powerInfo; - if (Math.abs(power) >= (TWO_POW_52*2)) { - // The binary digit just before comma is outside mantissa, - // thus it is always 0: power is an even integer. - powerInfo = 1; - } else { - // If power's magnitude permits, we cast into int instead of into long, - // as it is faster. - if (Math.abs(power) <= (double)Integer.MAX_VALUE) { - int powerAsInt = (int)power; - if (power == (double)powerAsInt) { - powerInfo = ((powerAsInt & 1) == 0) ? 1 : -1; - } else { // power is not an integer (and not NaN, due to test against Integer.MAX_VALUE) - powerInfo = 0; - } - } else { - long powerAsLong = (long)power; - if (power == (double)powerAsLong) { - powerInfo = ((powerAsLong & 1) == 0) ? 1 : -1; - } else { // power is not an integer, or is NaN - if (power != power) { - return Double.NaN; - } - powerInfo = 0; - } - } - } - - if (value == 0.0) { - if (power < 0.0) { - return (powerInfo < 0) ? 1/value : Double.POSITIVE_INFINITY; - } else { // power > 0.0 (0 and NaN cases already treated) - return (powerInfo < 0) ? value : 0.0; - } - } else { // value < 0.0 - if (value == Double.NEGATIVE_INFINITY) { - if (powerInfo < 0) { // power odd integer - return (power < 0.0) ? -0.0 : Double.NEGATIVE_INFINITY; - } else { // power even integer, or not an integer - return (power < 0.0) ? 0.0 : Double.POSITIVE_INFINITY; - } - } else { - return (powerInfo == 0) ? Double.NaN : powerInfo * exp(power*log(-value)); - } - } - } else { // value > 0.0, or value is NaN - return exp(power*log(value)); - } - } - - /** - * Quick pow, with a max relative error of about 1e-2 - * for value >= Double.MIN_NORMAL and 1e-10 < |value^power| < 1e10, - * of about 6e-2 for value >= Double.MIN_NORMAL and 1e-40 < |value^power| < 1e40, - * and worse accuracy otherwise. - * - * @param value A double value, in ]0,+Infinity[ (strictly positive and finite). - * @param power A double value. - * @return value^power. - */ - public static double powQuick(double value, double power) { - if (USE_JDK_MATH) { - return StrictMath.pow(value,power); - } - return exp(power*logQuick(value)); - } - - /** - * This treatment is somehow accurate for low values of |power|, - * and for |power*getExponent(value)| < 1023 or so (to stay away - * from double extreme magnitudes (large and small)). - * - * @param value A double value. - * @param power A power. - * @return value^power. - */ - public static double powFast(double value, int power) { - if (USE_JDK_MATH) { - return StrictMath.pow(value,power); - } - if (power < 3) { - if (power < 0) { - // Opposite of Integer.MIN_VALUE does not exist as int. - if (power == Integer.MIN_VALUE) { - // Integer.MAX_VALUE = -(power+1) - return 1.0/(powFast(value,Integer.MAX_VALUE) * value); - } else { - return 1.0/powFast(value,-power); - } - } else { - // Here, power is in [0,2]. - if (power == 2) { // Most common case first. - return value * value; - } else if (power == 0) { - return 1.0; - } else { // power == 1 - return value; - } - } - } else { // power >= 4 - double oddRemains = 1.0; - // If power <= 5, faster to finish outside the loop. - while (power > 5) { - // Test if power is odd. - if ((power & 1) != 0) { - oddRemains *= value; - } - value *= value; - power >>= 1; // power = power / 2 - } - // Here, power is in [3,5]. - if (power == 3) { - return oddRemains * value * value * value; - } else { // power in [4,5]. - double v2 = value * value; - if (power == 4) { - return oddRemains * v2 * v2; - } else { // power == 5 - return oddRemains * v2 * v2 * value; - } - } - } - } - - /** - * @param value A float value. - * @return value*value. - */ - public static float pow2(float value) { - return value*value; - } - - /** - * @param value A double value. - * @return value*value. - */ - public static double pow2(double value) { - return value*value; - } - - /** - * @param value A float value. - * @return value*value*value. - */ - public static float pow3(float value) { - return value*value*value; - } - - /** - * @param value A double value. - * @return value*value*value. - */ - public static double pow3(double value) { - return value*value*value; - } - - /* - * roots - */ - - /** - * @param value A double value. - * @return Value square root. - */ - public static double sqrt(double value) { - if (USE_JDK_MATH || (!USE_REDEFINED_SQRT)) { - return StrictMath.sqrt(value); - } - // See cbrt for comments, sqrt uses the same ideas. - - if (!(value > 0.0)) { // value <= 0.0, or value is NaN - if (ANTI_JIT_OPTIM_CRASH_ON_NAN) { - return (value < 0.0) ? Double.NaN : value; - } else { - return (value == 0.0) ? value : Double.NaN; - } - } else if (value == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } - - double h; - if (value < DOUBLE_MIN_NORMAL) { - value *= TWO_POW_52; - h = 2*TWO_POW_N26; - } else { - h = 2.0; - } - - int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); - int valueExponentIndex = (valueBitsHi>>20)+(-MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT); - int xIndex = ((valueBitsHi<<12)>>>(32-SQRT_LO_BITS)); - - double result = MyTSqrt.sqrtXSqrtHiTab[valueExponentIndex] * MyTSqrt.sqrtXSqrtLoTab[xIndex]; - double slope = MyTSqrt.sqrtSlopeHiTab[valueExponentIndex] * MyTSqrt.sqrtSlopeLoTab[xIndex]; - value *= 0.25; - - result += (value - result * result) * slope; - result += (value - result * result) * slope; - return h*(result + (value - result * result) * slope); - } - - /** - * Quick sqrt, with with a max relative error of about 3.41e-2 - * for values in [Double.MIN_NORMAL,Double.MAX_VALUE], and worse - * accuracy outside this range. - * - * @param value A double value. - * @return Value square root. - */ - public static double sqrtQuick(double value) { - if (USE_JDK_MATH) { - return StrictMath.sqrt(value); - } - final long bits = Double.doubleToRawLongBits(value); - /* - * Constant determined empirically, using a random-based metaheuristic. - * Should be possible to find a better one. - */ - return Double.longBitsToDouble((bits+4606859074900000000L)>>>1); - } - - /** - * Quick inverse of square root, with a max relative error of about 3.44e-2 - * for values in [Double.MIN_NORMAL,Double.MAX_VALUE], and worse accuracy - * outside this range. - * - * This implementation uses zero step of Newton's method. - * Here are the max relative errors on [Double.MIN_NORMAL,Double.MAX_VALUE] - * depending on number of steps, if you want to copy-paste this code - * and use your own number: - * n=0: about 3.44e-2 - * n=1: about 1.75e-3 - * n=2: about 4.6e-6 - * n=3: about 3.17e-11 - * n=4: about 3.92e-16 - * n=5: about 3.03e-16 - * - * @param value A double value. - * @return Inverse of value square root. - */ - public static double invSqrtQuick(double value) { - if (USE_JDK_MATH) { - return 1/StrictMath.sqrt(value); - } - /* - * http://en.wikipedia.org/wiki/Fast_inverse_square_root - */ - if (false) { - // With one Newton step (much slower than - // 1/Math.sqrt(double) if not optimized). - final double halfInitial = value * 0.5; - long bits = Double.doubleToRawLongBits(value); - // If n=0, 6910474759270000000L might be better (3.38e-2 max relative error). - bits = 0x5FE6EB50C7B537A9L - (bits>>1); - value = Double.longBitsToDouble(bits); - value = value * (1.5 - halfInitial * value * value); // Newton step, can repeat. - return value; - } else { - return Double.longBitsToDouble(0x5FE6EB50C7B537A9L - (Double.doubleToRawLongBits(value)>>1)); - } - } - - /** - * @param value A double value. - * @return Value cubic root. - */ - public static double cbrt(double value) { - if (USE_JDK_MATH) { - return StrictMath.cbrt(value); - } - double h; - if (value < 0.0) { - if (value == Double.NEGATIVE_INFINITY) { - return Double.NEGATIVE_INFINITY; - } - value = -value; - // Making sure value is normal. - if (value < DOUBLE_MIN_NORMAL) { - value *= (TWO_POW_52*TWO_POW_26); - // h = * / - h = -2*TWO_POW_N26; - } else { - h = -2.0; - } - } else { - if (!(value < Double.POSITIVE_INFINITY)) { // value is +Infinity, or value is NaN - return value; - } - // Making sure value is normal. - if (value < DOUBLE_MIN_NORMAL) { - if (value == 0.0) { - // cbrt(0.0) = 0.0, cbrt(-0.0) = -0.0 - return value; - } - value *= (TWO_POW_52*TWO_POW_26); - h = 2*TWO_POW_N26; - } else { - h = 2.0; - } - } - - // Normal value is (2^ * ). - // First member cubic root is computed, and multiplied with an approximation - // of the cubic root of the second member, to end up with a good guess of - // the result before using Newton's (or Archimedes's) method. - // To compute the cubic root approximation, we use the formula "cbrt(value) = cbrt(x) * cbrt(value/x)", - // choosing x as close to value as possible but inferior to it, so that cbrt(value/x) is close to 1 - // (we could iterate on this method, using value/x as new value for each iteration, - // but finishing with Newton's method is faster). - - // Shift and cast into an int, which overall is faster than working with a long. - int valueBitsHi = (int)(Double.doubleToRawLongBits(value)>>32); - int valueExponentIndex = (valueBitsHi>>20)+(-MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT); - // Getting the first CBRT_LO_BITS bits of the mantissa. - int xIndex = ((valueBitsHi<<12)>>>(32-CBRT_LO_BITS)); - double result = MyTCbrt.cbrtXCbrtHiTab[valueExponentIndex] * MyTCbrt.cbrtXCbrtLoTab[xIndex]; - double slope = MyTCbrt.cbrtSlopeHiTab[valueExponentIndex] * MyTCbrt.cbrtSlopeLoTab[xIndex]; - - // Lowering values to avoid overflows when using Newton's method - // (we will then just have to return twice the result). - // result^3 = value - // (result/2)^3 = value/8 - value *= 0.125; - // No need to divide result here, as division is factorized in result computation tables. - // result *= 0.5; - - // Newton's method, looking for y = x^(1/p): - // y(n) = y(n-1) + (x-y(n-1)^p) * slope(y(n-1)) - // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(x(n-1)^(1/p-1)) - // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(x(n-1)^((1-p)/p)) - // with x(n-1)=y(n-1)^p, i.e.: - // y(n) = y(n-1) + (x-y(n-1)^p) * (1/p)*(y(n-1)^(1-p)) - // - // For p=3: - // y(n) = y(n-1) + (x-y(n-1)^3) * (1/(3*y(n-1)^2)) - - // To save time, we don't recompute the slope between Newton's method steps, - // as initial slope is good enough for a few iterations. - // - // NB: slope = 1/(3*trueResult*trueResult) - // As we have result = trueResult/2 (to avoid overflows), we have: - // slope = 4/(3*result*result) - // = (4/3)*resultInv*resultInv - // with newResultInv = 1/newResult - // = 1/(oldResult+resultDelta) - // = (oldResultInv)*1/(1+resultDelta/oldResult) - // = (oldResultInv)*1/(1+resultDelta*oldResultInv) - // ~= (oldResultInv)*(1-resultDelta*oldResultInv) - // ===> Successive slopes could be computed without division, if needed, - // by computing resultInv (instead of slope right away) and retrieving - // slopes from it. - - result += (value - result * result * result) * slope; - result += (value - result * result * result) * slope; - return h*(result + (value - result * result * result) * slope); - } - - /** - * @return sqrt(x^2+y^2) without intermediate overflow or underflow. - */ - public static double hypot(double x, double y) { - if (USE_JDK_MATH) { - return StrictMath.hypot(x,y); - } - x = Math.abs(x); - y = Math.abs(y); - // Ensuring x <= y. - if (y < x) { - double a = x; - x = y; - y = a; - } else if (!(y >= x)) { // Testing if we have some NaN. - return hypot_NaN(x, y); - } - - if (y-x == y) { - // x too small to subtract from y. - return y; - } else { - double factor; - if (y > HYPOT_MAX_MAG) { - // y is too large: scaling down. - x *= (1/HYPOT_FACTOR); - y *= (1/HYPOT_FACTOR); - factor = HYPOT_FACTOR; - } else if (x < (1/HYPOT_MAX_MAG)) { - // x is too small: scaling up. - x *= HYPOT_FACTOR; - y *= HYPOT_FACTOR; - factor = (1/HYPOT_FACTOR); - } else { - factor = 1.0; - } - return factor * sqrt(x*x+y*y); - } - } - - /** - * @return sqrt(x^2+y^2+z^2) without intermediate overflow or underflow. - */ - public static double hypot(double x, double y, double z) { - if (USE_JDK_MATH) { - // No simple JDK equivalent. - } - x = Math.abs(x); - y = Math.abs(y); - z = Math.abs(z); - /* - * Considering that z magnitude is the most likely to be the smaller, - * hence ensuring z <= y <= x, and not x <= y <= z, for less swaps. - */ - // Ensuring z <= y. - if (z > y) { - // y < z: swapping y and z - double a = z; - z = y; - y = a; - } else if (!(z <= y)) { // Testing if y or z is NaN. - return hypot_NaN(x, y, z); - } - // Ensuring y <= x. - if (z > x) { - // x < z <= y: moving x - double oldZ = z; - z = x; - double oldY = y; - y = oldZ; - x = oldY; - } else if (y > x) { - // z <= x < y: swapping x and y - double a = y; - y = x; - x = a; - } else if (x != x) { // Testing if x is NaN. - return hypot_NaN(x, y, z); - } - - if (x-y == x) { - // y, hence z, too small to subtract from x. - return x; - } else if (y-z == y) { - // z too small to subtract from y, hence x. - double factor; - if (x > HYPOT_MAX_MAG) { - // x is too large: scaling down. - x *= (1/HYPOT_FACTOR); - y *= (1/HYPOT_FACTOR); - factor = HYPOT_FACTOR; - } else if (y < (1/HYPOT_MAX_MAG)) { - // y is too small: scaling up. - x *= HYPOT_FACTOR; - y *= HYPOT_FACTOR; - factor = (1/HYPOT_FACTOR); - } else { - factor = 1.0; - } - return factor * sqrt(x*x+y*y); - } else { - double factor; - if (x > HYPOT_MAX_MAG) { - // x is too large: scaling down. - x *= (1/HYPOT_FACTOR); - y *= (1/HYPOT_FACTOR); - z *= (1/HYPOT_FACTOR); - factor = HYPOT_FACTOR; - } else if (z < (1/HYPOT_MAX_MAG)) { - // z is too small: scaling up. - x *= HYPOT_FACTOR; - y *= HYPOT_FACTOR; - z *= HYPOT_FACTOR; - factor = (1/HYPOT_FACTOR); - } else { - factor = 1.0; - } - // Adding smaller magnitudes together first. - return factor * sqrt(x*x+(y*y+z*z)); - } - } - - /* - * close values - */ - - /** - * @param value A float value. - * @return Floor of value. - */ - public static float floor(float value) { - final int exponent = getExponent(value); - if (exponent < 0) { - // abs(value) < 1. - if (value < 0.0f) { - return -1.0f; - } else { - // 0.0f, or -0.0f if value is -0.0f - return 0.0f * value; - } - } else if (exponent < 23) { - // A bit faster than using casts. - final int bits = Float.floatToRawIntBits(value); - final int anteCommaBits = bits & (0xFF800000>>exponent); - if ((value < 0.0f) && (anteCommaBits != bits)) { - return Float.intBitsToFloat(anteCommaBits) - 1.0f; - } else { - return Float.intBitsToFloat(anteCommaBits); - } - } else { - // +-Infinity, NaN, or a mathematical integer. - return value; - } - } - - /** - * @param value A double value. - * @return Floor of value. - */ - public static double floor(double value) { - if (USE_JDK_MATH) { - return StrictMath.floor(value); - } - if (ANTI_SLOW_CASTS) { - double valueAbs = Math.abs(value); - if (valueAbs <= (double)Integer.MAX_VALUE) { - if (value > 0.0) { - return (double)(int)value; - } else if (value < 0.0) { - double anteCommaDigits = (double)(int)value; - if (value != anteCommaDigits) { - return anteCommaDigits - 1.0; - } else { - return anteCommaDigits; - } - } else { // value is +-0.0 (not NaN due to test against Integer.MAX_VALUE) - return value; - } - } else if (valueAbs < TWO_POW_52) { - // We split the value in two: - // high part, which is a mathematical integer, - // and the rest, for which we can get rid of the - // post comma digits by casting into an int. - double highPart = ((int)(value * TWO_POW_N26)) * TWO_POW_26; - if (value > 0.0) { - return highPart + (double)((int)(value - highPart)); - } else { - double anteCommaDigits = highPart + (double)((int)(value - highPart)); - if (value != anteCommaDigits) { - return anteCommaDigits - 1.0; - } else { - return anteCommaDigits; - } - } - } else { // abs(value) >= 2^52, or value is NaN - return value; - } - } else { - final int exponent = getExponent(value); - if (exponent < 0) { - // abs(value) < 1. - if (value < 0.0) { - return -1.0; - } else { - // 0.0, or -0.0 if value is -0.0 - return 0.0 * value; - } - } else if (exponent < 52) { - // A bit faster than working on bits. - final long matIntPart = (long)value; - final double matIntToValue = value-(double)matIntPart; - if (matIntToValue >= 0.0) { - return (double)matIntPart; - } else { - return (double)(matIntPart - 1); - } - } else { - // +-Infinity, NaN, or a mathematical integer. - return value; - } - } - } - - /** - * @param value A float value. - * @return Ceiling of value. - */ - public static float ceil(float value) { - return -floor(-value); - } - - /** - * @param value A double value. - * @return Ceiling of value. - */ - public static double ceil(double value) { - if (USE_JDK_MATH) { - return StrictMath.ceil(value); - } - return -floor(-value); - } - - /** - * Might have different semantics than StrictMath.round(float), - * see bugs 6430675 and 8010430. - * - * @param value A double value. - * @return Value rounded to nearest int, choosing superior int in case two - * are equally close (i.e. rounding-up). - */ - public static int round(float value) { - /* - * Not delegating to JDK, because we want delegation to provide - * at least as good results, and some supported JDK versions - * have bugged round() methods. - */ - // Algorithm by Dmitry Nadezhin (but replaced an if by a multiply) - // (http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-August/020247.html). - final int bits = Float.floatToRawIntBits(value); - final int biasedExp = ((bits>>23)&0xFF); - // Shift to get rid of bits past comma except first one: will need to - // 1-shift to the right to end up with correct magnitude. - final int shift = (23 - 1 + MAX_FLOAT_EXPONENT) - biasedExp; - if ((shift & -32) == 0) { - int bitsSignum = (((bits >> 31) << 1) + 1); - // shift in [0,31], so unbiased exp in [-9,22]. - int extendedMantissa = (0x00800000 | (bits & 0x007FFFFF)) * bitsSignum; - // If value is positive and first bit past comma is 0, rounding - // to lower integer, else to upper one, which is what "+1" and - // then ">>1" do. - return ((extendedMantissa >> shift) + 1) >> 1; - } else { - // +-Infinity, NaN, or a mathematical integer, or tiny. - if (false && ANTI_SLOW_CASTS) { // not worth it - if (Math.abs(value) >= -(float)Integer.MIN_VALUE) { - // +-Infinity or a mathematical integer (mostly) out of int range. - return (value < 0.0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; - } - // NaN or a mathematical integer (mostly) in int range. - } - return (int)value; - } - } - - /** - * Might have different semantics than StrictMath.round(double), - * see bugs 6430675 and 8010430. - * - * @param value A double value. - * @return Value rounded to nearest long, choosing superior long in case two - * are equally close (i.e. rounding-up). - */ - public static long round(double value) { - /* - * Not delegating to JDK, because we want delegation to provide - * at least as good results, and some supported JDK versions - * have bugged round() methods. - */ - final long bits = Double.doubleToRawLongBits(value); - final int biasedExp = (((int)(bits>>52))&0x7FF); - // Shift to get rid of bits past comma except first one: will need to - // 1-shift to the right to end up with correct magnitude. - final int shift = (52 - 1 + MAX_DOUBLE_EXPONENT) - biasedExp; - if ((shift & -64) == 0) { - long bitsSignum = (((bits >> 63) << 1) + 1); - // shift in [0,63], so unbiased exp in [-12,51]. - long extendedMantissa = (0x0010000000000000L | (bits & 0x000FFFFFFFFFFFFFL)) * bitsSignum; - // If value is positive and first bit past comma is 0, rounding - // to lower integer, else to upper one, which is what "+1" and - // then ">>1" do. - return ((extendedMantissa >> shift) + 1L) >> 1; - } else { - // +-Infinity, NaN, or a mathematical integer, or tiny. - if (ANTI_SLOW_CASTS) { - if (Math.abs(value) >= -(double)Long.MIN_VALUE) { - // +-Infinity or a mathematical integer (mostly) out of long range. - return (value < 0.0) ? Long.MIN_VALUE : Long.MAX_VALUE; - } - // NaN or a mathematical integer (mostly) in long range. - } - return (long)value; - } - } - - /** - * @param value A float value. - * @return Value rounded to nearest int, choosing even int in case two - * are equally close. - */ - public static int roundEven(float value) { - final int sign = signFromBit(value); - value = Math.abs(value); - if (ANTI_SLOW_CASTS) { - if (value < TWO_POW_23_F) { - // Getting rid of post-comma bits. - value = ((value + TWO_POW_23_F) - TWO_POW_23_F); - return sign * (int)value; - } else if (value < (float)Integer.MAX_VALUE) { // "<=" doesn't work, because of float precision - // value is in [-Integer.MAX_VALUE,Integer.MAX_VALUE] - return sign * (int)value; - } - } else { - if (value < TWO_POW_23_F) { - // Getting rid of post-comma bits. - value = ((value + TWO_POW_23_F) - TWO_POW_23_F); - } - } - return (int)(sign * value); - } - - /** - * @param value A double value. - * @return Value rounded to nearest long, choosing even long in case two - * are equally close. - */ - public static long roundEven(double value) { - final int sign = (int)signFromBit(value); - value = Math.abs(value); - if (value < TWO_POW_52) { - // Getting rid of post-comma bits. - value = ((value + TWO_POW_52) - TWO_POW_52); - } - if (ANTI_SLOW_CASTS) { - if (value <= (double)Integer.MAX_VALUE) { - // value is in [-Integer.MAX_VALUE,Integer.MAX_VALUE] - return sign * (int)value; - } - } - return (long)(sign * value); - } - - /** - * @param value A float value. - * @return The float mathematical integer closest to the specified value, - * choosing even one if two are equally close, or respectively - * NaN, +-Infinity or +-0.0f if the value is any of these. - */ - public static float rint(float value) { - final int sign = signFromBit(value); - value = Math.abs(value); - if (value < TWO_POW_23_F) { - // Getting rid of post-comma bits. - value = ((TWO_POW_23_F + value ) - TWO_POW_23_F); - } - // Restoring original sign. - return sign * value; - } - - /** - * @param value A double value. - * @return The double mathematical integer closest to the specified value, - * choosing even one if two are equally close, or respectively - * NaN, +-Infinity or +-0.0 if the value is any of these. - */ - public static double rint(double value) { - if (USE_JDK_MATH) { - return StrictMath.rint(value); - } - final int sign = (int)signFromBit(value); - value = Math.abs(value); - if (value < TWO_POW_52) { - // Getting rid of post-comma bits. - value = ((TWO_POW_52 + value ) - TWO_POW_52); - } - // Restoring original sign. - return sign * value; - } - - /* - * close int values - * - * Never delegating to JDK for these methods, for we should always - * be faster and exact, and JDK doesn't exactly have such methods. - */ - - /** - * @param value A double value. - * @return Floor of value as int, or closest int if floor is out - * of int range, or 0 if value is NaN. - */ - public static int floorToInt(double value) { - int valueInt = (int) value; - if (value < 0.0) { - if (value == (double) valueInt) { - return valueInt; - } else { - if (valueInt == Integer.MIN_VALUE) { - return valueInt; - } else { - return valueInt - 1; - } - } - } else { // >= 0 or NaN. - return valueInt; - } - } - - /** - * @param value A double value. - * @return Ceiling of value as int, or closest int if ceiling is out - * of int range, or 0 if value is NaN. - */ - public static int ceilToInt(double value) { - int valueInt = (int) value; - if (value > 0.0) { - if (value == (double) valueInt) { - return valueInt; - } else { - if (valueInt == Integer.MAX_VALUE) { - return valueInt; - } else { - return valueInt + 1; - } - } - } else { // <= 0 or NaN. - return valueInt; - } - } - - /** - * @param value A double value. - * @return Value rounded to nearest int, choosing superior int in case two - * are equally close (i.e. rounding-up). - */ - public static int roundToInt(double value) { - /* - * We don't gain much by reimplementing rounding, except for - * pathologically large values, which should not be a common case - * when dealing with ints, so we just use round(double). - */ - return NumbersUtils.toInt(round(value)); - } - - /** - * @param value A double value. - * @return Value rounded to nearest int, choosing even int in case two - * are equally close. - */ - public static int roundEvenToInt(double value) { - final int sign = (int)signFromBit(value); - value = Math.abs(value); - /* - * Applying the post-comma bits removal logic even if value is out - * of int range, to avoid a test, for it doesn't mess up the result, - * and we want to optimize for the case of values in int range. - */ - value = ((value + TWO_POW_52) - TWO_POW_52); - return (int)(sign * value); - } - - /* - * ranges - */ - - /** - * @param min A float value. - * @param max A float value. - * @param value A float value. - * @return min if value < min, max if value > max, value otherwise. - */ - public static float toRange(float min, float max, float value) { - return NumbersUtils.toRange(min, max, value); - } - - /** - * @param min A double value. - * @param max A double value. - * @param value A double value. - * @return min if value < min, max if value > max, value otherwise. - */ - public static double toRange(double min, double max, double value) { - return NumbersUtils.toRange(min, max, value); - } - - /* - * binary operators (/,%) - */ - - /** - * Returns dividend - divisor * n, where n is the mathematical integer - * closest to dividend/divisor. - * If dividend/divisor is equally close to surrounding integers, - * we choose n to be the integer of smallest magnitude, which makes - * this treatment differ from StrictMath.IEEEremainder(double,double), - * where n is chosen to be the even integer. - * Note that the choice of n is not done considering the double - * approximation of dividend/divisor, because it could cause - * result to be outside [-|divisor|/2,|divisor|/2] range. - * The practical effect is that if multiple results would be possible, - * we always choose the result that is the closest to (and has the same - * sign as) the dividend. - * Ex. : - * - for (-3.0,2.0), this method returns -1.0, - * whereas StrictMath.IEEEremainder returns 1.0. - * - for (-5.0,2.0), both this method and StrictMath.IEEEremainder return -1.0. - * - * If the remainder is zero, its sign is the same as the sign of the first argument. - * If either argument is NaN, or the first argument is infinite, - * or the second argument is positive zero or negative zero, - * then the result is NaN. - * If the first argument is finite and the second argument is - * infinite, then the result is the same as the first argument. - * - * NB: - * - Modulo operator (%) returns a value in ]-|divisor|,|divisor|[, - * which sign is the same as dividend. - * - As for modulo operator, the sign of the divisor has no effect on the result. - * - On some architecture, % operator has been observed to return NaN - * for some subnormal values of divisor, when dividend exponent is 1023, - * which impacts the correctness of this method. - * - * @param dividend Dividend. - * @param divisor Divisor. - * @return Remainder of dividend/divisor, i.e. a value in [-|divisor|/2,|divisor|/2]. - */ - public static double remainder(double dividend, double divisor) { - if (Double.isInfinite(divisor)) { - if (Double.isInfinite(dividend)) { - return Double.NaN; - } else { - return dividend; - } - } - double value = dividend % divisor; - if (Math.abs(value+value) > Math.abs(divisor)) { - return value + ((value > 0.0) ? -Math.abs(divisor) : Math.abs(divisor)); - } else { - return value; - } - } - - /** - * @param angle Angle in radians. - * @return The same angle, in radians, but in [-PI,PI]. - */ - public static double normalizeMinusPiPi(double angle) { - // Not modifying values in output range. - if ((angle >= -Math.PI) && (angle <= Math.PI)) { - return angle; - } - return remainderTwoPi(angle); - } - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return The same angle, in radians, but in [-PI,PI]. - */ - public static double normalizeMinusPiPiFast(double angle) { - // Not modifying values in output range. - if ((angle >= -Math.PI) && (angle <= Math.PI)) { - return angle; - } - return remainderTwoPiFast(angle); - } - - /** - * @param angle Angle in radians. - * @return The same angle, in radians, but in [0,2*PI]. - */ - public static double normalizeZeroTwoPi(double angle) { - // Not modifying values in output range. - if ((angle >= 0.0) && (angle <= 2*Math.PI)) { - return angle; - } - angle = remainderTwoPi(angle); - if (angle < 0.0) { - // LO then HI is theoretically better (when starting near 0). - return (angle + TWOPI_LO) + TWOPI_HI; - } else { - return angle; - } - } - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return The same angle, in radians, but in [0,2*PI]. - */ - public static double normalizeZeroTwoPiFast(double angle) { - // Not modifying values in output range. - if ((angle >= 0.0) && (angle <= 2*Math.PI)) { - return angle; - } - angle = remainderTwoPiFast(angle); - if (angle < 0.0) { - // LO then HI is theoretically better (when starting near 0). - return (angle + TWOPI_LO) + TWOPI_HI; - } else { - return angle; - } - } - - /** - * @param angle Angle in radians. - * @return Angle value modulo PI, in radians, in [-PI/2,PI/2]. - */ - public static double normalizeMinusHalfPiHalfPi(double angle) { - // Not modifying values in output range. - if ((angle >= -Math.PI/2) && (angle <= Math.PI/2)) { - return angle; - } - return remainderPi(angle); - } - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return Angle value modulo PI, in radians, in [-PI/2,PI/2]. - */ - public static double normalizeMinusHalfPiHalfPiFast(double angle) { - // Not modifying values in output range. - if ((angle >= -Math.PI/2) && (angle <= Math.PI/2)) { - return angle; - } - return remainderPiFast(angle); - } - - /* - * floating points utils - */ - - /** - * @param value A float value. - * @return true if the specified value is NaN or +-Infinity, false otherwise. - */ - public static boolean isNaNOrInfinite(float value) { - return NumbersUtils.isNaNOrInfinite(value); - } - - /** - * @param value A double value. - * @return true if the specified value is NaN or +-Infinity, false otherwise. - */ - public static boolean isNaNOrInfinite(double value) { - return NumbersUtils.isNaNOrInfinite(value); - } - - /** - * @param value A float value. - * @return Value unbiased exponent. - */ - public static int getExponent(float value) { - return ((Float.floatToRawIntBits(value)>>23)&0xFF)-MAX_FLOAT_EXPONENT; - } - - /** - * @param value A double value. - * @return Value unbiased exponent. - */ - public static int getExponent(double value) { - return (((int)(Double.doubleToRawLongBits(value)>>52))&0x7FF)-MAX_DOUBLE_EXPONENT; - } - - /** - * @param value A float value. - * @return -1.0f if the specified value is < 0, 1.0f if it is > 0, - * and the value itself if it is NaN or +-0.0f. - */ - public static float signum(float value) { - if (USE_JDK_MATH) { - return StrictMath.signum(value); - } - if ((value == 0.0f) || (value != value)) { - return value; - } - return (float)signFromBit(value); - } - - /** - * @param value A double value. - * @return -1.0 if the specified value is < 0, 1.0 if it is > 0, - * and the value itself if it is NaN or +-0.0. - */ - public static double signum(double value) { - if (USE_JDK_MATH) { - return StrictMath.signum(value); - } - if ((value == 0.0) || (value != value)) { - return value; - } - if (ANTI_SLOW_CASTS) { - return (double)(int)signFromBit(value); - } else { - return (double)signFromBit(value); - } - } - - /** - * @param value A float value. - * @return -1 if sign bit is 1, 1 if sign bit is 0. - */ - public static int signFromBit(float value) { - return ((Float.floatToRawIntBits(value)>>30)|1); - } - - /** - * @param value A double value. - * @return -1 if sign bit is 1, 1 if sign bit is 0. - */ - public static long signFromBit(double value) { - // Returning a long, to avoid useless cast into int. - return ((Double.doubleToRawLongBits(value)>>62)|1); - } - - /** - * A sign of NaN is interpreted as positive. - * - * @param magnitude A float value. - * @param sign A float value. - * @return A value with the magnitude of the first argument, and the sign - * of the second argument. - */ - public static float copySign(float magnitude, float sign) { - return Float.intBitsToFloat( - (Float.floatToRawIntBits((sign != sign) ? 1.0f : sign) & Integer.MIN_VALUE) - | (Float.floatToRawIntBits(magnitude) & Integer.MAX_VALUE)); - } - - /** - * A sign of NaN is interpreted as positive. - * - * @param magnitude A double value. - * @param sign A double value. - * @return A value with the magnitude of the first argument, and the sign - * of the second argument. - */ - public static double copySign(double magnitude, double sign) { - return Double.longBitsToDouble( - (Double.doubleToRawLongBits((sign != sign) ? 1.0 : sign) & Long.MIN_VALUE) - | (Double.doubleToRawLongBits(magnitude) & Long.MAX_VALUE)); - } - - /** - * The ULP (Unit in the Last Place) is the distance to the next value larger - * in magnitude. - * - * @param value A float value. - * @return The size of an ulp of the specified value, or Float.MIN_VALUE - * if it is +-0.0f, or +Infinity if it is +-Infinity, or NaN - * if it is NaN. - */ - public static float ulp(float value) { - if (USE_JDK_MATH) { - return StrictMath.ulp(value); - } - /* - * Look-up table not really worth it in micro-benchmark, - * so should be worse with cache-misses. - */ - final int exponent = getExponent(value); - if (exponent >= (MIN_FLOAT_NORMAL_EXPONENT+23)) { - if (exponent == MAX_FLOAT_EXPONENT+1) { - // NaN or +-Infinity - return Math.abs(value); - } - // normal: returning 2^(exponent-23) - return Float.intBitsToFloat((exponent+(MAX_FLOAT_EXPONENT-23))<<23); - } else { - if (exponent == MIN_FLOAT_NORMAL_EXPONENT-1) { - // +-0.0f or subnormal - return Float.MIN_VALUE; - } - // subnormal result - return Float.intBitsToFloat(1<<(exponent-MIN_FLOAT_NORMAL_EXPONENT)); - } - } - - /** - * The ULP (Unit in the Last Place) is the distance to the next value larger - * in magnitude. - * - * @param value A double value. - * @return The size of an ulp of the specified value, or Double.MIN_VALUE - * if it is +-0.0, or +Infinity if it is +-Infinity, or NaN - * if it is NaN. - */ - public static double ulp(double value) { - if (USE_JDK_MATH) { - return StrictMath.ulp(value); - } - /* - * Look-up table not really worth it in micro-benchmark, - * so should be worse with cache-misses. - */ - final int exponent = getExponent(value); - if (exponent >= (MIN_DOUBLE_NORMAL_EXPONENT+52)) { - if (exponent == MAX_DOUBLE_EXPONENT+1) { - // NaN or +-Infinity - return Math.abs(value); - } - // normal: returning 2^(exponent-52) - return Double.longBitsToDouble((exponent+(MAX_DOUBLE_EXPONENT-52L))<<52); - } else { - if (exponent == MIN_DOUBLE_NORMAL_EXPONENT-1) { - // +-0.0f or subnormal - return Double.MIN_VALUE; - } - // subnormal result - return Double.longBitsToDouble(1L<<(exponent-MIN_DOUBLE_NORMAL_EXPONENT)); - } - } - - /** - * If both arguments are +-0.0(f), (float)direction is returned. - * - * If both arguments are +Infinity or -Infinity, - * respectively +Infinity or -Infinity is returned. - * - * @param start A float value. - * @param direction A double value. - * @return The float adjacent to start towards direction, considering that - * +(-)Float.MIN_VALUE is adjacent to +(-)0.0f, and that - * +(-)Float.MAX_VALUE is adjacent to +(-)Infinity, - * or NaN if any argument is NaN. - */ - public static float nextAfter(float start, double direction) { - if (direction < start) { - // Going towards -Infinity. - if (start == 0.0f) { - // +-0.0f - return -Float.MIN_VALUE; - } - final int bits = Float.floatToRawIntBits(start); - return Float.intBitsToFloat(bits + ((bits > 0) ? -1 : 1)); - } else if (direction > start) { - // Going towards +Infinity. - // +0.0f to get rid of eventual -0.0f - final int bits = Float.floatToRawIntBits(start + 0.0f); - return Float.intBitsToFloat(bits + (bits >= 0 ? 1 : -1)); - } else if (start == direction) { - return (float)direction; - } else { - // Returning a NaN derived from the input NaN(s). - return start + (float)direction; - } - } - - /** - * If both arguments are +-0.0, direction is returned. - * - * If both arguments are +Infinity or -Infinity, - * respectively +Infinity or -Infinity is returned. - * - * @param start A double value. - * @param direction A double value. - * @return The double adjacent to start towards direction, considering that - * +(-)Double.MIN_VALUE is adjacent to +(-)0.0, and that - * +(-)Double.MAX_VALUE is adjacent to +(-)Infinity, - * or NaN if any argument is NaN. - */ - public static double nextAfter(double start, double direction) { - if (direction < start) { - // Going towards -Infinity. - if (start == 0.0) { - // +-0.0 - return -Double.MIN_VALUE; - } - final long bits = Double.doubleToRawLongBits(start); - return Double.longBitsToDouble(bits + ((bits > 0) ? -1 : 1)); - } else if (direction > start) { - // Going towards +Infinity. - // +0.0 to get rid of eventual -0.0 - final long bits = Double.doubleToRawLongBits(start + 0.0f); - return Double.longBitsToDouble(bits + (bits >= 0 ? 1 : -1)); - } else if (start == direction) { - return direction; - } else { - // Returning a NaN derived from the input NaN(s). - return start + direction; - } - } - - /** - * Semantically equivalent to nextAfter(start,Double.NEGATIVE_INFINITY). - */ - public static float nextDown(float start) { - if (start > Float.NEGATIVE_INFINITY) { - if (start == 0.0f) { - // +-0.0f - return -Float.MIN_VALUE; - } - final int bits = Float.floatToRawIntBits(start); - return Float.intBitsToFloat(bits + ((bits > 0) ? -1 : 1)); - } else if (start == Float.NEGATIVE_INFINITY) { - return Float.NEGATIVE_INFINITY; - } else { - // NaN - return start; - } - } - - /** - * Semantically equivalent to nextAfter(start,Double.NEGATIVE_INFINITY). - */ - public static double nextDown(double start) { - if (start > Double.NEGATIVE_INFINITY) { - if (start == 0.0) { - // +-0.0 - return -Double.MIN_VALUE; - } - final long bits = Double.doubleToRawLongBits(start); - return Double.longBitsToDouble(bits + ((bits > 0) ? -1 : 1)); - } else if (start == Double.NEGATIVE_INFINITY) { - return Double.NEGATIVE_INFINITY; - } else { - // NaN - return start; - } - } - - /** - * Semantically equivalent to nextAfter(start,Double.POSITIVE_INFINITY). - */ - public static float nextUp(float start) { - if (start < Float.POSITIVE_INFINITY) { - // +0.0f to get rid of eventual -0.0f - final int bits = Float.floatToRawIntBits(start + 0.0f); - return Float.intBitsToFloat(bits + (bits >= 0 ? 1 : -1)); - } else if (start == Float.POSITIVE_INFINITY) { - return Float.POSITIVE_INFINITY; - } else { - // NaN - return start; - } - } - - /** - * Semantically equivalent to nextAfter(start,Double.POSITIVE_INFINITY). - */ - public static double nextUp(double start) { - if (start < Double.POSITIVE_INFINITY) { - // +0.0 to get rid of eventual -0.0 - final long bits = Double.doubleToRawLongBits(start + 0.0); - return Double.longBitsToDouble(bits + (bits >= 0 ? 1 : -1)); - } else if (start == Double.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } else { - // NaN - return start; - } - } - - /** - * Precision may be lost if the result is subnormal. - * - * @param value A float value. - * @param scaleFactor An int value. - * @return value * 2^scaleFactor, or a value equivalent to the specified - * one if it is NaN, +-Infinity or +-0.0f. - */ - public static float scalb(float value, int scaleFactor) { - // Large enough to imply overflow or underflow for - // a finite non-zero value. - final int MAX_SCALE = 2*MAX_FLOAT_EXPONENT+23+1; - - // Making sure scaling factor is in a reasonable range. - scaleFactor = Math.max(Math.min(scaleFactor, MAX_SCALE), -MAX_SCALE); - - return (float)(((double)value) * twoPowNormal(scaleFactor)); - } - - /** - * Precision may be lost if the result is subnormal. - * - * @param value A double value. - * @param scaleFactor An int value. - * @return value * 2^scaleFactor, or a value equivalent to the specified - * one if it is NaN, +-Infinity or +-0.0. - */ - public static double scalb(double value, int scaleFactor) { - if ((scaleFactor > -MAX_DOUBLE_EXPONENT) && (scaleFactor <= MAX_DOUBLE_EXPONENT)) { - // Quick case (as done in apache FastMath). - return value * twoPowNormal(scaleFactor); - } - - // Large enough to imply overflow or underflow for - // a finite non-zero value. - final int MAX_SCALE = 2*MAX_DOUBLE_EXPONENT+52+1; - - // Making sure scaling factor is in a reasonable range. - final int exponentAdjust; - final int scaleIncrement; - final double exponentDelta; - if (scaleFactor < 0) { - scaleFactor = Math.max(scaleFactor, -MAX_SCALE); - scaleIncrement = -512; - exponentDelta = TWO_POW_N512; - } else { - scaleFactor = Math.min(scaleFactor, MAX_SCALE); - scaleIncrement = 512; - exponentDelta = TWO_POW_512; - } - - // Calculating (scaleFactor % +-512), 512 = 2^9, using - // technique from "Hacker's Delight" section 10-2. - final int t = ((scaleFactor >> (9-1)) >>> (32-9)); - exponentAdjust = ((scaleFactor + t) & (512-1)) - t; - - value *= twoPowNormal(exponentAdjust); - scaleFactor -= exponentAdjust; - - while (scaleFactor != 0) { - value *= exponentDelta; - scaleFactor -= scaleIncrement; - } - - return value; - } - - /* - * Non-redefined StrictMath public values and treatments. - */ - - public static float abs(float a) { - return StrictMath.abs(a); - } - - public static double abs(double a) { - return StrictMath.abs(a); - } - - public static float min(float a, float b) { - return StrictMath.min(a,b); - } - - public static double min(double a, double b) { - return StrictMath.min(a,b); - } - - public static float max(float a, float b) { - return StrictMath.max(a,b); - } - - public static double max(double a, double b) { - return StrictMath.max(a,b); - } - - public static double IEEEremainder(double f1, double f2) { - return StrictMath.IEEEremainder(f1,f2); - } - - public static double random() { - return StrictMath.random(); - } - - //-------------------------------------------------------------------------- - // PRIVATE METHODS - //-------------------------------------------------------------------------- - - /** - * Non-instantiable. - */ - private StrictFastMath() { - } - - /* - * Remainders (accurate). - */ - - /** - * @param angle Angle in radians. - * @return Remainder of (angle % (2*PI)), in [-PI,PI]. - */ - private static double remainderTwoPi(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderTwoPi(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle <= (4*NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2)) { - double fn = (double)(int)(angle*TWOPI_INV+0.5); - angle = (angle - fn*TWOPI_HI) - fn*TWOPI_LO; - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI) { - angle = (angle + TWOPI_HI) + TWOPI_LO; - } else if (angle > Math.PI) { - angle = (angle - TWOPI_HI) - TWOPI_LO; - } - return negateResult ? -angle : angle; - } else if (angle < Double.POSITIVE_INFINITY) { - angle = heavyRemainderTwoPi(angle); - return negateResult ? -angle : angle; - } else { // angle is +Infinity or NaN - return Double.NaN; - } - } - - /** - * @param angle Angle in radians. - * @return Remainder of (angle % PI), in [-PI/2,PI/2]. - */ - private static double remainderPi(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderPi(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle <= (2*NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2)) { - double fn = (double)(int)(angle*PI_INV+0.5); - angle = (angle - fn*PI_HI) - fn*PI_LO; - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI/2) { - angle = (angle + PI_HI) + PI_LO; - } else if (angle > Math.PI/2) { - angle = (angle - PI_HI) - PI_LO; - } - return negateResult ? -angle : angle; - } else if (angle < Double.POSITIVE_INFINITY) { - angle = heavyRemainderPi(angle); - return negateResult ? -angle : angle; - } else { // angle is +Infinity or NaN - return Double.NaN; - } - } - - /** - * @param angle Angle in radians. - * @return Bits of double corresponding to remainder of (angle % (PI/2)), - * in [-PI/4,PI/4], with quadrant encoded in exponent bits. - */ - private static long remainderPiO2(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderPiO2(angle, false); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - if (angle <= NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2) { - int n = (int)(angle*PIO2_INV+0.5); - double fn = (double)n; - angle = (angle - fn*PIO2_HI) - fn*PIO2_LO; - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI/4) { - angle = (angle + PIO2_HI) + PIO2_LO; - n--; - } else if (angle > Math.PI/4) { - angle = (angle - PIO2_HI) - PIO2_LO; - n++; - } - if (negateResult) { - angle = -angle; - } - return encodeRemainderAndQuadrant(angle, n&3); - } else if (angle < Double.POSITIVE_INFINITY) { - return heavyRemainderPiO2(angle, negateResult); - } else { // angle is +Infinity or NaN - return encodeRemainderAndQuadrant(Double.NaN, 0); - } - } - - /* - * Remainders (fast). - */ - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return Remainder of (angle % (2*PI)), in [-PI,PI]. - */ - private static double remainderTwoPiFast(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderTwoPi(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - // - We don't bother with values higher than (2*PI*(2^52)), - // since they are spaced by 2*PI or more from each other. - // - For large values, we don't use % because it might be very slow, - // and we split computation in two, because cast from double to int - // with large numbers might be very slow also. - if (angle <= TWO_POW_26*(2*Math.PI)) { - // ok - } else if (angle <= TWO_POW_52*(2*Math.PI)) { - // Computing remainder of angle modulo TWO_POW_26*(2*PI). - double fn = (double)(int)(angle*(TWOPI_INV/TWO_POW_26)+0.5); - angle = (angle - fn*(TWOPI_HI*TWO_POW_26)) - fn*(TWOPI_LO*TWO_POW_26); - // Here, angle is in [-TWO_POW_26*PI,TWO_POW_26*PI], or so. - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } else if (angle < Double.POSITIVE_INFINITY) { - return 0.0; - } else { // angle is +Infinity or NaN - return Double.NaN; - } - - // Computing remainder of angle modulo 2*PI. - double fn = (double)(int)(angle*TWOPI_INV+0.5); - angle = (angle - fn*TWOPI_HI) - fn*TWOPI_LO; - - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI) { - angle = (angle + TWOPI_HI) + TWOPI_LO; - } else if (angle > Math.PI) { - angle = (angle - TWOPI_HI) - TWOPI_LO; - } - return negateResult ? -angle : angle; - } - - /** - * Not accurate for large values. - * - * @param angle Angle in radians. - * @return Remainder of (angle % PI), in [-PI/2,PI/2]. - */ - private static double remainderPiFast(double angle) { - if (USE_JDK_MATH) { - return jdkRemainderPi(angle); - } - boolean negateResult = false; - if (angle < 0.0) { - angle = -angle; - negateResult = true; - } - // - We don't bother with values higher than (PI*(2^52)), - // since they are spaced by PI or more from each other. - // - For large values, we don't use % because it might be very slow, - // and we split computation in two, because cast from double to int - // with large numbers might be very slow also. - if (angle <= TWO_POW_26*Math.PI) { - // ok - } else if (angle <= TWO_POW_52*Math.PI) { - // Computing remainder of angle modulo TWO_POW_26*PI. - double fn = (double)(int)(angle*(PI_INV/TWO_POW_26)+0.5); - angle = (angle - fn*(PI_HI*TWO_POW_26)) - fn*(PI_LO*TWO_POW_26); - // Here, angle is in [-TWO_POW_26*PI/2,TWO_POW_26*PI/2], or so. - if (angle < 0.0) { - angle = -angle; - negateResult = !negateResult; - } - } else if (angle < Double.POSITIVE_INFINITY) { - return 0.0; - } else { // angle is +Infinity or NaN - return Double.NaN; - } - - // Computing remainder of angle modulo PI. - double fn = (double)(int)(angle*PI_INV+0.5); - angle = (angle - fn*PI_HI) - fn*PI_LO; - - // Ensuring range. - // HI/LO can help a bit, even though we are always far from 0. - if (angle < -Math.PI/2) { - angle = (angle + PI_HI) + PI_LO; - } else if (angle > Math.PI/2) { - angle = (angle - PI_HI) - PI_LO; - } - return negateResult ? -angle : angle; - } -} From abb3d9fe5024f31d72354a38efeb3582b9357f46 Mon Sep 17 00:00:00 2001 From: therealansh Date: Thu, 3 Jun 2021 10:17:13 +0530 Subject: [PATCH 12/39] add: Double using StrictMath --- .../kscience/kmath/jafama/KMathJafama.kt | 103 +++++++++--------- 1 file changed, 53 insertions(+), 50 deletions(-) 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 2557004e9..9d4341036 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 @@ -4,56 +4,7 @@ import space.kscience.kmath.operations.* import net.jafama.* /** - * Advanced Number-like semifield that implements basic operations. - */ -public interface ExtendedFieldOperations : - FieldOperations, - TrigonometricOperations, - PowerOperations, - ExponentialOperations { - public override fun tan(arg: T): T = sin(arg) / cos(arg) - public override fun tanh(arg: T): T = sinh(arg) / cosh(arg) - - public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { - TrigonometricOperations.COS_OPERATION -> ::cos - TrigonometricOperations.SIN_OPERATION -> ::sin - TrigonometricOperations.TAN_OPERATION -> ::tan - TrigonometricOperations.ACOS_OPERATION -> ::acos - TrigonometricOperations.ASIN_OPERATION -> ::asin - TrigonometricOperations.ATAN_OPERATION -> ::atan - PowerOperations.SQRT_OPERATION -> ::sqrt - ExponentialOperations.EXP_OPERATION -> ::exp - ExponentialOperations.LN_OPERATION -> ::ln - ExponentialOperations.COSH_OPERATION -> ::cosh - ExponentialOperations.SINH_OPERATION -> ::sinh - ExponentialOperations.TANH_OPERATION -> ::tanh - ExponentialOperations.ACOSH_OPERATION -> ::acosh - ExponentialOperations.ASINH_OPERATION -> ::asinh - ExponentialOperations.ATANH_OPERATION -> ::atanh - else -> super.unaryOperationFunction(operation) - } -} - -/** - * Advanced Number-like field that implements basic operations. - */ -public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra, ScaleOperations { - public override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 - public override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 - public override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) - public override fun asinh(arg: T): T = ln(sqrt(arg * arg + one) + arg) - public override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) - public override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0 - - public override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = - when (operation) { - PowerOperations.POW_OPERATION -> ::power - else -> super.rightSideNumberOperationFunction(operation) - } -} - -/** - * A field for [Double] without boxing. Does not produce appropriate field element. + * 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 { @@ -101,3 +52,55 @@ public object JafamaDoubleField : ExtendedField, Norm, S public override inline fun Double.times(b: Double): Double = this * b public override inline fun Double.div(b: Double): Double = this / b } + +/** + * 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 override inline val zero: Double get() = 0.0 + public override inline val one: Double get() = 1.0 + + public override fun number(value: Number): Double = value.toDouble() + + public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = + when (operation) { + PowerOperations.POW_OPERATION -> ::power + else -> super.binaryOperationFunction(operation) + } + + public override inline fun add(a: Double, b: Double): Double = a + b + + public override inline fun multiply(a: Double, b: Double): Double = a * b + public override inline fun divide(a: Double, b: Double): Double = a / b + + public override fun scale(a: Double, value: Double): Double = a * value + + public override inline fun sin(arg: Double): Double = StrictFastMath.sin(arg) + public override inline fun cos(arg: Double): Double = StrictFastMath.cos(arg) + public override inline fun tan(arg: Double): Double = StrictFastMath.tan(arg) + public override inline fun acos(arg: Double): Double = StrictFastMath.acos(arg) + public override inline fun asin(arg: Double): Double = StrictFastMath.asin(arg) + public override inline fun atan(arg: Double): Double = StrictFastMath.atan(arg) + + public override inline fun sinh(arg: Double): Double = StrictFastMath.sinh(arg) + public override inline fun cosh(arg: Double): Double = StrictFastMath.cosh(arg) + public override inline fun tanh(arg: Double): Double = StrictFastMath.tanh(arg) + public override inline fun asinh(arg: Double): Double = StrictFastMath.asinh(arg) + public override inline fun acosh(arg: Double): Double = StrictFastMath.acosh(arg) + public override inline fun atanh(arg: Double): Double = StrictFastMath.atanh(arg) + + public override inline fun power(arg: Double, pow: Number): Double = StrictFastMath.pow(arg, pow.toDouble()) + public override inline fun exp(arg: Double): Double = StrictFastMath.exp(arg) + public override inline fun ln(arg: Double): Double = StrictFastMath.log(arg) + + public override inline fun norm(arg: Double): Double = StrictFastMath.abs(arg) + + public override inline fun Double.unaryMinus(): Double = -this + public override inline fun Double.plus(b: Double): Double = this + b + public override inline fun Double.minus(b: Double): Double = this - b + public override inline fun Double.times(b: Double): Double = this * b + public override inline fun Double.div(b: Double): Double = this / b +} + + From 590910ac2dcb0028046442ad0b740328eaecd356 Mon Sep 17 00:00:00 2001 From: therealansh Date: Sat, 5 Jun 2021 11:14:02 +0530 Subject: [PATCH 13/39] add: example and Readme --- README.md | 6 +++++ examples/build.gradle.kts | 2 ++ .../kscience/kmath/jafama/KMathaJafamaDemo.kt | 17 +++++++++++++ kmath-jafama/README.md | 24 +++++++++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt create mode 100644 kmath-jafama/README.md diff --git a/README.md b/README.md index 7c6f7ea2b..90ab524e2 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,12 @@ One can still use generic algebras though. > **Maturity**: PROTOTYPE
+* ### [kmath-jafama](kmath-jafama) +> +> +> **Maturity**: PROTOTYPE +
+ * ### [kmath-jupyter](kmath-jupyter) > > diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 568bde153..406b8f470 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -44,6 +44,8 @@ dependencies { implementation("org.slf4j:slf4j-simple:1.7.30") // plotting implementation("space.kscience:plotlykt-server:0.4.0") + //jafama + implementation(project(":kmath-jafama")) } kotlin.sourceSets.all { diff --git a/examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt new file mode 100644 index 000000000..879aab08f --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.jafama + +import net.jafama.FastMath + + +fun main(){ + val a = JafamaDoubleField.number(2.0) + val b = StrictJafamaDoubleField.power(FastMath.E,a) + + println(JafamaDoubleField.add(b,a)) + println(StrictJafamaDoubleField.ln(b)) +} diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md new file mode 100644 index 000000000..fab777bf4 --- /dev/null +++ b/kmath-jafama/README.md @@ -0,0 +1,24 @@ +# Module kmath-jafama + +Jafama based implementation of DoubleField of kmath-operations. + +- JafamaDoubleField : DoubleField implementation using FastMath +- StrictJafamaDoubleField - DoubleField implementation using StrictFastMath + +## Examples + +Different Operations on DoubleField + +```kotlin +package space.kscience.kmath.jafama + +import net.jafama.FastMath + + +fun main(){ + val a = JafamaDoubleField.number(2.0) + val b = StrictJafamaDoubleField.power(FastMath.E,a) + println(JafamaDoubleField.add(b,a)) + println(StrictJafamaDoubleField.ln(b)) +} +``` From 9a9ebc730453735c5b6c0364d9fdbed1e92b3bc3 Mon Sep 17 00:00:00 2001 From: therealansh Date: Tue, 8 Jun 2021 19:19:55 +0530 Subject: [PATCH 14/39] add: benchmarks for Jafama --- benchmarks/build.gradle.kts | 7 +- .../kmath/benchmarks/JafamaBenchmark.kt | 48 ++++++++ .../kscience/kmath/jafama/KMathJafama.kt | 104 +++++++++--------- 3 files changed, 106 insertions(+), 53 deletions(-) create mode 100644 benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 98ffc5a96..182c182d9 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -30,6 +30,7 @@ kotlin { implementation(project(":kmath-stat")) implementation(project(":kmath-dimensions")) implementation(project(":kmath-for-real")) + implementation(project(":kmath-jafama")) implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.0") } } @@ -42,7 +43,6 @@ kotlin { implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-viktor")) implementation("org.nd4j:nd4j-native:1.0.0-beta7") - // uncomment if your system supports AVX2 // val os = System.getProperty("os.name") // @@ -95,6 +95,11 @@ benchmark { commonConfiguration() include("BigIntBenchmark") } + + configurations.register("jafamaDouble") { + commonConfiguration() + include("JafamaBenchmark") + } } // Fix kotlinx-benchmarks bug diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt new file mode 100644 index 000000000..c828de82b --- /dev/null +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Blackhole +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State +import space.kscience.kmath.jafama.JafamaDoubleField +import space.kscience.kmath.jafama.StrictJafamaDoubleField +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke + + +@State(Scope.Benchmark) +internal class JafamaBenchmark { + @Benchmark + fun jafamaBench(blackhole: Blackhole) = invokeBenchmarks(jafama, blackhole) + + @Benchmark + fun coreBench(blackhole: Blackhole) = invokeBenchmarks(core,blackhole) + + @Benchmark + fun strictJafamaBench(blackhole: Blackhole) = invokeBenchmarks(strictJafama,blackhole) + + private fun invokeBenchmarks(expr: Double, blackhole: Blackhole) { + blackhole.consume(expr) + } + + private companion object { + private val x: Double = Double.MAX_VALUE + + private val jafama = JafamaDoubleField{ + x * power(x, 1_000_000) * exp(x) / cos(x) + } + + private val core = DoubleField { + x * power(x, 1_000_000) * exp(x) / cos(x) + } + + private val strictJafama = StrictJafamaDoubleField { + x * power(x, 1_000_000) * exp(x) / cos(x) + } + } +} 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 9d4341036..f37d8e7b3 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,8 +8,8 @@ import net.jafama.* */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object JafamaDoubleField : ExtendedField, Norm, ScaleOperations { - public override inline val zero: Double get() = 0.0 - public override inline val one: Double get() = 1.0 + public override val zero: Double get() = 0.0 + public override val one: Double get() = 1.0 public override fun number(value: Number): Double = value.toDouble() @@ -19,38 +19,38 @@ public object JafamaDoubleField : ExtendedField, Norm, S else -> super.binaryOperationFunction(operation) } - public override inline fun add(a: Double, b: Double): Double = a + b + public override fun add(a: Double, b: Double): Double = a + b - public override inline fun multiply(a: Double, b: Double): Double = a * b - public override inline fun divide(a: Double, b: Double): Double = a / b + public override fun multiply(a: Double, b: Double): Double = a * b + public override fun divide(a: Double, b: Double): Double = a / b public override fun scale(a: Double, value: Double): Double = a * value - public override inline fun sin(arg: Double): Double = FastMath.sin(arg) - public override inline fun cos(arg: Double): Double = FastMath.cos(arg) - public override inline fun tan(arg: Double): Double = FastMath.tan(arg) - public override inline fun acos(arg: Double): Double = FastMath.acos(arg) - public override inline fun asin(arg: Double): Double = FastMath.asin(arg) - public override inline fun atan(arg: Double): Double = FastMath.atan(arg) + public override fun sin(arg: Double): Double = FastMath.sin(arg) + public override fun cos(arg: Double): Double = FastMath.cos(arg) + public override fun tan(arg: Double): Double = FastMath.tan(arg) + public override fun acos(arg: Double): Double = FastMath.acos(arg) + public override fun asin(arg: Double): Double = FastMath.asin(arg) + public override fun atan(arg: Double): Double = FastMath.atan(arg) - public override inline fun sinh(arg: Double): Double = FastMath.sinh(arg) - public override inline fun cosh(arg: Double): Double = FastMath.cosh(arg) - public override inline fun tanh(arg: Double): Double = FastMath.tanh(arg) - public override inline fun asinh(arg: Double): Double = FastMath.asinh(arg) - public override inline fun acosh(arg: Double): Double = FastMath.acosh(arg) - public override inline fun atanh(arg: Double): Double = FastMath.atanh(arg) + public override fun sinh(arg: Double): Double = FastMath.sinh(arg) + public override fun cosh(arg: Double): Double = FastMath.cosh(arg) + public override fun tanh(arg: Double): Double = FastMath.tanh(arg) + public override fun asinh(arg: Double): Double = FastMath.asinh(arg) + public override fun acosh(arg: Double): Double = FastMath.acosh(arg) + public override fun atanh(arg: Double): Double = FastMath.atanh(arg) - public override inline fun power(arg: Double, pow: Number): Double = FastMath.pow(arg, pow.toDouble()) - public override inline fun exp(arg: Double): Double = FastMath.exp(arg) - public override inline fun ln(arg: Double): Double = FastMath.log(arg) + public override fun power(arg: Double, pow: Number): Double = FastMath.pow(arg, pow.toDouble()) + public override fun exp(arg: Double): Double = FastMath.exp(arg) + public override fun ln(arg: Double): Double = FastMath.log(arg) - public override inline fun norm(arg: Double): Double = FastMath.abs(arg) + public override fun norm(arg: Double): Double = FastMath.abs(arg) - public override inline fun Double.unaryMinus(): Double = -this - public override inline fun Double.plus(b: Double): Double = this + b - public override inline fun Double.minus(b: Double): Double = this - b - public override inline fun Double.times(b: Double): Double = this * b - public override inline fun Double.div(b: Double): Double = this / b + public override fun Double.unaryMinus(): Double = -this + public override fun Double.plus(b: Double): Double = this + b + public override fun Double.minus(b: Double): Double = this - b + public override fun Double.times(b: Double): Double = this * b + public override fun Double.div(b: Double): Double = this / b } /** @@ -58,8 +58,8 @@ public object JafamaDoubleField : ExtendedField, Norm, S */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object StrictJafamaDoubleField : ExtendedField, Norm, ScaleOperations { - public override inline val zero: Double get() = 0.0 - public override inline val one: Double get() = 1.0 + public override val zero: Double get() = 0.0 + public override val one: Double get() = 1.0 public override fun number(value: Number): Double = value.toDouble() @@ -69,38 +69,38 @@ public object StrictJafamaDoubleField : ExtendedField, Norm super.binaryOperationFunction(operation) } - public override inline fun add(a: Double, b: Double): Double = a + b + public override fun add(a: Double, b: Double): Double = a + b - public override inline fun multiply(a: Double, b: Double): Double = a * b - public override inline fun divide(a: Double, b: Double): Double = a / b + public override fun multiply(a: Double, b: Double): Double = a * b + public override fun divide(a: Double, b: Double): Double = a / b public override fun scale(a: Double, value: Double): Double = a * value - public override inline fun sin(arg: Double): Double = StrictFastMath.sin(arg) - public override inline fun cos(arg: Double): Double = StrictFastMath.cos(arg) - public override inline fun tan(arg: Double): Double = StrictFastMath.tan(arg) - public override inline fun acos(arg: Double): Double = StrictFastMath.acos(arg) - public override inline fun asin(arg: Double): Double = StrictFastMath.asin(arg) - public override inline fun atan(arg: Double): Double = StrictFastMath.atan(arg) + public override fun sin(arg: Double): Double = StrictFastMath.sin(arg) + public override fun cos(arg: Double): Double = StrictFastMath.cos(arg) + public override fun tan(arg: Double): Double = StrictFastMath.tan(arg) + public override fun acos(arg: Double): Double = StrictFastMath.acos(arg) + public override fun asin(arg: Double): Double = StrictFastMath.asin(arg) + public override fun atan(arg: Double): Double = StrictFastMath.atan(arg) - public override inline fun sinh(arg: Double): Double = StrictFastMath.sinh(arg) - public override inline fun cosh(arg: Double): Double = StrictFastMath.cosh(arg) - public override inline fun tanh(arg: Double): Double = StrictFastMath.tanh(arg) - public override inline fun asinh(arg: Double): Double = StrictFastMath.asinh(arg) - public override inline fun acosh(arg: Double): Double = StrictFastMath.acosh(arg) - public override inline fun atanh(arg: Double): Double = StrictFastMath.atanh(arg) + public override fun sinh(arg: Double): Double = StrictFastMath.sinh(arg) + public override fun cosh(arg: Double): Double = StrictFastMath.cosh(arg) + public override fun tanh(arg: Double): Double = StrictFastMath.tanh(arg) + public override fun asinh(arg: Double): Double = StrictFastMath.asinh(arg) + public override fun acosh(arg: Double): Double = StrictFastMath.acosh(arg) + public override fun atanh(arg: Double): Double = StrictFastMath.atanh(arg) - public override inline fun power(arg: Double, pow: Number): Double = StrictFastMath.pow(arg, pow.toDouble()) - public override inline fun exp(arg: Double): Double = StrictFastMath.exp(arg) - public override inline fun ln(arg: Double): Double = StrictFastMath.log(arg) + public override fun power(arg: Double, pow: Number): Double = StrictFastMath.pow(arg, pow.toDouble()) + public override fun exp(arg: Double): Double = StrictFastMath.exp(arg) + public override fun ln(arg: Double): Double = StrictFastMath.log(arg) - public override inline fun norm(arg: Double): Double = StrictFastMath.abs(arg) + public override fun norm(arg: Double): Double = StrictFastMath.abs(arg) - public override inline fun Double.unaryMinus(): Double = -this - public override inline fun Double.plus(b: Double): Double = this + b - public override inline fun Double.minus(b: Double): Double = this - b - public override inline fun Double.times(b: Double): Double = this * b - public override inline fun Double.div(b: Double): Double = this / b + public override fun Double.unaryMinus(): Double = -this + public override fun Double.plus(b: Double): Double = this + b + public override fun Double.minus(b: Double): Double = this - b + public override fun Double.times(b: Double): Double = this * b + public override fun Double.div(b: Double): Double = this / b } From b99d0b96d82289a738326b7b4a71df6064734519 Mon Sep 17 00:00:00 2001 From: therealansh Date: Tue, 8 Jun 2021 19:28:34 +0530 Subject: [PATCH 15/39] add:benchmarks to readme --- kmath-jafama/README.md | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index fab777bf4..bc5655a1e 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -22,3 +22,47 @@ fun main(){ println(StrictJafamaDoubleField.ln(b)) } ``` + +## Benchmarks +Comparing Operations on DoubleField and JafamaDoubleField +```bash +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench + +Warm-up 1: 242556635.528 ops/s +Iteration 1: 236249893.335 ops/s +Iteration 2: 294526940.968 ops/s +Iteration 3: 295973752.533 ops/s +Iteration 4: 296467676.763 ops/s +Iteration 5: 295929441.421 ops/s + +283829541.004 ±(99.9%) 102456604.440 ops/s [Average] + (min, avg, max) = (236249893.335, 283829541.004, 296467676.763), stdev = 26607654.808 + CI (99.9%): [181372936.564, 386286145.444] (assumes normal distribution) + +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench + +Warm-up 1: 234737640.196 ops/s +Iteration 1: 231689614.905 ops/s +Iteration 2: 296629612.909 ops/s +Iteration 3: 297456237.453 ops/s +Iteration 4: 296754794.513 ops/s +Iteration 5: 293722557.848 ops/s + +283250563.526 ±(99.9%) 111125582.233 ops/s [Average] + (min, avg, max) = (231689614.905, 283250563.526, 297456237.453), stdev = 28858960.811 + CI (99.9%): [172124981.293, 394376145.759] (assumes normal distribution) + +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench + +Warm-up 1: 234895701.589 ops/s +Iteration 1: 236061284.195 ops/s +Iteration 2: 296894799.416 ops/s +Iteration 3: 286852020.677 ops/s +Iteration 4: 284021863.614 ops/s +Iteration 5: 284404358.656 ops/s + +277646865.312 ±(99.9%) 91748868.927 ops/s [Average] + (min, avg, max) = (236061284.195, 277646865.312, 296894799.416), stdev = 23826889.899 + CI (99.9%): [185897996.385, 369395734.239] (assumes normal distribution) + +``` From 03be37bb4f6843a8fb08b3c44256df4f6bbdb15f Mon Sep 17 00:00:00 2001 From: therealansh Date: Sat, 12 Jun 2021 10:00:36 +0530 Subject: [PATCH 16/39] add: kotlin math benchmarks --- .../kmath/benchmarks/JafamaBenchmark.kt | 8 +++ kmath-jafama/README.md | 68 +++++++++++-------- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt index c828de82b..e998054fb 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt @@ -13,6 +13,9 @@ import space.kscience.kmath.jafama.JafamaDoubleField import space.kscience.kmath.jafama.StrictJafamaDoubleField import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke +import kotlin.math.cos +import kotlin.math.exp +import kotlin.math.pow @State(Scope.Benchmark) @@ -26,6 +29,9 @@ internal class JafamaBenchmark { @Benchmark fun strictJafamaBench(blackhole: Blackhole) = invokeBenchmarks(strictJafama,blackhole) + @Benchmark + fun kotlinMathBench(blackhole: Blackhole) = invokeBenchmarks(kotlinMath, blackhole) + private fun invokeBenchmarks(expr: Double, blackhole: Blackhole) { blackhole.consume(expr) } @@ -37,6 +43,8 @@ internal class JafamaBenchmark { x * power(x, 1_000_000) * exp(x) / cos(x) } + private val kotlinMath = x * x.pow(1_000_000) * exp(x) / cos(x) + private val core = DoubleField { x * power(x, 1_000_000) * exp(x) / cos(x) } diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index bc5655a1e..d170f6591 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -28,41 +28,53 @@ Comparing Operations on DoubleField and JafamaDoubleField ```bash jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench -Warm-up 1: 242556635.528 ops/s -Iteration 1: 236249893.335 ops/s -Iteration 2: 294526940.968 ops/s -Iteration 3: 295973752.533 ops/s -Iteration 4: 296467676.763 ops/s -Iteration 5: 295929441.421 ops/s +Warm-up 1: 384414358.081 ops/s +Iteration 1: 374827571.951 ops/s +Iteration 2: 479335182.332 ops/s +Iteration 3: 475483069.577 ops/s +Iteration 4: 478235949.414 ops/s +Iteration 5: 472256385.114 ops/s -283829541.004 ±(99.9%) 102456604.440 ops/s [Average] - (min, avg, max) = (236249893.335, 283829541.004, 296467676.763), stdev = 26607654.808 - CI (99.9%): [181372936.564, 386286145.444] (assumes normal distribution) +456027631.678 ±(99.9%) 175106815.384 ops/s [Average] + (min, avg, max) = (374827571.951, 456027631.678, 479335182.332), stdev = 45474683.880 + CI (99.9%): [280920816.294, 631134447.061] (assumes normal distribution) jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench -Warm-up 1: 234737640.196 ops/s -Iteration 1: 231689614.905 ops/s -Iteration 2: 296629612.909 ops/s -Iteration 3: 297456237.453 ops/s -Iteration 4: 296754794.513 ops/s -Iteration 5: 293722557.848 ops/s +Warm-up 1: 359418665.041 ops/s +Iteration 1: 335704885.798 ops/s +Iteration 2: 427684801.542 ops/s +Iteration 3: 452193034.265 ops/s +Iteration 4: 433855064.931 ops/s +Iteration 5: 453863386.566 ops/s -283250563.526 ±(99.9%) 111125582.233 ops/s [Average] - (min, avg, max) = (231689614.905, 283250563.526, 297456237.453), stdev = 28858960.811 - CI (99.9%): [172124981.293, 394376145.759] (assumes normal distribution) +420660234.620 ±(99.9%) 188028426.875 ops/s [Average] + (min, avg, max) = (335704885.798, 420660234.620, 453863386.566), stdev = 48830385.349 + CI (99.9%): [232631807.746, 608688661.495] (assumes normal distribution) + +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.kotlinMathBench + +Warm-up 1: 371570418.113 ops/s +Iteration 1: 379281146.127 ops/s +Iteration 2: 465234403.109 ops/s +Iteration 3: 470621634.240 ops/s +Iteration 4: 467074553.006 ops/s +Iteration 5: 466424840.144 ops/s + +449727315.325 ±(99.9%) 151837475.500 ops/s [Average] + (min, avg, max) = (379281146.127, 449727315.325, 470621634.240), stdev = 39431710.207 + CI (99.9%): [297889839.825, 601564790.825] (assumes normal distribution) jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench -Warm-up 1: 234895701.589 ops/s -Iteration 1: 236061284.195 ops/s -Iteration 2: 296894799.416 ops/s -Iteration 3: 286852020.677 ops/s -Iteration 4: 284021863.614 ops/s -Iteration 5: 284404358.656 ops/s - -277646865.312 ±(99.9%) 91748868.927 ops/s [Average] - (min, avg, max) = (236061284.195, 277646865.312, 296894799.416), stdev = 23826889.899 - CI (99.9%): [185897996.385, 369395734.239] (assumes normal distribution) +Warm-up 1: 371241281.065 ops/s +Iteration 1: 374490259.387 ops/s +Iteration 2: 464995837.424 ops/s +Iteration 3: 469788706.385 ops/s +Iteration 4: 469528470.682 ops/s +Iteration 5: 456727921.978 ops/s +447106239.171 ±(99.9%) 157629035.980 ops/s [Average] + (min, avg, max) = (374490259.387, 447106239.171, 469788706.385), stdev = 40935760.071 + CI (99.9%): [289477203.192, 604735275.151] (assumes normal distribution) ``` From 4d6428a3082c4c1b775cc1e70e35b42032e5ad49 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Mon, 14 Jun 2021 21:51:06 +0700 Subject: [PATCH 17/39] Update Jafama module documentation with some minor code amendments --- README.md | 8 +- benchmarks/build.gradle.kts | 1 + .../kmath/benchmarks/JafamaBenchmark.kt | 45 ++--- kmath-ast/build.gradle.kts | 7 +- .../kmath/ast/TestCompilerOperations.kt | 1 - .../kscience/kmath/operations/numbers.kt | 6 +- kmath-functions/build.gradle.kts | 5 +- kmath-jafama/README.md | 178 ++++++++++++------ kmath-jafama/build.gradle.kts | 7 + kmath-jafama/docs/README-TEMPLATE.md | 118 ++++++++++++ .../kscience/kmath/jafama/KMathJafama.kt | 124 ++++++------ 11 files changed, 341 insertions(+), 159 deletions(-) create mode 100644 kmath-jafama/docs/README-TEMPLATE.md diff --git a/README.md b/README.md index 90ab524e2..015988cd3 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ One can still use generic algebras though.
* ### [kmath-functions](kmath-functions) -> Functions, integration and interpolation +> > > **Maturity**: EXPERIMENTAL > @@ -201,9 +201,13 @@ One can still use generic algebras though.
* ### [kmath-jafama](kmath-jafama) -> +> > > **Maturity**: PROTOTYPE +> +> **Features:** +> - [jafama-double](kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama +
* ### [kmath-jupyter](kmath-jupyter) diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 182c182d9..f171437d3 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -12,6 +12,7 @@ repositories { maven("https://repo.kotlin.link") maven("https://clojars.org/repo") maven("https://jitpack.io") + maven("http://logicrunch.research.it.uu.se/maven") { isAllowInsecureProtocol = true } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt index e998054fb..260eea2b6 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt @@ -13,44 +13,27 @@ import space.kscience.kmath.jafama.JafamaDoubleField import space.kscience.kmath.jafama.StrictJafamaDoubleField import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke -import kotlin.math.cos -import kotlin.math.exp -import kotlin.math.pow - +import kotlin.random.Random @State(Scope.Benchmark) internal class JafamaBenchmark { @Benchmark - fun jafamaBench(blackhole: Blackhole) = invokeBenchmarks(jafama, blackhole) - - @Benchmark - fun coreBench(blackhole: Blackhole) = invokeBenchmarks(core,blackhole) - - @Benchmark - fun strictJafamaBench(blackhole: Blackhole) = invokeBenchmarks(strictJafama,blackhole) - - @Benchmark - fun kotlinMathBench(blackhole: Blackhole) = invokeBenchmarks(kotlinMath, blackhole) - - private fun invokeBenchmarks(expr: Double, blackhole: Blackhole) { - blackhole.consume(expr) + fun jafamaBench(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> + JafamaDoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } } - private companion object { - private val x: Double = Double.MAX_VALUE + @Benchmark + fun coreBench(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> + DoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } + } - private val jafama = JafamaDoubleField{ - x * power(x, 1_000_000) * exp(x) / cos(x) - } + @Benchmark + fun strictJafamaBench(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> + StrictJafamaDoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } + } - private val kotlinMath = x * x.pow(1_000_000) * exp(x) / cos(x) - - private val core = DoubleField { - x * power(x, 1_000_000) * exp(x) / cos(x) - } - - private val strictJafama = StrictJafamaDoubleField { - x * power(x, 1_000_000) * exp(x) / cos(x) - } + private inline fun invokeBenchmarks(blackhole: Blackhole, expr: (Double) -> Double) { + val rng = Random(0) + repeat(1000000) { blackhole.consume(expr(rng.nextDouble())) } } } diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 508374d82..89647c9e9 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -37,10 +37,9 @@ kotlin.sourceSets { jsMain { dependencies { - implementation(npm("astring", "1.7.4")) - implementation(npm("binaryen", "100.0")) - implementation(npm("js-base64", "3.6.0")) - implementation(npm("webassembly", "0.11.0")) + implementation(npm("astring", "1.7.5")) + implementation(npm("binaryen", "101.0.0")) + implementation(npm("js-base64", "3.6.1")) } } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt index f869efd62..929d17775 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt @@ -9,7 +9,6 @@ import space.kscience.kmath.expressions.MstExtendedField import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.invoke import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals 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 0d6d9e98d..36c13d6ec 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 @@ -64,7 +64,7 @@ public object DoubleField : ExtendedField, Norm, ScaleOp public override inline val zero: Double get() = 0.0 public override inline val one: Double get() = 1.0 - public override fun number(value: Number): Double = value.toDouble() + public override inline fun number(value: Number): Double = value.toDouble() public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { @@ -77,7 +77,7 @@ public object DoubleField : ExtendedField, Norm, ScaleOp public override inline fun multiply(a: Double, b: Double): Double = a * b public override inline fun divide(a: Double, b: Double): Double = a / b - public override fun scale(a: Double, value: Double): Double = a * value + public override inline fun scale(a: Double, value: Double): Double = a * value public override inline fun sin(arg: Double): Double = kotlin.math.sin(arg) public override inline fun cos(arg: Double): Double = kotlin.math.cos(arg) @@ -93,6 +93,7 @@ public object DoubleField : ExtendedField, Norm, ScaleOp public override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg) public override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg) + public override inline fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg) public override inline fun power(arg: Double, pow: Number): Double = arg.kpow(pow.toDouble()) public override inline fun exp(arg: Double): Double = kotlin.math.exp(arg) public override inline fun ln(arg: Double): Double = kotlin.math.ln(arg) @@ -143,6 +144,7 @@ public object FloatField : ExtendedField, Norm { public override inline fun acosh(arg: Float): Float = kotlin.math.acosh(arg) public override inline fun atanh(arg: Float): Float = kotlin.math.atanh(arg) + public override inline fun sqrt(arg: Float): Float = kotlin.math.sqrt(arg) public override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat()) public override inline fun exp(arg: Float): Float = kotlin.math.exp(arg) public override inline fun ln(arg: Float): Float = kotlin.math.ln(arg) diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 622b8f8da..f77df3833 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -3,6 +3,8 @@ plugins { id("ru.mipt.npm.gradle.common") } +description = "Functions, integration and interpolation" + kotlin.sourceSets.commonMain { dependencies { api(project(":kmath-core")) @@ -10,7 +12,6 @@ kotlin.sourceSets.commonMain { } readme { - description = "Functions, integration and interpolation" maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) @@ -29,4 +30,4 @@ readme { feature("integration") { "Univariate and multivariate quadratures" } -} \ No newline at end of file +} diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index d170f6591..9b439c5c2 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -1,80 +1,144 @@ # Module kmath-jafama -Jafama based implementation of DoubleField of kmath-operations. +Integration with [Jafama](https://github.com/jeffhain/jafama). -- JafamaDoubleField : DoubleField implementation using FastMath -- StrictJafamaDoubleField - DoubleField implementation using StrictFastMath + - [jafama-double](src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama -## Examples -Different Operations on DoubleField +## Artifact: +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-13`. + +**Gradle:** +```gradle +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-jafama:0.3.0-dev-13' +} +``` +**Gradle Kotlin DSL:** ```kotlin -package space.kscience.kmath.jafama +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} -import net.jafama.FastMath - - -fun main(){ - val a = JafamaDoubleField.number(2.0) - val b = StrictJafamaDoubleField.power(FastMath.E,a) - println(JafamaDoubleField.add(b,a)) - println(StrictJafamaDoubleField.ln(b)) +dependencies { + implementation("space.kscience:kmath-jafama:0.3.0-dev-13") } ``` -## Benchmarks -Comparing Operations on DoubleField and JafamaDoubleField -```bash +## Example usage + +All the `DoubleField` uses can be replaced with `JafamaDoubleField` or `StrictJafamaDoubleField`. + +```kotlin +import space.kscience.kmath.jafama.* +import space.kscience.kmath.operations.* + +fun main() { + val a = 2.0 + val b = StrictJafamaDoubleField { exp(a) } + println(JafamaDoubleField { b + a }) + println(StrictJafamaDoubleField { ln(b) }) +} +``` + +## Performance + +According to benchmarking data, on Hotspot Jafama functions are 20% faster than JDK math. On GraalVM, they are slower. + +
+Raw data: + +**Hotspot** + +``` jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench -Warm-up 1: 384414358.081 ops/s -Iteration 1: 374827571.951 ops/s -Iteration 2: 479335182.332 ops/s -Iteration 3: 475483069.577 ops/s -Iteration 4: 478235949.414 ops/s -Iteration 5: 472256385.114 ops/s +Warm-up 1: 11.447 ops/s +Iteration 1: 13.354 ops/s +Iteration 2: 14.237 ops/s +Iteration 3: 14.708 ops/s +Iteration 4: 14.629 ops/s +Iteration 5: 14.692 ops/s -456027631.678 ±(99.9%) 175106815.384 ops/s [Average] - (min, avg, max) = (374827571.951, 456027631.678, 479335182.332), stdev = 45474683.880 - CI (99.9%): [280920816.294, 631134447.061] (assumes normal distribution) +14.324 ±(99.9%) 2.217 ops/s [Average] + (min, avg, max) = (13.354, 14.324, 14.708), stdev = 0.576 + CI (99.9%): [12.107, 16.541] (assumes normal distribution) jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench -Warm-up 1: 359418665.041 ops/s -Iteration 1: 335704885.798 ops/s -Iteration 2: 427684801.542 ops/s -Iteration 3: 452193034.265 ops/s -Iteration 4: 433855064.931 ops/s -Iteration 5: 453863386.566 ops/s +Warm-up 1: 15.628 ops/s +Iteration 1: 15.991 ops/s +Iteration 2: 16.633 ops/s +Iteration 3: 16.583 ops/s +Iteration 4: 16.716 ops/s +Iteration 5: 16.762 ops/s -420660234.620 ±(99.9%) 188028426.875 ops/s [Average] - (min, avg, max) = (335704885.798, 420660234.620, 453863386.566), stdev = 48830385.349 - CI (99.9%): [232631807.746, 608688661.495] (assumes normal distribution) - -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.kotlinMathBench - -Warm-up 1: 371570418.113 ops/s -Iteration 1: 379281146.127 ops/s -Iteration 2: 465234403.109 ops/s -Iteration 3: 470621634.240 ops/s -Iteration 4: 467074553.006 ops/s -Iteration 5: 466424840.144 ops/s - -449727315.325 ±(99.9%) 151837475.500 ops/s [Average] - (min, avg, max) = (379281146.127, 449727315.325, 470621634.240), stdev = 39431710.207 - CI (99.9%): [297889839.825, 601564790.825] (assumes normal distribution) +16.537 ±(99.9%) 1.205 ops/s [Average] + (min, avg, max) = (15.991, 16.537, 16.762), stdev = 0.313 + CI (99.9%): [15.332, 17.743] (assumes normal distribution) jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench -Warm-up 1: 371241281.065 ops/s -Iteration 1: 374490259.387 ops/s -Iteration 2: 464995837.424 ops/s -Iteration 3: 469788706.385 ops/s -Iteration 4: 469528470.682 ops/s -Iteration 5: 456727921.978 ops/s +Warm-up 1: 13.378 ops/s +Iteration 1: 15.049 ops/s +Iteration 2: 14.468 ops/s +Iteration 3: 14.469 ops/s +Iteration 4: 14.753 ops/s +Iteration 5: 14.958 ops/s -447106239.171 ±(99.9%) 157629035.980 ops/s [Average] - (min, avg, max) = (374490259.387, 447106239.171, 469788706.385), stdev = 40935760.071 - CI (99.9%): [289477203.192, 604735275.151] (assumes normal distribution) +14.739 ±(99.9%) 1.038 ops/s [Average] + (min, avg, max) = (14.468, 14.739, 15.049), stdev = 0.269 + CI (99.9%): [13.701, 15.777] (assumes normal distribution) ``` + +**GraalVM** + +``` +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench + +Warm-up 1: 14.357 ops/s +Iteration 1: 14.768 ops/s +Iteration 2: 14.922 ops/s +Iteration 3: 14.966 ops/s +Iteration 4: 14.805 ops/s +Iteration 5: 14.520 ops/s + +14.796 ±(99.9%) 0.671 ops/s [Average] + (min, avg, max) = (14.520, 14.796, 14.966), stdev = 0.174 + CI (99.9%): [14.125, 15.468] (assumes normal distribution) + +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench + +Warm-up 1: 11.592 ops/s +Iteration 1: 12.174 ops/s +Iteration 2: 11.734 ops/s +Iteration 3: 11.939 ops/s +Iteration 4: 12.026 ops/s +Iteration 5: 12.221 ops/s + +12.019 ±(99.9%) 0.752 ops/s [Average] + (min, avg, max) = (11.734, 12.019, 12.221), stdev = 0.195 + CI (99.9%): [11.267, 12.771] (assumes normal distribution) + +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench + +Warm-up 1: 12.097 ops/s +Iteration 1: 13.072 ops/s +Iteration 2: 13.112 ops/s +Iteration 3: 13.103 ops/s +Iteration 4: 12.950 ops/s +Iteration 5: 13.011 ops/s + +13.049 ±(99.9%) 0.263 ops/s [Average] + (min, avg, max) = (12.950, 13.049, 13.112), stdev = 0.068 + CI (99.9%): [12.787, 13.312] (assumes normal distribution) +``` + +
diff --git a/kmath-jafama/build.gradle.kts b/kmath-jafama/build.gradle.kts index f31f2602f..9cf328d0b 100644 --- a/kmath-jafama/build.gradle.kts +++ b/kmath-jafama/build.gradle.kts @@ -2,6 +2,8 @@ plugins { id("ru.mipt.npm.gradle.jvm") } +description = "Jafama integration module" + dependencies { api(project(":kmath-core")) api("net.jafama:jafama:2.3.2") @@ -13,6 +15,11 @@ repositories { readme { maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) + + feature("jafama-double", "src/main/kotlin/space/kscience/kmath/jafama/") { + "Double ExtendedField implementations based on Jafama" + } } kotlin.sourceSets.all { diff --git a/kmath-jafama/docs/README-TEMPLATE.md b/kmath-jafama/docs/README-TEMPLATE.md new file mode 100644 index 000000000..fa58f7697 --- /dev/null +++ b/kmath-jafama/docs/README-TEMPLATE.md @@ -0,0 +1,118 @@ +# Module kmath-jafama + +Integration with [Jafama](https://github.com/jeffhain/jafama). + +${features} + +${artifact} + +## Example usage + +All the `DoubleField` uses can be replaced with `JafamaDoubleField` or `StrictJafamaDoubleField`. + +```kotlin +import space.kscience.kmath.jafama.* +import space.kscience.kmath.operations.* + +fun main() { + val a = 2.0 + val b = StrictJafamaDoubleField { exp(a) } + println(JafamaDoubleField { b + a }) + println(StrictJafamaDoubleField { ln(b) }) +} +``` + +## Performance + +According to benchmarking data, on Hotspot Jafama functions are 20% faster than JDK math. On GraalVM, they are slower. + +
+Raw data: + +**Hotspot** + +``` +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench + +Warm-up 1: 11.447 ops/s +Iteration 1: 13.354 ops/s +Iteration 2: 14.237 ops/s +Iteration 3: 14.708 ops/s +Iteration 4: 14.629 ops/s +Iteration 5: 14.692 ops/s + +14.324 ±(99.9%) 2.217 ops/s [Average] + (min, avg, max) = (13.354, 14.324, 14.708), stdev = 0.576 + CI (99.9%): [12.107, 16.541] (assumes normal distribution) + +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench + +Warm-up 1: 15.628 ops/s +Iteration 1: 15.991 ops/s +Iteration 2: 16.633 ops/s +Iteration 3: 16.583 ops/s +Iteration 4: 16.716 ops/s +Iteration 5: 16.762 ops/s + +16.537 ±(99.9%) 1.205 ops/s [Average] + (min, avg, max) = (15.991, 16.537, 16.762), stdev = 0.313 + CI (99.9%): [15.332, 17.743] (assumes normal distribution) + +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench + +Warm-up 1: 13.378 ops/s +Iteration 1: 15.049 ops/s +Iteration 2: 14.468 ops/s +Iteration 3: 14.469 ops/s +Iteration 4: 14.753 ops/s +Iteration 5: 14.958 ops/s + +14.739 ±(99.9%) 1.038 ops/s [Average] + (min, avg, max) = (14.468, 14.739, 15.049), stdev = 0.269 + CI (99.9%): [13.701, 15.777] (assumes normal distribution) +``` + +**GraalVM** + +``` +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench + +Warm-up 1: 14.357 ops/s +Iteration 1: 14.768 ops/s +Iteration 2: 14.922 ops/s +Iteration 3: 14.966 ops/s +Iteration 4: 14.805 ops/s +Iteration 5: 14.520 ops/s + +14.796 ±(99.9%) 0.671 ops/s [Average] + (min, avg, max) = (14.520, 14.796, 14.966), stdev = 0.174 + CI (99.9%): [14.125, 15.468] (assumes normal distribution) + +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench + +Warm-up 1: 11.592 ops/s +Iteration 1: 12.174 ops/s +Iteration 2: 11.734 ops/s +Iteration 3: 11.939 ops/s +Iteration 4: 12.026 ops/s +Iteration 5: 12.221 ops/s + +12.019 ±(99.9%) 0.752 ops/s [Average] + (min, avg, max) = (11.734, 12.019, 12.221), stdev = 0.195 + CI (99.9%): [11.267, 12.771] (assumes normal distribution) + +jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench + +Warm-up 1: 12.097 ops/s +Iteration 1: 13.072 ops/s +Iteration 2: 13.112 ops/s +Iteration 3: 13.103 ops/s +Iteration 4: 12.950 ops/s +Iteration 5: 13.011 ops/s + +13.049 ±(99.9%) 0.263 ops/s [Average] + (min, avg, max) = (12.950, 13.049, 13.112), stdev = 0.068 + CI (99.9%): [12.787, 13.312] (assumes normal distribution) +``` + +
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 f37d8e7b3..cf6f9471d 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 @@ -1,17 +1,21 @@ package space.kscience.kmath.jafama -import space.kscience.kmath.operations.* -import net.jafama.* +import net.jafama.FastMath +import net.jafama.StrictFastMath +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.Norm +import space.kscience.kmath.operations.PowerOperations +import space.kscience.kmath.operations.ScaleOperations /** * 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 override val zero: Double get() = 0.0 - public override val one: Double get() = 1.0 + public override inline val zero: Double get() = 0.0 + public override inline val one: Double get() = 1.0 - public override fun number(value: Number): Double = value.toDouble() + public override inline fun number(value: Number): Double = value.toDouble() public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { @@ -19,38 +23,39 @@ public object JafamaDoubleField : ExtendedField, Norm, S else -> super.binaryOperationFunction(operation) } - public override fun add(a: Double, b: Double): Double = a + b + public override inline fun add(a: Double, b: Double): Double = a + b - public override fun multiply(a: Double, b: Double): Double = a * b - public override fun divide(a: Double, b: Double): Double = a / b + public override inline fun multiply(a: Double, b: Double): Double = a * b + public override inline fun divide(a: Double, b: Double): Double = a / b - public override fun scale(a: Double, value: Double): Double = a * value + public override inline fun scale(a: Double, value: Double): Double = a * value - public override fun sin(arg: Double): Double = FastMath.sin(arg) - public override fun cos(arg: Double): Double = FastMath.cos(arg) - public override fun tan(arg: Double): Double = FastMath.tan(arg) - public override fun acos(arg: Double): Double = FastMath.acos(arg) - public override fun asin(arg: Double): Double = FastMath.asin(arg) - public override fun atan(arg: Double): Double = FastMath.atan(arg) + public override inline fun sin(arg: Double): Double = FastMath.sin(arg) + public override inline fun cos(arg: Double): Double = FastMath.cos(arg) + public override inline fun tan(arg: Double): Double = FastMath.tan(arg) + public override inline fun acos(arg: Double): Double = FastMath.acos(arg) + public override inline fun asin(arg: Double): Double = FastMath.asin(arg) + public override inline fun atan(arg: Double): Double = FastMath.atan(arg) - public override fun sinh(arg: Double): Double = FastMath.sinh(arg) - public override fun cosh(arg: Double): Double = FastMath.cosh(arg) - public override fun tanh(arg: Double): Double = FastMath.tanh(arg) - public override fun asinh(arg: Double): Double = FastMath.asinh(arg) - public override fun acosh(arg: Double): Double = FastMath.acosh(arg) - public override fun atanh(arg: Double): Double = FastMath.atanh(arg) + public override inline fun sinh(arg: Double): Double = FastMath.sinh(arg) + public override inline fun cosh(arg: Double): Double = FastMath.cosh(arg) + public override inline fun tanh(arg: Double): Double = FastMath.tanh(arg) + public override inline fun asinh(arg: Double): Double = FastMath.asinh(arg) + public override inline fun acosh(arg: Double): Double = FastMath.acosh(arg) + public override inline fun atanh(arg: Double): Double = FastMath.atanh(arg) - public override fun power(arg: Double, pow: Number): Double = FastMath.pow(arg, pow.toDouble()) - public override fun exp(arg: Double): Double = FastMath.exp(arg) - public override fun ln(arg: Double): Double = FastMath.log(arg) + public override inline fun sqrt(arg: Double): Double = FastMath.sqrt(arg) + public override inline fun power(arg: Double, pow: Number): Double = FastMath.pow(arg, pow.toDouble()) + public override inline fun exp(arg: Double): Double = FastMath.exp(arg) + public override inline fun ln(arg: Double): Double = FastMath.log(arg) - public override fun norm(arg: Double): Double = FastMath.abs(arg) + public override inline fun norm(arg: Double): Double = FastMath.abs(arg) - public override fun Double.unaryMinus(): Double = -this - public override fun Double.plus(b: Double): Double = this + b - public override fun Double.minus(b: Double): Double = this - b - public override fun Double.times(b: Double): Double = this * b - public override fun Double.div(b: Double): Double = this / b + public override inline fun Double.unaryMinus(): Double = -this + public override inline fun Double.plus(b: Double): Double = this + b + public override inline fun Double.minus(b: Double): Double = this - b + public override inline fun Double.times(b: Double): Double = this * b + public override inline fun Double.div(b: Double): Double = this / b } /** @@ -58,10 +63,10 @@ public object JafamaDoubleField : ExtendedField, Norm, S */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object StrictJafamaDoubleField : ExtendedField, Norm, ScaleOperations { - public override val zero: Double get() = 0.0 - public override val one: Double get() = 1.0 + public override inline val zero: Double get() = 0.0 + public override inline val one: Double get() = 1.0 - public override fun number(value: Number): Double = value.toDouble() + public override inline fun number(value: Number): Double = value.toDouble() public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { @@ -69,38 +74,37 @@ public object StrictJafamaDoubleField : ExtendedField, Norm super.binaryOperationFunction(operation) } - public override fun add(a: Double, b: Double): Double = a + b + public override inline fun add(a: Double, b: Double): Double = a + b - public override fun multiply(a: Double, b: Double): Double = a * b - public override fun divide(a: Double, b: Double): Double = a / b + public override inline fun multiply(a: Double, b: Double): Double = a * b + public override inline fun divide(a: Double, b: Double): Double = a / b - public override fun scale(a: Double, value: Double): Double = a * value + public override inline fun scale(a: Double, value: Double): Double = a * value - public override fun sin(arg: Double): Double = StrictFastMath.sin(arg) - public override fun cos(arg: Double): Double = StrictFastMath.cos(arg) - public override fun tan(arg: Double): Double = StrictFastMath.tan(arg) - public override fun acos(arg: Double): Double = StrictFastMath.acos(arg) - public override fun asin(arg: Double): Double = StrictFastMath.asin(arg) - public override fun atan(arg: Double): Double = StrictFastMath.atan(arg) + public override inline fun sin(arg: Double): Double = StrictFastMath.sin(arg) + public override inline fun cos(arg: Double): Double = StrictFastMath.cos(arg) + public override inline fun tan(arg: Double): Double = StrictFastMath.tan(arg) + public override inline fun acos(arg: Double): Double = StrictFastMath.acos(arg) + public override inline fun asin(arg: Double): Double = StrictFastMath.asin(arg) + public override inline fun atan(arg: Double): Double = StrictFastMath.atan(arg) - public override fun sinh(arg: Double): Double = StrictFastMath.sinh(arg) - public override fun cosh(arg: Double): Double = StrictFastMath.cosh(arg) - public override fun tanh(arg: Double): Double = StrictFastMath.tanh(arg) - public override fun asinh(arg: Double): Double = StrictFastMath.asinh(arg) - public override fun acosh(arg: Double): Double = StrictFastMath.acosh(arg) - public override fun atanh(arg: Double): Double = StrictFastMath.atanh(arg) + public override inline fun sinh(arg: Double): Double = StrictFastMath.sinh(arg) + public override inline fun cosh(arg: Double): Double = StrictFastMath.cosh(arg) + public override inline fun tanh(arg: Double): Double = StrictFastMath.tanh(arg) + public override inline fun asinh(arg: Double): Double = StrictFastMath.asinh(arg) + public override inline fun acosh(arg: Double): Double = StrictFastMath.acosh(arg) + public override inline fun atanh(arg: Double): Double = StrictFastMath.atanh(arg) - public override fun power(arg: Double, pow: Number): Double = StrictFastMath.pow(arg, pow.toDouble()) - public override fun exp(arg: Double): Double = StrictFastMath.exp(arg) - public override fun ln(arg: Double): Double = StrictFastMath.log(arg) + public override inline fun sqrt(arg: Double): Double = StrictFastMath.sqrt(arg) + public override inline fun power(arg: Double, pow: Number): Double = StrictFastMath.pow(arg, pow.toDouble()) + public override inline fun exp(arg: Double): Double = StrictFastMath.exp(arg) + public override inline fun ln(arg: Double): Double = StrictFastMath.log(arg) - public override fun norm(arg: Double): Double = StrictFastMath.abs(arg) + public override inline fun norm(arg: Double): Double = StrictFastMath.abs(arg) - public override fun Double.unaryMinus(): Double = -this - public override fun Double.plus(b: Double): Double = this + b - public override fun Double.minus(b: Double): Double = this - b - public override fun Double.times(b: Double): Double = this * b - public override fun Double.div(b: Double): Double = this / b + public override inline fun Double.unaryMinus(): Double = -this + public override inline fun Double.plus(b: Double): Double = this + b + public override inline fun Double.minus(b: Double): Double = this - b + public override inline fun Double.times(b: Double): Double = this * b + public override inline fun Double.div(b: Double): Double = this / b } - - From 45f158817551cf277688d42c3cdb8994f6401023 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 15 Jun 2021 13:18:40 +0700 Subject: [PATCH 18/39] Generated benchmarking reports --- benchmarks/build.gradle.kts | 8 +- .../kmath/benchmarks/JafamaBenchmark.kt | 6 +- buildSrc/build.gradle.kts | 16 ++- .../kscience/kmath/benchmarks/JmhReport.kt | 60 ++++++++++ .../benchmarks/addBenchmarkProperties.kt | 105 ++++++++++++++++++ kmath-ast/build.gradle.kts | 12 +- kmath-jafama/README.md | 97 +++------------- kmath-jafama/docs/README-TEMPLATE.md | 93 +--------------- settings.gradle.kts | 2 +- 9 files changed, 210 insertions(+), 189 deletions(-) create mode 100644 buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt create mode 100644 buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index f171437d3..2198ac5d6 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -1,3 +1,7 @@ +@file:Suppress("UNUSED_VARIABLE") + +import space.kscience.kmath.benchmarks.addBenchmarkProperties + plugins { kotlin("multiplatform") kotlin("plugin.allopen") @@ -32,7 +36,7 @@ kotlin { implementation(project(":kmath-dimensions")) implementation(project(":kmath-for-real")) implementation(project(":kmath-jafama")) - implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.0") + implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.1") } } @@ -130,3 +134,5 @@ tasks.withType { readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL } + +addBenchmarkProperties() diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt index 260eea2b6..24a730375 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt @@ -18,17 +18,17 @@ import kotlin.random.Random @State(Scope.Benchmark) internal class JafamaBenchmark { @Benchmark - fun jafamaBench(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> + fun jafama(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> JafamaDoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } } @Benchmark - fun coreBench(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> + fun core(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> DoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } } @Benchmark - fun strictJafamaBench(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> + fun strictJafama(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> StrictJafamaDoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 7ca4df19d..8ff1c4369 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,5 +1,19 @@ plugins { `kotlin-dsl` + kotlin("plugin.serialization") version "1.4.31" } -repositories.mavenCentral() +repositories { + gradlePluginPortal() + mavenCentral() +} + +dependencies { + api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") + api("ru.mipt.npm:gradle-tools:0.9.10") + api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.3.1") +} + +kotlin.sourceSets.all { + languageSettings.useExperimentalAnnotation("kotlin.ExperimentalStdlibApi") +} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt new file mode 100644 index 000000000..eaa0f59d8 --- /dev/null +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.serialization.Serializable + +@Serializable +data class JmhReport( + val jmhVersion: String, + val benchmark: String, + val mode: String, + val threads: Int, + val forks: Int, + val jvm: String, + val jvmArgs: List, + val jdkVersion: String, + val vmName: String, + val vmVersion: String, + val warmupIterations: Int, + val warmupTime: String, + val warmupBatchSize: Int, + val measurementIterations: Int, + val measurementTime: String, + val measurementBatchSize: Int, + val params: Map = emptyMap(), + val primaryMetric: PrimaryMetric, + val secondaryMetrics: Map, +) { + interface Metric { + val score: Double + val scoreError: Double + val scoreConfidence: List + val scorePercentiles: Map + val scoreUnit: String + } + + @Serializable + data class PrimaryMetric( + override val score: Double, + override val scoreError: Double, + override val scoreConfidence: List, + override val scorePercentiles: Map, + override val scoreUnit: String, + val rawDataHistogram: List>>>? = null, + val rawData: List>? = null, + ) : Metric + + @Serializable + data class SecondaryMetric( + override val score: Double, + override val scoreError: Double, + override val scoreConfidence: List, + override val scorePercentiles: Map, + override val scoreUnit: String, + val rawData: List>, + ) : Metric +} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt new file mode 100644 index 000000000..31d952157 --- /dev/null +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.serialization.* +import org.gradle.api.Project +import java.time.* +import java.time.format.* +import java.time.temporal.ChronoField.* + +private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run { + parseCaseInsensitive() + appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + appendLiteral('-') + appendValue(MONTH_OF_YEAR, 2) + appendLiteral('-') + appendValue(DAY_OF_MONTH, 2) + appendLiteral('T') + appendValue(HOUR_OF_DAY, 2) + appendLiteral('.') + appendValue(MINUTE_OF_HOUR, 2) + optionalStart() + appendLiteral('.') + appendValue(SECOND_OF_MINUTE, 2) + optionalStart() + appendFraction(NANO_OF_SECOND, 0, 9, true) + optionalStart() + appendOffsetId() + optionalStart() + appendLiteral('[') + parseCaseSensitive() + appendZoneRegionId() + appendLiteral(']') + toFormatter() +} + +private fun noun(number: Number, singular: String, plural: String) = if (number.toLong() == 1L) singular else plural + +fun Project.addBenchmarkProperties() { + val benchmarksProject = this + rootProject.subprojects.forEach { p -> + p.extensions.findByType(ru.mipt.npm.gradle.KScienceReadmeExtension::class.java)?.run { + benchmarksProject.extensions.findByType(kotlinx.benchmark.gradle.BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> + // TODO remove this hack when https://github.com/mipt-npm/gradle-tools/pull/15 is merged + @Suppress("UNCHECKED_CAST") + (javaClass.getDeclaredField("properties") + .also { + it.isAccessible = true + }[this] as MutableMap Any?>)["benchmark${cfg.name.replaceFirstChar(Char::uppercase)}"] = + { + val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}") + + val resDirectory = launches.listFiles()?.maxByOrNull { + LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant() + } + + if (resDirectory == null) { + "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." + } else { + val reports = + kotlinx.serialization.json.Json.decodeFromString>( + resDirectory.resolve("jvm.json").readText() + ) + + buildString { + appendLine("
") + appendLine("") + appendLine("Report for benchmark configuration ${cfg.name}") + appendLine("") + appendLine() + val first = reports.first() + + appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:") + appendLine() + appendLine("```") + appendLine("${first.jvm} ${ + first.jvmArgs.joinToString(" ") + }") + appendLine("```") + + appendLine("* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${ + noun(first.warmupIterations, "iteration", "iterations") + } by ${first.warmupTime} and ${first.measurementIterations} measurement ${ + noun(first.measurementIterations, "iteration", "iterations") + } by ${first.measurementTime}.") + + appendLine() + appendLine("| Benchmark | Score |") + appendLine("|:---------:|:-----:|") + + reports.forEach { report -> + appendLine("|`${report.benchmark}`|${report.primaryMetric.score} ± ${report.primaryMetric.scoreError} ${report.primaryMetric.scoreUnit}|") + } + + appendLine("
") + } + } + } + } + } + } +} diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 89647c9e9..8209a0dad 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -62,25 +62,21 @@ readme { feature( id = "expression-language", - description = "Expression language and its parser", ref = "src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt" - ) + ) { "Expression language and its parser" } feature( id = "mst-jvm-codegen", - description = "Dynamic MST to JVM bytecode compiler", ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt" - ) + ) { "Dynamic MST to JVM bytecode compiler" } feature( id = "mst-js-codegen", - description = "Dynamic MST to JS compiler", ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt" - ) + ) { "Dynamic MST to JS compiler" } feature( id = "rendering", - description = "Extendable MST rendering", ref = "src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt" - ) + ) { "Extendable MST rendering" } } diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index 9b439c5c2..ef8fcd352 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -50,95 +50,24 @@ fun main() { ## Performance -According to benchmarking data, on Hotspot Jafama functions are 20% faster than JDK math. On GraalVM, they are slower. +According to KMath benchmarks on GraalVM, Jafama functions are slower than JDK math; however, there are indications that on Hotspot Jafama is a bit faster.
-Raw data: + +Report for benchmark configuration jafamaDouble + -**Hotspot** +* Run on OpenJDK 64-Bit Server VM (build 11.0.11+8-jvmci-21.1-b05) with Java process: ``` -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench - -Warm-up 1: 11.447 ops/s -Iteration 1: 13.354 ops/s -Iteration 2: 14.237 ops/s -Iteration 3: 14.708 ops/s -Iteration 4: 14.629 ops/s -Iteration 5: 14.692 ops/s - -14.324 ±(99.9%) 2.217 ops/s [Average] - (min, avg, max) = (13.354, 14.324, 14.708), stdev = 0.576 - CI (99.9%): [12.107, 16.541] (assumes normal distribution) - -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench - -Warm-up 1: 15.628 ops/s -Iteration 1: 15.991 ops/s -Iteration 2: 16.633 ops/s -Iteration 3: 16.583 ops/s -Iteration 4: 16.716 ops/s -Iteration 5: 16.762 ops/s - -16.537 ±(99.9%) 1.205 ops/s [Average] - (min, avg, max) = (15.991, 16.537, 16.762), stdev = 0.313 - CI (99.9%): [15.332, 17.743] (assumes normal distribution) - -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench - -Warm-up 1: 13.378 ops/s -Iteration 1: 15.049 ops/s -Iteration 2: 14.468 ops/s -Iteration 3: 14.469 ops/s -Iteration 4: 14.753 ops/s -Iteration 5: 14.958 ops/s - -14.739 ±(99.9%) 1.038 ops/s [Average] - (min, avg, max) = (14.468, 14.739, 15.049), stdev = 0.269 - CI (99.9%): [13.701, 15.777] (assumes normal distribution) -``` - -**GraalVM** - -``` -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench - -Warm-up 1: 14.357 ops/s -Iteration 1: 14.768 ops/s -Iteration 2: 14.922 ops/s -Iteration 3: 14.966 ops/s -Iteration 4: 14.805 ops/s -Iteration 5: 14.520 ops/s - -14.796 ±(99.9%) 0.671 ops/s [Average] - (min, avg, max) = (14.520, 14.796, 14.966), stdev = 0.174 - CI (99.9%): [14.125, 15.468] (assumes normal distribution) - -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench - -Warm-up 1: 11.592 ops/s -Iteration 1: 12.174 ops/s -Iteration 2: 11.734 ops/s -Iteration 3: 11.939 ops/s -Iteration 4: 12.026 ops/s -Iteration 5: 12.221 ops/s - -12.019 ±(99.9%) 0.752 ops/s [Average] - (min, avg, max) = (11.734, 12.019, 12.221), stdev = 0.195 - CI (99.9%): [11.267, 12.771] (assumes normal distribution) - -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench - -Warm-up 1: 12.097 ops/s -Iteration 1: 13.072 ops/s -Iteration 2: 13.112 ops/s -Iteration 3: 13.103 ops/s -Iteration 4: 12.950 ops/s -Iteration 5: 13.011 ops/s - -13.049 ±(99.9%) 0.263 ops/s [Average] - (min, avg, max) = (12.950, 13.049, 13.112), stdev = 0.068 - CI (99.9%): [12.787, 13.312] (assumes normal distribution) +/home/commandertvis/graalvm-ce-java11/bin/java -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCIProduct -XX:-UnlockExperimentalVMOptions -XX:ThreadPriorityPolicy=1 -javaagent:/home/commandertvis/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core-jvm/1.5.0/d8cebccdcddd029022aa8646a5a953ff88b13ac8/kotlinx-coroutines-core-jvm-1.5.0.jar -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -ea ``` +* JMH 1.21 was used in `thrpt` mode with 1 warmup iteration by 1000 ms and 5 measurement iterations by 1000 ms. +| Benchmark | Score | +|:---------:|:-----:| +|`space.kscience.kmath.benchmarks.JafamaBenchmark.core`|14.296120859512893 ± 0.36462633435888736 ops/s| +|`space.kscience.kmath.benchmarks.JafamaBenchmark.jafama`|11.431566395649781 ± 2.570896777898243 ops/s| +|`space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafama`|11.746020495694117 ± 6.205909559197869 ops/s|
+ diff --git a/kmath-jafama/docs/README-TEMPLATE.md b/kmath-jafama/docs/README-TEMPLATE.md index fa58f7697..54348467b 100644 --- a/kmath-jafama/docs/README-TEMPLATE.md +++ b/kmath-jafama/docs/README-TEMPLATE.md @@ -24,95 +24,6 @@ fun main() { ## Performance -According to benchmarking data, on Hotspot Jafama functions are 20% faster than JDK math. On GraalVM, they are slower. +According to KMath benchmarks on GraalVM, Jafama functions are slower than JDK math; however, there are indications that on Hotspot Jafama is a bit faster. -
-Raw data: - -**Hotspot** - -``` -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench - -Warm-up 1: 11.447 ops/s -Iteration 1: 13.354 ops/s -Iteration 2: 14.237 ops/s -Iteration 3: 14.708 ops/s -Iteration 4: 14.629 ops/s -Iteration 5: 14.692 ops/s - -14.324 ±(99.9%) 2.217 ops/s [Average] - (min, avg, max) = (13.354, 14.324, 14.708), stdev = 0.576 - CI (99.9%): [12.107, 16.541] (assumes normal distribution) - -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench - -Warm-up 1: 15.628 ops/s -Iteration 1: 15.991 ops/s -Iteration 2: 16.633 ops/s -Iteration 3: 16.583 ops/s -Iteration 4: 16.716 ops/s -Iteration 5: 16.762 ops/s - -16.537 ±(99.9%) 1.205 ops/s [Average] - (min, avg, max) = (15.991, 16.537, 16.762), stdev = 0.313 - CI (99.9%): [15.332, 17.743] (assumes normal distribution) - -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench - -Warm-up 1: 13.378 ops/s -Iteration 1: 15.049 ops/s -Iteration 2: 14.468 ops/s -Iteration 3: 14.469 ops/s -Iteration 4: 14.753 ops/s -Iteration 5: 14.958 ops/s - -14.739 ±(99.9%) 1.038 ops/s [Average] - (min, avg, max) = (14.468, 14.739, 15.049), stdev = 0.269 - CI (99.9%): [13.701, 15.777] (assumes normal distribution) -``` - -**GraalVM** - -``` -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.coreBench - -Warm-up 1: 14.357 ops/s -Iteration 1: 14.768 ops/s -Iteration 2: 14.922 ops/s -Iteration 3: 14.966 ops/s -Iteration 4: 14.805 ops/s -Iteration 5: 14.520 ops/s - -14.796 ±(99.9%) 0.671 ops/s [Average] - (min, avg, max) = (14.520, 14.796, 14.966), stdev = 0.174 - CI (99.9%): [14.125, 15.468] (assumes normal distribution) - -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.jafamaBench - -Warm-up 1: 11.592 ops/s -Iteration 1: 12.174 ops/s -Iteration 2: 11.734 ops/s -Iteration 3: 11.939 ops/s -Iteration 4: 12.026 ops/s -Iteration 5: 12.221 ops/s - -12.019 ±(99.9%) 0.752 ops/s [Average] - (min, avg, max) = (11.734, 12.019, 12.221), stdev = 0.195 - CI (99.9%): [11.267, 12.771] (assumes normal distribution) - -jvm: space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafamaBench - -Warm-up 1: 12.097 ops/s -Iteration 1: 13.072 ops/s -Iteration 2: 13.112 ops/s -Iteration 3: 13.103 ops/s -Iteration 4: 12.950 ops/s -Iteration 5: 13.011 ops/s - -13.049 ±(99.9%) 0.263 ops/s [Average] - (min, avg, max) = (12.950, 13.049, 13.112), stdev = 0.068 - CI (99.9%): [12.787, 13.312] (assumes normal distribution) -``` - -
+${benchmarkJafamaDouble} diff --git a/settings.gradle.kts b/settings.gradle.kts index 15a6a176c..710017588 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,7 +5,7 @@ pluginManagement { gradlePluginPortal() } - val toolsVersion = "0.9.9" + val toolsVersion = "0.9.10" val kotlinVersion = "1.5.0" plugins { From 94c58b7749e5e4ea69d167cda4ea282fa3d9077f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 15 Jun 2021 13:45:08 +0300 Subject: [PATCH 19/39] Fix Univariate histogram filling --- CHANGELOG.md | 1 + build.gradle.kts | 2 +- .../kmath/histogram/TreeHistogramSpace.kt | 89 ++++++++++--------- .../kmath/histogram/UnivariateHistogram.kt | 6 +- .../kmath/histogram/TreeHistogramTest.kt | 24 +++++ 5 files changed, 77 insertions(+), 45 deletions(-) create mode 100644 kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f7b6b529..12540821e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ ### Fixed - Ring inherits RingOperations, not GroupOperations +- Univariate histogram filling ### Security diff --git a/build.gradle.kts b/build.gradle.kts index 86394d792..9978281f2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,7 +17,7 @@ allprojects { } group = "space.kscience" - version = "0.3.0-dev-13" + version = "0.3.0-dev-14" } subprojects { diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt index 6ae8b5ee3..8d05df68a 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt @@ -35,51 +35,56 @@ public class TreeHistogram( override val bins: Collection get() = binMap.values } +@OptIn(UnstableKMathAPI::class) +private class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain) : UnivariateHistogramBuilder { + + private class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : + ClosedFloatingPointRange by domain.range + + private val bins: TreeMap = TreeMap() + + fun get(value: Double): BinCounter? = bins.getBin(value) + + fun createBin(value: Double): BinCounter { + val binDefinition = binFactory(value) + val newBin = BinCounter(binDefinition) + synchronized(this) { bins[binDefinition.center] = newBin } + return newBin + } + + /** + * Thread safe put operation + */ + override fun putValue(at: Double, value: Double) { + (get(at) ?: createBin(at)).apply { + counter.add(value) + } + } + + override fun putValue(point: Buffer, value: Number) { + require(point.size == 1) { "Only points with single value could be used in univariate histogram" } + putValue(point[0], value.toDouble()) + } + + fun build(): TreeHistogram { + val map = bins.mapValuesTo(TreeMap()) { (_, binCounter) -> + val count = binCounter.counter.value + UnivariateBin(binCounter.domain, count, sqrt(count)) + } + return TreeHistogram(map) + } +} + /** * A space for univariate histograms with variable bin borders based on a tree map */ @UnstableKMathAPI public class TreeHistogramSpace( - public val binFactory: (Double) -> UnivariateDomain, + private val binFactory: (Double) -> UnivariateDomain, ) : Group, ScaleOperations { - private class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : - ClosedFloatingPointRange by domain.range - - public fun produce(builder: UnivariateHistogramBuilder.() -> Unit): UnivariateHistogram { - val bins: TreeMap = TreeMap() - val hBuilder = object : UnivariateHistogramBuilder { - - fun get(value: Double): BinCounter? = bins.getBin(value) - - fun createBin(value: Double): BinCounter { - val binDefinition = binFactory(value) - val newBin = BinCounter(binDefinition) - synchronized(this) { bins[binDefinition.center] = newBin } - return newBin - } - - /** - * Thread safe put operation - */ - override fun putValue(at: Double, value: Double) { - (get(at) ?: createBin(at)).apply { - counter.add(value) - } - } - - override fun putValue(point: Buffer, value: Number) { - put(point[0], value.toDouble()) - } - } - hBuilder.apply(builder) - val resBins = TreeMap() - bins.forEach { (key, binCounter) -> - val count = binCounter.counter.value - resBins[key] = UnivariateBin(binCounter.domain, count, sqrt(count)) - } - return TreeHistogram(resBins) - } + public fun fill(block: UnivariateHistogramBuilder.() -> Unit): UnivariateHistogram = + TreeHistogramBuilder(binFactory).apply(block).build() override fun add( a: UnivariateHistogram, @@ -89,7 +94,8 @@ public class TreeHistogramSpace( // require(b.context == this) { "Histogram $b does not belong to this context" } val bins = TreeMap().apply { (a.bins.map { it.domain } union b.bins.map { it.domain }).forEach { def -> - put(def.center, + put( + def.center, UnivariateBin( def, value = (a[def.center]?.value ?: 0.0) + (b[def.center]?.value ?: 0.0), @@ -105,7 +111,8 @@ public class TreeHistogramSpace( override fun scale(a: UnivariateHistogram, value: Double): UnivariateHistogram { val bins = TreeMap().apply { a.bins.forEach { bin -> - put(bin.domain.center, + put( + bin.domain.center, UnivariateBin( bin.domain, value = bin.value * value.toDouble(), @@ -120,7 +127,7 @@ public class TreeHistogramSpace( override fun UnivariateHistogram.unaryMinus(): UnivariateHistogram = this * (-1) - override val zero: UnivariateHistogram = produce { } + override val zero: UnivariateHistogram by lazy { fill { } } public companion object { /** diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt index 70125e22e..0ad96ad46 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt @@ -13,7 +13,7 @@ import space.kscience.kmath.structures.asSequence @UnstableKMathAPI public val UnivariateDomain.center: Double - get() = (range.endInclusive - range.start) / 2 + get() = (range.endInclusive + range.start) / 2 /** * A univariate bin based an a range @@ -45,7 +45,7 @@ public interface UnivariateHistogram : Histogram{ binSize: Double, start: Double = 0.0, builder: UnivariateHistogramBuilder.() -> Unit, - ): UnivariateHistogram = TreeHistogramSpace.uniform(binSize, start).produce(builder) + ): UnivariateHistogram = TreeHistogramSpace.uniform(binSize, start).fill(builder) /** * Build and fill a histogram with custom borders. Returns a read-only histogram. @@ -53,7 +53,7 @@ public interface UnivariateHistogram : Histogram{ public fun custom( borders: DoubleArray, builder: UnivariateHistogramBuilder.() -> Unit, - ): UnivariateHistogram = TreeHistogramSpace.custom(borders).produce(builder) + ): UnivariateHistogram = TreeHistogramSpace.custom(borders).fill(builder) } } diff --git a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt new file mode 100644 index 000000000..28a1b03cb --- /dev/null +++ b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.histogram + +import org.junit.jupiter.api.Test +import kotlin.random.Random +import kotlin.test.assertTrue + +class TreeHistogramTest { + + @Test + fun normalFill() { + val histogram = UnivariateHistogram.uniform(0.1) { + repeat(100_000) { + putValue(Random.nextDouble()) + } + } + + assertTrue { histogram.bins.count() > 10 } + } +} \ No newline at end of file From 5d5f84ad55e65af19c8b4a8daa549ba306a9f722 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 15 Jun 2021 20:37:40 +0700 Subject: [PATCH 20/39] Some refactoring of AST rendering --- .../kmath/ast/rendering/MathRenderer.kt | 6 +- .../kscience/kmath/ast/rendering/features.kt | 41 +++++---- .../ast/rendering/{stages.kt => phases.kt} | 89 ++++++++++--------- 3 files changed, 68 insertions(+), 68 deletions(-) rename kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/{stages.kt => phases.kt} (76%) diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt index c33f95483..68d829724 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt @@ -54,7 +54,7 @@ public open class FeaturedMathRenderer(public val features: List) @UnstableKMathAPI public open class FeaturedMathRendererWithPostProcess( features: List, - public val stages: List, + public val stages: List, ) : FeaturedMathRenderer(features) { public override fun render(mst: MST): MathSyntax { val res = super.render(mst) @@ -65,7 +65,7 @@ public open class FeaturedMathRendererWithPostProcess( /** * Logical unit of [MathSyntax] post-processing. */ - public fun interface PostProcessStage { + public fun interface PostProcessPhase { /** * Performs the specified action over [MathSyntax]. */ @@ -102,7 +102,7 @@ public open class FeaturedMathRendererWithPostProcess( // Printing terminal nodes as string PrintNumeric, - PrintSymbolic, + PrintSymbol, ), listOf( BetterExponent, diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt index 863825799..a2f42d1bf 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt @@ -13,15 +13,14 @@ import space.kscience.kmath.operations.* import kotlin.reflect.KClass /** - * Prints any [MST.Symbolic] as a [SymbolSyntax] containing the [MST.Symbolic.value] of it. + * Prints any [Symbol] as a [SymbolSyntax] containing the [Symbol.value] of it. * * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object PrintSymbolic : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): SymbolSyntax? = - if (node !is Symbol) null - else SymbolSyntax(string = node.identity) +public val PrintSymbol: RenderFeature = RenderFeature { _, node -> + if (node !is Symbol) null + else SymbolSyntax(string = node.identity) } /** @@ -30,8 +29,8 @@ public object PrintSymbolic : RenderFeature { * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object PrintNumeric : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): NumberSyntax? = if (node !is MST.Numeric) +public val PrintNumeric: RenderFeature = RenderFeature { _, node -> + if (node !is MST.Numeric) null else NumberSyntax(string = node.value.toString()) @@ -141,7 +140,7 @@ public class PrettyPrintIntegers(public val types: Set>) : Re */ @UnstableKMathAPI public class PrettyPrintPi(public val symbols: Set) : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): SpecialSymbolSyntax? = + public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = if (node !is Symbol || node.identity !in symbols) null else @@ -203,7 +202,7 @@ public abstract class Binary(public val operations: Collection?) : Rende */ @UnstableKMathAPI public class BinaryPlus(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): BinaryPlusSyntax = + public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryPlusSyntax( operation = node.operation, left = OperandSyntax(parent.render(node.left), true), @@ -225,7 +224,7 @@ public class BinaryPlus(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class BinaryMinus(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): BinaryMinusSyntax = + public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryMinusSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), @@ -247,7 +246,7 @@ public class BinaryMinus(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class UnaryPlus(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryPlusSyntax = UnaryPlusSyntax( + public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryPlusSyntax( operation = node.operation, operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), ) @@ -267,7 +266,7 @@ public class UnaryPlus(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class UnaryMinus(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryMinusSyntax = UnaryMinusSyntax( + public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryMinusSyntax( operation = node.operation, operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), ) @@ -287,7 +286,7 @@ public class UnaryMinus(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class Fraction(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): FractionSyntax = FractionSyntax( + public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = FractionSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), right = OperandSyntax(operand = parent.render(node.right), parentheses = true), @@ -309,7 +308,7 @@ public class Fraction(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class BinaryOperator(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): BinaryOperatorSyntax = + public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(name = node.operation), @@ -332,7 +331,7 @@ public class BinaryOperator(operations: Collection?) : Binary(operations */ @UnstableKMathAPI public class UnaryOperator(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryOperatorSyntax = + public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(node.operation), @@ -354,7 +353,7 @@ public class UnaryOperator(operations: Collection?) : Unary(operations) */ @UnstableKMathAPI public class Power(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): SuperscriptSyntax = + public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = SuperscriptSyntax( operation = node.operation, left = OperandSyntax(parent.render(node.left), true), @@ -374,7 +373,7 @@ public class Power(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class SquareRoot(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): RadicalSyntax = + public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = RadicalSyntax(operation = node.operation, operand = parent.render(node.value)) public companion object { @@ -392,7 +391,7 @@ public class SquareRoot(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class Exponent(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): ExponentSyntax = ExponentSyntax( + public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = ExponentSyntax( operation = node.operation, operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), useOperatorForm = true, @@ -413,7 +412,7 @@ public class Exponent(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class Multiplication(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MultiplicationSyntax = + public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = MultiplicationSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), @@ -436,7 +435,7 @@ public class Multiplication(operations: Collection?) : Binary(operations */ @UnstableKMathAPI public class InverseTrigonometricOperations(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryOperatorSyntax = + public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "arc")), @@ -463,7 +462,7 @@ public class InverseTrigonometricOperations(operations: Collection?) : U */ @UnstableKMathAPI public class InverseHyperbolicOperations(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryOperatorSyntax = + public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "ar")), diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt similarity index 76% rename from kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt rename to kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt index 1f31af853..6da4994a6 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.ast.rendering +import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess.PostProcessPhase import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.FieldOperations import space.kscience.kmath.operations.GroupOperations @@ -17,8 +18,8 @@ import space.kscience.kmath.operations.RingOperations * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostProcessStage { - public override fun perform(node: MathSyntax): Unit = when (node) { +public val BetterMultiplication: PostProcessPhase = PostProcessPhase { node -> + fun perform(node: MathSyntax): Unit = when (node) { is NumberSyntax -> Unit is SymbolSyntax -> Unit is OperatorNameSyntax -> Unit @@ -81,6 +82,8 @@ public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostPro perform(node.right) } } + + perform(node) } /** @@ -89,68 +92,68 @@ public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostPro * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object BetterFraction : FeaturedMathRendererWithPostProcess.PostProcessStage { - private fun perform0(node: MathSyntax, infix: Boolean = false): Unit = when (node) { +public val BetterFraction: PostProcessPhase = PostProcessPhase { node -> + fun perform(node: MathSyntax, infix: Boolean = false): Unit = when (node) { is NumberSyntax -> Unit is SymbolSyntax -> Unit is OperatorNameSyntax -> Unit is SpecialSymbolSyntax -> Unit - is OperandSyntax -> perform0(node.operand, infix) + is OperandSyntax -> perform(node.operand, infix) is UnaryOperatorSyntax -> { - perform0(node.prefix, infix) - perform0(node.operand, infix) + perform(node.prefix, infix) + perform(node.operand, infix) } - is UnaryPlusSyntax -> perform0(node.operand, infix) - is UnaryMinusSyntax -> perform0(node.operand, infix) - is RadicalSyntax -> perform0(node.operand, infix) - is ExponentSyntax -> perform0(node.operand, infix) + is UnaryPlusSyntax -> perform(node.operand, infix) + is UnaryMinusSyntax -> perform(node.operand, infix) + is RadicalSyntax -> perform(node.operand, infix) + is ExponentSyntax -> perform(node.operand, infix) is SuperscriptSyntax -> { - perform0(node.left, true) - perform0(node.right, true) + perform(node.left, true) + perform(node.right, true) } is SubscriptSyntax -> { - perform0(node.left, true) - perform0(node.right, true) + perform(node.left, true) + perform(node.right, true) } is BinaryOperatorSyntax -> { - perform0(node.prefix, infix) - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.prefix, infix) + perform(node.left, infix) + perform(node.right, infix) } is BinaryPlusSyntax -> { - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.left, infix) + perform(node.right, infix) } is BinaryMinusSyntax -> { - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.left, infix) + perform(node.right, infix) } is FractionSyntax -> { node.infix = infix - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.left, infix) + perform(node.right, infix) } is RadicalWithIndexSyntax -> { - perform0(node.left, true) - perform0(node.right, true) + perform(node.left, true) + perform(node.right, true) } is MultiplicationSyntax -> { - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.left, infix) + perform(node.right, infix) } } - public override fun perform(node: MathSyntax): Unit = perform0(node) + perform(node) } /** @@ -160,39 +163,37 @@ public object BetterFraction : FeaturedMathRendererWithPostProcess.PostProcessSt * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object BetterExponent : FeaturedMathRendererWithPostProcess.PostProcessStage { - private fun perform0(node: MathSyntax): Boolean { +public val BetterExponent: PostProcessPhase = PostProcessPhase { node -> + fun perform(node: MathSyntax): Boolean { return when (node) { is NumberSyntax -> false is SymbolSyntax -> false is OperatorNameSyntax -> false is SpecialSymbolSyntax -> false - is OperandSyntax -> perform0(node.operand) - is UnaryOperatorSyntax -> perform0(node.prefix) || perform0(node.operand) - is UnaryPlusSyntax -> perform0(node.operand) - is UnaryMinusSyntax -> perform0(node.operand) + is OperandSyntax -> perform(node.operand) + is UnaryOperatorSyntax -> perform(node.prefix) || perform(node.operand) + is UnaryPlusSyntax -> perform(node.operand) + is UnaryMinusSyntax -> perform(node.operand) is RadicalSyntax -> true is ExponentSyntax -> { - val r = perform0(node.operand) + val r = perform(node.operand) node.useOperatorForm = r r } is SuperscriptSyntax -> true is SubscriptSyntax -> true - is BinaryOperatorSyntax -> perform0(node.prefix) || perform0(node.left) || perform0(node.right) - is BinaryPlusSyntax -> perform0(node.left) || perform0(node.right) - is BinaryMinusSyntax -> perform0(node.left) || perform0(node.right) + is BinaryOperatorSyntax -> perform(node.prefix) || perform(node.left) || perform(node.right) + is BinaryPlusSyntax -> perform(node.left) || perform(node.right) + is BinaryMinusSyntax -> perform(node.left) || perform(node.right) is FractionSyntax -> true is RadicalWithIndexSyntax -> true - is MultiplicationSyntax -> perform0(node.left) || perform0(node.right) + is MultiplicationSyntax -> perform(node.left) || perform(node.right) } } - public override fun perform(node: MathSyntax) { - perform0(node) - } + perform(node) } /** @@ -203,7 +204,7 @@ public object BetterExponent : FeaturedMathRendererWithPostProcess.PostProcessSt */ @UnstableKMathAPI public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) : - FeaturedMathRendererWithPostProcess.PostProcessStage { + PostProcessPhase { public override fun perform(node: MathSyntax): Unit = when (node) { is NumberSyntax -> Unit is SymbolSyntax -> Unit From 7feb87ff052b0a99b5790cf788814fbee46f08cc Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 19 Jun 2021 20:52:26 +0700 Subject: [PATCH 21/39] Refactor benchmark report writer --- build.gradle.kts | 4 +- buildSrc/build.gradle.kts | 5 +- .../benchmarks/addBenchmarkProperties.kt | 89 +++++++++---------- settings.gradle.kts | 2 +- 4 files changed, 47 insertions(+), 53 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9978281f2..93cd67d47 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,9 +10,7 @@ allprojects { maven("http://logicrunch.research.it.uu.se/maven") { isAllowInsecureProtocol = true } - maven("https://oss.sonatype.org/content/repositories/snapshots") { - - } + maven("https://oss.sonatype.org/content/repositories/snapshots") mavenCentral() } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8ff1c4369..fe69b05c6 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -4,13 +4,14 @@ plugins { } repositories { - gradlePluginPortal() + maven("https://repo.kotlin.link") mavenCentral() + gradlePluginPortal() } dependencies { api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") - api("ru.mipt.npm:gradle-tools:0.9.10") + api("ru.mipt.npm:gradle-tools:0.10.0") api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.3.1") } diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt index 31d952157..b55e1320e 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -5,8 +5,11 @@ package space.kscience.kmath.benchmarks +import kotlinx.benchmark.gradle.BenchmarksExtension import kotlinx.serialization.* +import kotlinx.serialization.json.* import org.gradle.api.Project +import ru.mipt.npm.gradle.KScienceReadmeExtension import java.time.* import java.time.format.* import java.time.temporal.ChronoField.* @@ -42,63 +45,55 @@ private fun noun(number: Number, singular: String, plural: String) = if (number. fun Project.addBenchmarkProperties() { val benchmarksProject = this rootProject.subprojects.forEach { p -> - p.extensions.findByType(ru.mipt.npm.gradle.KScienceReadmeExtension::class.java)?.run { - benchmarksProject.extensions.findByType(kotlinx.benchmark.gradle.BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> - // TODO remove this hack when https://github.com/mipt-npm/gradle-tools/pull/15 is merged - @Suppress("UNCHECKED_CAST") - (javaClass.getDeclaredField("properties") - .also { - it.isAccessible = true - }[this] as MutableMap Any?>)["benchmark${cfg.name.replaceFirstChar(Char::uppercase)}"] = - { - val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}") + p.extensions.findByType(KScienceReadmeExtension::class.java)?.run { + benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> + property("benchmark${cfg.name.replaceFirstChar(Char::uppercase)}") { + val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}") - val resDirectory = launches.listFiles()?.maxByOrNull { - LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant() - } + val resDirectory = launches.listFiles()?.maxByOrNull { + LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant() + } - if (resDirectory == null) { - "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." - } else { - val reports = - kotlinx.serialization.json.Json.decodeFromString>( - resDirectory.resolve("jvm.json").readText() - ) + if (resDirectory == null) { + "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." + } else { + val reports = + Json.decodeFromString>(resDirectory.resolve("jvm.json").readText()) - buildString { - appendLine("
") - appendLine("") - appendLine("Report for benchmark configuration ${cfg.name}") - appendLine("") - appendLine() - val first = reports.first() + buildString { + appendLine("
") + appendLine("") + appendLine("Report for benchmark configuration ${cfg.name}") + appendLine("") + appendLine() + val first = reports.first() - appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:") - appendLine() - appendLine("```") - appendLine("${first.jvm} ${ - first.jvmArgs.joinToString(" ") - }") - appendLine("```") + appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:") + appendLine() + appendLine("```") + appendLine("${first.jvm} ${ + first.jvmArgs.joinToString(" ") + }") + appendLine("```") - appendLine("* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${ - noun(first.warmupIterations, "iteration", "iterations") - } by ${first.warmupTime} and ${first.measurementIterations} measurement ${ - noun(first.measurementIterations, "iteration", "iterations") - } by ${first.measurementTime}.") + appendLine("* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${ + noun(first.warmupIterations, "iteration", "iterations") + } by ${first.warmupTime} and ${first.measurementIterations} measurement ${ + noun(first.measurementIterations, "iteration", "iterations") + } by ${first.measurementTime}.") - appendLine() - appendLine("| Benchmark | Score |") - appendLine("|:---------:|:-----:|") + appendLine() + appendLine("| Benchmark | Score |") + appendLine("|:---------:|:-----:|") - reports.forEach { report -> - appendLine("|`${report.benchmark}`|${report.primaryMetric.score} ± ${report.primaryMetric.scoreError} ${report.primaryMetric.scoreUnit}|") - } - - appendLine("
") + reports.forEach { report -> + appendLine("|`${report.benchmark}`|${report.primaryMetric.score} ± ${report.primaryMetric.scoreError} ${report.primaryMetric.scoreUnit}|") } + + appendLine("
") } } + } } } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 710017588..063c69280 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,7 +5,7 @@ pluginManagement { gradlePluginPortal() } - val toolsVersion = "0.9.10" + val toolsVersion = "0.10.0" val kotlinVersion = "1.5.0" plugins { From 9f513b355c767c2c0536c5e4d7ad8df7dc6c2691 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Jun 2021 01:16:08 +0700 Subject: [PATCH 22/39] Update CMRandomGeneratorWrapper --- .../kmath/commons/random/CMRandomGeneratorWrapper.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt index 16a6967e2..4e2fbf980 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt @@ -5,7 +5,11 @@ package space.kscience.kmath.commons.random +import kotlinx.coroutines.runBlocking +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.stat.next public class CMRandomGeneratorWrapper( public val factory: (IntArray) -> RandomGenerator, @@ -33,7 +37,10 @@ public class CMRandomGeneratorWrapper( public override fun nextInt(): Int = generator.nextInt() public override fun nextInt(n: Int): Int = generator.nextInt(n) - public override fun nextGaussian(): Double = TODO() + + @PerformancePitfall + public override fun nextGaussian(): Double = runBlocking { GaussianSampler(0.0, 1.0).next(generator) } + public override fun nextDouble(): Double = generator.nextDouble() public override fun nextLong(): Long = generator.nextLong() } From 83fc4e28d825343860c724f9a16fcf0b86f5f56b Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 3 Jul 2021 17:11:47 +0700 Subject: [PATCH 23/39] Generate README, bump versions of Kotlin, Gradle, ND4J, ASM --- README.md | 4 ++-- benchmarks/build.gradle.kts | 2 +- build.gradle.kts | 8 ++++++-- gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- kmath-ast/README.md | 6 +++--- kmath-ast/build.gradle.kts | 3 +-- kmath-complex/README.md | 6 +++--- kmath-core/README.md | 6 +++--- kmath-ejml/README.md | 6 +++--- kmath-for-real/README.md | 6 +++--- kmath-functions/README.md | 6 +++--- kmath-jafama/README.md | 12 ++++++------ kmath-kotlingrad/README.md | 6 +++--- kmath-nd4j/README.md | 6 +++--- kmath-nd4j/build.gradle.kts | 5 ++--- kmath-tensors/README.md | 6 +++--- settings.gradle.kts | 5 ++--- 19 files changed, 49 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 015988cd3..7645256d9 100644 --- a/README.md +++ b/README.md @@ -309,8 +309,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:0.3.0-dev-13") - // api("space.kscience:kmath-core-jvm:0.3.0-dev-13") for jvm-specific version + api("space.kscience:kmath-core:0.3.0-dev-14") + // api("space.kscience:kmath-core-jvm:0.3.0-dev-14") for jvm-specific version } ``` diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 2198ac5d6..d96c5a8b6 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -47,7 +47,7 @@ kotlin { implementation(project(":kmath-nd4j")) implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-viktor")) - implementation("org.nd4j:nd4j-native:1.0.0-beta7") + implementation("org.nd4j:nd4j-native:1.0.0-M1") // uncomment if your system supports AVX2 // val os = System.getProperty("os.name") // diff --git a/build.gradle.kts b/build.gradle.kts index 93cd67d47..d0f6ced78 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,12 +28,16 @@ subprojects { dokkaSourceSets.all { val readmeFile = File(this@subprojects.projectDir, "README.md") if (readmeFile.exists()) includes.from(readmeFile.absolutePath) - externalDocumentationLink("http://ejml.org/javadoc/") + externalDocumentationLink("https://ejml.org/javadoc/") externalDocumentationLink("https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/") externalDocumentationLink("https://deeplearning4j.org/api/latest/") externalDocumentationLink("https://axelclk.bitbucket.io/symja/javadoc/") externalDocumentationLink("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/") - externalDocumentationLink("https://breandan.net/kotlingrad/kotlingrad/", "https://breandan.net/kotlingrad/kotlingrad/kotlingrad/package-list") + + externalDocumentationLink( + "https://breandan.net/kotlingrad/kotlingrad/", + "https://breandan.net/kotlingrad/kotlingrad/kotlingrad/package-list", + ) } } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 18435 zcmY&<19zBR)MXm8v2EM7ZQHi-#I|kQZfv7Tn#Q)%81v4zX3d)U4d4 zYYc!v@NU%|U;_sM`2z(4BAilWijmR>4U^KdN)D8%@2KLcqkTDW%^3U(Wg>{qkAF z&RcYr;D1I5aD(N-PnqoEeBN~JyXiT(+@b`4Pv`;KmkBXYN48@0;iXuq6!ytn`vGp$ z6X4DQHMx^WlOek^bde&~cvEO@K$oJ}i`T`N;M|lX0mhmEH zuRpo!rS~#&rg}ajBdma$$}+vEhz?JAFUW|iZEcL%amAg_pzqul-B7Itq6Y_BGmOCC zX*Bw3rFz3R)DXpCVBkI!SoOHtYstv*e-May|+?b80ZRh$MZ$FerlC`)ZKt} zTd0Arf9N2dimjs>mg5&@sfTPsRXKXI;0L~&t+GH zkB<>wxI9D+k5VHHcB7Rku{Z>i3$&hgd9Mt_hS_GaGg0#2EHzyV=j=u5xSyV~F0*qs zW{k9}lFZ?H%@4hII_!bzao!S(J^^ZZVmG_;^qXkpJb7OyR*sPL>))Jx{K4xtO2xTr@St!@CJ=y3q2wY5F`77Tqwz8!&Q{f7Dp zifvzVV1!Dj*dxG%BsQyRP6${X+Tc$+XOG zzvq5xcC#&-iXlp$)L=9t{oD~bT~v^ZxQG;FRz|HcZj|^L#_(VNG)k{=_6|6Bs-tRNCn-XuaZ^*^hpZ@qwi`m|BxcF6IWc?_bhtK_cDZRTw#*bZ2`1@1HcB
`mLUmo_>@2R&nj7&CiH zF&laHkG~7#U>c}rn#H)q^|sk+lc!?6wg0xy`VPn!{4P=u@cs%-V{VisOxVqAR{XX+ zw}R;{Ux@6A_QPka=48|tph^^ZFjSHS1BV3xfrbY84^=?&gX=bmz(7C({=*oy|BEp+ zYgj;<`j)GzINJA>{HeSHC)bvp6ucoE`c+6#2KzY9)TClmtEB1^^Mk)(mXWYvup02e%Ghm9qyjz#fO3bNGBX} zFiB>dvc1+If!>I10;qZk`?6pEd*(?bI&G*3YLt;MWw&!?=Mf7%^Op?qnyXWur- zwX|S^P>jF?{m9c&mmK-epCRg#WB+-VDe!2d2~YVoi%7_q(dyC{(}zB${!ElKB2D}P z7QNFM!*O^?FrPMGZ}wQ0TrQAVqZy!weLhu_Zq&`rlD39r*9&2sJHE(JT0EY5<}~x@ z1>P0!L2IFDqAB!($H9s2fI`&J_c+5QT|b#%99HA3@zUWOuYh(~7q7!Pf_U3u!ij5R zjFzeZta^~RvAmd_TY+RU@e}wQaB_PNZI26zmtzT4iGJg9U(Wrgrl>J%Z3MKHOWV(? zj>~Ph$<~8Q_sI+)$DOP^9FE6WhO09EZJ?1W|KidtEjzBX3RCLUwmj9qH1CM=^}MaK z59kGxRRfH(n|0*lkE?`Rpn6d^u5J6wPfi0WF(rucTv(I;`aW)3;nY=J=igkjsn?ED ztH&ji>}TW8)o!Jg@9Z}=i2-;o4#xUksQHu}XT~yRny|kg-$Pqeq!^78xAz2mYP9+4 z9gwAoti2ICvUWxE&RZ~}E)#M8*zy1iwz zHqN%q;u+f6Ti|SzILm0s-)=4)>eb5o-0K zbMW8ecB4p^6OuIX@u`f{>Yn~m9PINEl#+t*jqalwxIx=TeGB9(b6jA}9VOHnE$9sC zH`;epyH!k-3kNk2XWXW!K`L_G!%xOqk0ljPCMjK&VweAxEaZ==cT#;!7)X&C|X{dY^IY(e4D#!tx^vV3NZqK~--JW~wtXJ8X19adXim?PdN(|@o(OdgH3AiHts~?#QkolO?*=U_buYC&tQ3sc(O5HGHN~=6wB@dgIAVT$ z_OJWJ^&*40Pw&%y^t8-Wn4@l9gOl`uU z{Uda_uk9!Iix?KBu9CYwW9Rs=yt_lE11A+k$+)pkY5pXpocxIEJe|pTxwFgB%Kpr&tH;PzgOQ&m|(#Otm?@H^r`v)9yiR8v&Uy>d#TNdRfyN4Jk;`g zp+jr5@L2A7TS4=G-#O<`A9o;{En5!I8lVUG?!PMsv~{E_yP%QqqTxxG%8%KxZ{uwS zOT+EA5`*moN8wwV`Z=wp<3?~f#frmID^K?t7YL`G^(X43gWbo!6(q*u%HxWh$$^2EOq`Hj zp=-fS#Av+s9r-M)wGIggQ)b<@-BR`R8l1G@2+KODmn<_$Tzb7k35?e8;!V0G>`(!~ zY~qZz!6*&|TupOcnvsQYPbcMiJ!J{RyfezB^;fceBk znpA1XS)~KcC%0^_;ihibczSxwBuy;^ksH7lwfq7*GU;TLt*WmUEVQxt{ zKSfJf;lk$0XO8~48Xn2dnh8tMC9WHu`%DZj&a`2!tNB`5%;Md zBs|#T0Ktf?vkWQ)Y+q!At1qgL`C|nbzvgc(+28Q|4N6Geq)Il%+I5c@t02{9^=QJ?=h2BTe`~BEu=_u3xX2&?^zwcQWL+)7dI>JK0g8_`W1n~ zMaEP97X>Ok#=G*nkPmY`VoP8_{~+Rp7DtdSyWxI~?TZHxJ&=6KffcO2Qx1?j7=LZA z?GQt`oD9QpXw+s7`t+eeLO$cpQpl9(6h3_l9a6OUpbwBasCeCw^UB6we!&h9Ik@1zvJ`j4i=tvG9X8o34+N|y(ay~ho$f=l z514~mP>Z>#6+UxM<6@4z*|hFJ?KnkQBs_9{H(-v!_#Vm6Z4(xV5WgWMd3mB9A(>@XE292#k(HdI7P zJkQ2)`bQXTKlr}{VrhSF5rK9TsjtGs0Rs&nUMcH@$ZX_`Hh$Uje*)(Wd&oLW($hZQ z_tPt`{O@f8hZ<}?aQc6~|9iHt>=!%We3=F9yIfiqhXqp=QUVa!@UY@IF5^dr5H8$R zIh{=%S{$BHG+>~a=vQ={!B9B=<-ID=nyjfA0V8->gN{jRL>Qc4Rc<86;~aY+R!~Vs zV7MI~gVzGIY`B*Tt@rZk#Lg}H8sL39OE31wr_Bm%mn}8n773R&N)8B;l+-eOD@N$l zh&~Wz`m1qavVdxwtZLACS(U{rAa0;}KzPq9r76xL?c{&GaG5hX_NK!?)iq`t7q*F# zFoKI{h{*8lb>&sOeHXoAiqm*vV6?C~5U%tXR8^XQ9Y|(XQvcz*>a?%HQ(Vy<2UhNf zVmGeOO#v159KV@1g`m%gJ)XGPLa`a|?9HSzSSX{j;)xg>G(Ncc7+C>AyAWYa(k}5B3mtzg4tsA=C^Wfezb1&LlyrBE1~kNfeiubLls{C)!<%#m@f}v^o+7<VZ6!FZ;JeiAG@5vw7Li{flC8q1%jD_WP2ApBI{fQ}kN zhvhmdZ0bb5(qK@VS5-)G+@GK(tuF6eJuuV5>)Odgmt?i_`tB69DWpC~e8gqh!>jr_ zL1~L0xw@CbMSTmQflpRyjif*Y*O-IVQ_OFhUw-zhPrXXW>6X}+73IoMsu2?uuK3lT>;W#38#qG5tDl66A7Y{mYh=jK8Se!+f=N7%nv zYSHr6a~Nxd`jqov9VgII{%EpC_jFCEc>>SND0;}*Ja8Kv;G)MK7?T~h((c&FEBcQq zvUU1hW2^TX(dDCeU@~a1LF-(+#lz3997A@pipD53&Dr@III2tlw>=!iGabjXzbyUJ z4Hi~M1KCT-5!NR#I%!2Q*A>mqI{dpmUa_mW)%SDs{Iw1LG}0y=wbj@0ba-`q=0!`5 zr(9q1p{#;Rv2CY!L#uTbs(UHVR5+hB@m*zEf4jNu3(Kj$WwW|v?YL*F_0x)GtQC~! zzrnZRmBmwt+i@uXnk05>uR5&1Ddsx1*WwMrIbPD3yU*2By`71pk@gt{|H0D<#B7&8 z2dVmXp*;B)SWY)U1VSNs4ds!yBAj;P=xtatUx^7_gC5tHsF#vvdV;NmKwmNa1GNWZ zi_Jn-B4GnJ%xcYWD5h$*z^haku#_Irh818x^KB)3-;ufjf)D0TE#6>|zFf@~pU;Rs zNw+}c9S+6aPzxkEA6R%s*xhJ37wmgc)-{Zd1&mD5QT}4BQvczWr-Xim>(P^)52`@R z9+Z}44203T5}`AM_G^Snp<_KKc!OrA(5h7{MT^$ZeDsSr(R@^kI?O;}QF)OU zQ9-`t^ys=6DzgLcWt0U{Q(FBs22=r zKD%fLQ^5ZF24c-Z)J{xv?x$&4VhO^mswyb4QTIofCvzq+27*WlYm;h@;Bq%i;{hZA zM97mHI6pP}XFo|^pRTuWQzQs3B-8kY@ajLV!Fb?OYAO3jFv*W-_;AXd;G!CbpZt04iW`Ie^_+cQZGY_Zd@P<*J9EdRsc>c=edf$K|;voXRJ zk*aC@@=MKwR120(%I_HX`3pJ+8GMeO>%30t?~uXT0O-Tu-S{JA;zHoSyXs?Z;fy58 zi>sFtI7hoxNAdOt#3#AWFDW)4EPr4kDYq^`s%JkuO7^efX+u#-qZ56aoRM!tC^P6O zP(cFuBnQGjhX(^LJ(^rVe4-_Vk*3PkBCj!?SsULdmVr0cGJM^=?8b0^DuOFq>0*yA zk1g|C7n%pMS0A8@Aintd$fvRbH?SNdRaFrfoAJ=NoX)G5Gr}3-$^IGF+eI&t{I-GT zp=1fj)2|*ur1Td)+s&w%p#E6tDXX3YYOC{HGHLiCvv?!%%3DO$B$>A}aC;8D0Ef#b z{7NNqC8j+%1n95zq8|hFY`afAB4E)w_&7?oqG0IPJZv)lr{MT}>9p?}Y`=n+^CZ6E zKkjIXPub5!82(B-O2xQojW^P(#Q*;ETpEr^+Wa=qDJ9_k=Wm@fZB6?b(u?LUzX(}+ zE6OyapdG$HC& z&;oa*ALoyIxVvB2cm_N&h&{3ZTuU|aBrJlGOLtZc3KDx)<{ z27@)~GtQF@%6B@w3emrGe?Cv_{iC@a#YO8~OyGRIvp@%RRKC?fclXMP*6GzBFO z5U4QK?~>AR>?KF@I;|(rx(rKxdT9-k-anYS+#S#e1SzKPslK!Z&r8iomPsWG#>`Ld zJ<#+8GFHE!^wsXt(s=CGfVz5K+FHYP5T0E*?0A-z*lNBf)${Y`>Gwc@?j5{Q|6;Bl zkHG1%r$r&O!N^><8AEL+=y(P$7E6hd=>BZ4ZZ9ukJ2*~HR4KGvUR~MUOe$d>E5UK3 z*~O2LK4AnED}4t1Fs$JgvPa*O+WeCji_cn1@Tv7XQ6l@($F1K%{E$!naeX)`bfCG> z8iD<%_M6aeD?a-(Qqu61&fzQqC(E8ksa%CulMnPvR35d{<`VsmaHyzF+B zF6a@1$CT0xGVjofcct4SyxA40uQ`b#9kI)& z?B67-12X-$v#Im4CVUGZHXvPWwuspJ610ITG*A4xMoRVXJl5xbk;OL(;}=+$9?H`b z>u2~yd~gFZ*V}-Q0K6E@p}mtsri&%Zep?ZrPJmv`Qo1>94Lo||Yl)nqwHXEbe)!g( zo`w|LU@H14VvmBjjkl~=(?b{w^G$~q_G(HL`>|aQR%}A64mv0xGHa`S8!*Wb*eB}` zZh)&rkjLK!Rqar)UH)fM<&h&@v*YyOr!Xk2OOMV%$S2mCRdJxKO1RL7xP_Assw)bb z9$sQ30bapFfYTS`i1PihJZYA#0AWNmp>x(;C!?}kZG7Aq?zp!B+gGyJ^FrXQ0E<>2 zCjqZ(wDs-$#pVYP3NGA=en<@_uz!FjFvn1&w1_Igvqs_sL>ExMbcGx4X5f%`Wrri@ z{&vDs)V!rd=pS?G(ricfwPSg(w<8P_6=Qj`qBC7_XNE}1_5>+GBjpURPmvTNE7)~r)Y>ZZecMS7Ro2` z0}nC_GYo3O7j|Wux?6-LFZs%1IV0H`f`l9or-8y0=5VGzjPqO2cd$RRHJIY06Cnh- ztg@Pn1OeY=W`1Mv3`Ti6!@QIT{qcC*&vptnX4Pt1O|dWv8u2s|(CkV`)vBjAC_U5` zCw1f&c4o;LbBSp0=*q z3Y^horBAnR)u=3t?!}e}14%K>^562K!)Vy6r~v({5{t#iRh8WIL|U9H6H97qX09xp zjb0IJ^9Lqxop<-P*VA0By@In*5dq8Pr3bTPu|ArID*4tWM7w+mjit0PgmwLV4&2PW z3MnIzbdR`3tPqtUICEuAH^MR$K_u8~-U2=N1)R=l>zhygus44>6V^6nJFbW-`^)f} zI&h$FK)Mo*x?2`0npTD~jRd}5G~-h8=wL#Y-G+a^C?d>OzsVl7BFAaM==(H zR;ARWa^C3J)`p~_&FRsxt|@e+M&!84`eq)@aO9yBj8iifJv0xVW4F&N-(#E=k`AwJ z3EFXWcpsRlB%l_0Vdu`0G(11F7( zsl~*@XP{jS@?M#ec~%Pr~h z2`M*lIQaolzWN&;hkR2*<=!ORL(>YUMxOzj(60rQfr#wTrkLO!t{h~qg% zv$R}0IqVIg1v|YRu9w7RN&Uh7z$ijV=3U_M(sa`ZF=SIg$uY|=NdC-@%HtkUSEqJv zg|c}mKTCM=Z8YmsFQu7k{VrXtL^!Cts-eb@*v0B3M#3A7JE*)MeW1cfFqz~^S6OXFOIP&iL;Vpy z4dWKsw_1Wn%Y;eW1YOfeP_r1s4*p1C(iDG_hrr~-I%kA>ErxnMWRYu{IcG{sAW;*t z9T|i4bI*g)FXPpKM@~!@a7LDVVGqF}C@mePD$ai|I>73B+9!Ks7W$pw;$W1B%-rb; zJ*-q&ljb=&41dJ^*A0)7>Wa@khGZ;q1fL(2qW=|38j43mTl_;`PEEw07VKY%71l6p z@F|jp88XEnm1p~<5c*cVXvKlj0{THF=n3sU7g>Ki&(ErR;!KSmfH=?49R5(|c_*xw z4$jhCJ1gWT6-g5EV)Ahg?Nw=}`iCyQ6@0DqUb%AZEM^C#?B-@Hmw?LhJ^^VU>&phJ zlB!n5&>I>@sndh~v$2I2Ue23F?0!0}+9H~jg7E`?CS_ERu75^jSwm%!FTAegT`6s7 z^$|%sj2?8wtPQR>@D3sA0-M-g-vL@47YCnxdvd|1mPymvk!j5W1jHnVB&F-0R5e-vs`@u8a5GKdv`LF7uCfKncI4+??Z4iG@AxuX7 z6+@nP^TZ5HX#*z(!y+-KJ3+Ku0M90BTY{SC^{ z&y2#RZPjfX_PE<<>XwGp;g4&wcXsQ0T&XTi(^f+}4qSFH1%^GYi+!rJo~t#ChTeAX zmR0w(iODzQOL+b&{1OqTh*psAb;wT*drr^LKdN?c?HJ*gJl+%kEH&48&S{s28P=%p z7*?(xFW_RYxJxxILS!kdLIJYu@p#mnQ(?moGD1)AxQd66X6b*KN?o&e`u9#N4wu8% z^Gw#G!@|>c740RXziOR=tdbkqf(v~wS_N^CS^1hN-N4{Dww1lvSWcBTX*&9}Cz|s@ z*{O@jZ4RVHq19(HC9xSBZI0M)E;daza+Q*zayrX~N5H4xJ33BD4gn5Ka^Hj{995z4 zzm#Eo?ntC$q1a?)dD$qaC_M{NW!5R!vVZ(XQqS67xR3KP?rA1^+s3M$60WRTVHeTH z6BJO$_jVx0EGPXy}XK_&x597 zt(o6ArN8vZX0?~(lFGHRtHP{gO0y^$iU6Xt2e&v&ugLxfsl;GD)nf~3R^ACqSFLQ< zV7`cXgry((wDMJB55a6D4J;13$z6pupC{-F+wpToW%k1qKjUS^$Mo zN3@}T!ZdpiV7rkNvqP3KbpEn|9aB;@V;gMS1iSb@ zwyD7!5mfj)q+4jE1dq3H`sEKgrVqk|y8{_vmn8bMOi873!rmnu5S=1=-DFx+Oj)Hi zx?~ToiJqOrvSou?RVALltvMADodC7BOg7pOyc4m&6yd(qIuV5?dYUpYzpTe!BuWKi zpTg(JHBYzO&X1e{5o|ZVU-X5e?<}mh=|eMY{ldm>V3NsOGwyxO2h)l#)rH@BI*TN; z`yW26bMSp=k6C4Ja{xB}s`dNp zE+41IwEwo>7*PA|7v-F#jLN>h#a`Er9_86!fwPl{6yWR|fh?c%qc44uP~Ocm2V*(* zICMpS*&aJjxutxKC0Tm8+FBz;3;R^=ajXQUB*nTN*Lb;mruQHUE<&=I7pZ@F-O*VMkJbI#FOrBM8`QEL5Uy=q5e2 z_BwVH%c0^uIWO0*_qD;0jlPoA@sI7BPwOr-mrp7y`|EF)j;$GYdOtEPFRAKyUuUZS z(N4)*6R*ux8s@pMdC*TP?Hx`Zh{{Ser;clg&}CXriXZCr2A!wIoh;j=_eq3_%n7V} za?{KhXg2cXPpKHc90t6=`>s@QF-DNcTJRvLTS)E2FTb+og(wTV7?$kI?QZYgVBn)& zdpJf@tZ{j>B;<MVHiPl_U&KlqBT)$ic+M0uUQWK|N1 zCMl~@o|}!!7yyT%7p#G4?T^Azxt=D(KP{tyx^lD_(q&|zNFgO%!i%7T`>mUuU^FeR zHP&uClWgXm6iXgI8*DEA!O&X#X(zdrNctF{T#pyax16EZ5Lt5Z=RtAja!x+0Z31U8 zjfaky?W)wzd+66$L>o`n;DISQNs09g{GAv%8q2k>2n8q)O^M}=5r#^WR^=se#WSCt zQ`7E1w4qdChz4r@v6hgR?nsaE7pg2B6~+i5 zcTTbBQ2ghUbC-PV(@xvIR(a>Kh?{%YAsMV#4gt1nxBF?$FZ2~nFLKMS!aK=(`WllA zHS<_7ugqKw!#0aUtQwd#A$8|kPN3Af?Tkn)dHF?_?r#X68Wj;|$aw)Wj2Dkw{6)*^ zZfy!TWwh=%g~ECDCy1s8tTgWCi}F1BvTJ9p3H6IFq&zn#3FjZoecA_L_bxGWgeQup zAAs~1IPCnI@H>g|6Lp^Bk)mjrA3_qD4(D(65}l=2RzF-8@h>|Aq!2K-qxt(Q9w7c^ z;gtx`I+=gKOl;h=#fzSgw-V*YT~2_nnSz|!9hIxFb{~dKB!{H zSi??dnmr@%(1w^Be=*Jz5bZeofEKKN&@@uHUMFr-DHS!pb1I&;x9*${bmg6=2I4Zt zHb5LSvojY7ubCNGhp)=95jQ00sMAC{IZdAFsN!lAVQDeiec^HAu=8);2AKqNTT!&E zo+FAR`!A1#T6w@0A+o%&*yzkvxsrqbrfVTG+@z8l4+mRi@j<&)U9n6L>uZoezW>qS zA4YfO;_9dQSyEYpkWnsk0IY}Nr2m(ql@KuQjLgY-@g z4=$uai6^)A5+~^TvLdvhgfd+y?@+tRE^AJabamheJFnpA#O*5_B%s=t8<;?I;qJ}j z&g-9?hbwWEez-!GIhqpB>nFvyi{>Yv>dPU=)qXnr;3v-cd`l}BV?6!v{|cHDOx@IG z;TSiQQ(8=vlH^rCEaZ@Yw}?4#a_Qvx=}BJuxACxm(E7tP4hki^jU@8A zUS|4tTLd)gr@T|F$1eQXPY%fXb7u}(>&9gsd3It^B{W#6F2_g40cgo1^)@-xO&R5X z>qKon+Nvp!4v?-rGQu#M_J2v+3e+?N-WbgPQWf`ZL{Xd9KO^s{uIHTJ6~@d=mc7i z+##ya1p+ZHELmi%3C>g5V#yZt*jMv( zc{m*Y;7v*sjVZ-3mBuaT{$g+^sbs8Rp7BU%Ypi+c%JxtC4O}|9pkF-p-}F{Z7-+45 zDaJQx&CNR)8x~0Yf&M|-1rw%KW3ScjWmKH%J1fBxUp(;F%E+w!U470e_3%+U_q7~P zJm9VSWmZ->K`NfswW(|~fGdMQ!K2z%k-XS?Bh`zrjZDyBMu74Fb4q^A=j6+Vg@{Wc zPRd5Vy*-RS4p1OE-&8f^Fo}^yDj$rb+^>``iDy%t)^pHSV=En5B5~*|32#VkH6S%9 zxgIbsG+|{-$v7mhOww#v-ejaS>u(9KV9_*X!AY#N*LXIxor9hDv%aie@+??X6@Et=xz>6ev9U>6Pn$g4^!}w2Z%Kpqpp+M%mk~?GE-jL&0xLC zy(`*|&gm#mLeoRU8IU?Ujsv=;ab*URmsCl+r?%xcS1BVF*rP}XRR%MO_C!a9J^fOe>U;Y&3aj3 zX`3?i12*^W_|D@VEYR;h&b^s#Kd;JMNbZ#*x8*ZXm(jgw3!jyeHo14Zq!@_Q`V;Dv zKik~!-&%xx`F|l^z2A92aCt4x*I|_oMH9oeqsQgQDgI0j2p!W@BOtCTK8Jp#txi}7 z9kz);EX-2~XmxF5kyAa@n_$YYP^Hd4UPQ>O0-U^-pw1*n{*kdX`Jhz6{!W=V8a$0S z9mYboj#o)!d$gs6vf8I$OVOdZu7L5%)Vo0NhN`SwrQFhP3y4iXe2uV@(G{N{yjNG( zKvcN{k@pXkxyB~9ucR(uPSZ7{~sC=lQtz&V(^A^HppuN!@B4 zS>B=kb14>M-sR>{`teApuHlca6YXs6&sRvRV;9G!XI08CHS~M$=%T~g5Xt~$exVk` zWP^*0h{W%`>K{BktGr@+?ZP}2t0&smjKEVw@3=!rSjw5$gzlx`{dEajg$A58m|Okx zG8@BTPODSk@iqLbS*6>FdVqk}KKHuAHb0UJNnPm!(XO{zg--&@#!niF4T!dGVdNif z3_&r^3+rfQuV^8}2U?bkI5Ng*;&G>(O4&M<86GNxZK{IgKNbRfpg>+32I>(h`T&uv zUN{PRP&onFj$tn1+Yh|0AF330en{b~R+#i9^QIbl9fBv>pN|k&IL2W~j7xbkPyTL^ z*TFONZUS2f33w3)fdzr?)Yg;(s|||=aWZV(nkDaACGSxNCF>XLJSZ=W@?$*` z#sUftY&KqTV+l@2AP5$P-k^N`Bme-xcWPS|5O~arUq~%(z8z87JFB|llS&h>a>Som zC34(_uDViE!H2jI3<@d+F)LYhY)hoW6)i=9u~lM*WH?hI(yA$X#ip}yYld3RAv#1+sBt<)V_9c4(SN9Fn#$}_F}A-}P>N+8io}I3mh!}> z*~*N}ZF4Zergb;`R_g49>ZtTCaEsCHiFb(V{9c@X0`YV2O^@c6~LXg2AE zhA=a~!ALnP6aO9XOC^X15(1T)3!1lNXBEVj5s*G|Wm4YBPV`EOhU&)tTI9-KoLI-U zFI@adu6{w$dvT(zu*#aW*4F=i=!7`P!?hZy(9iL;Z^De3?AW`-gYTPALhrZ*K2|3_ zfz;6xQN9?|;#_U=4t^uS2VkQ8$|?Ub5CgKOj#Ni5j|(zX>x#K(h7LgDP-QHwok~-I zOu9rn%y97qrtKdG=ep)4MKF=TY9^n6CugQ3#G2yx;{))hvlxZGE~rzZ$qEHy-8?pU#G;bwufgSN6?*BeA!7N3RZEh{xS>>-G1!C(e1^ zzd#;39~PE_wFX3Tv;zo>5cc=md{Q}(Rb?37{;YPtAUGZo7j*yHfGH|TOVR#4ACaM2 z;1R0hO(Gl}+0gm9Bo}e@lW)J2OU4nukOTVKshHy7u)tLH^9@QI-jAnDBp(|J8&{fKu=_97$v&F67Z zq+QsJ=gUx3_h_%=+q47msQ*Ub=gMzoSa@S2>`Y9Cj*@Op4plTc!jDhu51nSGI z^sfZ(4=yzlR}kP2rcHRzAY9@T7f`z>fdCU0zibx^gVg&fMkcl)-0bRyWe12bT0}<@ z^h(RgGqS|1y#M;mER;8!CVmX!j=rfNa6>#_^j{^C+SxGhbSJ_a0O|ae!ZxiQCN2qA zKs_Z#Zy|9BOw6x{0*APNm$6tYVG2F$K~JNZ!6>}gJ_NLRYhcIsxY1z~)mt#Yl0pvC zO8#Nod;iow5{B*rUn(0WnN_~~M4|guwfkT(xv;z)olmj=f=aH#Y|#f_*d1H!o( z!EXNxKxth9w1oRr0+1laQceWfgi8z`YS#uzg#s9-QlTT7y2O^^M1PZx z3YS7iegfp6Cs0-ixlG93(JW4wuE7)mfihw}G~Uue{Xb+#F!BkDWs#*cHX^%(We}3% zT%^;m&Juw{hLp^6eyM}J({luCL_$7iRFA6^8B!v|B9P{$42F>|M`4Z_yA{kK()WcM zu#xAZWG%QtiANfX?@+QQOtbU;Avr*_>Yu0C2>=u}zhH9VLp6M>fS&yp*-7}yo8ZWB z{h>ce@HgV?^HgwRThCYnHt{Py0MS=Ja{nIj5%z;0S@?nGQ`z`*EVs&WWNwbzlk`(t zxDSc)$dD+4G6N(p?K>iEKXIk>GlGKTH{08WvrehnHhh%tgpp&8db4*FLN zETA@<$V=I7S^_KxvYv$Em4S{gO>(J#(Wf;Y%(NeECoG3n+o;d~Bjme-4dldKukd`S zRVAnKxOGjWc;L#OL{*BDEA8T=zL8^`J=2N)d&E#?OMUqk&9j_`GX*A9?V-G zdA5QQ#(_Eb^+wDkDiZ6RXL`fck|rVy%)BVv;dvY#`msZ}{x5fmd! zInmWSxvRgXbJ{unxAi*7=Lt&7_e0B#8M5a=Ad0yX#0rvMacnKnXgh>4iiRq<&wit93n!&p zeq~-o37qf)L{KJo3!{l9l9AQb;&>)^-QO4RhG>j`rBlJ09~cbfNMR_~pJD1$UzcGp zOEGTzz01j$=-kLC+O$r8B|VzBotz}sj(rUGOa7PDYwX~9Tum^sW^xjjoncxSz;kqz z$Pz$Ze|sBCTjk7oM&`b5g2mFtuTx>xl{dj*U$L%y-xeQL~|i>KzdUHeep-Yd@}p&L*ig< zgg__3l9T=nbM3bw0Sq&Z2*FA)P~sx0h634BXz0AxV69cED7QGTbK3?P?MENkiy-mV zZ1xV5ry3zIpy>xmThBL0Q!g+Wz@#?6fYvzmEczs(rcujrfCN=^!iWQ6$EM zaCnRThqt~gI-&6v@KZ78unqgv9j6-%TOxpbV`tK{KaoBbhc}$h+rK)5h|bT6wY*t6st-4$e99+Egb#3ip+ERbve08G@Ref&hP)qB&?>B94?eq5i3k;dOuU#!y-@+&5>~!FZik=z4&4|YHy=~!F254 zQAOTZr26}Nc7jzgJ;V~+9ry#?7Z0o*;|Q)k+@a^87lC}}1C)S))f5tk+lMNqw>vh( z`A9E~5m#b9!ZDBltf7QIuMh+VheCoD7nCFhuzThlhA?|8NCt3w?oWW|NDin&&eDU6 zwH`aY=))lpWG?{fda=-auXYp1WIPu&3 zwK|t(Qiqvc@<;1_W#ALDJ}bR;3&v4$9rP)eAg`-~iCte`O^MY+SaP!w%~+{{1tMo` zbp?T%ENs|mHP)Lsxno=nWL&qizR+!Ib=9i%4=B@(Umf$|7!WVxkD%hfRjvxV`Co<; zG*g4QG_>;RE{3V_DOblu$GYm&!+}%>G*yO{-|V9GYG|bH2JIU2iO}ZvY>}Fl%1!OE zZFsirH^$G>BDIy`8;R?lZl|uu@qWj2T5}((RG``6*05AWsVVa2Iu>!F5U>~7_Tlv{ zt=Dpgm~0QVa5mxta+fUt)I0gToeEm9eJX{yYZ~3sLR&nCuyuFWuiDIVJ+-lwViO(E zH+@Rg$&GLueMR$*K8kOl>+aF84Hss5p+dZ8hbW$=bWNIk0paB!qEK$xIm5{*^ad&( zgtA&gb&6FwaaR2G&+L+Pp>t^LrG*-B&Hv;-s(h0QTuYWdnUObu8LRSZoAVd7SJ;%$ zh%V?58mD~3G2X<$H7I)@x?lmbeeSY7X~QiE`dfQ5&K^FB#9e!6!@d9vrSt!);@ZQZ zO#84N5yH$kjm9X4iY#f+U`FKhg=x*FiDoUeu1O5LcC2w&$~5hKB9ZnH+8BpbTGh5T zi_nfmyQY$vQh%ildbR7T;7TKPxSs#vhKR|uup`qi1PufMa(tNCjRbllakshQgn1)a8OO-j8W&aBc_#q1hKDF5-X$h`!CeT z+c#Ial~fDsGAenv7~f@!icm(~)a3OKi((=^zcOb^qH$#DVciGXslUwTd$gt{7)&#a`&Lp ze%AnL0#U?lAl8vUkv$n>bxH*`qOujO0HZkPWZnE0;}0DSEu1O!hg-d9#{&#B1Dm)L zvN%r^hdEt1vR<4zwshg*0_BNrDWjo65be1&_82SW8#iKWs7>TCjUT;-K~*NxpG2P% zovXUo@S|fMGudVSRQrP}J3-Wxq;4xIxJJC|Y#TQBr>pwfy*%=`EUNE*dr-Y?9y9xK zmh1zS@z{^|UL}v**LNYY!?1qIRPTvr!gNXzE{%=-`oKclPrfMKwn` zUwPeIvLcxkIV>(SZ-SeBo-yw~{p!<&_}eELG?wxp zee-V59%@BtB+Z&Xs=O(@P$}v_qy1m=+`!~r^aT> zY+l?+6(L-=P%m4ScfAYR8;f9dyVw)@(;v{|nO#lAPI1xDHXMYt~-BGiP&9y2OQsYdh7-Q1(vL<$u6W0nxVn-qh=nwuRk}{d!uACozccRGx6~xZQ;=#JCE?OuA@;4 zadp$sm}jfgW4?La(pb!3f0B=HUI{5A4b$2rsB|ZGb?3@CTA{|zBf07pYpQ$NM({C6Srv6%_{rVkCndT=1nS}qyEf}Wjtg$e{ng7Wgz$7itYy0sWW_$qld);iUm85GBH)fk3b=2|5mvflm?~inoVo zDH_%e;y`DzoNj|NgZ`U%a9(N*=~8!qqy0Etkxo#`r!!{|(NyT0;5= z8nVZ6AiM+SjMG8J@6c4_f-KXd_}{My?Se1GWP|@wROFpD^5_lu?I%CBzpwi(`x~xh B8dv}T delta 17845 zcmV)CK*GO}(F4QI1F(Jx4W$DjNjn4p0N4ir06~)x5+0MO2`GQvQyWzj|J`gh3(E#l zNGO!HfVMRRN~%`0q^)g%XlN*vP!O#;m*h5VyX@j-1N|HN;8S1vqEAj=eCdn`)tUB9 zXZjcT^`bL6qvL}gvXj%9vrOD+x!Gc_0{$Zg+6lTXG$bmoEBV z*%y^c-mV0~Rjzv%e6eVI)yl>h;TMG)Ft8lqpR`>&IL&`>KDi5l$AavcVh9g;CF0tY zw_S0eIzKD?Nj~e4raA8wxiiImTRzv6;b6|LFmw)!E4=CiJ4I%&axSey4zE-MIh@*! z*P;K2Mx{xVYPLeagKA}Hj=N=1VrWU`ukuBnc14iBG?B}Uj>?=2UMk4|42=()8KOnc zrJzAxxaEIfjw(CKV6F$35u=1qyf(%cY8fXaS9iS?yetY{mQ#Xyat*7sSoM9fJlZqq zyasQ3>D>6p^`ck^Y|kYYZB*G})uAbQ#7)Jeb~glGz@2rPu}zBWDzo5K$tP<|meKV% z{Swf^eq6NBioF)v&~9NLIxHMTKe6gJ@QQ^A6fA!n#u1C&n`aG7TDXKM1Jly-DwTB` z+6?=Y)}hj;C#r5>&x;MCM4U13nuXVK*}@yRY~W3X%>U>*CB2C^K6_OZsXD!nG2RSX zQg*0)$G3%Es$otA@p_1N!hIPT(iSE=8OPZG+t)oFyD~{nevj0gZen$p>U<7}uRE`t5Mk1f4M0K*5 zbn@3IG5I2mk;8K>*RZ zPV6iL006)S001s%0eYj)9hu1 z9o)iQT9(v*sAuZ|ot){RrZ0Qw4{E0A+!Yx_M~#Pj&OPUM&i$RU=Uxu}e*6Sr2ror= z&?lmvFCO$)BY+^+21E>ENWe`I0{02H<-lz&?})gIVFyMWxX0B|0b?S6?qghp3lDgz z2?0|ALJU=7s-~Lb3>9AA5`#UYCl!Xeh^i@bxs5f&SdiD!WN}CIgq&WI4VCW;M!UJL zX2};d^sVj5oVl)OrkapV-C&SrG)*x=X*ru!2s04TjZ`pY$jP)4+%)7&MlpiZ`lgoF zo_p>^4qGz^(Y*uB10dY2kcIbt=$FIdYNqk;~47wf@)6|nJp z1cocL3zDR9N2Pxkw)dpi&_rvMW&Dh0@T*_}(1JFSc0S~Ph2Sr=vy)u*=TY$i_IHSo zR+&dtWFNxHE*!miRJ%o5@~GK^G~4$LzEYR-(B-b(L*3jyTq}M3d0g6sdx!X3-m&O% zK5g`P179KHJKXpIAAX`A2MFUA;`nXx^b?mboVbQgigIHTU8FI>`q53AjWaD&aowtj z{XyIX>c)*nLO~-WZG~>I)4S1d2q@&?nwL)CVSWqWi&m1&#K1!gt`g%O4s$u^->Dwq ziKc&0O9KQ7000OG0000%03-m(e&Y`S09YWC4iYDSty&3q8^?8ij|8zxaCt!zCFq1@ z9TX4Hl68`nY>}cQNW4Ullqp$~SHO~l1!CdFLKK}ij_t^a?I?C^CvlvnZkwiVn>dl2 z2$V(JN{`5`-8ShF_ek6HNRPBlPuIPYu>TAeAV5O2)35r3*_k(Q-h1+h5pb(Zu%oJ__pBsW0n5ILw`!&QR&YV`g0Fe z(qDM!FX_7;`U3rxX#QHT{f%h;)Eursw=*#qvV)~y%^Uo^% zi-%sMe^uz;#Pe;@{JUu05zT*i=u7mU9{MkT`ft(vPdQZoK&2mg=tnf8FsaNQ+QcPg zB>vP8Rd6Z0JoH5_Q`zldg;hx4azQCq*rRZThqlqTRMzn1O3_rQTrHk8LQ<{5UYN~` zM6*~lOGHyAnx&#yCK{i@%N1Us@=6cw=UQxpSE;<(LnnES%6^q^QhBYQ-VCSmIu8wh z@_LmwcFDfAhIn>`%h7L{)iGBzu`Md4dj-m3C8mA9+BL*<>q z#$7^ttIBOE-=^|zmG`K8yUKT{yjLu2SGYsreN0*~9yhFxn4U};Nv1XXj1fH*v-g=3 z@tCPc`YdzQGLp%zXwo*o$m9j-+~nSWls#s|?PyrHO%SUGdk**X9_=|b)Y%^j_V$3S z>mL2A-V)Q}qb(uZipEFVm?}HWc+%G6_K+S+87g-&RkRQ8-{0APDil115eG|&>WQhU zufO*|e`hFks^cJJmx_qNx{ltSp3aT|XgD5-VxGGXb7gkiOG$w^qMVBDjR8%!Sbh72niHRDV* ziFy8LE+*$j?t^6aZP9qt-ow;hzkmhvy*Hn-X^6?yVMbtNbyqZQ^rXg58`gk+I%Wv} zn_)dRq+3xjc8D%}EQ%nnTF7L7m}o9&*^jf`_qvUhVKY7w9Zgxr-0YHWFRd3$l_6UX zpXt^U&TiC*qZWx#pOG6k?3Tg)pra*fw(O6_45>lUBN1U5Qmc>^DHt)5b~Ntjsw!NI z1n4{$HWFeIi)*qvgK^ui;(81VQc1(wJ8C#tjR>Dkjf{xYC^_B^#qrdCc)uZxtgua6 zk98UGQF|;;k`c+0_z)tQ&9DwLB~&12@D1!*mTz_!3Mp=cg;B7Oq4cKN>5v&dW7q@H zal=g6Ipe`siZN4NZiBrkJCU*x216gmbV(FymgHuG@%%|8sgD?gR&0*{y4n=pukZnd z4=Nl~_>jVfbIehu)pG)WvuUpLR}~OKlW|)=S738Wh^a&L+Vx~KJU25o6%G7+Cy5mB zgmYsgkBC|@K4Jm_PwPoz`_|5QSk}^p`XV`649#jr4Lh^Q>Ne~#6Cqxn$7dNMF=%Va z%z9Ef6QmfoXAlQ3)PF8#3Y% zadcE<1`fd1&Q9fMZZnyI;&L;YPuy#TQ8b>AnXr*SGY&xUb>2678A+Y z8K%HOdgq_4LRFu_M>Ou|kj4W%sPPaV)#zDzN~25klE!!PFz_>5wCxglj7WZI13U5| zEq_YLKPH;v8sEhyG`dV_jozR);a6dBvkauhC;1dk%mr+J*Z6MMH9jqxFk@)&h{mHl zrf^i_d-#mTF=6-T8Rk?(1+rPGgl$9=j%#dkf@x6>czSc`jk7$f!9SrV{do%m!t8{? z_iAi$Qe&GDR#Nz^#uJ>-_?(E$ns)(3)X3cYY)?gFvU+N>nnCoBSmwB2<4L|xH19+4 z`$u#*Gt%mRw=*&|em}h_Y`Pzno?k^8e*hEwfM`A_yz-#vJtUfkGb=s>-!6cHfR$Mz z`*A8jVcz7T{n8M>ZTb_sl{EZ9Ctau4naX7TX?&g^VLE?wZ+}m)=YW4ODRy*lV4%-0 zG1XrPs($mVVfpnqoSihnIFkLdxG9um&n-U|`47l{bnr(|8dmglO7H~yeK7-wDwZXq zaHT($Qy2=MMuj@lir(iyxI1HnMlaJwpX86je}e=2n|Esb6hB?SmtDH3 z2qH6o`33b{;M{mDa5@@~1or8+Zcio*97pi1Jkx6v5MXCaYsb~Ynq)eWpKnF{n)FXZ z?Xd;o7ESu&rtMFr5(yJ(B7V>&0gnDdL*4MZH&eO+r*t!TR98ssbMRaw`7;`SLI8mT z=)hSAt~F=mz;JbDI6g~J%w!;QI(X14AnOu;uve^4wyaP3>(?jSLp+LQ7uU(iib%IyB(d&g@+hg;78M>h7yAeq$ALRoHGkKXA+E z$Sk-hd$Fs2nL4w9p@O*Y$c;U)W#d~)&8Js;i^Dp^* z0*7*zEGj~VehF4sRqSGny*K_CxeF=T^8;^lb}HF125G{kMRV?+hYktZWfNA^Mp7y8 zK~Q?ycf%rr+wgLaHQ|_<6z^eTG7izr@99SG9Q{$PCjJabSz`6L_QJJe7{LzTc$P&pwTy<&3RRUlSHmK;?}=QAhQaDW3#VWcNAH3 zeBPRTDf3?3mfdI$&WOg(nr9Gyzg`&u^o!f2rKJ57D_>p z6|?Vg?h(@(*X=o071{g^le>*>qSbVam`o}sAK8>b|11%e&;%`~b2OP7--q%0^2YDS z`2M`{2QYr1VC)sIW9WOu8<~7Q>^$*Og{KF+kI;wFegvaIDkB%3*%PWtWKSq7l`1YcDxQQ2@nv{J!xWV?G+w6C zhUUxUYVf%(Q(40_xrZB@rbxL=Dj3RV^{*yHd>4n-TOoHVRnazDOxxkS9kiZyN}IN3 zB^5N=* zRSTO+rA<{*P8-$GZdyUNOB=MzddG$*@q>mM;pUIiQ_z)hbE#Ze-IS)9G}Rt$5PSB{ zZZ;#h9nS7Rf1ecW&n(Gpu9}{vXQZ-f`UHIvD?cTbF`YvH*{rgE(zE22pLAQfhg-`U zuh612EpByB(~{w7svCylrBk%5$LCIyuhrGi=yOfca`=8ltKxHcSNfDRt@62QH^R_0 z&eQL6rRk>Dvf6rjMQv5ZXzg}S`HqV69hJT^pPHtdhqsrPJWs|IT9>BvpQa@*(FX6v zG}TYjreQCnH(slMt5{NgUf)qsS1F&Bb(M>$X}tWI&yt2I&-rJbqveuj?5J$`Dyfa2 z)m6Mq0XH@K)Y2v8X=-_4=4niodT&Y7W?$KLQhjA<+R}WTdYjX9>kD+SRS^oOY1{A= zZTId-(@wF^UEWso($wZtrs%e7t<}YaC_;#@`r0LUzKY&|qPJz*y~RHG`E6bypP5AX zN!p0^AUu8uDR>xM-ALFzBxXM~Q3z=}fHWCIG>0&I6x2Iu7&U)49j7qeMI&?qb$=4I zdMmhAJrO%@0f%YW! z^gLByEGSk+R0v4*d4w*N$Ju6z#j%HBI}6y$2en=-@S3=6+yZX94m&1j@s- z7T6|#0$c~dYq9IkA!P)AGkp~S$zYJ1SXZ#RM0|E~Q0PSm?DsT4N3f^)b#h(u9%_V5 zX*&EIX|gD~P!vtx?ra71pl%v)F!W~X2hcE!h8cu@6uKURdmo1-7icN4)ej4H1N~-C zjXgOK+mi#aJv4;`DZ%QUbVVZclkx;9`2kgbAhL^d{@etnm+5N8pB#fyH)bxtZGCAv z(%t0kPgBS{Q2HtjrfI0B$$M0c?{r~2T=zeXo7V&&aprCzww=i*}Atu7g^(*ivauMz~kkB%Vt{Wydlz%%2c26%>0PAbZO zVHx%tK(uzDl#ZZK`cW8TD2)eD77wB@gum{B2bO_jnqGl~01EF_^jx4Uqu1yfA~*&g zXJ`-N?D-n~5_QNF_5+Un-4&l$1b zVlHFqtluoN85b^C{A==lp#hS9J(npJ#6P4aY41r) zzCmv~c77X5L}H%sj>5t&@0heUDy;S1gSOS>JtH1v-k5l}z2h~i3^4NF6&iMb;ZYVE zMw*0%-9GdbpF1?HHim|4+)Zed=Fk<2Uz~GKc^P(Ig@x0&XuX0<-K(gA*KkN&lY2Xu zG054Q8wbK~$jE32#Ba*Id2vkqmfV{U$Nx9vJ;jeI`X+j1kh7hB8$CBTe@ANmT^tI8 z%U>zrTKuECin-M|B*gy(SPd`(_xvxjUL?s137KOyH>U{z01cBcFFt=Fp%d+BK4U;9 zQG_W5i)JASNpK)Q0wQpL<+Ml#cei41kCHe&P9?>p+KJN>I~`I^vK1h`IKB7k^xi`f z$H_mtr_+@M>C5+_xt%v}{#WO{86J83;VS@Ei3JLtp<*+hsY1oGzo z0?$?OJO$79;{|@aP!fO6t9TJ!?8i&|c&UPWRMbkwT3nEeFH`Yyyh6b%Rm^nBuTt@9 z+$&-4lf!G|@LCo3<8=yN@5dYbc%uq|Hz|0tiiLQKiUoM9g14zyECKGv0}3AWv2WJ zUAXGUhvkNk`0-H%ACsRSmy4fJ@kxBD3ZKSj6g(n1KPw?g{v19phcBr3BEF>J%lL|d zud3LNuL;cR*xS+;X+N^Br+x2{&hDMhb-$6_fKU(Pt0FQUXgNrZvzsVCnsFqv?#L z4-FYsQ-?D>;LdjHu_TT1CHN~aGkmDjWJkJg4G^!+V_APd%_48tErDv6BW5;ji^UDD zRu5Sw7wwplk`w{OGEKWJM&61c-AWn!SeUP8G#+beH4_Ov*)NUV?eGw&GHNDI6G(1Y zTfCv?T*@{QyK|!Q09wbk5koPD>=@(cA<~i4pSO?f(^5sSbdhUc+K$DW#_7^d7i%At z?KBg#vm$?P4h%?T=XymU;w*AsO_tJr)`+HUll+Uk_zx6vNw>G3jT){w3ck+Z=>7f0 zZVkM*!k^Z_E@_pZK6uH#|vzoL{-j1VFlUHP&5~q?j=UvJJNQG ztQdiCF$8_EaN_Pu8+afN6n8?m5UeR_p_6Log$5V(n9^W)-_vS~Ws`RJhQNPb1$C?| zd9D_ePe*`aI9AZ~Ltbg)DZ;JUo@-tu*O7CJ=T)ZI1&tn%#cisS85EaSvpS~c#CN9B z#Bx$vw|E@gm{;cJOuDi3F1#fxWZ9+5JCqVRCz5o`EDW890NUfNCuBn)3!&vFQE{E$L`Cf7FMSSX%ppLH+Z}#=p zSow$)$z3IL7frW#M>Z4|^9T!=Z8}B0h*MrWXXiVschEA=$a|yX9T~o!=%C?T+l^Cc zJx&MB$me(a*@lLLWZ=>PhKs!}#!ICa0! zq%jNgnF$>zrBZ3z%)Y*yOqHbKzEe_P=@<5$u^!~9G2OAzi#}oP&UL9JljG!zf{JIK z++G*8j)K=$#57N)hj_gSA8golO7xZP|KM?elUq)qLS)i(?&lk{oGMJh{^*FgklBY@Xfl<_Q zXP~(}ST6V01$~VfOmD6j!Hi}lsE}GQikW1YmBH)`f_+)KI!t#~B7=V;{F*`umxy#2Wt8(EbQ~ks9wZS(KV5#5Tn3Ia90r{}fI%pfbqBAG zhZ)E7)ZzqA672%@izC5sBpo>dCcpXi$VNFztSQnmI&u`@zQ#bqFd9d&ls?RomgbSh z9a2rjfNiKl2bR!$Y1B*?3Ko@s^L5lQN|i6ZtiZL|w5oq%{Fb@@E*2%%j=bcma{K~9 z*g1%nEZ;0g;S84ZZ$+Rfurh;Nhq0;{t~(EIRt}D@(Jb7fbe+_@H=t&)I)gPCtj*xI z9S>k?WEAWBmJZ|gs}#{3*pR`-`!HJ)1Dkx8vAM6Tv1bHZhH=MLI;iC#Y!$c|$*R>h zjP{ETat(izXB{@tTOAC4nWNhh1_%7AVaf!kVI5D=Jf5I1!?}stbx_Yv23hLf$iUTb z-)WrTtd2X+;vBW_q*Z6}B!10fs=2FA=3gy*dljsE43!G*3Uw(Is>(-a*5E!T4}b-Y zfvOC)-HYjNfcpi`=kG%(X3XcP?;p&=pz+F^6LKqRom~pA}O* zitR+Np{QZ(D2~p_Jh-k|dL!LPmexLM?tEqI^qRDq9Mg z5XBftj3z}dFir4oScbB&{m5>s{v&U=&_trq#7i&yQN}Z~OIu0}G)>RU*`4<}@7bB% zKYxGx0#L#u199YKSWZwV$nZd>D>{mDTs4qDNyi$4QT6z~D_%Bgf?>3L#NTtvX;?2D zS3IT*2i$Snp4fjDzR#<)A``4|dA(}wv^=L?rB!;kiotwU_gma`w+@AUtkSyhwp{M} z!e`jbUR3AG4XvnBVcyIZht6Vi~?pCC!$XF2 z*V~)DBVm8H7$*OZQJYl3482hadhsI2NCz~_NINtpC?|KI6H3`SG@1d%PsDdw{u}hq zN;OU~F7L1jT&KAitilb&Fl3X12zfSuFm;X)xQWOHL&7d)Q5wgn{78QJ6k5J;is+XP zCPO8_rlGMJB-kuQ*_=Yo1TswG4xnZd&eTjc8=-$6J^8TAa~kEnRQ@Zp-_W&B(4r@F zA==}0vBzsF1mB~743XqBmL9=0RSkGn$cvHf*hyc{<2{@hW+jKjbC|y%CNupHY_NC% zivz^btBLP-cDyV8j>u)=loBs>HoI5ME)xg)oK-Q0wAy|8WD$fm>K{-`0|W{H00;;G z000j`0OWQ8aHA9e04^;603eeQIvtaXMG=2tcr1y8Fl-J;AS+=<0%DU8Bp3oEEDhA^ zOY)M8%o5+cF$rC?trfMcty*f)R;^v=f~}||Xe!#;T3eTDZELN&-50xk+J1heP5AQ>h5O#S_uO;O@;~REd*_G$x$hVeE#bchX)otXQy|S5(oB)2a2%Sc(iDHm z=d>V|a!BLp9^#)o7^EQ2kg=K4%nI^sK2w@-kmvB+ARXYdq?xC2age6)e4$^UaY=wn zgLD^{X0A+{ySY+&7RpldwpC6=E zSPq?y(rl8ZN%(A*sapd4PU+dIakIwT0=zxIJEUW0kZSo|(zFEWdETY*ZjIk9uNMUA ze11=mHu8lUUlgRx!hItf0dAF#HfdIB+#aOuY--#QN9Ry zbx|XkG?PrBb@l6Owl{9Oa9w{x^R}%GwcEEfY;L-6OU8|9RXvu`-ECS`jcO1x1MP{P zcr;Bw##*Dod9K@pEx9z9G~MiNi>8v1OU-}vk*HbI)@CM? zn~b=jWUF%HP=CS+VCP>GiAU_UOz$aq3%%Z2laq^Gx`WAEmuNScCN)OlW>YHGYFgV2 z42lO5ZANs5VMXLS-RZTvBJkWy*OeV#L;7HwWg51*E|RpFR=H}h(|N+79g)tIW!RBK ze08bg^hlygY$C2`%N>7bDm`UZ(5M~DTanh3d~dg+OcNdUanr8azO?})g}EfnUB;5- zE1FX=ru?X=zAk4_6@__o1fE+ml1r&u^f1Kb24Jf-)zKla%-dbd>UZ1 zrj3!RR!Jg`ZnllKJ)4Yfg)@z>(fFepeOcp=F-^VHv?3jSxfa}-NB~*qkJ5Uq(yn+( z<8)qbZh{C!xnO@-XC~XMNVnr-Z+paowv!$H7>`ypMwA(X4(knx7z{UcWWe-wXM!d? zYT}xaVy|7T@yCbNOoy)$D=E%hUNTm(lPZqL)?$v+-~^-1P8m@Jm2t^L%4#!JK#Vtg zyUjM+Y*!$);1<)0MUqL00L0*EZcsE&usAK-?|{l|-)b7|PBKl}?TM6~#j9F+eZq25_L&oSl}DOMv^-tacpDI)l*Ws3u+~jO@;t(T)P=HCEZ#s_5q=m zOsVY!QsOJn)&+Ge6Tm)Ww_Bd@0PY(78ZJ)7_eP-cnXYk`>j9q`x2?Xc6O@55wF+6R zUPdIX!2{VGA;FSivN@+;GNZ7H2(pTDnAOKqF*ARg+C54vZ@Ve`i?%nDDvQRh?m&`1 zq46gH)wV=;UrwfCT3F(m!Q5qYpa!#f6qr0wF=5b9rk%HF(ITc!*R3wIFaCcftGwPt z(kzx{$*>g5L<;u}HzS4XD%ml zmdStbJcY@pn`!fUmkzJ8N>*8Y+DOO^r}1f4ix-`?x|khoRvF%jiA)8)P{?$8j2_qN zcl3Lm9-s$xdYN9)>3j6BPFK)Jbovl|Sf_p((CHe!4hx@F)hd&&*Xb&{TBj>%pT;-n z{3+hA^QZYnjXxtF2XwxPZ`S#J8h>5qLwtwM-{5abbEnRS z`9_`Zq8FJiI#0syE_V_3M&trw$P=ezkHosV$8&I5c0(*-9KBE5DJOC-Xv zw}1bq~AD0_Xerm`%ryiG9_$S z5G|btfiAUNdV09SO2l9v+e#(H6HYOdQs=^ z@xwZQU)~;p1L*~ciC}9ao{nQ-@B>rpUzKBxv=cUusOP5Trs3QnvHxGh9e>s7AM{V1|HfYe z3QwH;nHHR49fYzuGc3W3l5xrDAI392SFXx>lWE3V9Ds9il3PyZaN5>oC3>9W-^7vC z3~KZ-@iD?tIkhg+6t{m;RGk2%>@I0&kf)o$+-^ls0(YABNbM(=l#ad@nKp_j=b~Xs ziR;xu_+)lxy6|+af!@}gO2H_x)p;nZ-tYxW5Omq=l`GzMp*GTLr>vZN1?e}^C$t*Z zvzEdIc2|HA2RFN_4#EkzMqKnbbw!?!?%B@M0^^5Z;K?x-%lg?Z>}wMV8zEqHZ$cr~Y#Wv>9+)KMUZatUqbRU8 z8t9qrek(H^C0Tuzq|cP2$WL7tzj+Dj5y^2SF1D154CnsB$xbz`$wV||n-cG%rsT$p z+3RHdadK(3-noj(2L#8c5lODg)V8pv(GEnNb@F>dEHQr>!qge@L>#qg)RAUtiOYqF ziiV_ETExwD)bQ<))?-9$)E(FiRBYyC@}issHS!j9n)~I1tarxnQ2LfjdIJ)*jp{0E z&1oTd%!Qbw$W58s!6ms>F z=p0!~_Mv~8jyaicOS*t(ntw`5uFi0Bc4*mH8kSkk$>!f0;FM zX_t14I55!ZVsg0O$D2iuEDb7(J>5|NKW^Z~kzm@dax z9(|As$U7^}LF%#`6r&UPB*6`!Rf74h~*C=ami6xUxYCwiJxdr$+`z zKSC4A%8!s%R&j*2si(OEc*fy!q)?%=TjDZJ2}O zxT6o>jlKXz_7_Y$N})}IG`*#KfMzs#R(SI#)3*ZEzCv%_tu(VTZ5J| zw2$5kK)xTa>xGFgS0?X(NecjzFVKG%VVn?neu=&eQ+DJ1APlY1E?Q1s!Kk=yf7Uho z>8mg_!U{cKqpvI3ucSkC2V`!d^XMDk;>GG~>6>&X_z75-kv0UjevS5ORHV^e8r{tr z-9z*y&0eq3k-&c_AKw~<`8dtjsP0XgFv6AnG?0eo5P14T{xW#b*Hn2gEnt5-KvN1z zy!TUSi>IRbD3u+h@;fn7fy{F&hAKx7dG4i!c?5_GnvYV|_d&F16p;)pzEjB{zL-zr z(0&AZUkQ!(A>ghC5U-)t7(EXb-3)tNgb=z`>8m8n+N?vtl-1i&*ftMbE~0zsKG^I$ zSbh+rUiucsb!Ax@yB}j>yGeiKIZk1Xj!i#K^I*LZW_bWQIA-}FmJ~^}>p=K$bX9F{}z{s^KWc~OK(zl_X57aB^J9v}yQ5h#BE$+C)WOglV)nd0WWtaF{7`_Ur`my>4*NleQG#xae4fIo(b zW(&|g*#YHZNvDtE|6}yHvu(hDekJ-t*f!2RK;FZHRMb*l@Qwkh*~CqQRNLaepXypX z1?%ATf_nHIu3z6gK<7Dmd;{`0a!|toT0ck|TL$U;7Wr-*piO@R)KrbUz8SXO0vr1K z>76arfrqImq!ny+VkH!4?x*IR$d6*;ZA}Mhro(mzUa?agrFZpHi*)P~4~4N;XoIvH z9N%4VK|j4mV2DRQUD!_-9fmfA2(YVYyL#S$B;vqu7fnTbAFMqH``wS7^B5=|1O&fL z)qq(oV6_u4x(I(**#mD}MnAy(C&B4a1n6V%$&=vrIDq^F_KhE5Uw8_@{V`_#M0vCu zaNUXB=n0HT@D+ppDXi8-vp{tj)?7+k>1j}VvEKRgQ~DWva}8*pp`W8~KRo*kJ*&X} zP!~2fxQr@dM*q0dI|)Fux=pZWBk==RI7i{^BQf`kWlD2%|@R9!JA7& zLbM$uJ12y}_62$|T|{)@OJZtzfpL^t@1nMTYHutrF#D+^?~CN~9`YQ@#&&@c_Zf)( zbC~y8!2LO8jHwQXv>G~1q?c68ipT*%dY&c{8wd_!Y#~tMJ7yk!F8| zt?m_CLVw6cU@@p(#h4cY&Qsfz2Xp3w^4Cg%m03Tmq~9n%hyoMH^KY7{(QkRyn_!YB zzZa!Tgr~5$MAG$x)Fs71#6j}Kvcv3=9VUX8CH< zbP3|fY8f#$K*<5JQ7whM(v=GN2k26Xsh)#0!HKS(koLgAp-;)8z0w&_Z=nG4v6n8u z&Tm0Fi){4_!Y5Kp?!zv$FKfUifQ{%c82uYfrvE{%ejUd72aNYmI*0z3-a-EYr+bB->oH3#t(AY3 zV{Z=(SJr;D#0(`u*dc*~9T7D8Pudw894%!>c4wU&V1m<~0InidR6fbi?yPl(z+sKa zdF*kS>_4^1UO>y4T%Ar>epSr5&vp`$KdY7B(F%P0@VyHk@1fJ=6X0=aGjD-)BrOJD zW}IU@hg~^2r>a1fQvjTtvL*mKJ7q;pfP*U2=URL`VB_Y_JojbZ+MS=vaVN0C6L_MV zG1#5=35-E`KsD%r>-Q_ndvJ2tOYcMMP9f*t0iJ`(Z`^+YP)h>@lR(@Wvrt-`0tHG+ zuP2R@@mx=T@fPoQ1s`e^1I0H*kQPBGDky@!ZQG@8jY-+2ihreG5q$6i{3vmDTg0j$ zzRb*-nKN@{_wD`V6+i*YS)?$XfrA-sW?js?SYU8#vXxxQCc|*K!EbpWfu)3~jwq6_@KC0m;3A%jH^18_a0;ksC2DEwa@2{9@{ z9@T??<4QwR69zk{UvcHHX;`ICOwrF;@U;etd@YE)4MzI1WCsadP=`%^B>xPS-{`=~ zZ+2im8meb#4p~XIL9}ZOBg7D8R=PC8V}ObDcxEEK(4yGKcyCQWUe{9jCs+@k!_y|I z%s{W(&>P4w@hjQ>PQL$zY+=&aDU6cWr#hG)BVCyfP)h>@3IG5I2mk;8K>)Ppba*!h z005B=001VF5fT=Y4_ytCUk`sv8hJckqSy&Gc2Jx^WJ$J~08N{il-M$fz_ML$)Cpil z(nOv_nlZB^c4s&&O3h=OLiCz&(|f0 zxWU_-JZy>hxP*gvR>CLnNeQ1~g;6{g#-}AbkIzWR;j=8=6!AHpKQCbjFYxf9h%bov zVi;eNa1>t-<14KERUW>^KwoF+8zNo`Y*WiQwq}3m0_2RYtL9Wmu`JaRaQMQ)`Si^6+VbM`!rH~T?DX2=(n4nT zf`G`(Rpq*pDk*v~wMYPZ@vMNZDMPnxMYmU!lA{Xfo?n=Ibb4y3eyY1@Dut4|Y^ml& zqs$r}jAo=B(Ml>ogeEjyv(E`=kBzPf2uv9TQtO$~bamD#=Tv`lNy(K|w$J2O6jS51 zzZtOCHDWz7W0=L1XDW5WR5mtLGc~W+>*vX5{e~U@rE~?7e>vKU-v8bj;F4#abtcV(3ZtwXo9ia93HiETyQXwW4a-0){;$OU*l` zW^bjkyZTJ6_DL^0}`*)#EZ|2nvKRzMLH9-~@Z6$v#t8Dm%(qpP+DgzNe6d)1q zBqhyF$jJTyYFvl_=a>#I8jhJ)d6SBNPg#xg2^kZ3NX8kQ74ah(Y5Z8mlXyzTD&}Q8 ziY(pj-N-V2f>&hZQJ`Di%wp2fN(I%F@l)3M8GcSdNy+#HuO{$I8NXubRlFkL)cY@b z#`v{}-^hRXEq*8B_cG=%PZvI$eo(|8Wc(2o8L#0_GX9L$1@yV>%7mGk)QTD1R*OvS z4OW;ym1)%k9Bfem0tOqq3yyAUWp&q|LsN!RDnxa|j;>R|Mm2rIv7=tej5GFaa+`#| z;7u9Z_^XV+vD@2hF8Xe63+Qd`oig6S9jX(*DbjzPb*K-H7c^7E-(~!R6E%TrgW;RvG;WS{Ziv*W*a*`9Bb;$Er3?MyF~5GcXv`k>U)n}lwv$Sp+H@IKA5$mKk0g*4Ln{!tfvITeY zzr%8JJ5BdcEYsR9eGzJ4B&$}4FMmbRU6{8{_w7Kl77@PNe7|Bc#c?5(C5&Z=kJ#(oM90D4`rh2S!|^L!P#e#1hkD5@~-- z`63GV0~*rOZSqw7k^#-Y$Q4z3Oa2SPRURqEahB1B^h{7~+p03SwzqL9QU#$3-X zdYtQ?-K5xDAdfomEd6(yPtZ!yY_<35bMedeq`z2JWorljz5-f9<^93HM-$#+acw%9r!JOM%O<|BR`W& zd-%j_?b^q7Kl6{q^N{cg2u;11rFB5EP+oqG9&pHD#_Mo@aNMj;LUvsl&nK(ca(hT( zzFc2oHC6WQv8g7jo+3ZSwK+9G$cvfRnql)?g=XeQ3+LTh3)79nhEle8OqS3T$qn(> z(=5Bg?EWq-ldEywgzXW965%H(9^ik*rH(8dNdkbcS9|ow&_r`X~R^R?B+(oTiMzzlx8KnHqUi z8Rh-)VAnS-CO+3}yxqm8)X+N+uzieFVm-F#syP#M1p5&$wX3MJ8 z+R@grZ*5G^Uh4I@VT=>C4RJNc^~3mx$kS1F{L?3)BzdduD2MZKdu#jNno&f2&d{?` zW(>$oktzY@GO{|Ln~Bt^A4)(%?l-&(Dm!iL#$K_xOyhwAf=K2<+Bom zw7|hl6E5}B$d%n0sfZvfQRy9Fyz2~ z83#=#LaHnf1th^k*p|ux8!!8pfHE!)x*%=_hAddl)P%4h4%&8!5-W#xqqb}c=H(i|wqcIS&oDQ{ zhI7N-$f$ra3=RjPmMh?-IEkJYQ<}R9Z!}wmp$#~Uc%u1oh#TP}wF*kJJmQX2#27kL z_dz(yKufo<=m71bZfLp^Ll#t3(IHkrgMcvx@~om%Ib(h(<$Da7urTI`x|%`wD--sN zJEEa>4DGSEG?0ulkosfj8IMNN4)B=ZtvGG{|4Fp=Xhg!wPNgYzS>{Bp%%Qa+624X@ X49Luk)baa85H9$5YCsTPT`SVRWMtMW diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f371643ee..05679dc3c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c8..744e882ed 100755 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) diff --git a/kmath-ast/README.md b/kmath-ast/README.md index 026c5a625..c3c4c38a1 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Performance and visualization extensions to MST API. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-14`. **Gradle:** ```gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-13' + implementation 'space.kscience:kmath-ast:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-13") + implementation("space.kscience:kmath-ast:0.3.0-dev-14") } ``` diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 8209a0dad..9de7e9980 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -45,8 +45,7 @@ kotlin.sourceSets { jvmMain { dependencies { - implementation("org.ow2.asm:asm:9.1") - implementation("org.ow2.asm:asm-commons:9.1") + implementation("org.ow2.asm:asm-commons:9.2") } } } diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 18a83756d..110529b72 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,7 +8,7 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-14`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-13' + implementation 'space.kscience:kmath-complex:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-13") + implementation("space.kscience:kmath-complex:0.3.0-dev-14") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index 6ca8c8ef8..a563552bb 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-14`. **Gradle:** ```gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-13' + implementation 'space.kscience:kmath-core:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-13") + implementation("space.kscience:kmath-core:0.3.0-dev-14") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index 10e7bd606..f88f53000 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-14`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-13' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-13") + implementation("space.kscience:kmath-ejml:0.3.0-dev-14") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 6339782dd..d449b4540 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-14`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-13' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0-dev-13") + implementation("space.kscience:kmath-for-real:0.3.0-dev-14") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 77f55528a..d0beae2c8 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-14`. **Gradle:** ```gradle @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-13' + implementation 'space.kscience:kmath-functions:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0-dev-13") + implementation("space.kscience:kmath-functions:0.3.0-dev-14") } ``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index ef8fcd352..71097771d 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,7 +7,7 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-14`. **Gradle:** ```gradle @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0-dev-13' + implementation 'space.kscience:kmath-jafama:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0-dev-13") + implementation("space.kscience:kmath-jafama:0.3.0-dev-14") } ``` @@ -66,8 +66,8 @@ Report for benchmark configuration jafamaDouble | Benchmark | Score | |:---------:|:-----:| -|`space.kscience.kmath.benchmarks.JafamaBenchmark.core`|14.296120859512893 ± 0.36462633435888736 ops/s| -|`space.kscience.kmath.benchmarks.JafamaBenchmark.jafama`|11.431566395649781 ± 2.570896777898243 ops/s| -|`space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafama`|11.746020495694117 ± 6.205909559197869 ops/s| +|`space.kscience.kmath.benchmarks.JafamaBenchmark.core`|14.35014650168397 ± 0.9200669832937576 ops/s| +|`space.kscience.kmath.benchmarks.JafamaBenchmark.jafama`|12.048429204455887 ± 1.2882929181842269 ops/s| +|`space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafama`|12.977653357239152 ± 1.4122819627470866 ops/s| diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 31c7bb819..304a0639b 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-14`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-13' + implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-13") + implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-14") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 1c945f06a..5cbb31d5a 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-14`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-13' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-13") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-14") } ``` diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts index abcc02962..6e890a937 100644 --- a/kmath-nd4j/build.gradle.kts +++ b/kmath-nd4j/build.gradle.kts @@ -7,9 +7,8 @@ description = "ND4J NDStructure implementation and according NDAlgebra classes" dependencies { api(project(":kmath-tensors")) - api("org.nd4j:nd4j-api:1.0.0-beta7") - testImplementation("org.nd4j:nd4j-native:1.0.0-beta7") - testImplementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") + api("org.nd4j:nd4j-api:1.0.0-M1") + testImplementation("org.nd4j:nd4j-native-platform:1.0.0-M1") testImplementation("org.slf4j:slf4j-simple:1.7.30") } diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index dd21a9f2f..6b991d5df 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-13`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-14`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-13' + implementation 'space.kscience:kmath-tensors:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-13") + implementation("space.kscience:kmath-tensors:0.3.0-dev-14") } ``` diff --git a/settings.gradle.kts b/settings.gradle.kts index 063c69280..02b75cddc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,7 +6,7 @@ pluginManagement { } val toolsVersion = "0.10.0" - val kotlinVersion = "1.5.0" + val kotlinVersion = "1.5.20" plugins { id("ru.mipt.npm.gradle.project") version toolsVersion @@ -17,7 +17,6 @@ pluginManagement { kotlin("plugin.allopen") version kotlinVersion id("org.jetbrains.kotlinx.benchmark") version "0.3.1" kotlin("jupyter.api") version "0.10.0-25" - } } @@ -45,5 +44,5 @@ include( ":kmath-symja", ":kmath-jafama", ":examples", - ":benchmarks" + ":benchmarks", ) From 5d2eaaf68aeb0b4c5d455aa46e366436d61de77d Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 13 Jul 2021 00:21:46 +0700 Subject: [PATCH 24/39] Add contracts to some functions, fix multiple style issues --- .../kmath/benchmarks/JafamaBenchmark.kt | 13 +++--- .../benchmarks/MatrixInverseBenchmark.kt | 4 +- docs/nd-structure.md | 2 + .../space/kscience/kmath/ast/astRendering.kt | 2 +- .../kscience/kmath/ast/rendering/features.kt | 2 +- .../TestCompilerConsistencyWithInterpreter.kt | 1 - .../kmath/ast/TestCompilerVariables.kt | 1 - .../kscience/kmath/internal/estree/estree.kt | 2 + .../kotlin/space/kscience/kmath/ast/utils.kt | 3 ++ .../kscience/kmath/wasm/TestWasmSpecific.kt | 1 - .../kotlin/space/kscience/kmath/ast/utils.kt | 7 +++- .../DerivativeStructureExpression.kt | 2 +- .../commons/optimization/CMOptimization.kt | 4 +- .../commons/transform/Transformations.kt | 2 +- .../DerivativeStructureExpressionTest.kt | 2 +- .../kscience/kmath/complex/Quaternion.kt | 2 +- .../kscience/kmath/data/XYColumnarData.kt | 2 +- .../kscience/kmath/data/XYZColumnarData.kt | 4 +- .../space/kscience/kmath/domains/Domain.kt | 2 +- .../expressions/DifferentiableExpression.kt | 17 ++++---- .../FunctionalExpressionAlgebra.kt | 42 +++++++++++-------- .../kmath/expressions/SimpleAutoDiff.kt | 9 ++-- .../kmath/expressions/SymbolIndexer.kt | 14 +++++-- .../kmath/linear/BufferedLinearSpace.kt | 4 +- .../kscience/kmath/linear/LinearSpace.kt | 2 +- .../kscience/kmath/linear/MatrixFeatures.kt | 14 +++---- .../space/kscience/kmath/misc/cumulative.kt | 2 +- .../space/kscience/kmath/nd/AlgebraND.kt | 9 ++-- .../kscience/kmath/nd/BufferAlgebraND.kt | 6 +-- .../space/kscience/kmath/nd/ShortRingND.kt | 7 ++-- .../space/kscience/kmath/nd/StructureND.kt | 2 +- .../kmath/operations/AlgebraElements.kt | 2 +- .../space/kscience/kmath/operations/BigInt.kt | 2 +- .../kmath/structures/BufferAccessor2D.kt | 18 ++++---- .../kmath/structures/bufferOperation.kt | 4 +- .../kscience/kmath/linear/VectorSpaceTest.kt | 5 --- .../kscience/kmath/testutils/FieldVerifier.kt | 2 +- .../kscience/kmath/testutils/RingVerifier.kt | 2 +- .../kmath/chains/BlockingDoubleChain.kt | 2 +- .../kmath/coroutines/coroutinesExtra.kt | 15 ++++--- .../kscience/kmath/dimensions/Wrappers.kt | 10 ++--- .../kscience/dimensions/DMatrixContextTest.kt | 0 .../space/kscience/kmath/real/RealMatrix.kt | 2 +- .../kaceince/kmath/real/DoubleMatrixTest.kt | 2 +- .../kscience/kmath/functions/Piecewise.kt | 8 ++-- .../kscience/kmath/functions/Polynomial.kt | 4 +- .../kscience/kmath/integration/Integrand.kt | 2 +- .../kmath/integration/UnivariateIntegrand.kt | 2 +- .../kmath/interpolation/Interpolator.kt | 2 +- .../space/kscience/kmath/geometry/Line.kt | 2 +- .../kscience/kmath/histogram/Histogram.kt | 6 +-- .../kmath/histogram/IndexedHistogramSpace.kt | 2 +- .../kmath/histogram/TreeHistogramSpace.kt | 13 +++--- kmath-kotlingrad/build.gradle.kts | 6 +-- .../kscience/kmath/nd4j/Nd4jArrayIterator.kt | 2 +- .../kmath/optimization/Optimization.kt | 2 +- .../kmath/samplers/ConstantSampler.kt | 18 -------- .../space/kscience/kmath/stat/MCScope.kt | 14 +++++-- .../space/kscience/kmath/stat/Sampler.kt | 2 +- .../kscience/kmath/stat/SamplerAlgebra.kt | 6 +-- .../space/kscience/kmath/stat/Statistic.kt | 8 ++-- .../kscience/kmath/symja/SymjaExpression.kt | 3 +- kmath-tensors/README.md | 2 +- kmath-tensors/build.gradle.kts | 14 +++---- .../kmath/tensors/core/BufferedTensor.kt | 4 +- .../kmath/tensors/core/DoubleTensor.kt | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 20 ++++----- .../kmath/tensors/core/internal/linUtils.kt | 6 +-- .../tensors/core/internal/tensorCastsUtils.kt | 1 + .../kmath/tensors/core/internal/utils.kt | 1 + .../core/TestDoubleLinearOpsAlgebra.kt | 2 +- .../tensors/core/TestDoubleTensorAlgebra.kt | 2 +- .../kmath/viktor/ViktorStructureND.kt | 2 +- 73 files changed, 210 insertions(+), 200 deletions(-) delete mode 100644 kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt rename kmath-dimensions/src/commonTest/kotlin/{ => space}/kscience/dimensions/DMatrixContextTest.kt (100%) delete mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.kt diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt index 24a730375..5d4eee7c0 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt @@ -13,6 +13,8 @@ import space.kscience.kmath.jafama.JafamaDoubleField import space.kscience.kmath.jafama.StrictJafamaDoubleField import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.random.Random @State(Scope.Benchmark) @@ -31,9 +33,10 @@ internal class JafamaBenchmark { fun strictJafama(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> StrictJafamaDoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } } - - private inline fun invokeBenchmarks(blackhole: Blackhole, expr: (Double) -> Double) { - val rng = Random(0) - repeat(1000000) { blackhole.consume(expr(rng.nextDouble())) } - } +} + +private inline fun invokeBenchmarks(blackhole: Blackhole, expr: (Double) -> Double) { + contract { callsInPlace(expr, InvocationKind.AT_LEAST_ONCE) } + val rng = Random(0) + repeat(1000000) { blackhole.consume(expr(rng.nextDouble())) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt index 7bb32af28..e3179c05c 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt @@ -40,14 +40,14 @@ internal class MatrixInverseBenchmark { @Benchmark fun cmLUPInversion(blackhole: Blackhole) { - with(CMLinearSpace) { + CMLinearSpace { blackhole.consume(inverse(matrix)) } } @Benchmark fun ejmlInverse(blackhole: Blackhole) { - with(EjmlLinearSpaceDDRM) { + EjmlLinearSpaceDDRM { blackhole.consume(matrix.getFeature>()?.inverse) } } diff --git a/docs/nd-structure.md b/docs/nd-structure.md index ec9b4d521..ab214094e 100644 --- a/docs/nd-structure.md +++ b/docs/nd-structure.md @@ -115,6 +115,8 @@ via extension function. Usually it is bad idea to compare the direct numerical operation performance in different languages, but it hard to work completely without frame of reference. In this case, simple numpy code: ```python +import numpy as np + res = np.ones((1000,1000)) for i in range(1000): res = res + 1.0 diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt index e16769464..c4f263f97 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt @@ -10,7 +10,7 @@ import space.kscience.kmath.ast.rendering.LatexSyntaxRenderer import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer import space.kscience.kmath.ast.rendering.renderWithStringBuilder -public fun main() { +fun main() { val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath() val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst) println("MathSyntax:") diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt index a2f42d1bf..203cdf8b3 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt @@ -13,7 +13,7 @@ import space.kscience.kmath.operations.* import kotlin.reflect.KClass /** - * Prints any [Symbol] as a [SymbolSyntax] containing the [Symbol.value] of it. + * Prints any [Symbol] as a [SymbolSyntax] containing the [Symbol.identity] of it. * * @author Iaroslav Postovalov */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt index 3116466e6..1edb5923e 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt @@ -11,7 +11,6 @@ import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.interpret import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt index bed5bc7fa..af1a2e338 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt @@ -9,7 +9,6 @@ import space.kscience.kmath.expressions.MstRing import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.invoke import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt index e5254013e..b62b8c06c 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("ClassName") + package space.kscience.kmath.internal.estree import kotlin.js.RegExp 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 93b7e9449..0d896c6f6 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 @@ -10,6 +10,8 @@ import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import space.kscience.kmath.estree.compile as estreeCompile import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression import space.kscience.kmath.wasm.compile as wasmCompile @@ -34,6 +36,7 @@ private object ESTreeCompilerTestContext : CompilerTestContext { } internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { + contract { callsInPlace(action, InvocationKind.AT_LEAST_ONCE) } action(WasmCompilerTestContext) action(ESTreeCompilerTestContext) } diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt index 45776c191..8ae5fcb36 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt @@ -11,7 +11,6 @@ import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals 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 d3b554efd..a7f0bb3fb 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 @@ -10,6 +10,8 @@ import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import space.kscience.kmath.asm.compile as asmCompile import space.kscience.kmath.asm.compileToExpression as asmCompileToExpression @@ -22,4 +24,7 @@ private object AsmCompilerTestContext : CompilerTestContext { asmCompile(algebra, arguments) } -internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) = action(AsmCompilerTestContext) +internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + action(AsmCompilerTestContext) +} diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index 361027968..d0ab8b1e8 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -15,7 +15,7 @@ import space.kscience.kmath.operations.NumbersAddOperations * A field over commons-math [DerivativeStructure]. * * @property order The derivation order. - * @property bindings The map of bindings values. All bindings are considered free parameters + * @param bindings The map of bindings values. All bindings are considered free parameters */ @OptIn(UnstableKMathAPI::class) public class DerivativeStructureField( diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt index 400ee0310..a46f06568 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt @@ -52,11 +52,11 @@ public class CMOptimization( public fun exportOptimizationData(): List = optimizationData.values.toList() - public override fun initialGuess(map: Map): Unit { + public override fun initialGuess(map: Map) { addOptimizationData(InitialGuess(map.toDoubleArray())) } - public override fun function(expression: Expression): Unit { + public override fun function(expression: Expression) { val objectiveFunction = ObjectiveFunction { val args = it.toMap() expression(args) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt index d29491d63..6fef12138 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt @@ -32,7 +32,7 @@ public object Transformations { /** * Create a virtual buffer on top of array */ - private fun Array.asBuffer() = VirtualBuffer(size) { + private fun Array.asBuffer() = VirtualBuffer(size) { val value = get(it) Complex(value.real, value.imaginary) } diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt index 966675062..0bf1d53f0 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt @@ -16,7 +16,7 @@ internal inline fun diff( order: Int, vararg parameters: Pair, block: DerivativeStructureField.() -> Unit, -): Unit { +) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } DerivativeStructureField(order, mapOf(*parameters)).run(block) } 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 c59aabdcb..28aae7bb4 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 @@ -147,7 +147,7 @@ public object QuaternionField : Field, Norm, return if (arg.w > 0) Quaternion(ln(arg.w), 0, 0, 0) else { - val l = ComplexField { ComplexField.ln(arg.w.toComplex()) } + val l = ComplexField { ln(arg.w.toComplex()) } Quaternion(l.re, l.im, 0, 0) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt index 08bfd3ca3..920fcc021 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt @@ -16,7 +16,7 @@ import kotlin.math.max * The buffer of X values. */ @UnstableKMathAPI -public interface XYColumnarData : ColumnarData { +public interface XYColumnarData : ColumnarData { /** * The buffer of X values */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt index 39a6b858c..6050c311c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt @@ -14,7 +14,7 @@ import space.kscience.kmath.structures.Buffer * Inherits [XYColumnarData]. */ @UnstableKMathAPI -public interface XYZColumnarData : XYColumnarData { +public interface XYZColumnarData : XYColumnarData { public val z: Buffer override fun get(symbol: Symbol): Buffer? = when (symbol) { @@ -23,4 +23,4 @@ public interface XYZColumnarData : XYColumna Symbol.z -> z else -> null } -} \ No newline at end of file +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt index e6e703cbf..b5a84cf6c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt @@ -12,7 +12,7 @@ import space.kscience.kmath.linear.Point * * @param T the type of element of this domain. */ -public interface Domain { +public interface Domain { /** * Checks if the specified point is contained in this domain. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt index 1dcada6d3..ce1265b2f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt @@ -9,7 +9,6 @@ package space.kscience.kmath.expressions * Represents expression which structure can be differentiated. * * @param T the type this expression takes as argument and returns. - * @param R the type of expression this expression can be differentiated to. */ public interface DifferentiableExpression : Expression { /** @@ -24,16 +23,18 @@ public interface DifferentiableExpression : Expression { public fun DifferentiableExpression.derivative(symbols: List): Expression = derivativeOrNull(symbols) ?: error("Derivative by symbols $symbols not provided") -public fun DifferentiableExpression.derivative(vararg symbols: Symbol): Expression = +public fun DifferentiableExpression.derivative(vararg symbols: Symbol): Expression = derivative(symbols.toList()) -public fun DifferentiableExpression.derivative(name: String): Expression = +public fun DifferentiableExpression.derivative(name: String): Expression = derivative(StringSymbol(name)) /** - * A special type of [DifferentiableExpression] which returns typed expressions as derivatives + * A special type of [DifferentiableExpression] which returns typed expressions as derivatives. + * + * @param R the type of expression this expression can be differentiated to. */ -public interface SpecialDifferentiableExpression>: DifferentiableExpression { +public interface SpecialDifferentiableExpression> : DifferentiableExpression { override fun derivativeOrNull(symbols: List): R? } @@ -53,9 +54,9 @@ public abstract class FirstDerivativeExpression : DifferentiableExpression /** * Returns first derivative of this expression by given [symbol]. */ - public abstract fun derivativeOrNull(symbol: Symbol): Expression? + public abstract fun derivativeOrNull(symbol: Symbol): Expression? - public final override fun derivativeOrNull(symbols: List): Expression? { + public final override fun derivativeOrNull(symbols: List): Expression? { val dSymbol = symbols.firstOrNull() ?: return null return derivativeOrNull(dSymbol) } @@ -64,6 +65,6 @@ public abstract class FirstDerivativeExpression : DifferentiableExpression /** * A factory that converts an expression in autodiff variables to a [DifferentiableExpression] */ -public fun interface AutoDiffProcessor, out R : Expression> { +public fun interface AutoDiffProcessor, out R : Expression> { public fun process(function: A.() -> I): DifferentiableExpression } 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 951ec9474..a10e29cf0 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,13 +6,15 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract /** * A context class for [Expression] construction. * * @param algebra The algebra to provide for Expressions built. */ -public abstract class FunctionalExpressionAlgebra>( +public abstract class FunctionalExpressionAlgebra>( public val algebra: A, ) : ExpressionAlgebra> { /** @@ -29,9 +31,6 @@ public abstract class FunctionalExpressionAlgebra>( ?: error("Symbol '$value' is not supported in $this") } - /** - * Builds an Expression of dynamic call of binary operation [operation] on [left] and [right]. - */ public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = { left, right -> Expression { arguments -> @@ -39,9 +38,6 @@ public abstract class FunctionalExpressionAlgebra>( } } - /** - * Builds an Expression of dynamic call of unary operation with name [operation] on [arg]. - */ public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> Expression { arguments -> algebra.unaryOperationFunction(operation)(arg.invoke(arguments)) } } @@ -50,7 +46,7 @@ public abstract class FunctionalExpressionAlgebra>( /** * A context class for [Expression] construction for [Ring] algebras. */ -public open class FunctionalExpressionGroup>( +public open class FunctionalExpressionGroup>( algebra: A, ) : FunctionalExpressionAlgebra(algebra), Group> { public override val zero: Expression get() = const(algebra.zero) @@ -84,7 +80,7 @@ public open class FunctionalExpressionGroup>( } -public open class FunctionalExpressionRing>( +public open class FunctionalExpressionRing>( algebra: A, ) : FunctionalExpressionGroup(algebra), Ring> { public override val one: Expression get() = const(algebra.one) @@ -105,7 +101,7 @@ public open class FunctionalExpressionRing>( super.binaryOperationFunction(operation) } -public open class FunctionalExpressionField>( +public open class FunctionalExpressionField>( algebra: A, ) : FunctionalExpressionRing(algebra), Field>, ScaleOperations> { /** @@ -131,7 +127,7 @@ public open class FunctionalExpressionField>( super.bindSymbolOrNull(value) } -public open class FunctionalExpressionExtendedField>( +public open class FunctionalExpressionExtendedField>( algebra: A, ) : FunctionalExpressionField(algebra), ExtendedField> { public override fun number(value: Number): Expression = const(algebra.number(value)) @@ -172,14 +168,26 @@ public open class FunctionalExpressionExtendedField>( public override fun bindSymbol(value: String): Expression = super.bindSymbol(value) } -public inline fun > A.expressionInSpace(block: FunctionalExpressionGroup.() -> Expression): Expression = - FunctionalExpressionGroup(this).block() +public inline fun > A.expressionInGroup( + block: FunctionalExpressionGroup.() -> Expression, +): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionGroup(this).block() +} -public inline fun > A.expressionInRing(block: FunctionalExpressionRing.() -> Expression): Expression = - FunctionalExpressionRing(this).block() +public inline fun > A.expressionInRing( + block: FunctionalExpressionRing.() -> Expression, +): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionRing(this).block() +} -public inline fun > A.expressionInField(block: FunctionalExpressionField.() -> Expression): Expression = - FunctionalExpressionField(this).block() +public inline fun > A.expressionInField( + block: FunctionalExpressionField.() -> Expression, +): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionField(this).block() +} public inline fun > A.expressionInExtendedField( block: FunctionalExpressionExtendedField.() -> Expression, diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt index 478b85620..960f6fd79 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt @@ -119,8 +119,6 @@ public open class SimpleAutoDiffField>( get() = getDerivative(this) set(value) = setDerivative(this, value) - public inline fun const(block: F.() -> T): AutoDiffValue = const(context.block()) - /** * Performs update of derivative after the rest of the formula in the back-pass. * @@ -194,6 +192,11 @@ public open class SimpleAutoDiffField>( } } +public inline fun > SimpleAutoDiffField.const(block: F.() -> T): AutoDiffValue { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return const(context.block()) +} + /** * Runs differentiation and establishes [SimpleAutoDiffField] context inside the block of code. @@ -208,7 +211,7 @@ public open class SimpleAutoDiffField>( * assertEquals(9.0, x.d) // dy/dx * ``` * - * @param body the action in [SimpleAutoDiffField] context returning [AutoDiffVariable] to differentiate with respect to. + * @param body the action in [SimpleAutoDiffField] context returning [AutoDiffValue] to differentiate with respect to. * @return the result of differentiation. */ public fun > F.simpleAutoDiff( diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt index 06634704c..c02bdad02 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt @@ -9,6 +9,8 @@ import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.structures.BufferFactory +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.jvm.JvmInline /** @@ -65,9 +67,13 @@ public value class SimpleSymbolIndexer(override val symbols: List) : Sym * Execute the block with symbol indexer based on given symbol order */ @UnstableKMathAPI -public inline fun withSymbols(vararg symbols: Symbol, block: SymbolIndexer.() -> R): R = - with(SimpleSymbolIndexer(symbols.toList()), block) +public inline fun withSymbols(vararg symbols: Symbol, block: SymbolIndexer.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return with(SimpleSymbolIndexer(symbols.toList()), block) +} @UnstableKMathAPI -public inline fun withSymbols(symbols: Collection, block: SymbolIndexer.() -> R): R = - with(SimpleSymbolIndexer(symbols.toList()), block) \ No newline at end of file +public inline fun withSymbols(symbols: Collection, block: SymbolIndexer.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return with(SimpleSymbolIndexer(symbols.toList()), block) +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt index 9b4451a62..f1839077f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt @@ -15,7 +15,7 @@ import space.kscience.kmath.structures.VirtualBuffer import space.kscience.kmath.structures.indices -public class BufferedLinearSpace>( +public class BufferedLinearSpace>( override val elementAlgebra: A, private val bufferFactory: BufferFactory, ) : LinearSpace { @@ -88,4 +88,4 @@ public class BufferedLinearSpace>( override fun Matrix.times(value: T): Matrix = ndRing(rowNum, colNum).run { unwrap().map { it * value }.as2D() } -} \ No newline at end of file +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index ec073ac48..badf2794e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt @@ -32,7 +32,7 @@ public typealias Point = Buffer * Basic operations on matrices and vectors. Operates on [Matrix]. * * @param T the type of items in the matrices. - * @param M the type of operated matrices. + * @param A the type of ring over [T]. */ public interface LinearSpace> { public val elementAlgebra: A diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt index 37c93d249..e0d733a66 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt @@ -35,7 +35,7 @@ public object UnitFeature : DiagonalFeature * * @param T the type of matrices' items. */ -public interface InverseMatrixFeature : MatrixFeature { +public interface InverseMatrixFeature : MatrixFeature { /** * The inverse matrix of the matrix that owns this feature. */ @@ -47,7 +47,7 @@ public interface InverseMatrixFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface DeterminantFeature : MatrixFeature { +public interface DeterminantFeature : MatrixFeature { /** * The determinant of the matrix that owns this feature. */ @@ -80,7 +80,7 @@ public object UFeature : MatrixFeature * * @param T the type of matrices' items. */ -public interface LUDecompositionFeature : MatrixFeature { +public interface LUDecompositionFeature : MatrixFeature { /** * The lower triangular matrix in this decomposition. It may have [LFeature]. */ @@ -98,7 +98,7 @@ public interface LUDecompositionFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface LupDecompositionFeature : MatrixFeature { +public interface LupDecompositionFeature : MatrixFeature { /** * The lower triangular matrix in this decomposition. It may have [LFeature]. */ @@ -126,7 +126,7 @@ public object OrthogonalFeature : MatrixFeature * * @param T the type of matrices' items. */ -public interface QRDecompositionFeature : MatrixFeature { +public interface QRDecompositionFeature : MatrixFeature { /** * The orthogonal matrix in this decomposition. It may have [OrthogonalFeature]. */ @@ -144,7 +144,7 @@ public interface QRDecompositionFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface CholeskyDecompositionFeature : MatrixFeature { +public interface CholeskyDecompositionFeature : MatrixFeature { /** * The triangular matrix in this decomposition. It may have either [UFeature] or [LFeature]. */ @@ -157,7 +157,7 @@ public interface CholeskyDecompositionFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface SingularValueDecompositionFeature : MatrixFeature { +public interface SingularValueDecompositionFeature : MatrixFeature { /** * The matrix in this decomposition. It is unitary, and it consists from left singular vectors. */ 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 889eb4f22..ee7f1d8be 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 @@ -34,7 +34,7 @@ public inline fun Iterable.cumulative(initial: R, crossinline operatio public inline fun Sequence.cumulative(initial: R, crossinline operation: (R, T) -> R): Sequence = Sequence { this@cumulative.iterator().cumulative(initial, operation) } -public fun List.cumulative(initial: R, operation: (R, T) -> R): List = +public inline fun List.cumulative(initial: R, crossinline operation: (R, T) -> R): List = iterator().cumulative(initial, operation).asSequence().toList() //Cumulative sum diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt index 35bbc44f6..38985f216 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt @@ -24,7 +24,6 @@ public class ShapeMismatchException(public val expected: IntArray, public val ac * * @param T the type of ND-structure element. * @param C the type of the element context. - * @param N the type of the structure. */ public interface AlgebraND> { /** @@ -118,8 +117,7 @@ internal fun > AlgebraND.checkShape(element: StructureND * Space of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param N the type of ND structure. - * @param S the type of space of structure elements. + * @param S the type of group over structure elements. */ public interface GroupND> : Group>, AlgebraND { /** @@ -186,8 +184,7 @@ public interface GroupND> : Group>, AlgebraND * Ring of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param N the type of ND structure. - * @param R the type of ring of structure elements. + * @param R the type of ring over structure elements. */ public interface RingND> : Ring>, GroupND { /** @@ -227,7 +224,7 @@ public interface RingND> : Ring>, GroupND> : Field>, RingND, ScaleOperations> { /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt index 2b82a36ae..6eacf1ca5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt @@ -57,7 +57,7 @@ public interface BufferAlgebraND> : AlgebraND { } } -public open class BufferedGroupND>( +public open class BufferedGroupND>( final override val shape: IntArray, final override val elementContext: A, final override val bufferFactory: BufferFactory, @@ -67,7 +67,7 @@ public open class BufferedGroupND>( override fun StructureND.unaryMinus(): StructureND = produce { -get(it) } } -public open class BufferedRingND>( +public open class BufferedRingND>( shape: IntArray, elementContext: R, bufferFactory: BufferFactory, @@ -75,7 +75,7 @@ public open class BufferedRingND>( override val one: BufferND by lazy { produce { one } } } -public open class BufferedFieldND>( +public open class BufferedFieldND>( shape: IntArray, elementContext: R, bufferFactory: BufferFactory, diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt index 720a06ace..1305558e5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt @@ -31,11 +31,10 @@ public class ShortRingND( /** * Fast element production using function inlining. */ -public inline fun BufferedRingND.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND { - return BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) -} +public inline fun BufferedRingND.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND = + BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) public inline fun ShortRing.nd(vararg shape: Int, action: ShortRingND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return ShortRingND(shape).run(action) -} \ No newline at end of file +} 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 7fc91e321..1ad8289bc 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 @@ -53,7 +53,7 @@ public interface StructureND { public fun elements(): Sequence> /** - * Feature is some additional strucure information which allows to access it special properties or hints. + * Feature is some additional structure information which allows to access it special properties or hints. * If the feature is not present, null is returned. */ @UnstableKMathAPI diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt index cc058d3fc..403a9c9b1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt @@ -15,7 +15,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI */ @UnstableKMathAPI @Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public interface AlgebraElement> { +public interface AlgebraElement> { /** * The context this element belongs to. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt index ac53c4d5e..c332b086e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt @@ -445,7 +445,7 @@ public fun UIntArray.toBigInt(sign: Byte): BigInt { * Returns null if a valid number can not be read from a string */ public fun String.parseBigInteger(): BigInt? { - if (this.isEmpty()) return null + if (isEmpty()) return null val sign: Int val positivePartIndex = when (this[0]) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt index 352c75956..03b3822c3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt @@ -14,30 +14,30 @@ import space.kscience.kmath.nd.as2D * A context that allows to operate on a [MutableBuffer] as on 2d array */ internal class BufferAccessor2D( - public val rowNum: Int, - public val colNum: Int, + val rowNum: Int, + val colNum: Int, val factory: MutableBufferFactory, ) { - public operator fun Buffer.get(i: Int, j: Int): T = get(i * colNum + j) + operator fun Buffer.get(i: Int, j: Int): T = get(i * colNum + j) - public operator fun MutableBuffer.set(i: Int, j: Int, value: T) { + operator fun MutableBuffer.set(i: Int, j: Int, value: T) { set(i * colNum + j, value) } - public inline fun create(crossinline init: (i: Int, j: Int) -> T): MutableBuffer = + inline fun create(crossinline init: (i: Int, j: Int) -> T): MutableBuffer = factory(rowNum * colNum) { offset -> init(offset / colNum, offset % colNum) } - public fun create(mat: Structure2D): MutableBuffer = create { i, j -> mat[i, j] } + fun create(mat: Structure2D): MutableBuffer = create { i, j -> mat[i, j] } //TODO optimize wrapper - public fun MutableBuffer.collect(): Structure2D = StructureND.buffered( + fun MutableBuffer.collect(): Structure2D = StructureND.buffered( DefaultStrides(intArrayOf(rowNum, colNum)), factory ) { (i, j) -> get(i, j) }.as2D() - public inner class Row(public val buffer: MutableBuffer, public val rowIndex: Int) : MutableBuffer { + inner class Row(val buffer: MutableBuffer, val rowIndex: Int) : MutableBuffer { override val size: Int get() = colNum override operator fun get(index: Int): T = buffer[rowIndex, index] @@ -54,5 +54,5 @@ internal class BufferAccessor2D( /** * Get row */ - public fun MutableBuffer.row(i: Int): Row = Row(this, i) + fun MutableBuffer.row(i: Int): Row = Row(this, i) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt index 1b89e7838..3dad14ac5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt @@ -67,9 +67,9 @@ public inline fun Buffer.map(block: (T) -> R): Buf * Create a new buffer from this one with the given mapping function. * Provided [bufferFactory] is used to construct the new buffer. */ -public fun Buffer.map( +public inline fun Buffer.map( bufferFactory: BufferFactory, - block: (T) -> R, + crossinline block: (T) -> R, ): Buffer = bufferFactory(size) { block(get(it)) } /** diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt deleted file mode 100644 index f2c7f1f90..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt +++ /dev/null @@ -1,5 +0,0 @@ -/* - * 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. - */ - diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt index bd09ff449..20a7b6a72 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt @@ -10,7 +10,7 @@ import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals import kotlin.test.assertNotEquals -internal class FieldVerifier>( +internal class FieldVerifier>( algebra: A, a: T, b: T, c: T, x: Number, ) : RingVerifier(algebra, a, b, c, x) { diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt index 885857f04..daf18834a 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt @@ -10,7 +10,7 @@ import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals -internal open class RingVerifier(algebra: A, a: T, b: T, c: T, x: Number) : +internal open class RingVerifier(algebra: A, a: T, b: T, c: T, x: Number) : SpaceVerifier(algebra, a, b, c, x) where A : Ring, A : ScaleOperations { override fun verify() { 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 526250cf0..88456e124 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 @@ -29,4 +29,4 @@ public fun BlockingDoubleChain.map(transform: (Double) -> Double): BlockingDoubl } override suspend fun fork(): BlockingDoubleChain = this@map.fork().map(transform) -} \ No newline at end of file +} diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt index 49f32f82f..1f17efe49 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt @@ -15,30 +15,33 @@ public val Dispatchers.Math: CoroutineDispatcher /** * An imitator of [Deferred] which holds a suspended function block and dispatcher */ -internal class LazyDeferred(val dispatcher: CoroutineDispatcher, val block: suspend CoroutineScope.() -> T) { +@PublishedApi +internal class LazyDeferred(val dispatcher: CoroutineDispatcher, val block: suspend CoroutineScope.() -> T) { private var deferred: Deferred? = null - internal fun start(scope: CoroutineScope) { + fun start(scope: CoroutineScope) { if (deferred == null) deferred = scope.async(dispatcher, block = block) } suspend fun await(): T = deferred?.await() ?: error("Coroutine not started") } -public class AsyncFlow internal constructor(internal val deferredFlow: Flow>) : Flow { +public class AsyncFlow @PublishedApi internal constructor( + @PublishedApi internal val deferredFlow: Flow>, +) : Flow { override suspend fun collect(collector: FlowCollector): Unit = deferredFlow.collect { collector.emit((it.await())) } } -public fun Flow.async( +public inline fun Flow.async( dispatcher: CoroutineDispatcher = Dispatchers.Default, - block: suspend CoroutineScope.(T) -> R, + crossinline block: suspend CoroutineScope.(T) -> R, ): AsyncFlow { val flow = map { LazyDeferred(dispatcher) { block(it) } } return AsyncFlow(flow) } -public fun AsyncFlow.map(action: (T) -> R): AsyncFlow = +public inline fun AsyncFlow.map(crossinline action: (T) -> R): AsyncFlow = AsyncFlow(deferredFlow.map { input -> //TODO add function composition LazyDeferred(input.dispatcher) { diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt index 2ebcc454d..a2ee14301 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt @@ -17,7 +17,7 @@ import kotlin.jvm.JvmInline /** * A matrix with compile-time controlled dimension */ -public interface DMatrix : Structure2D { +public interface DMatrix : Structure2D { public companion object { /** * Coerces a regular matrix to a matrix with type-safe dimensions and throws a error if coercion failed @@ -46,7 +46,7 @@ public interface DMatrix : Structure2D { * An inline wrapper for a Matrix */ @JvmInline -public value class DMatrixWrapper( +public value class DMatrixWrapper( private val structure: Structure2D, ) : DMatrix { override val shape: IntArray get() = structure.shape @@ -58,7 +58,7 @@ public value class DMatrixWrapper( /** * Dimension-safe point */ -public interface DPoint : Point { +public interface DPoint : Point { public companion object { public inline fun coerce(point: Point): DPoint { require(point.size == Dimension.dim().toInt()) { @@ -76,7 +76,7 @@ public interface DPoint : Point { * Dimension-safe point wrapper */ @JvmInline -public value class DPointWrapper(public val point: Point) : +public value class DPointWrapper(public val point: Point) : DPoint { override val size: Int get() = point.size @@ -111,7 +111,7 @@ public value class DMatrixContext>(public val context: ): DMatrix { val rows = Dimension.dim() val cols = Dimension.dim() - return context.buildMatrix(rows.toInt(), cols.toInt(), initializer).coerce() + return context.buildMatrix(rows.toInt(), cols.toInt(), initializer).coerce() } public inline fun point(noinline initializer: A.(Int) -> T): DPoint { diff --git a/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt similarity index 100% rename from kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt rename to kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt 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 8023236ea..091b5db3f 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 @@ -184,4 +184,4 @@ public fun tan(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.tan(it) } public fun ln(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.ln(it) } -public fun log10(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.log10(it) } \ No newline at end of file +public fun log10(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.log10(it) } diff --git a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt index b3e129c2e..a9c5f9e1a 100644 --- a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt @@ -32,7 +32,7 @@ internal class DoubleMatrixTest { @Test fun testSequenceToMatrix() { - val m = Sequence { + val m = Sequence { listOf( DoubleArray(10) { 10.0 }, DoubleArray(10) { 20.0 }, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 73fa57c7b..5f35d0ab6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -14,7 +14,7 @@ import space.kscience.kmath.operations.Ring * @param T the piece key type. * @param R the sub-function type. */ -public fun interface Piecewise { +public fun interface Piecewise { /** * Returns the appropriate sub-function for given piece key. */ @@ -23,7 +23,9 @@ public fun interface Piecewise { /** * Represents piecewise-defined function where all the sub-functions are polynomials. - * @param pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no "holes" in it. + * + * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no + * "holes" in it. */ public interface PiecewisePolynomial> : Piecewise> { public val pieces: Collection, Polynomial>> @@ -45,7 +47,7 @@ public fun > PiecewisePolynomial( /** * An optimized piecewise which uses not separate pieces, but a range separated by delimiters. - * The pices search is logarithmic + * The pieces search is logarithmic */ private class OrderedPiecewisePolynomial>( override val pieces: List, Polynomial>>, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index ba77d7b25..f0c858b03 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -17,7 +17,7 @@ import kotlin.math.pow * * @param coefficients constant is the leftmost coefficient. */ -public class Polynomial(public val coefficients: List) { +public class Polynomial(public val coefficients: List) { override fun toString(): String = "Polynomial$coefficients" } @@ -69,7 +69,7 @@ public fun Polynomial.differentiate( public fun Polynomial.integrate( algebra: A, ): Polynomial where A : Field, A : NumericAlgebra = algebra { - val integratedCoefficients = buildList(coefficients.size + 1) { + val integratedCoefficients = buildList(coefficients.size + 1) { add(zero) coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } } 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 f9c26e88b..4f565a893 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 @@ -18,7 +18,7 @@ public interface Integrand { public inline fun Integrand.getFeature(): T? = getFeature(T::class) -public class IntegrandValue(public val value: T) : IntegrandFeature { +public class IntegrandValue(public val value: T) : IntegrandFeature { override fun toString(): String = "Value($value)" } 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 e265f54e8..7f68284a7 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 @@ -93,7 +93,7 @@ public fun UnivariateIntegrator.integrate( ): UnivariateIntegrand = integrate(UnivariateIntegrand(function, IntegrationRange(range), *features)) /** - * A shortcut method to integrate a [function] in [range] with additional [features]. + * A shortcut method to integrate a [function] in [range] with additional features. * The [function] is placed in the end position to allow passing a lambda. */ @UnstableKMathAPI diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index c9ec0d527..f4a0abd5d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -18,7 +18,7 @@ import space.kscience.kmath.structures.asBuffer /** * And interpolator for data with x column type [X], y column type [Y]. */ -public fun interface Interpolator { +public fun interface Interpolator { public fun interpolate(points: XYColumnarData): (X) -> Y } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt index 5a6d23709..8c6ccb55e 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.geometry -public data class Line(val base: V, val direction: V) +public data class Line(val base: V, val direction: V) public typealias Line2D = Line public typealias Line3D = Line diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt index fcb5e96dc..31da4f392 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt @@ -13,14 +13,14 @@ import space.kscience.kmath.structures.asBuffer /** * The binned data element. Could be a histogram bin with a number of counts or an artificial construct */ -public interface Bin : Domain { +public interface Bin : Domain { /** * The value of this bin. */ public val value: Number } -public interface Histogram> { +public interface Histogram> { /** * Find existing bin, corresponding to given coordinates */ @@ -34,7 +34,7 @@ public interface Histogram> { public val bins: Iterable } -public fun interface HistogramBuilder { +public fun interface HistogramBuilder { /** * Increment appropriate bin diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt index e5f6830c5..6d48d3738 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt @@ -18,7 +18,7 @@ import space.kscience.kmath.operations.invoke /** * A simple histogram bin based on domain */ -public data class DomainBin>( +public data class DomainBin>( public val domain: Domain, public override val value: Number, ) : Bin, Domain by domain diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt index 8d05df68a..daea4a82e 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt @@ -36,9 +36,10 @@ public class TreeHistogram( } @OptIn(UnstableKMathAPI::class) -private class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain) : UnivariateHistogramBuilder { +@PublishedApi +internal class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain) : UnivariateHistogramBuilder { - private class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : + internal class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : ClosedFloatingPointRange by domain.range private val bins: TreeMap = TreeMap() @@ -80,10 +81,10 @@ private class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain) */ @UnstableKMathAPI public class TreeHistogramSpace( - private val binFactory: (Double) -> UnivariateDomain, + @PublishedApi internal val binFactory: (Double) -> UnivariateDomain, ) : Group, ScaleOperations { - public fun fill(block: UnivariateHistogramBuilder.() -> Unit): UnivariateHistogram = + public inline fun fill(block: UnivariateHistogramBuilder.() -> Unit): UnivariateHistogram = TreeHistogramBuilder(binFactory).apply(block).build() override fun add( @@ -115,8 +116,8 @@ public class TreeHistogramSpace( bin.domain.center, UnivariateBin( bin.domain, - value = bin.value * value.toDouble(), - standardDeviation = abs(bin.standardDeviation * value.toDouble()) + value = bin.value * value, + standardDeviation = abs(bin.standardDeviation * value) ) ) } diff --git a/kmath-kotlingrad/build.gradle.kts b/kmath-kotlingrad/build.gradle.kts index 01b42d7ba..d222ed7d6 100644 --- a/kmath-kotlingrad/build.gradle.kts +++ b/kmath-kotlingrad/build.gradle.kts @@ -18,14 +18,14 @@ readme { feature( "differentiable-mst-expression", - "src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt", + "src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt", ) { "MST based DifferentiableExpression." } feature( - "differentiable-mst-expression", - "src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt", + "scalars-adapters", + "src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt", ) { "Conversions between Kotlin∇'s SFun and MST" } 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 140a212f8..d4cad8996 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 @@ -25,7 +25,7 @@ private class Nd4jArrayIndicesIterator(private val iterateOver: INDArray) : Iter internal fun INDArray.indicesIterator(): Iterator = Nd4jArrayIndicesIterator(this) -private sealed class Nd4jArrayIteratorBase(protected val iterateOver: INDArray) : Iterator> { +private sealed class Nd4jArrayIteratorBase(protected val iterateOver: INDArray) : Iterator> { private var i: Int = 0 final override fun hasNext(): Boolean = i < iterateOver.length() diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt index 4a1676412..15ae494f6 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.expressions.Symbol public interface OptimizationFeature -public class OptimizationResult( +public class OptimizationResult( public val point: Map, public val value: T, public val features: Set = emptySet(), diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.kt deleted file mode 100644 index 0d38fe19b..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.BlockingBufferChain -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.stat.Sampler -import space.kscience.kmath.structures.Buffer - -public class ConstantSampler(public val const: T) : Sampler { - override fun sample(generator: RandomGenerator): BlockingBufferChain = object : BlockingBufferChain { - override fun nextBufferBlocking(size: Int): Buffer = Buffer.boxing(size) { const } - override suspend fun fork(): BlockingBufferChain = this - } -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt index 9e5c70a26..0e06fa162 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt @@ -6,6 +6,8 @@ package space.kscience.kmath.stat import kotlinx.coroutines.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.coroutineContext @@ -23,14 +25,18 @@ public class MCScope( /** * Launches a supervised Monte-Carlo scope */ -public suspend inline fun mcScope(generator: RandomGenerator, block: MCScope.() -> T): T = - MCScope(coroutineContext, generator).block() +public suspend inline fun mcScope(generator: RandomGenerator, block: MCScope.() -> T): T { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return MCScope(coroutineContext, generator).block() +} /** * Launch mc scope with a given seed */ -public suspend inline fun mcScope(seed: Long, block: MCScope.() -> T): T = - mcScope(RandomGenerator.default(seed), block) +public suspend inline fun mcScope(seed: Long, block: MCScope.() -> T): T { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return mcScope(RandomGenerator.default(seed), block) +} /** * Specialized launch for [MCScope]. Behaves the same way as regular [CoroutineScope.launch], but also stores the generator fork. diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index 51ae78d3d..4c11fdd65 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -12,7 +12,7 @@ import space.kscience.kmath.structures.* import kotlin.jvm.JvmName /** - * Sampler that generates chains of values of type [T] in a chain of type [C]. + * Sampler that generates chains of values of type [T]. */ public fun interface Sampler { /** diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt index b3d607ab0..27465eff4 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt @@ -18,7 +18,7 @@ import space.kscience.kmath.operations.invoke * * @property value the value to sample. */ -public class ConstantSampler(public val value: T) : Sampler { +public class ConstantSampler(public val value: T) : Sampler { public override fun sample(generator: RandomGenerator): Chain = ConstantChain(value) } @@ -27,7 +27,7 @@ public class ConstantSampler(public val value: T) : Sampler { * * @property chainBuilder the provider of [Chain]. */ -public class BasicSampler(public val chainBuilder: (RandomGenerator) -> Chain) : Sampler { +public class BasicSampler(public val chainBuilder: (RandomGenerator) -> Chain) : Sampler { public override fun sample(generator: RandomGenerator): Chain = chainBuilder(generator) } @@ -36,7 +36,7 @@ public class BasicSampler(public val chainBuilder: (RandomGenerator) -> * * @property algebra the space to provide addition and scalar multiplication for [T]. */ -public class SamplerSpace(public val algebra: S) : Group>, +public class SamplerSpace(public val algebra: S) : Group>, ScaleOperations> where S : Group, S : ScaleOperations { public override val zero: Sampler = ConstantSampler(algebra.zero) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt index 1b05aa9cd..f29b7415c 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt @@ -18,14 +18,14 @@ import space.kscience.kmath.structures.Buffer /** * A function, that transforms a buffer of random quantities to some resulting value */ -public interface Statistic { +public interface Statistic { public suspend fun evaluate(data: Buffer): R } -public interface BlockingStatistic: Statistic{ +public interface BlockingStatistic : Statistic { public fun evaluateBlocking(data: Buffer): R - override suspend fun evaluate(data: Buffer): R = evaluateBlocking(data) + override suspend fun evaluate(data: Buffer): R = evaluateBlocking(data) } /** @@ -34,7 +34,7 @@ public interface BlockingStatistic: Statistic{ * @param I - intermediate block type * @param R - result type */ -public interface ComposableStatistic : Statistic { +public interface ComposableStatistic : Statistic { //compute statistic on a single block public suspend fun computeIntermediate(data: Buffer): I diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt index a6773c709..88f0c941e 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt @@ -14,7 +14,8 @@ import space.kscience.kmath.expressions.interpret import space.kscience.kmath.operations.NumericAlgebra /** - * Represents [MST] based [DifferentiableExpression] relying on [Symja](https://github.com/axkr/symja_android_library). + * Represents [MST] based [space.kscience.kmath.expressions.DifferentiableExpression] relying on + * [Symja](https://github.com/axkr/symja_android_library). * * The principle of this API is converting the [mst] to an [org.matheclipse.core.interfaces.IExpr], differentiating it * with Symja's [F.D], then converting [org.matheclipse.core.interfaces.IExpr] back to [MST]. diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 6b991d5df..b19a55381 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -3,7 +3,7 @@ Common linear algebra operations on tensors. - [tensor algebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) - - [tensor algebra with broadcasting](src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. + - [tensor algebra with broadcasting](src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. - [linear algebra operations](src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index b7f24dc6a..2eff2d821 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -24,20 +24,16 @@ readme { feature( id = "tensor algebra", - description = "Basic linear algebra operations on tensors (plus, dot, etc.)", ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt" - ) + ) { "Basic linear algebra operations on tensors (plus, dot, etc.)" } feature( id = "tensor algebra with broadcasting", - description = "Basic linear algebra operations implemented with broadcasting.", - ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt" + ) { "Basic linear algebra operations implemented with broadcasting." } feature( id = "linear algebra operations", - description = "Advanced linear algebra operations like LU decomposition, SVD, etc.", ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt" - ) - -} \ No newline at end of file + ) { "Advanced linear algebra operations like LU decomposition, SVD, etc." } +} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 315dc4505..87ac2fdf6 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -11,8 +11,8 @@ import space.kscience.kmath.tensors.core.internal.TensorLinearStructure */ public open class BufferedTensor internal constructor( override val shape: IntArray, - internal val mutableBuffer: MutableBuffer, - internal val bufferStart: Int + @PublishedApi internal val mutableBuffer: MutableBuffer, + @PublishedApi internal val bufferStart: Int, ) : Tensor { /** 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 41df50cba..8e5116336 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 @@ -11,7 +11,7 @@ import space.kscience.kmath.tensors.core.internal.toPrettyString /** * Default [BufferedTensor] implementation for [Double] values */ -public class DoubleTensor internal constructor( +public class DoubleTensor @PublishedApi internal constructor( shape: IntArray, buffer: DoubleArray, offset: Int = 0 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 1fd46bd57..d182558c5 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 @@ -426,13 +426,11 @@ public open class DoubleTensorAlgebra : * @param transform the function to be applied to each element of the tensor. * @return the resulting tensor after applying the function. */ - public fun Tensor.map(transform: (Double) -> Double): DoubleTensor { - return DoubleTensor( - tensor.shape, - tensor.mutableBuffer.array().map { transform(it) }.toDoubleArray(), - tensor.bufferStart - ) - } + public inline fun Tensor.map(transform: (Double) -> Double): DoubleTensor = DoubleTensor( + tensor.shape, + tensor.mutableBuffer.array().map { transform(it) }.toDoubleArray(), + tensor.bufferStart + ) /** * Compares element-wise two tensors with a specified precision. @@ -519,14 +517,12 @@ public open class DoubleTensorAlgebra : * @param indices the [IntArray] of 1-dimensional indices * @return tensor with rows corresponding to rows by [indices] */ - public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor { - return stack(indices.map { this[it] }) - } + public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) - internal fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = + internal inline fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = foldFunction(tensor.toDoubleArray()) - internal fun Tensor.foldDim( + internal inline fun Tensor.foldDim( foldFunction: (DoubleArray) -> Double, dim: Int, keepDim: Boolean, 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 7d3617547..4c9c00552 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 @@ -10,15 +10,15 @@ import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.BufferedTensor +import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.valueOrNull +import space.kscience.kmath.tensors.core.IntTensor import kotlin.math.abs import kotlin.math.min import kotlin.math.sign import kotlin.math.sqrt - internal fun BufferedTensor.vectorSequence(): Sequence> = sequence { val n = shape.size val vectorOffset = shape[n - 1] diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index d965b6bcd..77264ff92 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -31,6 +31,7 @@ internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { else -> this.copyToBufferedTensor() } +@PublishedApi internal val Tensor.tensor: DoubleTensor get() = when (this) { is DoubleTensor -> this diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt index 0ffaf39e7..e337eeef9 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt @@ -24,6 +24,7 @@ internal fun Buffer.array(): IntArray = when (this) { /** * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer] or copy the data. */ +@PublishedApi internal fun Buffer.array(): DoubleArray = when (this) { is DoubleBuffer -> array else -> this.toDoubleArray() diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 347bb683f..c525d5c83 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -183,7 +183,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } -private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10): Unit { +private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10) { val svd = tensor.svd() val tensorSVD = svd.first diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index e7e898008..85c3e74e3 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -17,7 +17,7 @@ internal class TestDoubleTensorAlgebra { } @Test - fun TestDoubleDiv() = DoubleTensorAlgebra { + fun testDoubleDiv() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0)) val res = 2.0/tensor assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 0.5)) 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 b7abf4304..915637e2c 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 @@ -92,7 +92,7 @@ public class ViktorFieldND(public override val shape: IntArray) : FieldND, value: Double): ViktorStructureND = - (a.f64Buffer * value.toDouble()).asStructure() + (a.f64Buffer * value).asStructure() public override inline fun StructureND.plus(b: StructureND): ViktorStructureND = (f64Buffer + b.f64Buffer).asStructure() From ef41c3f1680ce67788c128ea3105c0c77e90c0c1 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 17 Jul 2021 01:12:14 +0700 Subject: [PATCH 25/39] Build infrastructure changes --- .github/workflows/build.yml | 7 +++-- .github/workflows/pages.yml | 25 ++++++++++-------- .github/workflows/publish.yml | 21 +++++---------- build.gradle.kts | 42 ++++++++++++++++++++---------- buildSrc/build.gradle.kts | 2 +- gradle.properties | 1 - kmath-core/README.md | 2 +- kmath-core/build.gradle.kts | 43 ++++++++++++------------------- kmath-coroutines/build.gradle.kts | 1 + kmath-ejml/build.gradle.kts | 8 +++--- kmath-for-real/build.gradle.kts | 1 + kmath-functions/build.gradle.kts | 1 + kmath-geometry/build.gradle.kts | 1 + kmath-histograms/build.gradle.kts | 1 + kmath-stat/build.gradle.kts | 1 + kmath-tensors/build.gradle.kts | 9 +++---- settings.gradle.kts | 6 ++--- 17 files changed, 87 insertions(+), 85 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 98f4d2ec2..2b611a46a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,8 +2,10 @@ name: Gradle build on: push: + branches: + - dev + - master pull_request: - types: [opened, edited] jobs: build: @@ -21,9 +23,6 @@ jobs: graalvm: 21.1.0 java: java11 arch: amd64 - - name: Add msys to path - if: matrix.os == 'windows-latest' - run: SETX PATH "%PATH%;C:\msys64\mingw64\bin" - name: Cache gradle uses: actions/cache@v2 with: diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 86fdac6a6..1836287c8 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -2,23 +2,26 @@ name: Dokka publication on: push: - branches: - - master + branches: [ master ] jobs: build: runs-on: ubuntu-20.04 steps: - - name: Checkout the repo - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v1 + - uses: actions/checkout@v2 + - uses: DeLaGuardo/setup-graalvm@4.0 with: - java-version: 11 - - name: Build - run: ./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace - - name: Deploy to GitHub Pages - uses: JamesIves/github-pages-deploy-action@4.1.0 + graalvm: 21.1.0 + java: java11 + arch: amd64 + - uses: actions/cache@v2 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} + restore-keys: | + ${{ runner.os }}-gradle- + - run: ./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace + - uses: JamesIves/github-pages-deploy-action@4.1.0 with: branch: gh-pages folder: build/dokka/htmlMultiModule diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c5c110e89..d1698d79b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,8 +3,7 @@ name: Gradle publish on: workflow_dispatch: release: - types: - - created + types: [ created ] jobs: publish: @@ -23,13 +22,12 @@ jobs: graalvm: 21.1.0 java: java11 arch: amd64 - - name: Add msys to path - if: matrix.os == 'windows-latest' - run: SETX PATH "%PATH%;C:\msys64\mingw64\bin" - name: Cache gradle uses: actions/cache@v2 with: - path: ~/.gradle/caches + path: | + ~/.gradle/caches + ~/.gradle/wrapper key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- @@ -43,19 +41,12 @@ jobs: - name: Publish Windows Artifacts if: matrix.os == 'windows-latest' run: > - ./gradlew release --no-daemon - -Ppublishing.enabled=true - -Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }} - -Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }} + ./gradlew release --no-daemon -Ppublishing.enabled=true -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }} -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }} - name: Publish Mac Artifacts if: matrix.os == 'macOS-latest' run: > - ./gradlew release --no-daemon - -Ppublishing.enabled=true - -Ppublishing.platform=macosX64 - -Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }} - -Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }} + ./gradlew release --no-daemon -Ppublishing.enabled=true -Ppublishing.platform=macosX64 -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }} -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }} diff --git a/build.gradle.kts b/build.gradle.kts index d0f6ced78..6bb19cd35 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import java.net.URL + plugins { id("ru.mipt.npm.gradle.project") kotlin("jupyter.api") apply false @@ -7,9 +9,11 @@ allprojects { repositories { maven("https://clojars.org/repo") maven("https://jitpack.io") + maven("http://logicrunch.research.it.uu.se/maven") { isAllowInsecureProtocol = true } + maven("https://oss.sonatype.org/content/repositories/snapshots") mavenCentral() } @@ -23,16 +27,30 @@ subprojects { afterEvaluate { tasks.withType { - dependsOn(tasks.getByName("assemble")) + dependsOn(tasks["assemble"]) dokkaSourceSets.all { - val readmeFile = File(this@subprojects.projectDir, "README.md") - if (readmeFile.exists()) includes.from(readmeFile.absolutePath) - externalDocumentationLink("https://ejml.org/javadoc/") + val readmeFile = this@subprojects.projectDir.resolve("README.md") + if (readmeFile.exists()) includes.from(readmeFile) + val kotlinDirPath = "src/$name/kotlin" + val kotlinDir = file(kotlinDirPath) + + if (kotlinDir.exists()) sourceLink { + localDirectory.set(kotlinDir) + + remoteUrl.set( + URL("https://github.com/mipt-npm/${rootProject.name}/tree/master/${this@subprojects.name}/$kotlinDirPath") + ) + } + externalDocumentationLink("https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/") externalDocumentationLink("https://deeplearning4j.org/api/latest/") externalDocumentationLink("https://axelclk.bitbucket.io/symja/javadoc/") - externalDocumentationLink("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/") + + externalDocumentationLink( + "https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/", + "https://kotlin.github.io/kotlinx.coroutines/package-list", + ) externalDocumentationLink( "https://breandan.net/kotlingrad/kotlingrad/", @@ -43,16 +61,12 @@ subprojects { } } -readme { - readmeTemplate = file("docs/templates/README-TEMPLATE.md") -} +readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") ksciencePublish { - github("kmath") - space() - sonatype() + vcs("https://github.com/mipt-npm/kmath") + space(publish = true) + sonatype(publish = true) } -apiValidation { - nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") -} +apiValidation.nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index fe69b05c6..3427a6d61 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -11,7 +11,7 @@ repositories { dependencies { api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") - api("ru.mipt.npm:gradle-tools:0.10.0") + api("ru.mipt.npm:gradle-tools:0.10.1") api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.3.1") } diff --git a/gradle.properties b/gradle.properties index 3aaade368..b97db1c54 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,6 @@ kotlin.code.style=official kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.mpp.stability.nowarn=true kotlin.native.enableDependencyPropagation=false -kotlin.parallel.tasks.in.project=true org.gradle.configureondemand=true org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G org.gradle.parallel=true diff --git a/kmath-core/README.md b/kmath-core/README.md index a563552bb..4ea493f44 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -10,7 +10,7 @@ The core interfaces of KMath. objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high performance calculations to code generation. - [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains - - [autodif](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation + - [autodiff](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation ## Artifact: diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 92a5f419d..564d06f49 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -19,51 +19,42 @@ readme { feature( id = "algebras", - description = """ - Algebraic structures like rings, spaces and fields. - """.trimIndent(), - ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt", + ) { "Algebraic structures like rings, spaces and fields." } feature( id = "nd", - description = "Many-dimensional structures and operations on them.", - ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt", + ) { "Many-dimensional structures and operations on them." } feature( id = "linear", - description = """ - Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition. - """.trimIndent(), - ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt", + ) { "Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition." } feature( id = "buffers", - description = "One-dimensional structure", - ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt", + ) { "One-dimensional structure" } feature( id = "expressions", - description = """ + ref = "src/commonMain/kotlin/space/kscience/kmath/expressions" + ) { + """ By writing a single mathematical expression once, users will be able to apply different types of objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high performance calculations to code generation. - """.trimIndent(), - ref = "src/commonMain/kotlin/space/kscience/kmath/expressions" - ) + """.trimIndent() + } feature( id = "domains", - description = "Domains", - ref = "src/commonMain/kotlin/space/kscience/kmath/domains" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/domains", + ) { "Domains" } feature( - id = "autodif", - description = "Automatic differentiation", + id = "autodiff", ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt" - ) + ) { "Automatic differentiation" } } diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts index 1546e7d96..317691ae5 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kotlin.sourceSets { diff --git a/kmath-ejml/build.gradle.kts b/kmath-ejml/build.gradle.kts index 5107cfb68..727d21e3a 100644 --- a/kmath-ejml/build.gradle.kts +++ b/kmath-ejml/build.gradle.kts @@ -6,10 +6,10 @@ plugins { } dependencies { - api("org.ejml:ejml-ddense:0.40") - api("org.ejml:ejml-fdense:0.40") - api("org.ejml:ejml-dsparse:0.40") - api("org.ejml:ejml-fsparse:0.40") + api("org.ejml:ejml-ddense:0.41") + api("org.ejml:ejml-fdense:0.41") + api("org.ejml:ejml-dsparse:0.41") + api("org.ejml:ejml-fsparse:0.41") api(project(":kmath-core")) } diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts index f6d12decd..25fdefaba 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kotlin.sourceSets.commonMain { diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index f77df3833..fadbac091 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } description = "Functions, integration and interpolation" diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index 9b6e593b2..7eb814683 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kotlin.sourceSets.commonMain { diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 2167726c0..7e511faa0 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kscience { diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index e8f629f7a..e3e396b6f 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kscience { diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index 2eff2d821..d084878ea 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -1,11 +1,14 @@ plugins { - id("ru.mipt.npm.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kotlin.sourceSets { all { languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } + commonMain { dependencies { api(project(":kmath-core")) @@ -14,10 +17,6 @@ kotlin.sourceSets { } } -tasks.dokkaHtml { - dependsOn(tasks.build) -} - readme { maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) diff --git a/settings.gradle.kts b/settings.gradle.kts index 02b75cddc..445f75c09 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,8 +5,8 @@ pluginManagement { gradlePluginPortal() } - val toolsVersion = "0.10.0" - val kotlinVersion = "1.5.20" + val toolsVersion = "0.10.1" + val kotlinVersion = "1.5.21" plugins { id("ru.mipt.npm.gradle.project") version toolsVersion @@ -16,7 +16,7 @@ pluginManagement { kotlin("jvm") version kotlinVersion kotlin("plugin.allopen") version kotlinVersion id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - kotlin("jupyter.api") version "0.10.0-25" + kotlin("jupyter.api") version "0.10.0-131-1" } } From b1998ed1a90152027ab809686229365a8de8bdd9 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Mon, 19 Jul 2021 03:12:41 +0700 Subject: [PATCH 26/39] Replace public override with override --- .../kmath/ejml/codegen/ejmlCodegen.kt | 44 ++-- .../ast/rendering/LatexSyntaxRenderer.kt | 2 +- .../ast/rendering/MathMLSyntaxRenderer.kt | 2 +- .../kmath/ast/rendering/MathRenderer.kt | 4 +- .../kmath/ast/rendering/MathSyntax.kt | 68 +++--- .../kscience/kmath/ast/rendering/features.kt | 32 +-- .../kscience/kmath/ast/rendering/phases.kt | 2 +- .../DerivativeStructureExpression.kt | 74 +++--- .../kscience/kmath/commons/linear/CMMatrix.kt | 22 +- .../commons/optimization/CMOptimization.kt | 6 +- .../random/CMRandomGeneratorWrapper.kt | 22 +- .../space/kscience/kmath/complex/Complex.kt | 42 ++-- .../kscience/kmath/complex/ComplexFieldND.kt | 36 +-- .../kscience/kmath/complex/Quaternion.kt | 50 ++-- .../kmath/domains/HyperSquareDomain.kt | 10 +- .../kmath/domains/UnconstrainedDomain.kt | 10 +- .../kmath/domains/UnivariateDomain.kt | 10 +- .../FunctionalExpressionAlgebra.kt | 64 ++--- .../kscience/kmath/expressions/MstAlgebra.kt | 138 +++++------ .../kmath/expressions/SimpleAutoDiff.kt | 60 ++--- .../kscience/kmath/linear/MatrixWrapper.kt | 4 +- .../space/kscience/kmath/nd/AlgebraND.kt | 8 +- .../space/kscience/kmath/nd/DoubleFieldND.kt | 48 ++-- .../space/kscience/kmath/nd/Structure1D.kt | 8 +- .../space/kscience/kmath/nd/Structure2D.kt | 2 +- .../kscience/kmath/operations/Algebra.kt | 10 +- .../space/kscience/kmath/operations/BigInt.kt | 6 +- .../kmath/operations/NumericAlgebra.kt | 2 +- .../kscience/kmath/operations/numbers.kt | 220 +++++++++--------- .../kmath/structures/DoubleBufferField.kt | 82 +++---- .../kscience/kmath/structures/MemoryBuffer.kt | 4 +- .../kscience/kmath/structures/ShortBuffer.kt | 10 +- .../kscience/kmath/operations/BigNumbers.kt | 36 +-- .../kscience/kmath/chains/BlockingChain.kt | 4 +- .../kmath/chains/BlockingDoubleChain.kt | 2 +- .../space/kscience/kmath/chains/Chain.kt | 16 +- .../kscience/kmath/streaming/RingBuffer.kt | 6 +- .../kmath/structures/LazyStructureND.kt | 6 +- .../space/kscience/kmath/ejml/EjmlMatrix.kt | 4 +- .../space/kscience/kmath/ejml/EjmlVector.kt | 6 +- .../space/kscience/kmath/ejml/_generated.kt | 160 ++++++------- .../kscience/kmath/functions/Piecewise.kt | 2 +- .../kscience/kmath/functions/Polynomial.kt | 6 +- .../kmath/interpolation/LinearInterpolator.kt | 4 +- .../kmath/interpolation/SplineInterpolator.kt | 4 +- .../kmath/geometry/Euclidean2DSpace.kt | 16 +- .../kmath/geometry/Euclidean3DSpace.kt | 16 +- .../kmath/histogram/IndexedHistogramSpace.kt | 2 +- .../kmath/histogram/UnivariateHistogram.kt | 6 +- .../kscience/kmath/jafama/KMathJafama.kt | 120 +++++----- .../kscience/kmath/kotlingrad/KMathNumber.kt | 6 +- .../kmath/kotlingrad/KotlingradExpression.kt | 4 +- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 112 ++++----- .../kscience/kmath/nd4j/Nd4jArrayStructure.kt | 4 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 120 +++++----- .../kmath/distributions/Distribution.kt | 2 +- .../kmath/distributions/NormalDistribution.kt | 6 +- .../AhrensDieterExponentialSampler.kt | 2 +- .../AhrensDieterMarsagliaTsangGammaSampler.kt | 4 +- .../samplers/AliasMethodDiscreteSampler.kt | 4 +- .../kmath/samplers/GaussianSampler.kt | 2 +- .../samplers/KempSmallMeanPoissonSampler.kt | 4 +- .../kscience/kmath/samplers/PoissonSampler.kt | 8 +- .../kotlin/space/kscience/kmath/stat/Mean.kt | 6 +- .../space/kscience/kmath/stat/Median.kt | 2 +- .../space/kscience/kmath/stat/RandomChain.kt | 2 +- .../kscience/kmath/stat/RandomGenerator.kt | 18 +- .../kscience/kmath/stat/SamplerAlgebra.kt | 12 +- .../space/kscience/kmath/stat/Statistic.kt | 2 +- .../kmath/stat/RandomSourceGenerator.kt | 34 +-- .../kscience/kmath/symja/SymjaExpression.kt | 4 +- .../kscience/kmath/viktor/ViktorBuffer.kt | 10 +- .../kmath/viktor/ViktorStructureND.kt | 58 ++--- 73 files changed, 972 insertions(+), 972 deletions(-) diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt index 5da7d0f67..a0d40c1ee 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt @@ -14,12 +14,12 @@ private fun Appendable.appendEjmlVector(type: String, ejmlMatrixType: String) { @Language("kotlin") val text = """/** * [EjmlVector] specialization for [$type]. */ -public class Ejml${type}Vector(public override val origin: M) : EjmlVector<$type, M>(origin) { +public class Ejml${type}Vector(override val origin: M) : EjmlVector<$type, M>(origin) { init { require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } } - public override operator fun get(index: Int): $type = origin[0, index] + override operator fun get(index: Int): $type = origin[0, index] }""" appendLine(text) appendLine() @@ -29,8 +29,8 @@ private fun Appendable.appendEjmlMatrix(type: String, ejmlMatrixType: String) { val text = """/** * [EjmlMatrix] specialization for [$type]. */ -public class Ejml${type}Matrix(public override val origin: M) : EjmlMatrix<$type, M>(origin) { - public override operator fun get(i: Int, j: Int): $type = origin[i, j] +public class Ejml${type}Matrix(override val origin: M) : EjmlMatrix<$type, M>(origin) { + override operator fun get(i: Int, j: Int): $type = origin[i, j] }""" appendLine(text) appendLine() @@ -54,23 +54,23 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, /** * The [${kmathAlgebra}] reference. */ - public override val elementAlgebra: $kmathAlgebra get() = $kmathAlgebra + override val elementAlgebra: $kmathAlgebra get() = $kmathAlgebra @Suppress("UNCHECKED_CAST") - public override fun Matrix<${type}>.toEjml(): Ejml${type}Matrix<${ejmlMatrixType}> = when { + override fun Matrix<${type}>.toEjml(): Ejml${type}Matrix<${ejmlMatrixType}> = when { this is Ejml${type}Matrix<*> && origin is $ejmlMatrixType -> this as Ejml${type}Matrix<${ejmlMatrixType}> else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } } @Suppress("UNCHECKED_CAST") - public override fun Point<${type}>.toEjml(): Ejml${type}Vector<${ejmlMatrixType}> = when { + override fun Point<${type}>.toEjml(): Ejml${type}Vector<${ejmlMatrixType}> = when { this is Ejml${type}Vector<*> && origin is $ejmlMatrixType -> this as Ejml${type}Vector<${ejmlMatrixType}> else -> Ejml${type}Vector(${ejmlMatrixType}(size, 1).also { (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } }) } - public override fun buildMatrix( + override fun buildMatrix( rows: Int, columns: Int, initializer: ${kmathAlgebra}.(i: Int, j: Int) -> ${type}, @@ -80,7 +80,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } }.wrapMatrix() - public override fun buildVector( + override fun buildVector( size: Int, initializer: ${kmathAlgebra}.(Int) -> ${type}, ): Ejml${type}Vector<${ejmlMatrixType}> = Ejml${type}Vector(${ejmlMatrixType}(size, 1).also { @@ -90,21 +90,21 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, private fun T.wrapMatrix() = Ejml${type}Matrix(this) private fun T.wrapVector() = Ejml${type}Vector(this) - public override fun Matrix<${type}>.unaryMinus(): Matrix<${type}> = this * elementAlgebra { -one } + override fun Matrix<${type}>.unaryMinus(): Matrix<${type}> = this * elementAlgebra { -one } - public override fun Matrix<${type}>.dot(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { + override fun Matrix<${type}>.dot(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.mult(toEjml().origin, other.toEjml().origin, out) return out.wrapMatrix() } - public override fun Matrix<${type}>.dot(vector: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Matrix<${type}>.dot(vector: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.mult(toEjml().origin, vector.toEjml().origin, out) return out.wrapVector() } - public override operator fun Matrix<${type}>.minus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { + override operator fun Matrix<${type}>.minus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.add( @@ -123,19 +123,19 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, return out.wrapMatrix() } - public override operator fun Matrix<${type}>.times(value: ${type}): Ejml${type}Matrix<${ejmlMatrixType}> { + override operator fun Matrix<${type}>.times(value: ${type}): Ejml${type}Matrix<${ejmlMatrixType}> { val res = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.scale(value, toEjml().origin, res) return res.wrapMatrix() } - public override fun Point<${type}>.unaryMinus(): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Point<${type}>.unaryMinus(): Ejml${type}Vector<${ejmlMatrixType}> { val res = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.changeSign(toEjml().origin, res) return res.wrapVector() } - public override fun Matrix<${type}>.plus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { + override fun Matrix<${type}>.plus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.add( @@ -154,7 +154,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, return out.wrapMatrix() } - public override fun Point<${type}>.plus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Point<${type}>.plus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.add( @@ -173,7 +173,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, return out.wrapVector() } - public override fun Point<${type}>.minus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Point<${type}>.minus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.add( @@ -192,18 +192,18 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, return out.wrapVector() } - public override fun ${type}.times(m: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> = m * this + override fun ${type}.times(m: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> = m * this - public override fun Point<${type}>.times(value: ${type}): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Point<${type}>.times(value: ${type}): Ejml${type}Vector<${ejmlMatrixType}> { val res = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.scale(value, toEjml().origin, res) return res.wrapVector() } - public override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this + override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this @UnstableKMathAPI - public override fun getFeature(structure: Matrix<${type}>, type: KClass): F? { + override fun getFeature(structure: Matrix<${type}>, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt index 01717b0f9..2df3d3cc7 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt @@ -27,7 +27,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI */ @UnstableKMathAPI public object LatexSyntaxRenderer : SyntaxRenderer { - public override fun render(node: MathSyntax, output: Appendable): Unit = output.run { + override fun render(node: MathSyntax, output: Appendable): Unit = output.run { fun render(syntax: MathSyntax) = render(syntax, output) when (node) { diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt index cda8e2322..8b5819b84 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt @@ -16,7 +16,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI */ @UnstableKMathAPI public object MathMLSyntaxRenderer : SyntaxRenderer { - public override fun render(node: MathSyntax, output: Appendable) { + override fun render(node: MathSyntax, output: Appendable) { output.append("") renderPart(node, output) output.append("") diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt index 68d829724..fdef35ebd 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt @@ -29,7 +29,7 @@ public fun interface MathRenderer { */ @UnstableKMathAPI public open class FeaturedMathRenderer(public val features: List) : MathRenderer { - public override fun render(mst: MST): MathSyntax { + override fun render(mst: MST): MathSyntax { for (feature in features) feature.render(this, mst)?.let { return it } throw UnsupportedOperationException("Renderer $this has no appropriate feature to render node $mst.") } @@ -56,7 +56,7 @@ public open class FeaturedMathRendererWithPostProcess( features: List, public val stages: List, ) : FeaturedMathRenderer(features) { - public override fun render(mst: MST): MathSyntax { + override fun render(mst: MST): MathSyntax { val res = super.render(mst) for (stage in stages) stage.perform(res) return res diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt index a71985fbc..38450403d 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt @@ -150,9 +150,9 @@ public data class OperandSyntax( */ @UnstableKMathAPI public data class UnaryOperatorSyntax( - public override val operation: String, + override val operation: String, public var prefix: MathSyntax, - public override val operand: OperandSyntax, + override val operand: OperandSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -166,8 +166,8 @@ public data class UnaryOperatorSyntax( */ @UnstableKMathAPI public data class UnaryPlusSyntax( - public override val operation: String, - public override val operand: OperandSyntax, + override val operation: String, + override val operand: OperandSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -181,8 +181,8 @@ public data class UnaryPlusSyntax( */ @UnstableKMathAPI public data class UnaryMinusSyntax( - public override val operation: String, - public override val operand: OperandSyntax, + override val operation: String, + override val operand: OperandSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -197,8 +197,8 @@ public data class UnaryMinusSyntax( */ @UnstableKMathAPI public data class RadicalSyntax( - public override val operation: String, - public override val operand: MathSyntax, + override val operation: String, + override val operand: MathSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -215,8 +215,8 @@ public data class RadicalSyntax( */ @UnstableKMathAPI public data class ExponentSyntax( - public override val operation: String, - public override val operand: OperandSyntax, + override val operation: String, + override val operand: OperandSyntax, public var useOperatorForm: Boolean, ) : UnarySyntax() { init { @@ -233,9 +233,9 @@ public data class ExponentSyntax( */ @UnstableKMathAPI public data class SuperscriptSyntax( - public override val operation: String, - public override val left: MathSyntax, - public override val right: MathSyntax, + override val operation: String, + override val left: MathSyntax, + override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -252,9 +252,9 @@ public data class SuperscriptSyntax( */ @UnstableKMathAPI public data class SubscriptSyntax( - public override val operation: String, - public override val left: MathSyntax, - public override val right: MathSyntax, + override val operation: String, + override val left: MathSyntax, + override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -270,10 +270,10 @@ public data class SubscriptSyntax( */ @UnstableKMathAPI public data class BinaryOperatorSyntax( - public override val operation: String, + override val operation: String, public var prefix: MathSyntax, - public override val left: MathSyntax, - public override val right: MathSyntax, + override val left: MathSyntax, + override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -290,9 +290,9 @@ public data class BinaryOperatorSyntax( */ @UnstableKMathAPI public data class BinaryPlusSyntax( - public override val operation: String, - public override val left: OperandSyntax, - public override val right: OperandSyntax, + override val operation: String, + override val left: OperandSyntax, + override val right: OperandSyntax, ) : BinarySyntax() { init { left.parent = this @@ -309,9 +309,9 @@ public data class BinaryPlusSyntax( */ @UnstableKMathAPI public data class BinaryMinusSyntax( - public override val operation: String, - public override val left: OperandSyntax, - public override val right: OperandSyntax, + override val operation: String, + override val left: OperandSyntax, + override val right: OperandSyntax, ) : BinarySyntax() { init { left.parent = this @@ -329,9 +329,9 @@ public data class BinaryMinusSyntax( */ @UnstableKMathAPI public data class FractionSyntax( - public override val operation: String, - public override val left: OperandSyntax, - public override val right: OperandSyntax, + override val operation: String, + override val left: OperandSyntax, + override val right: OperandSyntax, public var infix: Boolean, ) : BinarySyntax() { init { @@ -349,9 +349,9 @@ public data class FractionSyntax( */ @UnstableKMathAPI public data class RadicalWithIndexSyntax( - public override val operation: String, - public override val left: MathSyntax, - public override val right: MathSyntax, + override val operation: String, + override val left: MathSyntax, + override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -369,9 +369,9 @@ public data class RadicalWithIndexSyntax( */ @UnstableKMathAPI public data class MultiplicationSyntax( - public override val operation: String, - public override val left: OperandSyntax, - public override val right: OperandSyntax, + override val operation: String, + override val left: OperandSyntax, + override val right: OperandSyntax, public var times: Boolean, ) : BinarySyntax() { init { diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt index 203cdf8b3..37e9a8c19 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt @@ -57,7 +57,7 @@ else */ @UnstableKMathAPI public class PrettyPrintFloats(public val types: Set>) : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { + override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { if (node !is MST.Numeric || node.value::class !in types) return null val toString = when (val v = node.value) { @@ -117,7 +117,7 @@ public class PrettyPrintFloats(public val types: Set>) : Rend */ @UnstableKMathAPI public class PrettyPrintIntegers(public val types: Set>) : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = + override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = if (node !is MST.Numeric || node.value::class !in types) null else @@ -140,7 +140,7 @@ public class PrettyPrintIntegers(public val types: Set>) : Re */ @UnstableKMathAPI public class PrettyPrintPi(public val symbols: Set) : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = + override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = if (node !is Symbol || node.identity !in symbols) null else @@ -202,7 +202,7 @@ public abstract class Binary(public val operations: Collection?) : Rende */ @UnstableKMathAPI public class BinaryPlus(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryPlusSyntax( operation = node.operation, left = OperandSyntax(parent.render(node.left), true), @@ -224,7 +224,7 @@ public class BinaryPlus(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class BinaryMinus(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryMinusSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), @@ -246,7 +246,7 @@ public class BinaryMinus(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class UnaryPlus(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryPlusSyntax( + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryPlusSyntax( operation = node.operation, operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), ) @@ -266,7 +266,7 @@ public class UnaryPlus(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class UnaryMinus(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryMinusSyntax( + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryMinusSyntax( operation = node.operation, operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), ) @@ -286,7 +286,7 @@ public class UnaryMinus(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class Fraction(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = FractionSyntax( + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = FractionSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), right = OperandSyntax(operand = parent.render(node.right), parentheses = true), @@ -308,7 +308,7 @@ public class Fraction(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class BinaryOperator(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(name = node.operation), @@ -331,7 +331,7 @@ public class BinaryOperator(operations: Collection?) : Binary(operations */ @UnstableKMathAPI public class UnaryOperator(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(node.operation), @@ -353,7 +353,7 @@ public class UnaryOperator(operations: Collection?) : Unary(operations) */ @UnstableKMathAPI public class Power(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = SuperscriptSyntax( operation = node.operation, left = OperandSyntax(parent.render(node.left), true), @@ -373,7 +373,7 @@ public class Power(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class SquareRoot(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = RadicalSyntax(operation = node.operation, operand = parent.render(node.value)) public companion object { @@ -391,7 +391,7 @@ public class SquareRoot(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class Exponent(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = ExponentSyntax( + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = ExponentSyntax( operation = node.operation, operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), useOperatorForm = true, @@ -412,7 +412,7 @@ public class Exponent(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class Multiplication(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = MultiplicationSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), @@ -435,7 +435,7 @@ public class Multiplication(operations: Collection?) : Binary(operations */ @UnstableKMathAPI public class InverseTrigonometricOperations(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "arc")), @@ -462,7 +462,7 @@ public class InverseTrigonometricOperations(operations: Collection?) : U */ @UnstableKMathAPI public class InverseHyperbolicOperations(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "ar")), diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt index 6da4994a6..574bb54f4 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt @@ -205,7 +205,7 @@ public val BetterExponent: PostProcessPhase = PostProcessPhase { node -> @UnstableKMathAPI public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) : PostProcessPhase { - public override fun perform(node: MathSyntax): Unit = when (node) { + override fun perform(node: MathSyntax): Unit = when (node) { is NumberSyntax -> Unit is SymbolSyntax -> Unit is OperatorNameSyntax -> Unit diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index d0ab8b1e8..0925fee7e 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -25,10 +25,10 @@ public class DerivativeStructureField( NumbersAddOperations { public val numberOfVariables: Int = bindings.size - public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } - public override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) } + override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } + override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) } - public override fun number(value: Number): DerivativeStructure = const(value.toDouble()) + override fun number(value: Number): DerivativeStructure = const(value.toDouble()) /** * A class that implements both [DerivativeStructure] and a [Symbol] @@ -39,10 +39,10 @@ public class DerivativeStructureField( symbol: Symbol, value: Double, ) : DerivativeStructure(size, order, index, value), Symbol { - public override val identity: String = symbol.identity - public override fun toString(): String = identity - public override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity - public override fun hashCode(): Int = identity.hashCode() + override val identity: String = symbol.identity + override fun toString(): String = identity + override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity + override fun hashCode(): Int = identity.hashCode() } /** @@ -52,10 +52,10 @@ public class DerivativeStructureField( key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value) }.toMap() - public override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value) + override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value) - public override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[value] - public override fun bindSymbol(value: String): DerivativeStructureSymbol = variables.getValue(value) + override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[value] + override fun bindSymbol(value: String): DerivativeStructureSymbol = variables.getValue(value) public fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity] public fun bindSymbol(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity) @@ -68,45 +68,45 @@ public class DerivativeStructureField( public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList()) - public override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() + override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() - public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) + override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) - public override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value) + override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value) - public override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b) - public override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b) - public override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin() - public override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos() - public override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.tan() - public override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin() - public override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos() - public override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan() - public override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh() - public override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh() - public override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh() - public override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.asinh() - public override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.acosh() - public override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.atanh() + override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b) + override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b) + override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin() + override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos() + override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.tan() + override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin() + override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos() + override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan() + override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh() + override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh() + override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh() + override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.asinh() + override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.acosh() + override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.atanh() - public override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { + override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { is Double -> arg.pow(pow) is Int -> arg.pow(pow) else -> arg.pow(pow.toDouble()) } public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure = arg.pow(pow) - public override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() - public override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() + override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() + override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() - public override operator fun DerivativeStructure.plus(b: Number): DerivativeStructure = add(b.toDouble()) - public override operator fun DerivativeStructure.minus(b: Number): DerivativeStructure = subtract(b.toDouble()) - public override operator fun Number.plus(b: DerivativeStructure): DerivativeStructure = b + this - public override operator fun Number.minus(b: DerivativeStructure): DerivativeStructure = b - this + override operator fun DerivativeStructure.plus(b: Number): DerivativeStructure = add(b.toDouble()) + override operator fun DerivativeStructure.minus(b: Number): DerivativeStructure = subtract(b.toDouble()) + override operator fun Number.plus(b: DerivativeStructure): DerivativeStructure = b + this + override operator fun Number.minus(b: DerivativeStructure): DerivativeStructure = b - this public companion object : AutoDiffProcessor> { - public override fun process(function: DerivativeStructureField.() -> DerivativeStructure): DifferentiableExpression = + override fun process(function: DerivativeStructureField.() -> DerivativeStructure): DifferentiableExpression = DerivativeStructureExpression(function) } } @@ -117,13 +117,13 @@ public class DerivativeStructureField( public class DerivativeStructureExpression( public val function: DerivativeStructureField.() -> DerivativeStructure, ) : DifferentiableExpression { - public override operator fun invoke(arguments: Map): Double = + override operator fun invoke(arguments: Map): Double = DerivativeStructureField(0, arguments).function().value /** * Get the derivative expression with given orders */ - public override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> + override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> with(DerivativeStructureField(symbols.size, arguments)) { function().derivative(symbols) } } } diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt index 11b097831..1997a633e 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt @@ -15,18 +15,18 @@ import kotlin.reflect.KClass import kotlin.reflect.cast public class CMMatrix(public val origin: RealMatrix) : Matrix { - public override val rowNum: Int get() = origin.rowDimension - public override val colNum: Int get() = origin.columnDimension + override val rowNum: Int get() = origin.rowDimension + override val colNum: Int get() = origin.columnDimension - public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) + override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) } public class CMVector(public val origin: RealVector) : Point { - public override val size: Int get() = origin.dimension + override val size: Int get() = origin.dimension - public override operator fun get(index: Int): Double = origin.getEntry(index) + override operator fun get(index: Int): Double = origin.getEntry(index) - public override operator fun iterator(): Iterator = origin.toArray().iterator() + override operator fun iterator(): Iterator = origin.toArray().iterator() } public fun RealVector.toPoint(): CMVector = CMVector(this) @@ -34,7 +34,7 @@ public fun RealVector.toPoint(): CMVector = CMVector(this) public object CMLinearSpace : LinearSpace { override val elementAlgebra: DoubleField get() = DoubleField - public override fun buildMatrix( + override fun buildMatrix( rows: Int, columns: Int, initializer: DoubleField.(i: Int, j: Int) -> Double, @@ -73,16 +73,16 @@ public object CMLinearSpace : LinearSpace { override fun Point.minus(other: Point): CMVector = toCM().origin.subtract(other.toCM().origin).wrap() - public override fun Matrix.dot(other: Matrix): CMMatrix = + override fun Matrix.dot(other: Matrix): CMMatrix = toCM().origin.multiply(other.toCM().origin).wrap() - public override fun Matrix.dot(vector: Point): CMVector = + override fun Matrix.dot(vector: Point): CMVector = toCM().origin.preMultiply(vector.toCM().origin).wrap() - public override operator fun Matrix.minus(other: Matrix): CMMatrix = + override operator fun Matrix.minus(other: Matrix): CMMatrix = toCM().origin.subtract(other.toCM().origin).wrap() - public 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 = diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt index a46f06568..bca106e68 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt @@ -52,11 +52,11 @@ public class CMOptimization( public fun exportOptimizationData(): List = optimizationData.values.toList() - public override fun initialGuess(map: Map) { + override fun initialGuess(map: Map) { addOptimizationData(InitialGuess(map.toDoubleArray())) } - public override fun function(expression: Expression) { + override fun function(expression: Expression) { val objectiveFunction = ObjectiveFunction { val args = it.toMap() expression(args) @@ -64,7 +64,7 @@ public class CMOptimization( addOptimizationData(objectiveFunction) } - public override fun diffFunction(expression: DifferentiableExpression) { + override fun diffFunction(expression: DifferentiableExpression) { function(expression) val gradientFunction = ObjectiveFunctionGradient { val args = it.toMap() diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt index 4e2fbf980..afbfd9a24 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt @@ -16,31 +16,31 @@ public class CMRandomGeneratorWrapper( ) : org.apache.commons.math3.random.RandomGenerator { private var generator: RandomGenerator = factory(intArrayOf()) - public override fun nextBoolean(): Boolean = generator.nextBoolean() - public override fun nextFloat(): Float = generator.nextDouble().toFloat() + override fun nextBoolean(): Boolean = generator.nextBoolean() + override fun nextFloat(): Float = generator.nextDouble().toFloat() - public override fun setSeed(seed: Int) { + override fun setSeed(seed: Int) { generator = factory(intArrayOf(seed)) } - public override fun setSeed(seed: IntArray) { + override fun setSeed(seed: IntArray) { generator = factory(seed) } - public override fun setSeed(seed: Long) { + override fun setSeed(seed: Long) { setSeed(seed.toInt()) } - public override fun nextBytes(bytes: ByteArray) { + override fun nextBytes(bytes: ByteArray) { generator.fillBytes(bytes) } - public override fun nextInt(): Int = generator.nextInt() - public override fun nextInt(n: Int): Int = generator.nextInt(n) + override fun nextInt(): Int = generator.nextInt() + override fun nextInt(n: Int): Int = generator.nextInt(n) @PerformancePitfall - public override fun nextGaussian(): Double = runBlocking { GaussianSampler(0.0, 1.0).next(generator) } + override fun nextGaussian(): Double = runBlocking { GaussianSampler(0.0, 1.0).next(generator) } - public override fun nextDouble(): Double = generator.nextDouble() - public override fun nextLong(): Long = generator.nextLong() + override fun nextDouble(): Double = generator.nextDouble() + override fun nextLong(): Long = generator.nextLong() } diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt index a96d046c9..8b064a05f 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt @@ -54,8 +54,8 @@ private val PI_DIV_2 = Complex(PI / 2, 0) @OptIn(UnstableKMathAPI::class) public object ComplexField : ExtendedField, Norm, NumbersAddOperations, ScaleOperations { - public override val zero: Complex = 0.0.toComplex() - public override val one: Complex = 1.0.toComplex() + override val zero: Complex = 0.0.toComplex() + override val one: Complex = 1.0.toComplex() /** * The imaginary unit. @@ -68,13 +68,13 @@ public object ComplexField : ExtendedField, Norm, Num override fun scale(a: Complex, value: Double): Complex = Complex(a.re * value, a.im * value) - public override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im) -// public override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble()) + override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im) +// override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble()) - public override fun multiply(a: Complex, b: Complex): Complex = + override fun multiply(a: Complex, b: Complex): Complex = Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re) - public override fun divide(a: Complex, b: Complex): Complex = when { + override fun divide(a: Complex, b: Complex): Complex = when { abs(b.im) < abs(b.re) -> { val wr = b.im / b.re val wd = b.re + wr * b.im @@ -100,31 +100,31 @@ public object ComplexField : ExtendedField, Norm, Num override operator fun Complex.div(k: Number): Complex = Complex(re / k.toDouble(), im / k.toDouble()) - public override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2.0 - public override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2.0 + override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2.0 + override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2.0 - public override fun tan(arg: Complex): Complex { + override fun tan(arg: Complex): Complex { val e1 = exp(-i * arg) val e2 = exp(i * arg) return i * (e1 - e2) / (e1 + e2) } - public override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg) - public override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg) + override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg) + override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg) - public override fun atan(arg: Complex): Complex { + override fun atan(arg: Complex): Complex { val iArg = i * arg return i * (ln(1 - iArg) - ln(1 + iArg)) / 2 } - public override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) + override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) arg.re.pow(pow.toDouble()).toComplex() else exp(pow * ln(arg)) - public override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) + override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) - public override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re) + override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re) /** * Adds complex number to real one. @@ -171,9 +171,9 @@ public object ComplexField : ExtendedField, Norm, Num */ public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this) - public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) + override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) - public override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null + override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null } /** @@ -187,16 +187,16 @@ public data class Complex(val re: Double, val im: Double) { public constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble()) public constructor(re: Number) : this(re.toDouble(), 0.0) - public override fun toString(): String = "($re + i * $im)" + override fun toString(): String = "($re + i * $im)" public companion object : MemorySpec { - public override val objectSize: Int + override val objectSize: Int get() = 16 - public override fun MemoryReader.read(offset: Int): Complex = + override fun MemoryReader.read(offset: Int): Complex = Complex(readDouble(offset), readDouble(offset + 8)) - public override fun MemoryWriter.write(offset: Int, value: Complex) { + override fun MemoryWriter.write(offset: Int, value: Complex) { writeDouble(offset, value.re) writeDouble(offset + 8, value.im) } diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt index 2c783eda0..1b54fc227 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt @@ -27,10 +27,10 @@ public class ComplexFieldND( NumbersAddOperations>, ExtendedField> { - public override val zero: BufferND by lazy { produce { zero } } - public override val one: BufferND by lazy { produce { one } } + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } - public override fun number(value: Number): BufferND { + override fun number(value: Number): BufferND { val d = value.toComplex() // minimize conversions return produce { d } } @@ -81,25 +81,25 @@ public class ComplexFieldND( // return BufferedNDFieldElement(this, buffer) // } - public 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) } - public override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } + override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - public override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } + override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - public override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - public override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - public override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - public override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - public override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - public 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) } - public override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - public override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - public override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - public override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - public override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - public 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) } } 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 28aae7bb4..423cef1d1 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 @@ -63,20 +63,20 @@ public object QuaternionField : Field, Norm, */ public val k: Quaternion = Quaternion(0, 0, 0, 1) - public override fun add(a: Quaternion, b: Quaternion): Quaternion = + override fun add(a: Quaternion, b: Quaternion): Quaternion = Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z) - public override fun scale(a: Quaternion, value: Double): Quaternion = + override fun scale(a: Quaternion, value: Double): Quaternion = Quaternion(a.w * value, a.x * value, a.y * value, a.z * value) - public override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion( + override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion( a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x, a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w, ) - public override fun divide(a: Quaternion, b: Quaternion): Quaternion { + override fun divide(a: Quaternion, b: Quaternion): Quaternion { val s = b.w * b.w + b.x * b.x + b.y * b.y + b.z * b.z return Quaternion( @@ -87,7 +87,7 @@ public object QuaternionField : Field, Norm, ) } - public override fun power(arg: Quaternion, pow: Number): Quaternion { + override fun power(arg: Quaternion, pow: Number): Quaternion { if (pow is Int) return pwr(arg, pow) if (floor(pow.toDouble()) == pow.toDouble()) return pwr(arg, pow.toInt()) return exp(pow * ln(arg)) @@ -131,7 +131,7 @@ public object QuaternionField : Field, Norm, return Quaternion(a2 * a2 - 6 * a2 * n1 + n1 * n1, x.x * n2, x.y * n2, x.z * n2) } - public override fun exp(arg: Quaternion): Quaternion { + override fun exp(arg: Quaternion): Quaternion { val un = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z if (un == 0.0) return exp(arg.w).toQuaternion() val n1 = sqrt(un) @@ -140,7 +140,7 @@ public object QuaternionField : Field, Norm, return Quaternion(ea * cos(n1), n2 * arg.x, n2 * arg.y, n2 * arg.z) } - public override fun ln(arg: Quaternion): Quaternion { + override fun ln(arg: Quaternion): Quaternion { val nu2 = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z if (nu2 == 0.0) @@ -158,21 +158,21 @@ public object QuaternionField : Field, Norm, return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z) } - public override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z) + override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z) - public override operator fun Number.minus(b: Quaternion): Quaternion = + override operator fun Number.minus(b: Quaternion): Quaternion = Quaternion(toDouble() - b.w, -b.x, -b.y, -b.z) - public override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z) - public override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.toDouble(), x, y, z) + override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z) + override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.toDouble(), x, y, z) - public override operator fun Number.times(b: Quaternion): Quaternion = + override operator fun Number.times(b: Quaternion): Quaternion = Quaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z) - public override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) - public override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) + override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) + override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) - public override fun bindSymbolOrNull(value: String): Quaternion? = when (value) { + override fun bindSymbolOrNull(value: String): Quaternion? = when (value) { "i" -> i "j" -> j "k" -> k @@ -181,12 +181,12 @@ public object QuaternionField : Field, Norm, override fun number(value: Number): Quaternion = value.toQuaternion() - public override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 - public override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0 - public override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) - public override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg) - public override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one))) - public override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0 + override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 + override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0 + override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) + override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg) + override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one))) + override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0 } /** @@ -224,16 +224,16 @@ public data class Quaternion( /** * Returns a string representation of this quaternion. */ - public override fun toString(): String = "($w + $x * i + $y * j + $z * k)" + override fun toString(): String = "($w + $x * i + $y * j + $z * k)" public companion object : MemorySpec { - public override val objectSize: Int + override val objectSize: Int get() = 32 - public override fun MemoryReader.read(offset: Int): Quaternion = + override fun MemoryReader.read(offset: Int): Quaternion = Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24)) - public override fun MemoryWriter.write(offset: Int, value: Quaternion) { + override fun MemoryWriter.write(offset: Int, value: Quaternion) { writeDouble(offset, value.w) writeDouble(offset + 8, value.x) writeDouble(offset + 16, value.y) 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 f5560d935..bd5514623 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 @@ -17,17 +17,17 @@ import space.kscience.kmath.structures.indices */ @UnstableKMathAPI public class HyperSquareDomain(private val lower: Buffer, private val upper: Buffer) : DoubleDomain { - public override val dimension: Int get() = lower.size + override val dimension: Int get() = lower.size - public 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] } - public override fun getLowerBound(num: Int): Double = lower[num] + override fun getLowerBound(num: Int): Double = lower[num] - public override fun getUpperBound(num: Int): Double = upper[num] + override fun getUpperBound(num: Int): Double = upper[num] - public override fun volume(): Double { + override fun volume(): Double { var res = 1.0 for (i in 0 until dimension) { 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 7ffc0659d..32a5fc56c 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 @@ -8,12 +8,12 @@ import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI @UnstableKMathAPI -public class UnconstrainedDomain(public override val dimension: Int) : DoubleDomain { - public override operator fun contains(point: Point): Boolean = true +public class UnconstrainedDomain(override val dimension: Int) : DoubleDomain { + override operator fun contains(point: Point): Boolean = true - public override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY + override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY - public override fun getUpperBound(num: Int): Double = Double.POSITIVE_INFINITY + override fun getUpperBound(num: Int): Double = Double.POSITIVE_INFINITY - public override fun volume(): Double = Double.POSITIVE_INFINITY + override fun volume(): Double = Double.POSITIVE_INFINITY } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt index e7acada85..9020ef8cb 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt @@ -10,24 +10,24 @@ import space.kscience.kmath.misc.UnstableKMathAPI @UnstableKMathAPI public class UnivariateDomain(public val range: ClosedFloatingPointRange) : DoubleDomain { - public override val dimension: Int get() = 1 + override val dimension: Int get() = 1 public operator fun contains(d: Double): Boolean = range.contains(d) - public override operator fun contains(point: Point): Boolean { + override operator fun contains(point: Point): Boolean { require(point.size == 0) return contains(point[0]) } - public override fun getLowerBound(num: Int): Double { + override fun getLowerBound(num: Int): Double { require(num == 0) return range.start } - public override fun getUpperBound(num: Int): Double { + override fun getUpperBound(num: Int): Double { require(num == 0) return range.endInclusive } - public override fun volume(): Double = range.endInclusive - range.start + override fun volume(): Double = range.endInclusive - range.start } 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 a10e29cf0..5935424b6 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 @@ -20,25 +20,25 @@ public abstract class FunctionalExpressionAlgebra>( /** * Builds an Expression of constant expression which does not depend on arguments. */ - public override fun const(value: T): Expression = Expression { value } + override fun const(value: T): Expression = Expression { value } /** * Builds an Expression to access a variable. */ - public override fun bindSymbolOrNull(value: String): Expression? = Expression { arguments -> + override fun bindSymbolOrNull(value: String): Expression? = Expression { arguments -> algebra.bindSymbolOrNull(value) ?: arguments[StringSymbol(value)] ?: error("Symbol '$value' is not supported in $this") } - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = { left, right -> Expression { arguments -> algebra.binaryOperationFunction(operation)(left.invoke(arguments), right.invoke(arguments)) } } - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> Expression { arguments -> algebra.unaryOperationFunction(operation)(arg.invoke(arguments)) } } } @@ -49,21 +49,21 @@ public abstract class FunctionalExpressionAlgebra>( public open class FunctionalExpressionGroup>( algebra: A, ) : FunctionalExpressionAlgebra(algebra), Group> { - public override val zero: Expression get() = const(algebra.zero) + override val zero: Expression get() = const(algebra.zero) - public override fun Expression.unaryMinus(): Expression = + override fun Expression.unaryMinus(): Expression = unaryOperation(GroupOperations.MINUS_OPERATION, this) /** * Builds an Expression of addition of two another expressions. */ - public override fun add(a: Expression, b: Expression): Expression = + override fun add(a: Expression, b: Expression): Expression = binaryOperation(GroupOperations.PLUS_OPERATION, a, b) // /** // * Builds an Expression of multiplication of expression by number. // */ -// public override fun multiply(a: Expression, k: Number): Expression = Expression { arguments -> +// override fun multiply(a: Expression, k: Number): Expression = Expression { arguments -> // algebra.multiply(a.invoke(arguments), k) // } @@ -72,10 +72,10 @@ public open class FunctionalExpressionGroup>( public operator fun T.plus(arg: Expression): Expression = arg + this public operator fun T.minus(arg: Expression): Expression = arg - this - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) } @@ -83,21 +83,21 @@ public open class FunctionalExpressionGroup>( public open class FunctionalExpressionRing>( algebra: A, ) : FunctionalExpressionGroup(algebra), Ring> { - public override val one: Expression get() = const(algebra.one) + override val one: Expression get() = const(algebra.one) /** * Builds an Expression of multiplication of two expressions. */ - public override fun multiply(a: Expression, b: Expression): Expression = + override fun multiply(a: Expression, b: Expression): Expression = binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) public operator fun Expression.times(arg: T): Expression = this * const(arg) public operator fun T.times(arg: Expression): Expression = arg * this - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) } @@ -107,65 +107,65 @@ public open class FunctionalExpressionField>( /** * Builds an Expression of division an expression by another one. */ - public override fun divide(a: Expression, b: Expression): Expression = + override fun divide(a: Expression, b: Expression): Expression = binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) public operator fun Expression.div(arg: T): Expression = this / const(arg) public operator fun T.div(arg: Expression): Expression = arg / this - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) - public override fun scale(a: Expression, value: Double): Expression = algebra { + override fun scale(a: Expression, value: Double): Expression = algebra { Expression { args -> a(args) * value } } - public override fun bindSymbolOrNull(value: String): Expression? = + override fun bindSymbolOrNull(value: String): Expression? = super.bindSymbolOrNull(value) } public open class FunctionalExpressionExtendedField>( algebra: A, ) : FunctionalExpressionField(algebra), ExtendedField> { - public override fun number(value: Number): Expression = const(algebra.number(value)) + override fun number(value: Number): Expression = const(algebra.number(value)) - public override fun sqrt(arg: Expression): Expression = + override fun sqrt(arg: Expression): Expression = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) - public override fun sin(arg: Expression): Expression = + override fun sin(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) - public override fun cos(arg: Expression): Expression = + override fun cos(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) - public override fun asin(arg: Expression): Expression = + override fun asin(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) - public override fun acos(arg: Expression): Expression = + override fun acos(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) - public override fun atan(arg: Expression): Expression = + override fun atan(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) - public override fun power(arg: Expression, pow: Number): Expression = + override fun power(arg: Expression, pow: Number): Expression = binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) - public override fun exp(arg: Expression): Expression = + override fun exp(arg: Expression): Expression = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - public override fun ln(arg: Expression): Expression = + override fun ln(arg: Expression): Expression = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) - public override fun bindSymbol(value: String): Expression = super.bindSymbol(value) + override fun bindSymbol(value: String): Expression = super.bindSymbol(value) } public inline fun > A.expressionInGroup( diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt index 4729f19ea..d8489e30c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt @@ -12,14 +12,14 @@ import space.kscience.kmath.operations.* * [Algebra] over [MST] nodes. */ public object MstNumericAlgebra : NumericAlgebra { - public override fun number(value: Number): MST.Numeric = MST.Numeric(value) - public override fun bindSymbolOrNull(value: String): Symbol = StringSymbol(value) + 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) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = { arg -> MST.Unary(operation, arg) } - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = { left, right -> MST.Binary(operation, left, right) } } @@ -27,27 +27,27 @@ public object MstNumericAlgebra : NumericAlgebra { * [Group] over [MST] nodes. */ public object MstGroup : Group, NumericAlgebra, ScaleOperations { - public override val zero: MST.Numeric = number(0.0) + override val zero: MST.Numeric = number(0.0) - public override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value) - public override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOperations.PLUS_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST.Unary = + override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value) + override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) + override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOperations.PLUS_OPERATION)(a, b) + override operator fun MST.unaryPlus(): MST.Unary = unaryOperationFunction(GroupOperations.PLUS_OPERATION)(this) - public override operator fun MST.unaryMinus(): MST.Unary = + override operator fun MST.unaryMinus(): MST.Unary = unaryOperationFunction(GroupOperations.MINUS_OPERATION)(this) - public override operator fun MST.minus(b: MST): MST.Binary = + override operator fun MST.minus(b: MST): MST.Binary = binaryOperationFunction(GroupOperations.MINUS_OPERATION)(this, b) - public override fun scale(a: MST, value: Double): MST.Binary = + override fun scale(a: MST, value: Double): MST.Binary = binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(value)) - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstNumericAlgebra.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstNumericAlgebra.unaryOperationFunction(operation) } @@ -57,27 +57,27 @@ public object MstGroup : Group, NumericAlgebra, ScaleOperations { @Suppress("OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) public object MstRing : Ring, NumbersAddOperations, ScaleOperations { - public override inline val zero: MST.Numeric get() = MstGroup.zero - public override val one: MST.Numeric = number(1.0) + override inline val zero: MST.Numeric get() = MstGroup.zero + override val one: MST.Numeric = number(1.0) - public override fun number(value: Number): MST.Numeric = MstGroup.number(value) - public override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - public override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b) + override fun number(value: Number): MST.Numeric = MstGroup.number(value) + override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) + override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b) - public override fun scale(a: MST, value: Double): MST.Binary = + override fun scale(a: MST, value: Double): MST.Binary = MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - public override fun multiply(a: MST, b: MST): MST.Binary = + override fun multiply(a: MST, b: MST): MST.Binary = binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus } - public override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus } - public override operator fun MST.minus(b: MST): MST.Binary = MstGroup { this@minus - b } + override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus } + override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus } + override operator fun MST.minus(b: MST): MST.Binary = MstGroup { this@minus - b } - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstGroup.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstNumericAlgebra.unaryOperationFunction(operation) } @@ -87,28 +87,28 @@ public object MstRing : Ring, NumbersAddOperations, ScaleOperations, NumbersAddOperations, ScaleOperations { - public override inline val zero: MST.Numeric get() = MstRing.zero - public override inline val one: MST.Numeric get() = MstRing.one + override inline val zero: MST.Numeric get() = MstRing.zero + override inline val one: MST.Numeric get() = MstRing.one - public override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - public override fun number(value: Number): MST.Numeric = MstRing.number(value) - public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) + override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) + override fun number(value: Number): MST.Numeric = MstRing.number(value) + override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) - public override fun scale(a: MST, value: Double): MST.Binary = + override fun scale(a: MST, value: Double): MST.Binary = MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) - public override fun divide(a: MST, b: MST): MST.Binary = + override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) + override fun divide(a: MST, b: MST): MST.Binary = binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } - public override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } - public override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b } + override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } + override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } + override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b } - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstRing.unaryOperationFunction(operation) } @@ -117,45 +117,45 @@ public object MstField : Field, NumbersAddOperations, ScaleOperations< */ @Suppress("OVERRIDE_BY_INLINE") public object MstExtendedField : ExtendedField, NumericAlgebra { - public override inline val zero: MST.Numeric get() = MstField.zero - public override inline val one: MST.Numeric get() = MstField.one + override inline val zero: MST.Numeric get() = MstField.zero + override inline val one: MST.Numeric get() = MstField.one - public override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - public override fun number(value: Number): MST.Numeric = MstRing.number(value) - public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) - public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) - public override fun tan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.TAN_OPERATION)(arg) - public override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) - public override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) - public override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) - public override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.SINH_OPERATION)(arg) - public override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.COSH_OPERATION)(arg) - public override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.TANH_OPERATION)(arg) - public override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ASINH_OPERATION)(arg) - public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg) - public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg) - public override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b) - public override fun sqrt(arg: MST): MST = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) + override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) + override fun number(value: Number): MST.Numeric = MstRing.number(value) + override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) + override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) + override fun tan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.TAN_OPERATION)(arg) + override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) + override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) + override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) + override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.SINH_OPERATION)(arg) + override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.COSH_OPERATION)(arg) + override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.TANH_OPERATION)(arg) + override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ASINH_OPERATION)(arg) + override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg) + override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg) + override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b) + override fun sqrt(arg: MST): MST = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) - public override fun scale(a: MST, value: Double): MST = + override fun scale(a: MST, value: Double): MST = binaryOperation(GroupOperations.PLUS_OPERATION, a, number(value)) - public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) - public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) - public override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus } - public override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus } - public override operator fun MST.minus(b: MST): MST.Binary = MstField { this@minus - b } + override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) + override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) + override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus } + override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus } + override operator fun MST.minus(b: MST): MST.Binary = MstField { this@minus - b } - public override fun power(arg: MST, pow: Number): MST.Binary = + override fun power(arg: MST, pow: Number): MST.Binary = binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) - public override fun exp(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - public override fun ln(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) + override fun exp(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) + override fun ln(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstField.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstField.unaryOperationFunction(operation) } @@ -164,7 +164,7 @@ public object MstExtendedField : ExtendedField, NumericAlgebra { */ @UnstableKMathAPI public object MstLogicAlgebra : LogicAlgebra { - public override fun bindSymbolOrNull(value: String): MST = super.bindSymbolOrNull(value) ?: StringSymbol(value) + override fun bindSymbolOrNull(value: String): MST = super.bindSymbolOrNull(value) ?: StringSymbol(value) override fun const(boolean: Boolean): Symbol = if (boolean) { LogicAlgebra.TRUE diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt index 960f6fd79..bf9469f41 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt @@ -60,8 +60,8 @@ public open class SimpleAutoDiffField>( public val context: F, bindings: Map, ) : Field>, ExpressionAlgebra>, NumbersAddOperations> { - public override val zero: AutoDiffValue get() = const(context.zero) - public override val one: AutoDiffValue get() = const(context.one) + override val zero: AutoDiffValue get() = const(context.zero) + override val one: AutoDiffValue get() = const(context.one) // this stack contains pairs of blocks and values to apply them to private var stack: Array = arrayOfNulls(8) @@ -149,17 +149,17 @@ public open class SimpleAutoDiffField>( // // Overloads for Double constants // -// public override operator fun Number.plus(b: AutoDiffValue): AutoDiffValue = +// override operator fun Number.plus(b: AutoDiffValue): AutoDiffValue = // derive(const { this@plus.toDouble() * one + b.value }) { z -> // b.d += z.d // } // -// public override operator fun AutoDiffValue.plus(b: Number): AutoDiffValue = b.plus(this) +// override operator fun AutoDiffValue.plus(b: Number): AutoDiffValue = b.plus(this) // -// public override operator fun Number.minus(b: AutoDiffValue): AutoDiffValue = +// override operator fun Number.minus(b: AutoDiffValue): AutoDiffValue = // derive(const { this@minus.toDouble() * one - b.value }) { z -> b.d -= z.d } // -// public override operator fun AutoDiffValue.minus(b: Number): AutoDiffValue = +// override operator fun AutoDiffValue.minus(b: Number): AutoDiffValue = // derive(const { this@minus.value - one * b.toDouble() }) { z -> d += z.d } @@ -168,25 +168,25 @@ public open class SimpleAutoDiffField>( // Basic math (+, -, *, /) - public override fun add(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + override fun add(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = derive(const { a.value + b.value }) { z -> a.d += z.d b.d += z.d } - public override fun multiply(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + override fun multiply(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = derive(const { a.value * b.value }) { z -> a.d += z.d * b.value b.d += z.d * a.value } - public override fun divide(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + override fun divide(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = derive(const { a.value / b.value }) { z -> a.d += z.d / b.value b.d -= z.d * a.value / (b.value * b.value) } - public override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = + override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = derive(const { value * a.value }) { z -> a.d += z.d * value } @@ -236,12 +236,12 @@ public class SimpleAutoDiffExpression>( public val field: F, public val function: SimpleAutoDiffField.() -> AutoDiffValue, ) : FirstDerivativeExpression() { - public override operator fun invoke(arguments: Map): T { + override operator fun invoke(arguments: Map): T { //val bindings = arguments.entries.map { it.key.bind(it.value) } return SimpleAutoDiffField(field, arguments).function().value } - public override fun derivativeOrNull(symbol: Symbol): Expression = Expression { arguments -> + override fun derivativeOrNull(symbol: Symbol): Expression = Expression { arguments -> //val bindings = arguments.entries.map { it.key.bind(it.value) } val derivationResult = SimpleAutoDiffField(field, arguments).differentiate(function) derivationResult.derivative(symbol) @@ -346,28 +346,28 @@ public class SimpleAutoDiffExtendedField>( override fun bindSymbol(value: String): AutoDiffValue = super.bindSymbol(value) - public override fun number(value: Number): AutoDiffValue = const { number(value) } + override fun number(value: Number): AutoDiffValue = const { number(value) } - public override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = a * number(value) + override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = a * number(value) // x ^ 2 public fun sqr(x: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sqr(x) // x ^ 1/2 - public override fun sqrt(arg: AutoDiffValue): AutoDiffValue = + override fun sqrt(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sqrt(arg) // x ^ y (const) - public override fun power(arg: AutoDiffValue, pow: Number): AutoDiffValue = + override fun power(arg: AutoDiffValue, pow: Number): AutoDiffValue = (this as SimpleAutoDiffField).pow(arg, pow.toDouble()) // exp(x) - public override fun exp(arg: AutoDiffValue): AutoDiffValue = + override fun exp(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).exp(arg) // ln(x) - public override fun ln(arg: AutoDiffValue): AutoDiffValue = + override fun ln(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).ln(arg) // x ^ y (any) @@ -377,40 +377,40 @@ public class SimpleAutoDiffExtendedField>( ): AutoDiffValue = exp(y * ln(x)) // sin(x) - public override fun sin(arg: AutoDiffValue): AutoDiffValue = + override fun sin(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sin(arg) // cos(x) - public override fun cos(arg: AutoDiffValue): AutoDiffValue = + override fun cos(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).cos(arg) - public override fun tan(arg: AutoDiffValue): AutoDiffValue = + override fun tan(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).tan(arg) - public override fun asin(arg: AutoDiffValue): AutoDiffValue = + override fun asin(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).asin(arg) - public override fun acos(arg: AutoDiffValue): AutoDiffValue = + override fun acos(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).acos(arg) - public override fun atan(arg: AutoDiffValue): AutoDiffValue = + override fun atan(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).atan(arg) - public override fun sinh(arg: AutoDiffValue): AutoDiffValue = + override fun sinh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sinh(arg) - public override fun cosh(arg: AutoDiffValue): AutoDiffValue = + override fun cosh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).cosh(arg) - public override fun tanh(arg: AutoDiffValue): AutoDiffValue = + override fun tanh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).tanh(arg) - public override fun asinh(arg: AutoDiffValue): AutoDiffValue = + override fun asinh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).asinh(arg) - public override fun acosh(arg: AutoDiffValue): AutoDiffValue = + override fun acosh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).acosh(arg) - public override fun atanh(arg: AutoDiffValue): AutoDiffValue = + override fun atanh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).atanh(arg) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt index 16aadab3b..4b624b6a0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt @@ -26,11 +26,11 @@ public class MatrixWrapper internal constructor( */ @UnstableKMathAPI @Suppress("UNCHECKED_CAST") - public override fun getFeature(type: KClass): F? = + override fun getFeature(type: KClass): F? = features.singleOrNull(type::isInstance) as? F ?: origin.getFeature(type) - public override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$features)" + override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$features)" } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt index 38985f216..7b0b06a58 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt @@ -127,7 +127,7 @@ public interface GroupND> : Group>, AlgebraND * @param b the addend. * @return the sum. */ - public override fun add(a: StructureND, b: StructureND): StructureND = + override fun add(a: StructureND, b: StructureND): StructureND = combine(a, b) { aValue, bValue -> add(aValue, bValue) } // /** @@ -137,7 +137,7 @@ public interface GroupND> : Group>, AlgebraND // * @param k the multiplier. // * @return the product. // */ -// public override fun multiply(a: NDStructure, k: Number): NDStructure = a.map { multiply(it, k) } +// override fun multiply(a: NDStructure, k: Number): NDStructure = a.map { multiply(it, k) } // TODO move to extensions after KEEP-176 @@ -194,7 +194,7 @@ public interface RingND> : Ring>, GroupND, b: StructureND): StructureND = + override fun multiply(a: StructureND, b: StructureND): StructureND = combine(a, b) { aValue, bValue -> multiply(aValue, bValue) } //TODO move to extensions after KEEP-176 @@ -234,7 +234,7 @@ public interface FieldND> : Field>, RingND, b: StructureND): StructureND = + override fun divide(a: StructureND, b: StructureND): StructureND = combine(a, b) { aValue, bValue -> divide(aValue, bValue) } //TODO move to extensions after KEEP-176 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt index 71532594e..925301272 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt @@ -22,15 +22,15 @@ public class DoubleFieldND( ScaleOperations>, ExtendedField> { - public override val zero: BufferND by lazy { produce { zero } } - public override val one: BufferND by lazy { produce { one } } + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } - public override fun number(value: Number): BufferND { + override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions return produce { d } } - public override val StructureND.buffer: DoubleBuffer + override val StructureND.buffer: DoubleBuffer get() = when { !shape.contentEquals(this@DoubleFieldND.shape) -> throw ShapeMismatchException( this@DoubleFieldND.shape, @@ -41,7 +41,7 @@ public class DoubleFieldND( } @Suppress("OVERRIDE_BY_INLINE") - public override inline fun StructureND.map( + override inline fun StructureND.map( transform: DoubleField.(Double) -> Double, ): BufferND { val buffer = DoubleBuffer(strides.linearSize) { offset -> DoubleField.transform(buffer.array[offset]) } @@ -49,7 +49,7 @@ public class DoubleFieldND( } @Suppress("OVERRIDE_BY_INLINE") - public override inline fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { + override inline fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { val array = DoubleArray(strides.linearSize) { offset -> val index = strides.index(offset) DoubleField.initializer(index) @@ -58,7 +58,7 @@ public class DoubleFieldND( } @Suppress("OVERRIDE_BY_INLINE") - public override inline fun StructureND.mapIndexed( + override inline fun StructureND.mapIndexed( transform: DoubleField.(index: IntArray, Double) -> Double, ): BufferND = BufferND( strides, @@ -70,7 +70,7 @@ public class DoubleFieldND( }) @Suppress("OVERRIDE_BY_INLINE") - public override inline fun combine( + override inline fun combine( a: StructureND, b: StructureND, transform: DoubleField.(Double, Double) -> Double, @@ -81,26 +81,26 @@ public class DoubleFieldND( return BufferND(strides, buffer) } - public override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } + override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } - public 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) } - public override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - public override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } + override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } + override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - public override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - public override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - public override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - public override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - public override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - public 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) } - public override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - public override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - public override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - public override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - public override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - public 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) } } public fun AlgebraND.Companion.real(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt index 150ebf6fb..d916bc0d6 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt @@ -16,14 +16,14 @@ import kotlin.jvm.JvmInline * A structure that is guaranteed to be one-dimensional */ public interface Structure1D : StructureND, Buffer { - public override val dimension: Int get() = 1 + override val dimension: Int get() = 1 - public override operator fun get(index: IntArray): T { + override operator fun get(index: IntArray): T { require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" } return get(index[0]) } - public override operator fun iterator(): Iterator = (0 until size).asSequence().map(::get).iterator() + override operator fun iterator(): Iterator = (0 until size).asSequence().map(::get).iterator() public companion object } @@ -32,7 +32,7 @@ public interface Structure1D : StructureND, Buffer { * A mutable structure that is guaranteed to be one-dimensional */ public interface MutableStructure1D : Structure1D, MutableStructureND, MutableBuffer { - public override operator fun set(index: IntArray, value: T) { + override operator fun set(index: IntArray, value: T) { require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" } set(index[0], value) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index f353b6974..cb69bdc00 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -29,7 +29,7 @@ public interface Structure2D : StructureND { */ public val colNum: Int - public override val shape: IntArray get() = intArrayOf(rowNum, colNum) + override val shape: IntArray get() = intArrayOf(rowNum, colNum) /** * The buffer of rows of this structure. It gets elements from the structure dynamically. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt index 3a1ec430e..cef34dce2 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt @@ -166,13 +166,13 @@ public interface GroupOperations : Algebra { */ public operator fun T.minus(b: T): T = add(this, -b) - public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { + override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> +arg } MINUS_OPERATION -> { arg -> -arg } else -> super.unaryOperationFunction(operation) } - public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { + override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { PLUS_OPERATION -> ::add MINUS_OPERATION -> { left, right -> left - right } else -> super.binaryOperationFunction(operation) @@ -226,7 +226,7 @@ public interface RingOperations : GroupOperations { */ public operator fun T.times(b: T): T = multiply(this, b) - public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { + override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { TIMES_OPERATION -> ::multiply else -> super.binaryOperationFunction(operation) } @@ -277,7 +277,7 @@ public interface FieldOperations : RingOperations { */ public operator fun T.div(b: T): T = divide(this, b) - public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { + override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { DIV_OPERATION -> ::divide else -> super.binaryOperationFunction(operation) } @@ -298,5 +298,5 @@ public interface FieldOperations : RingOperations { * @param T the type of element of this field. */ public interface Field : Ring, FieldOperations, ScaleOperations, NumericAlgebra { - public override fun number(value: Number): T = scale(one, value.toDouble()) + override fun number(value: Number): T = scale(one, value.toDouble()) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt index c332b086e..4ccbfc531 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt @@ -49,16 +49,16 @@ public class BigInt internal constructor( private val sign: Byte, private val magnitude: Magnitude, ) : Comparable { - public override fun compareTo(other: BigInt): Int = when { + override fun compareTo(other: BigInt): Int = when { (sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0 sign < other.sign -> -1 sign > other.sign -> 1 else -> sign * compareMagnitudes(magnitude, other.magnitude) } - public override fun equals(other: Any?): Boolean = other is BigInt && compareTo(other) == 0 + override fun equals(other: Any?): Boolean = other is BigInt && compareTo(other) == 0 - public override fun hashCode(): Int = magnitude.hashCode() + sign + override fun hashCode(): Int = magnitude.hashCode() + sign public fun abs(): BigInt = if (sign == 0.toByte()) this else BigInt(1, magnitude) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt index deeb07e0e..7a8fa5668 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt @@ -87,7 +87,7 @@ public interface NumericAlgebra : Algebra { public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = rightSideNumberOperationFunction(operation)(left, right) - public override fun bindSymbolOrNull(value: String): T? = when (value) { + override fun bindSymbolOrNull(value: String): T? = when (value) { "pi" -> number(PI) "e" -> number(E) else -> super.bindSymbolOrNull(value) 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 36c13d6ec..19cb5f25c 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 @@ -15,10 +15,10 @@ public interface ExtendedFieldOperations : TrigonometricOperations, PowerOperations, ExponentialOperations { - public override fun tan(arg: T): T = sin(arg) / cos(arg) - public override fun tanh(arg: T): T = sinh(arg) / cosh(arg) + override fun tan(arg: T): T = sin(arg) / cos(arg) + override fun tanh(arg: T): T = sinh(arg) / cosh(arg) - public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { + override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { TrigonometricOperations.COS_OPERATION -> ::cos TrigonometricOperations.SIN_OPERATION -> ::sin TrigonometricOperations.TAN_OPERATION -> ::tan @@ -42,14 +42,14 @@ public interface ExtendedFieldOperations : * Advanced Number-like field that implements basic operations. */ public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra, ScaleOperations { - public override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 - public override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 - public override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) - public override fun asinh(arg: T): T = ln(sqrt(arg * arg + one) + arg) - public override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) - public override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0 + override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 + override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 + override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) + override fun asinh(arg: T): T = ln(sqrt(arg * arg + one) + arg) + override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) + override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0 - public override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = + override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = when (operation) { PowerOperations.POW_OPERATION -> ::power else -> super.rightSideNumberOperationFunction(operation) @@ -61,50 +61,50 @@ public interface ExtendedField : ExtendedFieldOperations, Field, Numeri */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object DoubleField : ExtendedField, Norm, ScaleOperations { - public override inline val zero: Double get() = 0.0 - public override inline val one: Double get() = 1.0 + override inline val zero: Double get() = 0.0 + override inline val one: Double get() = 1.0 - public override inline fun number(value: Number): Double = value.toDouble() + override inline fun number(value: Number): Double = value.toDouble() - public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = + override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - public override inline fun add(a: Double, b: Double): Double = a + b + override inline fun add(a: Double, b: Double): Double = a + b - public override inline fun multiply(a: Double, b: Double): Double = a * b - public override inline fun divide(a: Double, b: Double): Double = a / b + override inline fun multiply(a: Double, b: Double): Double = a * b + override inline fun divide(a: Double, b: Double): Double = a / b - public override inline fun scale(a: Double, value: Double): Double = a * value + override inline fun scale(a: Double, value: Double): Double = a * value - public override inline fun sin(arg: Double): Double = kotlin.math.sin(arg) - public override inline fun cos(arg: Double): Double = kotlin.math.cos(arg) - public override inline fun tan(arg: Double): Double = kotlin.math.tan(arg) - public override inline fun acos(arg: Double): Double = kotlin.math.acos(arg) - public override inline fun asin(arg: Double): Double = kotlin.math.asin(arg) - public override inline fun atan(arg: Double): Double = kotlin.math.atan(arg) + override inline fun sin(arg: Double): Double = kotlin.math.sin(arg) + override inline fun cos(arg: Double): Double = kotlin.math.cos(arg) + override inline fun tan(arg: Double): Double = kotlin.math.tan(arg) + override inline fun acos(arg: Double): Double = kotlin.math.acos(arg) + override inline fun asin(arg: Double): Double = kotlin.math.asin(arg) + override inline fun atan(arg: Double): Double = kotlin.math.atan(arg) - public override inline fun sinh(arg: Double): Double = kotlin.math.sinh(arg) - public override inline fun cosh(arg: Double): Double = kotlin.math.cosh(arg) - public override inline fun tanh(arg: Double): Double = kotlin.math.tanh(arg) - public override inline fun asinh(arg: Double): Double = kotlin.math.asinh(arg) - public override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg) - public override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg) + override inline fun sinh(arg: Double): Double = kotlin.math.sinh(arg) + override inline fun cosh(arg: Double): Double = kotlin.math.cosh(arg) + override inline fun tanh(arg: Double): Double = kotlin.math.tanh(arg) + override inline fun asinh(arg: Double): Double = kotlin.math.asinh(arg) + override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg) + override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg) - public override inline fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg) - public override inline fun power(arg: Double, pow: Number): Double = arg.kpow(pow.toDouble()) - public override inline fun exp(arg: Double): Double = kotlin.math.exp(arg) - public override inline fun ln(arg: Double): Double = kotlin.math.ln(arg) + override inline fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg) + override inline fun power(arg: Double, pow: Number): Double = arg.kpow(pow.toDouble()) + override inline fun exp(arg: Double): Double = kotlin.math.exp(arg) + override inline fun ln(arg: Double): Double = kotlin.math.ln(arg) - public override inline fun norm(arg: Double): Double = abs(arg) + override inline fun norm(arg: Double): Double = abs(arg) - public override inline fun Double.unaryMinus(): Double = -this - public override inline fun Double.plus(b: Double): Double = this + b - public override inline fun Double.minus(b: Double): Double = this - b - public override inline fun Double.times(b: Double): Double = this * b - public override inline fun Double.div(b: Double): Double = this / b + override inline fun Double.unaryMinus(): Double = -this + override inline fun Double.plus(b: Double): Double = this + b + override inline fun Double.minus(b: Double): Double = this - b + override inline fun Double.times(b: Double): Double = this * b + override inline fun Double.div(b: Double): Double = this / b } /** @@ -112,50 +112,50 @@ public object DoubleField : ExtendedField, Norm, ScaleOp */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object FloatField : ExtendedField, Norm { - public override inline val zero: Float get() = 0.0f - public override inline val one: Float get() = 1.0f + override inline val zero: Float get() = 0.0f + override inline val one: Float get() = 1.0f - public override fun number(value: Number): Float = value.toFloat() + override fun number(value: Number): Float = value.toFloat() - public override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = + override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = when (operation) { PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - public override inline fun add(a: Float, b: Float): Float = a + b - public override fun scale(a: Float, value: Double): Float = a * value.toFloat() + override inline fun add(a: Float, b: Float): Float = a + b + override fun scale(a: Float, value: Double): Float = a * value.toFloat() - public override inline fun multiply(a: Float, b: Float): Float = a * b + override inline fun multiply(a: Float, b: Float): Float = a * b - public override inline fun divide(a: Float, b: Float): Float = a / b + override inline fun divide(a: Float, b: Float): Float = a / b - public override inline fun sin(arg: Float): Float = kotlin.math.sin(arg) - public override inline fun cos(arg: Float): Float = kotlin.math.cos(arg) - public override inline fun tan(arg: Float): Float = kotlin.math.tan(arg) - public override inline fun acos(arg: Float): Float = kotlin.math.acos(arg) - public override inline fun asin(arg: Float): Float = kotlin.math.asin(arg) - public override inline fun atan(arg: Float): Float = kotlin.math.atan(arg) + override inline fun sin(arg: Float): Float = kotlin.math.sin(arg) + override inline fun cos(arg: Float): Float = kotlin.math.cos(arg) + override inline fun tan(arg: Float): Float = kotlin.math.tan(arg) + override inline fun acos(arg: Float): Float = kotlin.math.acos(arg) + override inline fun asin(arg: Float): Float = kotlin.math.asin(arg) + override inline fun atan(arg: Float): Float = kotlin.math.atan(arg) - public override inline fun sinh(arg: Float): Float = kotlin.math.sinh(arg) - public override inline fun cosh(arg: Float): Float = kotlin.math.cosh(arg) - public override inline fun tanh(arg: Float): Float = kotlin.math.tanh(arg) - public override inline fun asinh(arg: Float): Float = kotlin.math.asinh(arg) - public override inline fun acosh(arg: Float): Float = kotlin.math.acosh(arg) - public override inline fun atanh(arg: Float): Float = kotlin.math.atanh(arg) + override inline fun sinh(arg: Float): Float = kotlin.math.sinh(arg) + override inline fun cosh(arg: Float): Float = kotlin.math.cosh(arg) + override inline fun tanh(arg: Float): Float = kotlin.math.tanh(arg) + override inline fun asinh(arg: Float): Float = kotlin.math.asinh(arg) + override inline fun acosh(arg: Float): Float = kotlin.math.acosh(arg) + override inline fun atanh(arg: Float): Float = kotlin.math.atanh(arg) - public override inline fun sqrt(arg: Float): Float = kotlin.math.sqrt(arg) - public override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat()) - public override inline fun exp(arg: Float): Float = kotlin.math.exp(arg) - public override inline fun ln(arg: Float): Float = kotlin.math.ln(arg) + override inline fun sqrt(arg: Float): Float = kotlin.math.sqrt(arg) + override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat()) + override inline fun exp(arg: Float): Float = kotlin.math.exp(arg) + override inline fun ln(arg: Float): Float = kotlin.math.ln(arg) - public override inline fun norm(arg: Float): Float = abs(arg) + override inline fun norm(arg: Float): Float = abs(arg) - public override inline fun Float.unaryMinus(): Float = -this - public override inline fun Float.plus(b: Float): Float = this + b - public override inline fun Float.minus(b: Float): Float = this - b - public override inline fun Float.times(b: Float): Float = this * b - public override inline fun Float.div(b: Float): Float = this / b + override inline fun Float.unaryMinus(): Float = -this + override inline fun Float.plus(b: Float): Float = this + b + override inline fun Float.minus(b: Float): Float = this - b + override inline fun Float.times(b: Float): Float = this * b + override inline fun Float.div(b: Float): Float = this / b } /** @@ -163,21 +163,21 @@ public object FloatField : ExtendedField, Norm { */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object IntRing : Ring, Norm, NumericAlgebra { - public override inline val zero: Int + override inline val zero: Int get() = 0 - public override inline val one: Int + override inline val one: Int get() = 1 - public override fun number(value: Number): Int = value.toInt() - public override inline fun add(a: Int, b: Int): Int = a + b - public override inline fun multiply(a: Int, b: Int): Int = a * b - public override inline fun norm(arg: Int): Int = abs(arg) + override fun number(value: Number): Int = value.toInt() + override inline fun add(a: Int, b: Int): Int = a + b + override inline fun multiply(a: Int, b: Int): Int = a * b + override inline fun norm(arg: Int): Int = abs(arg) - public override inline fun Int.unaryMinus(): Int = -this - public override inline fun Int.plus(b: Int): Int = this + b - public override inline fun Int.minus(b: Int): Int = this - b - public override inline fun Int.times(b: Int): Int = this * b + override inline fun Int.unaryMinus(): Int = -this + override inline fun Int.plus(b: Int): Int = this + b + override inline fun Int.minus(b: Int): Int = this - b + override inline fun Int.times(b: Int): Int = this * b } /** @@ -185,21 +185,21 @@ public object IntRing : Ring, Norm, NumericAlgebra { */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object ShortRing : Ring, Norm, NumericAlgebra { - public override inline val zero: Short + override inline val zero: Short get() = 0 - public override inline val one: Short + override inline val one: Short get() = 1 - public override fun number(value: Number): Short = value.toShort() - public override inline fun add(a: Short, b: Short): Short = (a + b).toShort() - public override inline fun multiply(a: Short, b: Short): Short = (a * b).toShort() - public override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort() + override fun number(value: Number): Short = value.toShort() + override inline fun add(a: Short, b: Short): Short = (a + b).toShort() + override inline fun multiply(a: Short, b: Short): Short = (a * b).toShort() + override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort() - public override inline fun Short.unaryMinus(): Short = (-this).toShort() - public override inline fun Short.plus(b: Short): Short = (this + b).toShort() - public override inline fun Short.minus(b: Short): Short = (this - b).toShort() - public override inline fun Short.times(b: Short): Short = (this * b).toShort() + override inline fun Short.unaryMinus(): Short = (-this).toShort() + override inline fun Short.plus(b: Short): Short = (this + b).toShort() + override inline fun Short.minus(b: Short): Short = (this - b).toShort() + override inline fun Short.times(b: Short): Short = (this * b).toShort() } /** @@ -207,21 +207,21 @@ public object ShortRing : Ring, Norm, NumericAlgebra */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object ByteRing : Ring, Norm, NumericAlgebra { - public override inline val zero: Byte + override inline val zero: Byte get() = 0 - public override inline val one: Byte + override inline val one: Byte get() = 1 - public override fun number(value: Number): Byte = value.toByte() - public override inline fun add(a: Byte, b: Byte): Byte = (a + b).toByte() - public override inline fun multiply(a: Byte, b: Byte): Byte = (a * b).toByte() - public override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte() + override fun number(value: Number): Byte = value.toByte() + override inline fun add(a: Byte, b: Byte): Byte = (a + b).toByte() + override inline fun multiply(a: Byte, b: Byte): Byte = (a * b).toByte() + override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte() - public override inline fun Byte.unaryMinus(): Byte = (-this).toByte() - public override inline fun Byte.plus(b: Byte): Byte = (this + b).toByte() - public override inline fun Byte.minus(b: Byte): Byte = (this - b).toByte() - public override inline fun Byte.times(b: Byte): Byte = (this * b).toByte() + override inline fun Byte.unaryMinus(): Byte = (-this).toByte() + override inline fun Byte.plus(b: Byte): Byte = (this + b).toByte() + override inline fun Byte.minus(b: Byte): Byte = (this - b).toByte() + override inline fun Byte.times(b: Byte): Byte = (this * b).toByte() } /** @@ -229,19 +229,19 @@ public object ByteRing : Ring, Norm, NumericAlgebra { */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object LongRing : Ring, Norm, NumericAlgebra { - public override inline val zero: Long + override inline val zero: Long get() = 0L - public override inline val one: Long + override inline val one: Long get() = 1L - public override fun number(value: Number): Long = value.toLong() - public override inline fun add(a: Long, b: Long): Long = a + b - public override inline fun multiply(a: Long, b: Long): Long = a * b - public override fun norm(arg: Long): Long = abs(arg) + override fun number(value: Number): Long = value.toLong() + override inline fun add(a: Long, b: Long): Long = a + b + override inline fun multiply(a: Long, b: Long): Long = a * b + override fun norm(arg: Long): Long = abs(arg) - public override inline fun Long.unaryMinus(): Long = (-this) - public override inline fun Long.plus(b: Long): Long = (this + b) - public override inline fun Long.minus(b: Long): Long = (this - b) - public override inline fun Long.times(b: Long): Long = (this * b) + override inline fun Long.unaryMinus(): Long = (-this) + override inline fun Long.plus(b: Long): Long = (this + b) + override inline fun Long.minus(b: Long): Long = (this - b) + override inline fun Long.times(b: Long): Long = (this * b) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt index 34b5e373b..c83496853 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt @@ -19,7 +19,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, b: Buffer): DoubleBuffer { + override fun add(a: Buffer, b: Buffer): DoubleBuffer { require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } @@ -31,7 +31,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, k: Number): RealBuffer { +// override fun multiply(a: Buffer, k: Number): RealBuffer { // val kValue = k.toDouble() // // return if (a is RealBuffer) { @@ -40,7 +40,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, k: Number): RealBuffer { +// override fun divide(a: Buffer, k: Number): RealBuffer { // val kValue = k.toDouble() // // return if (a is RealBuffer) { @@ -49,7 +49,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, b: Buffer): DoubleBuffer { + override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } @@ -62,7 +62,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, b: Buffer): DoubleBuffer { + override fun divide(a: Buffer, b: Buffer): DoubleBuffer { require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } @@ -74,87 +74,87 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations): DoubleBuffer = if (arg is DoubleBuffer) { + override fun sin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) }) - public override fun cos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun cos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) }) - public override fun tan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun tan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { tan(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { tan(arg[it]) }) - public override fun asin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun asin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { asin(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { asin(arg[it]) }) - public override fun acos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun acos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { acos(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { acos(arg[it]) }) - public override fun atan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun atan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { atan(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { atan(arg[it]) }) - public override fun sinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun sinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { sinh(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { sinh(arg[it]) }) - public override fun cosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun cosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { cosh(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { cosh(arg[it]) }) - public override fun tanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun tanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { tanh(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { tanh(arg[it]) }) - public override fun asinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun asinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { asinh(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { asinh(arg[it]) }) - public override fun acosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun acosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { acosh(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { acosh(arg[it]) }) - public override fun atanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun atanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { atanh(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { atanh(arg[it]) }) - public override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (arg is DoubleBuffer) { + override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) }) } else DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) }) - public override fun exp(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun exp(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) }) } else DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) }) - public override fun ln(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun ln(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) }) } else @@ -167,8 +167,8 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations> { - public override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } - public override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } + override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } + override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } override fun number(value: Number): Buffer = DoubleBuffer(size) { value.toDouble() } @@ -176,12 +176,12 @@ public class DoubleBufferField(public val size: Int) : ExtendedField, b: Buffer): DoubleBuffer { + override fun add(a: Buffer, b: Buffer): DoubleBuffer { require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } return DoubleBufferFieldOperations.add(a, b) } - public override fun scale(a: Buffer, value: Double): DoubleBuffer { + override fun scale(a: Buffer, value: Double): DoubleBuffer { require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } return if (a is DoubleBuffer) { @@ -190,87 +190,87 @@ public class DoubleBufferField(public val size: Int) : ExtendedField, b: Buffer): DoubleBuffer { + override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } return DoubleBufferFieldOperations.multiply(a, b) } - public override fun divide(a: Buffer, b: Buffer): DoubleBuffer { + override fun divide(a: Buffer, b: Buffer): DoubleBuffer { require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } return DoubleBufferFieldOperations.divide(a, b) } - public override fun sin(arg: Buffer): DoubleBuffer { + override fun sin(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.sin(arg) } - public override fun cos(arg: Buffer): DoubleBuffer { + override fun cos(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.cos(arg) } - public override fun tan(arg: Buffer): DoubleBuffer { + override fun tan(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.tan(arg) } - public override fun asin(arg: Buffer): DoubleBuffer { + override fun asin(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.asin(arg) } - public override fun acos(arg: Buffer): DoubleBuffer { + override fun acos(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.acos(arg) } - public override fun atan(arg: Buffer): DoubleBuffer { + override fun atan(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.atan(arg) } - public override fun sinh(arg: Buffer): DoubleBuffer { + override fun sinh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.sinh(arg) } - public override fun cosh(arg: Buffer): DoubleBuffer { + override fun cosh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.cosh(arg) } - public override fun tanh(arg: Buffer): DoubleBuffer { + override fun tanh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.tanh(arg) } - public override fun asinh(arg: Buffer): DoubleBuffer { + override fun asinh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.asinh(arg) } - public override fun acosh(arg: Buffer): DoubleBuffer { + override fun acosh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.acosh(arg) } - public override fun atanh(arg: Buffer): DoubleBuffer { + override fun atanh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.atanh(arg) } - public override fun power(arg: Buffer, pow: Number): DoubleBuffer { + override fun power(arg: Buffer, pow: Number): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.power(arg, pow) } - public override fun exp(arg: Buffer): DoubleBuffer { + override fun exp(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.exp(arg) } - public override fun ln(arg: Buffer): DoubleBuffer { + override fun ln(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } return DoubleBufferFieldOperations.ln(arg) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt index 8c98ab9c8..5d660c8cb 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt @@ -48,8 +48,8 @@ public class MutableMemoryBuffer(memory: Memory, spec: MemorySpec) : private val writer: MemoryWriter = memory.writer() - public override operator fun set(index: Int, value: T): Unit = writer.write(spec, spec.objectSize * index, value) - public override fun copy(): MutableBuffer = MutableMemoryBuffer(memory.copy(), spec) + override operator fun set(index: Int, value: T): Unit = writer.write(spec, spec.objectSize * index, value) + override fun copy(): MutableBuffer = MutableMemoryBuffer(memory.copy(), spec) public companion object { public fun create(spec: MemorySpec, size: Int): MutableMemoryBuffer = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt index 3d4c68b3c..8dadecff7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt @@ -14,16 +14,16 @@ import kotlin.jvm.JvmInline */ @JvmInline public value class ShortBuffer(public val array: ShortArray) : MutableBuffer { - public override val size: Int get() = array.size + override val size: Int get() = array.size - public override operator fun get(index: Int): Short = array[index] + override operator fun get(index: Int): Short = array[index] - public override operator fun set(index: Int, value: Short) { + override operator fun set(index: Int, value: Short) { array[index] = value } - public override operator fun iterator(): ShortIterator = array.iterator() - public override fun copy(): MutableBuffer = ShortBuffer(array.copyOf()) + override operator fun iterator(): ShortIterator = array.iterator() + override fun copy(): MutableBuffer = ShortBuffer(array.copyOf()) } /** diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt index 9b46369bb..7ac2c6f83 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt @@ -13,16 +13,16 @@ import java.math.MathContext * A field over [BigInteger]. */ public object JBigIntegerField : Ring, NumericAlgebra { - public override val zero: BigInteger get() = BigInteger.ZERO + override val zero: BigInteger get() = BigInteger.ZERO - public override val one: BigInteger get() = BigInteger.ONE + override val one: BigInteger get() = BigInteger.ONE - public override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong()) - public override fun add(a: BigInteger, b: BigInteger): BigInteger = a.add(b) - public override operator fun BigInteger.minus(b: BigInteger): BigInteger = subtract(b) - public override fun multiply(a: BigInteger, b: BigInteger): BigInteger = a.multiply(b) + override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong()) + override fun add(a: BigInteger, b: BigInteger): BigInteger = a.add(b) + override operator fun BigInteger.minus(b: BigInteger): BigInteger = subtract(b) + override fun multiply(a: BigInteger, b: BigInteger): BigInteger = a.multiply(b) - public override operator fun BigInteger.unaryMinus(): BigInteger = negate() + override operator fun BigInteger.unaryMinus(): BigInteger = negate() } /** @@ -33,24 +33,24 @@ public object JBigIntegerField : Ring, NumericAlgebra { public abstract class JBigDecimalFieldBase internal constructor( private val mathContext: MathContext = MathContext.DECIMAL64, ) : Field, PowerOperations, NumericAlgebra, ScaleOperations { - public override val zero: BigDecimal + override val zero: BigDecimal get() = BigDecimal.ZERO - public override val one: BigDecimal + override val one: BigDecimal get() = BigDecimal.ONE - public override fun add(a: BigDecimal, b: BigDecimal): BigDecimal = a.add(b) - public override operator fun BigDecimal.minus(b: BigDecimal): BigDecimal = subtract(b) - public override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble()) + override fun add(a: BigDecimal, b: BigDecimal): BigDecimal = a.add(b) + override operator fun BigDecimal.minus(b: BigDecimal): BigDecimal = subtract(b) + override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble()) - public override fun scale(a: BigDecimal, value: Double): BigDecimal = + override fun scale(a: BigDecimal, value: Double): BigDecimal = a.multiply(value.toBigDecimal(mathContext), mathContext) - public override fun multiply(a: BigDecimal, b: BigDecimal): BigDecimal = a.multiply(b, mathContext) - public override fun divide(a: BigDecimal, b: BigDecimal): BigDecimal = a.divide(b, mathContext) - public override fun power(arg: BigDecimal, pow: Number): BigDecimal = arg.pow(pow.toInt(), mathContext) - public override fun sqrt(arg: BigDecimal): BigDecimal = arg.sqrt(mathContext) - public override operator fun BigDecimal.unaryMinus(): BigDecimal = negate(mathContext) + override fun multiply(a: BigDecimal, b: BigDecimal): BigDecimal = a.multiply(b, mathContext) + override fun divide(a: BigDecimal, b: BigDecimal): BigDecimal = a.divide(b, mathContext) + override fun power(arg: BigDecimal, pow: Number): BigDecimal = arg.pow(pow.toInt(), mathContext) + override fun sqrt(arg: BigDecimal): BigDecimal = arg.sqrt(mathContext) + override operator fun BigDecimal.unaryMinus(): BigDecimal = negate(mathContext) } /** diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt index 70849f942..87aebff61 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt @@ -32,9 +32,9 @@ public interface BlockingBufferChain : BlockingChain, BufferChain { public fun nextBufferBlocking(size: Int): Buffer - public override fun nextBlocking(): T = nextBufferBlocking(1)[0] + override fun nextBlocking(): T = nextBufferBlocking(1)[0] - public override suspend fun nextBuffer(size: Int): Buffer = nextBufferBlocking(size) + override suspend fun nextBuffer(size: Int): Buffer = nextBufferBlocking(size) override suspend fun fork(): BlockingBufferChain } 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 88456e124..25e20291e 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 @@ -15,7 +15,7 @@ public interface BlockingDoubleChain : BlockingBufferChain { /** * Returns an [DoubleArray] chunk of [size] values of [next]. */ - public override fun nextBufferBlocking(size: Int): DoubleBuffer + override fun nextBufferBlocking(size: Int): DoubleBuffer override suspend fun fork(): BlockingDoubleChain diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt index b29165e32..8523ac864 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt @@ -39,8 +39,8 @@ public fun Sequence.asChain(): Chain = iterator().asChain() * A simple chain of independent tokens. [fork] returns the same chain. */ public class SimpleChain(private val gen: suspend () -> R) : Chain { - public override suspend fun next(): R = gen() - public override suspend fun fork(): Chain = this + override suspend fun next(): R = gen() + override suspend fun fork(): Chain = this } /** @@ -52,13 +52,13 @@ public class MarkovChain(private val seed: suspend () -> R, private public fun value(): R? = value - public override suspend fun next(): R = mutex.withLock { + override suspend fun next(): R = mutex.withLock { val newValue = gen(value ?: seed()) value = newValue newValue } - public override suspend fun fork(): Chain = MarkovChain(seed = { value ?: seed() }, gen = gen) + override suspend fun fork(): Chain = MarkovChain(seed = { value ?: seed() }, gen = gen) } /** @@ -77,21 +77,21 @@ public class StatefulChain( public fun value(): R? = value - public override suspend fun next(): R = mutex.withLock { + override suspend fun next(): R = mutex.withLock { val newValue = state.gen(value ?: state.seed()) value = newValue newValue } - public override suspend fun fork(): Chain = StatefulChain(forkState(state), seed, forkState, gen) + override suspend fun fork(): Chain = StatefulChain(forkState(state), seed, forkState, gen) } /** * A chain that repeats the same value */ public class ConstantChain(public val value: T) : Chain { - public override suspend fun next(): T = value - public override suspend fun fork(): Chain = this + override suspend fun next(): T = value + override suspend fun fork(): Chain = this } /** diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt index 05f2876e3..93c4a401b 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt @@ -22,10 +22,10 @@ public class RingBuffer( ) : Buffer { private val mutex: Mutex = Mutex() - public override var size: Int = size + override var size: Int = size private set - public override operator fun get(index: Int): T { + override operator fun get(index: Int): T { require(index >= 0) { "Index must be positive" } require(index < size) { "Index $index is out of circular buffer size $size" } return buffer[startIndex.forward(index)] as T @@ -36,7 +36,7 @@ public class RingBuffer( /** * Iterator could provide wrong results if buffer is changed in initialization (iteration is safe) */ - public override operator fun iterator(): Iterator = object : AbstractIterator() { + override operator fun iterator(): Iterator = object : AbstractIterator() { private var count = size private var index = startIndex val copy = buffer.copy() diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt index ded8c9c44..f9ef62529 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt @@ -13,7 +13,7 @@ import space.kscience.kmath.nd.StructureND public class LazyStructureND( public val scope: CoroutineScope, - public override val shape: IntArray, + override val shape: IntArray, public val function: suspend (IntArray) -> T, ) : StructureND { private val cache: MutableMap> = HashMap() @@ -23,10 +23,10 @@ public class LazyStructureND( } public suspend fun await(index: IntArray): T = deferred(index).await() - public override operator fun get(index: IntArray): T = runBlocking { deferred(index).await() } + override operator fun get(index: IntArray): T = runBlocking { deferred(index).await() } @OptIn(PerformancePitfall::class) - public override fun elements(): Sequence> { + override fun elements(): Sequence> { val strides = DefaultStrides(shape) val res = runBlocking { strides.indices().toList().map { index -> index to await(index) } } return res.asSequence() diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt index cec31eb7d..27fd3fc53 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt @@ -17,6 +17,6 @@ import space.kscience.kmath.nd.Structure2D * @author Iaroslav Postovalov */ public abstract class EjmlMatrix(public open val origin: M) : Structure2D { - public override val rowNum: Int get() = origin.numRows - public override val colNum: Int get() = origin.numCols + override val rowNum: Int get() = origin.numRows + override val colNum: Int get() = origin.numCols } diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt index 5d10d1fbb..37995c27e 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt @@ -17,10 +17,10 @@ import space.kscience.kmath.linear.Point * @author Iaroslav Postovalov */ public abstract class EjmlVector(public open val origin: M) : Point { - public override val size: Int + override val size: Int get() = origin.numCols - public override operator fun iterator(): Iterator = object : Iterator { + override operator fun iterator(): Iterator = object : Iterator { private var cursor: Int = 0 override fun next(): T { @@ -31,5 +31,5 @@ public abstract class EjmlVector(public open val origin: override fun hasNext(): Boolean = cursor < origin.numCols * origin.numRows } - public override fun toString(): String = "EjmlVector(origin=$origin)" + override fun toString(): String = "EjmlVector(origin=$origin)" } diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt index 139c55697..5de8fc8a5 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt @@ -34,37 +34,37 @@ import kotlin.reflect.cast /** * [EjmlVector] specialization for [Double]. */ -public class EjmlDoubleVector(public override val origin: M) : EjmlVector(origin) { +public class EjmlDoubleVector(override val origin: M) : EjmlVector(origin) { init { require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } } - public override operator fun get(index: Int): Double = origin[0, index] + override operator fun get(index: Int): Double = origin[0, index] } /** * [EjmlVector] specialization for [Float]. */ -public class EjmlFloatVector(public override val origin: M) : EjmlVector(origin) { +public class EjmlFloatVector(override val origin: M) : EjmlVector(origin) { init { require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } } - public override operator fun get(index: Int): Float = origin[0, index] + override operator fun get(index: Int): Float = origin[0, index] } /** * [EjmlMatrix] specialization for [Double]. */ -public class EjmlDoubleMatrix(public override val origin: M) : EjmlMatrix(origin) { - public override operator fun get(i: Int, j: Int): Double = origin[i, j] +public class EjmlDoubleMatrix(override val origin: M) : EjmlMatrix(origin) { + override operator fun get(i: Int, j: Int): Double = origin[i, j] } /** * [EjmlMatrix] specialization for [Float]. */ -public class EjmlFloatMatrix(public override val origin: M) : EjmlMatrix(origin) { - public override operator fun get(i: Int, j: Int): Float = origin[i, j] +public class EjmlFloatMatrix(override val origin: M) : EjmlMatrix(origin) { + override operator fun get(i: Int, j: Int): Float = origin[i, j] } /** @@ -75,23 +75,23 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace.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") - public 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) } }) } - public override fun buildMatrix( + override fun buildMatrix( rows: Int, columns: Int, initializer: DoubleField.(i: Int, j: Int) -> Double, @@ -101,7 +101,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace Double, ): EjmlDoubleVector = EjmlDoubleVector(DMatrixRMaj(size, 1).also { @@ -111,21 +111,21 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace T.wrapMatrix() = EjmlDoubleMatrix(this) private fun T.wrapVector() = EjmlDoubleVector(this) - public override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - public 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() } - public 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() } - public override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { + override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.add( @@ -139,19 +139,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() } - public override fun Point.unaryMinus(): EjmlDoubleVector { + override fun Point.unaryMinus(): EjmlDoubleVector { val res = DMatrixRMaj(1, 1) CommonOps_DDRM.changeSign(toEjml().origin, res) return res.wrapVector() } - public override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { + override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.add( @@ -165,7 +165,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace.plus(other: Point): EjmlDoubleVector { + override fun Point.plus(other: Point): EjmlDoubleVector { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.add( @@ -179,7 +179,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace.minus(other: Point): EjmlDoubleVector { + override fun Point.minus(other: Point): EjmlDoubleVector { val out = DMatrixRMaj(1, 1) CommonOps_DDRM.add( @@ -193,18 +193,18 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace): EjmlDoubleMatrix = m * this + override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - public 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() } - public override fun Double.times(v: Point): EjmlDoubleVector = v * this + override fun Double.times(v: Point): EjmlDoubleVector = v * this @UnstableKMathAPI - public override fun getFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin @@ -309,23 +309,23 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace.toEjml(): EjmlFloatMatrix = when { + override fun Matrix.toEjml(): EjmlFloatMatrix = when { this is EjmlFloatMatrix<*> && origin is FMatrixRMaj -> this as EjmlFloatMatrix else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } } @Suppress("UNCHECKED_CAST") - public override fun Point.toEjml(): EjmlFloatVector = when { + override fun Point.toEjml(): EjmlFloatVector = when { this is EjmlFloatVector<*> && origin is FMatrixRMaj -> this as EjmlFloatVector else -> EjmlFloatVector(FMatrixRMaj(size, 1).also { (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } }) } - public override fun buildMatrix( + override fun buildMatrix( rows: Int, columns: Int, initializer: FloatField.(i: Int, j: Int) -> Float, @@ -335,7 +335,7 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace Float, ): EjmlFloatVector = EjmlFloatVector(FMatrixRMaj(size, 1).also { @@ -345,21 +345,21 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace T.wrapMatrix() = EjmlFloatMatrix(this) private fun T.wrapVector() = EjmlFloatVector(this) - public override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - public override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { + override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { val out = FMatrixRMaj(1, 1) CommonOps_FDRM.mult(toEjml().origin, other.toEjml().origin, out) return out.wrapMatrix() } - public override fun Matrix.dot(vector: Point): EjmlFloatVector { + override fun Matrix.dot(vector: Point): EjmlFloatVector { val out = FMatrixRMaj(1, 1) CommonOps_FDRM.mult(toEjml().origin, vector.toEjml().origin, out) return out.wrapVector() } - public override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { + override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { val out = FMatrixRMaj(1, 1) CommonOps_FDRM.add( @@ -373,19 +373,19 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace.times(value: Float): EjmlFloatMatrix { + override operator fun Matrix.times(value: Float): EjmlFloatMatrix { val res = FMatrixRMaj(1, 1) CommonOps_FDRM.scale(value, toEjml().origin, res) return res.wrapMatrix() } - public override fun Point.unaryMinus(): EjmlFloatVector { + override fun Point.unaryMinus(): EjmlFloatVector { val res = FMatrixRMaj(1, 1) CommonOps_FDRM.changeSign(toEjml().origin, res) return res.wrapVector() } - public override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { + override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { val out = FMatrixRMaj(1, 1) CommonOps_FDRM.add( @@ -399,7 +399,7 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace.plus(other: Point): EjmlFloatVector { + override fun Point.plus(other: Point): EjmlFloatVector { val out = FMatrixRMaj(1, 1) CommonOps_FDRM.add( @@ -413,7 +413,7 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace.minus(other: Point): EjmlFloatVector { + override fun Point.minus(other: Point): EjmlFloatVector { val out = FMatrixRMaj(1, 1) CommonOps_FDRM.add( @@ -427,18 +427,18 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace): EjmlFloatMatrix = m * this + override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - public override fun Point.times(value: Float): EjmlFloatVector { + override fun Point.times(value: Float): EjmlFloatVector { val res = FMatrixRMaj(1, 1) CommonOps_FDRM.scale(value, toEjml().origin, res) return res.wrapVector() } - public override fun Float.times(v: Point): EjmlFloatVector = v * this + override fun Float.times(v: Point): EjmlFloatVector = v * this @UnstableKMathAPI - public override fun getFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin @@ -543,23 +543,23 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace.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") - public 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) } }) } - public override fun buildMatrix( + override fun buildMatrix( rows: Int, columns: Int, initializer: DoubleField.(i: Int, j: Int) -> Double, @@ -569,7 +569,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace Double, ): EjmlDoubleVector = EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { @@ -579,21 +579,21 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace T.wrapMatrix() = EjmlDoubleMatrix(this) private fun T.wrapVector() = EjmlDoubleVector(this) - public override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - public 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() } - public 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() } - public override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { + override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.add( @@ -609,19 +609,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() } - public override fun Point.unaryMinus(): EjmlDoubleVector { + override fun Point.unaryMinus(): EjmlDoubleVector { val res = DMatrixSparseCSC(1, 1) CommonOps_DSCC.changeSign(toEjml().origin, res) return res.wrapVector() } - public override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { + override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.add( @@ -637,7 +637,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace.plus(other: Point): EjmlDoubleVector { + override fun Point.plus(other: Point): EjmlDoubleVector { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.add( @@ -653,7 +653,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace.minus(other: Point): EjmlDoubleVector { + override fun Point.minus(other: Point): EjmlDoubleVector { val out = DMatrixSparseCSC(1, 1) CommonOps_DSCC.add( @@ -669,18 +669,18 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace): EjmlDoubleMatrix = m * this + override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - public 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() } - public override fun Double.times(v: Point): EjmlDoubleVector = v * this + override fun Double.times(v: Point): EjmlDoubleVector = v * this @UnstableKMathAPI - public override fun getFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin @@ -772,23 +772,23 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace.toEjml(): EjmlFloatMatrix = when { + override fun Matrix.toEjml(): EjmlFloatMatrix = when { this is EjmlFloatMatrix<*> && origin is FMatrixSparseCSC -> this as EjmlFloatMatrix else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } } @Suppress("UNCHECKED_CAST") - public override fun Point.toEjml(): EjmlFloatVector = when { + override fun Point.toEjml(): EjmlFloatVector = when { this is EjmlFloatVector<*> && origin is FMatrixSparseCSC -> this as EjmlFloatVector else -> EjmlFloatVector(FMatrixSparseCSC(size, 1).also { (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } }) } - public override fun buildMatrix( + override fun buildMatrix( rows: Int, columns: Int, initializer: FloatField.(i: Int, j: Int) -> Float, @@ -798,7 +798,7 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace Float, ): EjmlFloatVector = EjmlFloatVector(FMatrixSparseCSC(size, 1).also { @@ -808,21 +808,21 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace T.wrapMatrix() = EjmlFloatMatrix(this) private fun T.wrapVector() = EjmlFloatVector(this) - public override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - public override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { + override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { val out = FMatrixSparseCSC(1, 1) CommonOps_FSCC.mult(toEjml().origin, other.toEjml().origin, out) return out.wrapMatrix() } - public override fun Matrix.dot(vector: Point): EjmlFloatVector { + override fun Matrix.dot(vector: Point): EjmlFloatVector { val out = FMatrixSparseCSC(1, 1) CommonOps_FSCC.mult(toEjml().origin, vector.toEjml().origin, out) return out.wrapVector() } - public override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { + override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { val out = FMatrixSparseCSC(1, 1) CommonOps_FSCC.add( @@ -838,19 +838,19 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace.times(value: Float): EjmlFloatMatrix { + override operator fun Matrix.times(value: Float): EjmlFloatMatrix { val res = FMatrixSparseCSC(1, 1) CommonOps_FSCC.scale(value, toEjml().origin, res) return res.wrapMatrix() } - public override fun Point.unaryMinus(): EjmlFloatVector { + override fun Point.unaryMinus(): EjmlFloatVector { val res = FMatrixSparseCSC(1, 1) CommonOps_FSCC.changeSign(toEjml().origin, res) return res.wrapVector() } - public override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { + override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { val out = FMatrixSparseCSC(1, 1) CommonOps_FSCC.add( @@ -866,7 +866,7 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace.plus(other: Point): EjmlFloatVector { + override fun Point.plus(other: Point): EjmlFloatVector { val out = FMatrixSparseCSC(1, 1) CommonOps_FSCC.add( @@ -882,7 +882,7 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace.minus(other: Point): EjmlFloatVector { + override fun Point.minus(other: Point): EjmlFloatVector { val out = FMatrixSparseCSC(1, 1) CommonOps_FSCC.add( @@ -898,18 +898,18 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace): EjmlFloatMatrix = m * this + override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - public override fun Point.times(value: Float): EjmlFloatVector { + override fun Point.times(value: Float): EjmlFloatVector { val res = FMatrixSparseCSC(1, 1) CommonOps_FSCC.scale(value, toEjml().origin, res) return res.wrapVector() } - public override fun Float.times(v: Point): EjmlFloatVector = v * this + override fun Float.times(v: Point): EjmlFloatVector = v * this @UnstableKMathAPI - public override fun getFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 5f35d0ab6..a2ad5801c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -30,7 +30,7 @@ public fun interface Piecewise { public interface PiecewisePolynomial> : Piecewise> { public val pieces: Collection, Polynomial>> - public override fun findPiece(arg: T): Polynomial? + override fun findPiece(arg: T): Polynomial? } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index f0c858b03..f0f744530 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -98,13 +98,13 @@ public fun > Polynomial.integrate( public class PolynomialSpace( private val ring: C, ) : Group>, ScaleOperations> where C : Ring, C : ScaleOperations { - public override val zero: Polynomial = Polynomial(emptyList()) + override val zero: Polynomial = Polynomial(emptyList()) override fun Polynomial.unaryMinus(): Polynomial = ring { Polynomial(coefficients.map { -it }) } - public override fun add(a: Polynomial, b: Polynomial): Polynomial { + override fun add(a: Polynomial, b: Polynomial): Polynomial { val dim = max(a.coefficients.size, b.coefficients.size) return ring { @@ -114,7 +114,7 @@ public class PolynomialSpace( } } - public override fun scale(a: Polynomial, value: Double): Polynomial = + override fun scale(a: Polynomial, value: Double): Polynomial = ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt index 24c049647..edd0e6b0a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -21,9 +21,9 @@ internal fun > insureSorted(points: XYColumnarData<*, T, *>) { /** * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java */ -public class LinearInterpolator>(public override val algebra: Field) : PolynomialInterpolator { +public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { @OptIn(UnstableKMathAPI::class) - public override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { require(points.size > 0) { "Point array should not be empty" } insureSorted(points) 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 bf291c315..39c33ee69 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 @@ -23,13 +23,13 @@ import space.kscience.kmath.structures.MutableBufferFactory * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java */ public class SplineInterpolator>( - public override val algebra: Field, + override val algebra: Field, public val bufferFactory: MutableBufferFactory, ) : PolynomialInterpolator { //TODO possibly optimize zeroed buffers @OptIn(UnstableKMathAPI::class) - public override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } insureSorted(points) // Number of intervals. The number of data points is n + 1. diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt index 2a4837ee0..2b91c2334 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt @@ -15,15 +15,15 @@ import kotlin.math.sqrt public interface Vector2D : Point, Vector{ public val x: Double public val y: Double - public override val size: Int get() = 2 + override val size: Int get() = 2 - public override operator fun get(index: Int): Double = when (index) { + override operator fun get(index: Int): Double = when (index) { 1 -> x 2 -> y else -> error("Accessing outside of point bounds") } - public override operator fun iterator(): Iterator = listOf(x, y).iterator() + override operator fun iterator(): Iterator = listOf(x, y).iterator() } public val Vector2D.r: Double @@ -41,13 +41,13 @@ private data class Vector2DImpl( * 2D Euclidean space */ public object Euclidean2DSpace : GeometrySpace, ScaleOperations { - public override val zero: Vector2D by lazy { Vector2D(0.0, 0.0) } + override val zero: Vector2D by lazy { Vector2D(0.0, 0.0) } public fun Vector2D.norm(): Double = sqrt(x * x + y * y) override fun Vector2D.unaryMinus(): Vector2D = Vector2D(-x, -y) - public override fun Vector2D.distanceTo(other: Vector2D): Double = (this - other).norm() - public override fun add(a: Vector2D, b: Vector2D): Vector2D = Vector2D(a.x + b.x, a.y + b.y) - public override fun scale(a: Vector2D, value: Double): Vector2D = Vector2D(a.x * value, a.y * value) - public override fun Vector2D.dot(other: Vector2D): Double = x * other.x + y * other.y + override fun Vector2D.distanceTo(other: Vector2D): Double = (this - other).norm() + override fun add(a: Vector2D, b: Vector2D): Vector2D = Vector2D(a.x + b.x, a.y + b.y) + override fun scale(a: Vector2D, value: Double): Vector2D = Vector2D(a.x * value, a.y * value) + override fun Vector2D.dot(other: Vector2D): Double = x * other.x + y * other.y } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt index 37e7d2cb2..628106b0b 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt @@ -16,16 +16,16 @@ public interface Vector3D : Point, Vector { public val x: Double public val y: Double public val z: Double - public override val size: Int get() = 3 + override val size: Int get() = 3 - public override operator fun get(index: Int): Double = when (index) { + override operator fun get(index: Int): Double = when (index) { 1 -> x 2 -> y 3 -> z else -> error("Accessing outside of point bounds") } - public override operator fun iterator(): Iterator = listOf(x, y, z).iterator() + override operator fun iterator(): Iterator = listOf(x, y, z).iterator() } @Suppress("FunctionName") @@ -40,19 +40,19 @@ private data class Vector3DImpl( ) : Vector3D public object Euclidean3DSpace : GeometrySpace, ScaleOperations { - public override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) } + override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) } public fun Vector3D.norm(): Double = sqrt(x * x + y * y + z * z) override fun Vector3D.unaryMinus(): Vector3D = Vector3D(-x, -y, -z) - public override fun Vector3D.distanceTo(other: Vector3D): Double = (this - other).norm() + override fun Vector3D.distanceTo(other: Vector3D): Double = (this - other).norm() - public override fun add(a: Vector3D, b: Vector3D): Vector3D = + override fun add(a: Vector3D, b: Vector3D): Vector3D = Vector3D(a.x + b.x, a.y + b.y, a.z + b.z) - public override fun scale(a: Vector3D, value: Double): Vector3D = + override fun scale(a: Vector3D, value: Double): Vector3D = Vector3D(a.x * value, a.y * value, a.z * value) - public override fun Vector3D.dot(other: Vector3D): Double = + override fun Vector3D.dot(other: Vector3D): Double = x * other.x + y * other.y + z * other.z } diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt index 6d48d3738..79b6b4e02 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt @@ -20,7 +20,7 @@ import space.kscience.kmath.operations.invoke */ public data class DomainBin>( public val domain: Domain, - public override val value: Number, + override val value: Number, ) : Bin, Domain by domain @OptIn(UnstableKMathAPI::class) diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt index 0ad96ad46..f461ee4fa 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt @@ -27,15 +27,15 @@ public class UnivariateBin( public val standardDeviation: Double, ) : Bin, ClosedFloatingPointRange by domain.range { - public override val dimension: Int get() = 1 + override val dimension: Int get() = 1 - public override fun contains(point: Buffer): Boolean = point.size == 1 && contains(point[0]) + override fun contains(point: Buffer): Boolean = point.size == 1 && contains(point[0]) } @OptIn(UnstableKMathAPI::class) public interface UnivariateHistogram : Histogram{ public operator fun get(value: Double): UnivariateBin? - public override operator fun get(point: Buffer): UnivariateBin? = get(point[0]) + override operator fun get(point: Buffer): UnivariateBin? = get(point[0]) public companion object { /** 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 cf6f9471d..a30020dff 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 @@ -12,50 +12,50 @@ import space.kscience.kmath.operations.ScaleOperations */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object JafamaDoubleField : ExtendedField, Norm, ScaleOperations { - public override inline val zero: Double get() = 0.0 - public override inline val one: Double get() = 1.0 + override inline val zero: Double get() = 0.0 + override inline val one: Double get() = 1.0 - public override inline fun number(value: Number): Double = value.toDouble() + override inline fun number(value: Number): Double = value.toDouble() - public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = + override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - public override inline fun add(a: Double, b: Double): Double = a + b + override inline fun add(a: Double, b: Double): Double = a + b - public override inline fun multiply(a: Double, b: Double): Double = a * b - public override inline fun divide(a: Double, b: Double): Double = a / b + override inline fun multiply(a: Double, b: Double): Double = a * b + override inline fun divide(a: Double, b: Double): Double = a / b - public override inline fun scale(a: Double, value: Double): Double = a * value + override inline fun scale(a: Double, value: Double): Double = a * value - public override inline fun sin(arg: Double): Double = FastMath.sin(arg) - public override inline fun cos(arg: Double): Double = FastMath.cos(arg) - public override inline fun tan(arg: Double): Double = FastMath.tan(arg) - public override inline fun acos(arg: Double): Double = FastMath.acos(arg) - public override inline fun asin(arg: Double): Double = FastMath.asin(arg) - public override inline fun atan(arg: Double): Double = FastMath.atan(arg) + override inline fun sin(arg: Double): Double = FastMath.sin(arg) + override inline fun cos(arg: Double): Double = FastMath.cos(arg) + override inline fun tan(arg: Double): Double = FastMath.tan(arg) + override inline fun acos(arg: Double): Double = FastMath.acos(arg) + override inline fun asin(arg: Double): Double = FastMath.asin(arg) + override inline fun atan(arg: Double): Double = FastMath.atan(arg) - public override inline fun sinh(arg: Double): Double = FastMath.sinh(arg) - public override inline fun cosh(arg: Double): Double = FastMath.cosh(arg) - public override inline fun tanh(arg: Double): Double = FastMath.tanh(arg) - public override inline fun asinh(arg: Double): Double = FastMath.asinh(arg) - public override inline fun acosh(arg: Double): Double = FastMath.acosh(arg) - public override inline fun atanh(arg: Double): Double = FastMath.atanh(arg) + override inline fun sinh(arg: Double): Double = FastMath.sinh(arg) + override inline fun cosh(arg: Double): Double = FastMath.cosh(arg) + override inline fun tanh(arg: Double): Double = FastMath.tanh(arg) + override inline fun asinh(arg: Double): Double = FastMath.asinh(arg) + override inline fun acosh(arg: Double): Double = FastMath.acosh(arg) + override inline fun atanh(arg: Double): Double = FastMath.atanh(arg) - public override inline fun sqrt(arg: Double): Double = FastMath.sqrt(arg) - public override inline fun power(arg: Double, pow: Number): Double = FastMath.pow(arg, pow.toDouble()) - public override inline fun exp(arg: Double): Double = FastMath.exp(arg) - public override inline fun ln(arg: Double): Double = FastMath.log(arg) + override inline fun sqrt(arg: Double): Double = FastMath.sqrt(arg) + override inline fun power(arg: Double, pow: Number): Double = FastMath.pow(arg, pow.toDouble()) + override inline fun exp(arg: Double): Double = FastMath.exp(arg) + override inline fun ln(arg: Double): Double = FastMath.log(arg) - public override inline fun norm(arg: Double): Double = FastMath.abs(arg) + override inline fun norm(arg: Double): Double = FastMath.abs(arg) - public override inline fun Double.unaryMinus(): Double = -this - public override inline fun Double.plus(b: Double): Double = this + b - public override inline fun Double.minus(b: Double): Double = this - b - public override inline fun Double.times(b: Double): Double = this * b - public override inline fun Double.div(b: Double): Double = this / b + override inline fun Double.unaryMinus(): Double = -this + override inline fun Double.plus(b: Double): Double = this + b + override inline fun Double.minus(b: Double): Double = this - b + override inline fun Double.times(b: Double): Double = this * b + override inline fun Double.div(b: Double): Double = this / b } /** @@ -63,48 +63,48 @@ public object JafamaDoubleField : ExtendedField, Norm, S */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object StrictJafamaDoubleField : ExtendedField, Norm, ScaleOperations { - public override inline val zero: Double get() = 0.0 - public override inline val one: Double get() = 1.0 + override inline val zero: Double get() = 0.0 + override inline val one: Double get() = 1.0 - public override inline fun number(value: Number): Double = value.toDouble() + override inline fun number(value: Number): Double = value.toDouble() - public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = + override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - public override inline fun add(a: Double, b: Double): Double = a + b + override inline fun add(a: Double, b: Double): Double = a + b - public override inline fun multiply(a: Double, b: Double): Double = a * b - public override inline fun divide(a: Double, b: Double): Double = a / b + override inline fun multiply(a: Double, b: Double): Double = a * b + override inline fun divide(a: Double, b: Double): Double = a / b - public override inline fun scale(a: Double, value: Double): Double = a * value + override inline fun scale(a: Double, value: Double): Double = a * value - public override inline fun sin(arg: Double): Double = StrictFastMath.sin(arg) - public override inline fun cos(arg: Double): Double = StrictFastMath.cos(arg) - public override inline fun tan(arg: Double): Double = StrictFastMath.tan(arg) - public override inline fun acos(arg: Double): Double = StrictFastMath.acos(arg) - public override inline fun asin(arg: Double): Double = StrictFastMath.asin(arg) - public override inline fun atan(arg: Double): Double = StrictFastMath.atan(arg) + override inline fun sin(arg: Double): Double = StrictFastMath.sin(arg) + override inline fun cos(arg: Double): Double = StrictFastMath.cos(arg) + override inline fun tan(arg: Double): Double = StrictFastMath.tan(arg) + override inline fun acos(arg: Double): Double = StrictFastMath.acos(arg) + override inline fun asin(arg: Double): Double = StrictFastMath.asin(arg) + override inline fun atan(arg: Double): Double = StrictFastMath.atan(arg) - public override inline fun sinh(arg: Double): Double = StrictFastMath.sinh(arg) - public override inline fun cosh(arg: Double): Double = StrictFastMath.cosh(arg) - public override inline fun tanh(arg: Double): Double = StrictFastMath.tanh(arg) - public override inline fun asinh(arg: Double): Double = StrictFastMath.asinh(arg) - public override inline fun acosh(arg: Double): Double = StrictFastMath.acosh(arg) - public override inline fun atanh(arg: Double): Double = StrictFastMath.atanh(arg) + override inline fun sinh(arg: Double): Double = StrictFastMath.sinh(arg) + override inline fun cosh(arg: Double): Double = StrictFastMath.cosh(arg) + override inline fun tanh(arg: Double): Double = StrictFastMath.tanh(arg) + override inline fun asinh(arg: Double): Double = StrictFastMath.asinh(arg) + override inline fun acosh(arg: Double): Double = StrictFastMath.acosh(arg) + override inline fun atanh(arg: Double): Double = StrictFastMath.atanh(arg) - public override inline fun sqrt(arg: Double): Double = StrictFastMath.sqrt(arg) - public override inline fun power(arg: Double, pow: Number): Double = StrictFastMath.pow(arg, pow.toDouble()) - public override inline fun exp(arg: Double): Double = StrictFastMath.exp(arg) - public override inline fun ln(arg: Double): Double = StrictFastMath.log(arg) + override inline fun sqrt(arg: Double): Double = StrictFastMath.sqrt(arg) + override inline fun power(arg: Double, pow: Number): Double = StrictFastMath.pow(arg, pow.toDouble()) + override inline fun exp(arg: Double): Double = StrictFastMath.exp(arg) + override inline fun ln(arg: Double): Double = StrictFastMath.log(arg) - public override inline fun norm(arg: Double): Double = StrictFastMath.abs(arg) + override inline fun norm(arg: Double): Double = StrictFastMath.abs(arg) - public override inline fun Double.unaryMinus(): Double = -this - public override inline fun Double.plus(b: Double): Double = this + b - public override inline fun Double.minus(b: Double): Double = this - b - public override inline fun Double.times(b: Double): Double = this * b - public override inline fun Double.div(b: Double): Double = this / b + override inline fun Double.unaryMinus(): Double = -this + override inline fun Double.plus(b: Double): Double = this + b + override inline fun Double.minus(b: Double): Double = this - b + override inline fun Double.times(b: Double): Double = this * b + override inline fun Double.div(b: Double): Double = this / b } diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt index 9c9d07b81..f4386f434 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt @@ -16,15 +16,15 @@ import space.kscience.kmath.operations.NumericAlgebra * @property algebra The algebra. * @property value The value of this number. */ -public class KMathNumber(public val algebra: A, public override val value: T) : +public class KMathNumber(public val algebra: A, override val value: T) : SConst>(value) where T : Number, A : NumericAlgebra { /** * Returns a string representation of the [value]. */ - public override fun toString(): String = value.toString() + override fun toString(): String = value.toString() /** * Wraps [Number] to [KMathNumber]. */ - public override fun wrap(number: Number): KMathNumber = KMathNumber(algebra, algebra.number(number)) + override fun wrap(number: Number): KMathNumber = KMathNumber(algebra, algebra.number(number)) } diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt index 28f6cd59e..3a94e8259 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt @@ -25,9 +25,9 @@ public class KotlingradExpression>( public val algebra: A, public val mst: MST, ) : SpecialDifferentiableExpression> { - public override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) + override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) - public override fun derivativeOrNull(symbols: List): KotlingradExpression = + override fun derivativeOrNull(symbols: List): KotlingradExpression = KotlingradExpression( algebra, symbols.map(Symbol::identity) 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 e94bda12a..7a650df3c 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 @@ -39,20 +39,20 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND.ndArray: INDArray - public override fun produce(initializer: C.(IntArray) -> T): Nd4jArrayStructure { + override fun produce(initializer: C.(IntArray) -> T): Nd4jArrayStructure { val struct = Nd4j.create(*shape)!!.wrap() struct.indicesIterator().forEach { struct[it] = elementContext.initializer(it) } return struct } @PerformancePitfall - public override fun StructureND.map(transform: C.(T) -> T): Nd4jArrayStructure { + override fun StructureND.map(transform: C.(T) -> T): Nd4jArrayStructure { val newStruct = ndArray.dup().wrap() newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) } return newStruct } - public override fun StructureND.mapIndexed( + override fun StructureND.mapIndexed( transform: C.(index: IntArray, T) -> T, ): Nd4jArrayStructure { val new = Nd4j.create(*this@Nd4jArrayAlgebra.shape).wrap() @@ -60,7 +60,7 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND, b: StructureND, transform: C.(T, T) -> T, @@ -79,16 +79,16 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND> : GroupND, Nd4jArrayAlgebra { - public override val zero: Nd4jArrayStructure + override val zero: Nd4jArrayStructure get() = Nd4j.zeros(*shape).wrap() - public override fun add(a: StructureND, b: StructureND): Nd4jArrayStructure = + override fun add(a: StructureND, b: StructureND): Nd4jArrayStructure = a.ndArray.add(b.ndArray).wrap() - public override operator fun StructureND.minus(b: StructureND): Nd4jArrayStructure = + override operator fun StructureND.minus(b: StructureND): Nd4jArrayStructure = ndArray.sub(b.ndArray).wrap() - public override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = + override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() public fun multiply(a: StructureND, k: Number): Nd4jArrayStructure = @@ -104,23 +104,23 @@ public sealed interface Nd4jArrayGroup> : GroupND, Nd4j @OptIn(UnstableKMathAPI::class) public sealed interface Nd4jArrayRing> : RingND, Nd4jArrayGroup { - public override val one: Nd4jArrayStructure + override val one: Nd4jArrayStructure get() = Nd4j.ones(*shape).wrap() - public override fun multiply(a: StructureND, b: StructureND): Nd4jArrayStructure = + override fun multiply(a: StructureND, b: StructureND): Nd4jArrayStructure = a.ndArray.mul(b.ndArray).wrap() // -// public override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { +// override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { // check(this) // return ndArray.sub(b).wrap() // } // -// public override operator fun Nd4jArrayStructure.plus(b: Number): Nd4jArrayStructure { +// override operator fun Nd4jArrayStructure.plus(b: Number): Nd4jArrayStructure { // check(this) // return ndArray.add(b).wrap() // } // -// public override operator fun Number.minus(b: Nd4jArrayStructure): Nd4jArrayStructure { +// override operator fun Number.minus(b: Nd4jArrayStructure): Nd4jArrayStructure { // check(b) // return b.ndArray.rsub(this).wrap() // } @@ -153,7 +153,7 @@ public sealed interface Nd4jArrayRing> : RingND, Nd4jAr * @param F the type field of structure elements. */ public sealed interface Nd4jArrayField> : FieldND, Nd4jArrayRing { - public override fun divide(a: StructureND, b: StructureND): Nd4jArrayStructure = + override fun divide(a: StructureND, b: StructureND): Nd4jArrayStructure = a.ndArray.div(b.ndArray).wrap() public operator fun Number.div(b: StructureND): Nd4jArrayStructure = b.ndArray.rdiv(this).wrap() @@ -194,38 +194,38 @@ public sealed interface Nd4jArrayField> : FieldND, Nd4 */ public sealed interface Nd4jArrayExtendedField> : ExtendedField>, Nd4jArrayField { - public override fun sin(arg: StructureND): StructureND = Transforms.sin(arg.ndArray).wrap() - public override fun cos(arg: StructureND): StructureND = Transforms.cos(arg.ndArray).wrap() - public override fun asin(arg: StructureND): StructureND = Transforms.asin(arg.ndArray).wrap() - public override fun acos(arg: StructureND): StructureND = Transforms.acos(arg.ndArray).wrap() - public override fun atan(arg: StructureND): StructureND = Transforms.atan(arg.ndArray).wrap() + override fun sin(arg: StructureND): StructureND = Transforms.sin(arg.ndArray).wrap() + override fun cos(arg: StructureND): StructureND = Transforms.cos(arg.ndArray).wrap() + override fun asin(arg: StructureND): StructureND = Transforms.asin(arg.ndArray).wrap() + override fun acos(arg: StructureND): StructureND = Transforms.acos(arg.ndArray).wrap() + override fun atan(arg: StructureND): StructureND = Transforms.atan(arg.ndArray).wrap() - public override fun power(arg: StructureND, pow: Number): StructureND = + override fun power(arg: StructureND, pow: Number): StructureND = Transforms.pow(arg.ndArray, pow).wrap() - public override fun exp(arg: StructureND): StructureND = Transforms.exp(arg.ndArray).wrap() - public override fun ln(arg: StructureND): StructureND = Transforms.log(arg.ndArray).wrap() - public override fun sqrt(arg: StructureND): StructureND = Transforms.sqrt(arg.ndArray).wrap() - public override fun sinh(arg: StructureND): StructureND = Transforms.sinh(arg.ndArray).wrap() - public override fun cosh(arg: StructureND): StructureND = Transforms.cosh(arg.ndArray).wrap() - public override fun tanh(arg: StructureND): StructureND = Transforms.tanh(arg.ndArray).wrap() + override fun exp(arg: StructureND): StructureND = Transforms.exp(arg.ndArray).wrap() + override fun ln(arg: StructureND): StructureND = Transforms.log(arg.ndArray).wrap() + override fun sqrt(arg: StructureND): StructureND = Transforms.sqrt(arg.ndArray).wrap() + override fun sinh(arg: StructureND): StructureND = Transforms.sinh(arg.ndArray).wrap() + override fun cosh(arg: StructureND): StructureND = Transforms.cosh(arg.ndArray).wrap() + override fun tanh(arg: StructureND): StructureND = Transforms.tanh(arg.ndArray).wrap() - public override fun asinh(arg: StructureND): StructureND = + override fun asinh(arg: StructureND): StructureND = Nd4j.getExecutioner().exec(ASinh(arg.ndArray, arg.ndArray.ulike())).wrap() - public override fun acosh(arg: StructureND): StructureND = + override fun acosh(arg: StructureND): StructureND = Nd4j.getExecutioner().exec(ACosh(arg.ndArray, arg.ndArray.ulike())).wrap() - public override fun atanh(arg: StructureND): StructureND = Transforms.atanh(arg.ndArray).wrap() + override fun atanh(arg: StructureND): StructureND = Transforms.atanh(arg.ndArray).wrap() } /** * Represents [FieldND] over [Nd4jArrayDoubleStructure]. */ -public class DoubleNd4jArrayField(public override val shape: IntArray) : Nd4jArrayExtendedField { - public override val elementContext: DoubleField get() = DoubleField +public class DoubleNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { + override val elementContext: DoubleField get() = DoubleField - public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asDoubleStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asDoubleStructure() @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray @@ -240,27 +240,27 @@ public class DoubleNd4jArrayField(public override val shape: IntArray) : Nd4jArr return a.ndArray.mul(value).wrap() } - public override operator fun StructureND.div(arg: Double): Nd4jArrayStructure { + override operator fun StructureND.div(arg: Double): Nd4jArrayStructure { return ndArray.div(arg).wrap() } - public override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure { + override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure { return ndArray.add(arg).wrap() } - public override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure { + override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure { return ndArray.sub(arg).wrap() } - public override operator fun StructureND.times(arg: Double): Nd4jArrayStructure { + override operator fun StructureND.times(arg: Double): Nd4jArrayStructure { return ndArray.mul(arg).wrap() } - public override operator fun Double.div(arg: StructureND): Nd4jArrayStructure { + override operator fun Double.div(arg: StructureND): Nd4jArrayStructure { return arg.ndArray.rdiv(this).wrap() } - public override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure { + override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure { return arg.ndArray.rsub(this).wrap() } } @@ -268,13 +268,13 @@ public class DoubleNd4jArrayField(public override val shape: IntArray) : Nd4jArr /** * Represents [FieldND] over [Nd4jArrayStructure] of [Float]. */ -public class FloatNd4jArrayField(public override val shape: IntArray) : Nd4jArrayExtendedField { - public override val elementContext: FloatField get() = FloatField +public class FloatNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { + override val elementContext: FloatField get() = FloatField - public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asFloatStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asFloatStructure() @OptIn(PerformancePitfall::class) - public override val StructureND.ndArray: INDArray + override val StructureND.ndArray: INDArray get() = when (this) { is Nd4jArrayStructure -> checkShape(ndArray) else -> Nd4j.zeros(*shape).also { @@ -285,36 +285,36 @@ public class FloatNd4jArrayField(public override val shape: IntArray) : Nd4jArra override fun scale(a: StructureND, value: Double): StructureND = a.ndArray.mul(value).wrap() - public override operator fun StructureND.div(arg: Float): Nd4jArrayStructure = + override operator fun StructureND.div(arg: Float): Nd4jArrayStructure = ndArray.div(arg).wrap() - public override operator fun StructureND.plus(arg: Float): Nd4jArrayStructure = + override operator fun StructureND.plus(arg: Float): Nd4jArrayStructure = ndArray.add(arg).wrap() - public override operator fun StructureND.minus(arg: Float): Nd4jArrayStructure = + override operator fun StructureND.minus(arg: Float): Nd4jArrayStructure = ndArray.sub(arg).wrap() - public override operator fun StructureND.times(arg: Float): Nd4jArrayStructure = + override operator fun StructureND.times(arg: Float): Nd4jArrayStructure = ndArray.mul(arg).wrap() - public override operator fun Float.div(arg: StructureND): Nd4jArrayStructure = + override operator fun Float.div(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rdiv(this).wrap() - public override operator fun Float.minus(arg: StructureND): Nd4jArrayStructure = + override operator fun Float.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() } /** * Represents [RingND] over [Nd4jArrayIntStructure]. */ -public class IntNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayRing { - public override val elementContext: IntRing +public class IntNd4jArrayRing(override val shape: IntArray) : Nd4jArrayRing { + override val elementContext: IntRing get() = IntRing - public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asIntStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asIntStructure() @OptIn(PerformancePitfall::class) - public override val StructureND.ndArray: INDArray + override val StructureND.ndArray: INDArray get() = when (this) { is Nd4jArrayStructure -> checkShape(ndArray) else -> Nd4j.zeros(*shape).also { @@ -322,15 +322,15 @@ public class IntNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayRi } } - public override operator fun StructureND.plus(arg: Int): Nd4jArrayStructure = + override operator fun StructureND.plus(arg: Int): Nd4jArrayStructure = ndArray.add(arg).wrap() - public override operator fun StructureND.minus(arg: Int): Nd4jArrayStructure = + override operator fun StructureND.minus(arg: Int): Nd4jArrayStructure = ndArray.sub(arg).wrap() - public override operator fun StructureND.times(arg: Int): Nd4jArrayStructure = + override operator fun StructureND.times(arg: Int): Nd4jArrayStructure = ndArray.mul(arg).wrap() - public override operator fun Int.minus(arg: StructureND): Nd4jArrayStructure = + override operator fun Int.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() } 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 ffddcef90..97427d5c6 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 @@ -22,13 +22,13 @@ public sealed class Nd4jArrayStructure : MutableStructureND { */ public abstract val ndArray: INDArray - public override val shape: IntArray get() = ndArray.shape().toIntArray() + override val shape: IntArray get() = ndArray.shape().toIntArray() internal abstract fun elementsIterator(): Iterator> internal fun indicesIterator(): Iterator = ndArray.indicesIterator() @PerformancePitfall - public override fun elements(): Sequence> = Sequence(::elementsIterator) + override fun elements(): Sequence> = Sequence(::elementsIterator) } private data class Nd4jArrayIntStructure(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 456f7c2a9..0674c565e 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 @@ -33,105 +33,105 @@ public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra */ public val StructureND.ndArray: INDArray - public override fun T.plus(other: Tensor): Tensor = other.ndArray.add(this).wrap() - public override fun Tensor.plus(value: T): Tensor = ndArray.add(value).wrap() + override fun T.plus(other: Tensor): Tensor = other.ndArray.add(this).wrap() + override fun Tensor.plus(value: T): Tensor = ndArray.add(value).wrap() - public override fun Tensor.plus(other: Tensor): Tensor = ndArray.add(other.ndArray).wrap() + override fun Tensor.plus(other: Tensor): Tensor = ndArray.add(other.ndArray).wrap() - public override fun Tensor.plusAssign(value: T) { + override fun Tensor.plusAssign(value: T) { ndArray.addi(value) } - public override fun Tensor.plusAssign(other: Tensor) { + override fun Tensor.plusAssign(other: Tensor) { ndArray.addi(other.ndArray) } - public override fun T.minus(other: Tensor): Tensor = other.ndArray.rsub(this).wrap() - public override fun Tensor.minus(value: T): Tensor = ndArray.sub(value).wrap() - public override fun Tensor.minus(other: Tensor): Tensor = ndArray.sub(other.ndArray).wrap() + override fun T.minus(other: Tensor): Tensor = other.ndArray.rsub(this).wrap() + override fun Tensor.minus(value: T): Tensor = ndArray.sub(value).wrap() + override fun Tensor.minus(other: Tensor): Tensor = ndArray.sub(other.ndArray).wrap() - public override fun Tensor.minusAssign(value: T) { + override fun Tensor.minusAssign(value: T) { ndArray.rsubi(value) } - public override fun Tensor.minusAssign(other: Tensor) { + override fun Tensor.minusAssign(other: Tensor) { ndArray.subi(other.ndArray) } - public override fun T.times(other: Tensor): Tensor = other.ndArray.mul(this).wrap() + override fun T.times(other: Tensor): Tensor = other.ndArray.mul(this).wrap() - public override fun Tensor.times(value: T): Tensor = + override fun Tensor.times(value: T): Tensor = ndArray.mul(value).wrap() - public override fun Tensor.times(other: Tensor): Tensor = ndArray.mul(other.ndArray).wrap() + override fun Tensor.times(other: Tensor): Tensor = ndArray.mul(other.ndArray).wrap() - public override fun Tensor.timesAssign(value: T) { + override fun Tensor.timesAssign(value: T) { ndArray.muli(value) } - public override fun Tensor.timesAssign(other: Tensor) { + override fun Tensor.timesAssign(other: Tensor) { ndArray.mmuli(other.ndArray) } - public override fun Tensor.unaryMinus(): Tensor = ndArray.neg().wrap() - public override fun Tensor.get(i: Int): Tensor = ndArray.slice(i.toLong()).wrap() - public override fun Tensor.transpose(i: Int, j: Int): Tensor = ndArray.swapAxes(i, j).wrap() - public override fun Tensor.dot(other: Tensor): Tensor = ndArray.mmul(other.ndArray).wrap() + override fun Tensor.unaryMinus(): Tensor = ndArray.neg().wrap() + override fun Tensor.get(i: Int): Tensor = ndArray.slice(i.toLong()).wrap() + override fun Tensor.transpose(i: Int, j: Int): Tensor = ndArray.swapAxes(i, j).wrap() + override fun Tensor.dot(other: Tensor): Tensor = ndArray.mmul(other.ndArray).wrap() - public override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor = ndArray.min(keepDim, dim).wrap() - public override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor = ndArray.sum(keepDim, dim).wrap() - public override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor = ndArray.max(keepDim, dim).wrap() - public override fun Tensor.view(shape: IntArray): Tensor = ndArray.reshape(shape).wrap() - public override fun Tensor.viewAs(other: Tensor): Tensor = view(other.shape) + override fun Tensor.view(shape: IntArray): Tensor = ndArray.reshape(shape).wrap() + override fun Tensor.viewAs(other: Tensor): Tensor = view(other.shape) - public override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor = ndBase.get().argmax(ndArray, keepDim, dim).wrap() - public override fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor = ndArray.mean(keepDim, dim).wrap() + override fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor = ndArray.mean(keepDim, dim).wrap() - public override fun Tensor.exp(): Tensor = Transforms.exp(ndArray).wrap() - public override fun Tensor.ln(): Tensor = Transforms.log(ndArray).wrap() - public override fun Tensor.sqrt(): Tensor = Transforms.sqrt(ndArray).wrap() - public override fun Tensor.cos(): Tensor = Transforms.cos(ndArray).wrap() - public override fun Tensor.acos(): Tensor = Transforms.acos(ndArray).wrap() - public override fun Tensor.cosh(): Tensor = Transforms.cosh(ndArray).wrap() + override fun Tensor.exp(): Tensor = Transforms.exp(ndArray).wrap() + override fun Tensor.ln(): Tensor = Transforms.log(ndArray).wrap() + override fun Tensor.sqrt(): Tensor = Transforms.sqrt(ndArray).wrap() + override fun Tensor.cos(): Tensor = Transforms.cos(ndArray).wrap() + override fun Tensor.acos(): Tensor = Transforms.acos(ndArray).wrap() + override fun Tensor.cosh(): Tensor = Transforms.cosh(ndArray).wrap() - public override fun Tensor.acosh(): Tensor = + override fun Tensor.acosh(): Tensor = Nd4j.getExecutioner().exec(ACosh(ndArray, ndArray.ulike())).wrap() - public override fun Tensor.sin(): Tensor = Transforms.sin(ndArray).wrap() - public override fun Tensor.asin(): Tensor = Transforms.asin(ndArray).wrap() - public override fun Tensor.sinh(): Tensor = Transforms.sinh(ndArray).wrap() + override fun Tensor.sin(): Tensor = Transforms.sin(ndArray).wrap() + override fun Tensor.asin(): Tensor = Transforms.asin(ndArray).wrap() + override fun Tensor.sinh(): Tensor = Transforms.sinh(ndArray).wrap() - public override fun Tensor.asinh(): Tensor = + override fun Tensor.asinh(): Tensor = Nd4j.getExecutioner().exec(ASinh(ndArray, ndArray.ulike())).wrap() - public override fun Tensor.tan(): Tensor = Transforms.tan(ndArray).wrap() - public override fun Tensor.atan(): Tensor = Transforms.atan(ndArray).wrap() - public override fun Tensor.tanh(): Tensor = Transforms.tanh(ndArray).wrap() - public override fun Tensor.atanh(): Tensor = Transforms.atanh(ndArray).wrap() - public override fun Tensor.ceil(): Tensor = Transforms.ceil(ndArray).wrap() - public override fun Tensor.floor(): Tensor = Transforms.floor(ndArray).wrap() - public override fun Tensor.std(dim: Int, keepDim: Boolean): Tensor = ndArray.std(true, keepDim, dim).wrap() - public override fun T.div(other: Tensor): Tensor = other.ndArray.rdiv(this).wrap() - public override fun Tensor.div(value: T): Tensor = ndArray.div(value).wrap() - public override fun Tensor.div(other: Tensor): Tensor = ndArray.div(other.ndArray).wrap() + override fun Tensor.tan(): Tensor = Transforms.tan(ndArray).wrap() + override fun Tensor.atan(): Tensor = Transforms.atan(ndArray).wrap() + override fun Tensor.tanh(): Tensor = Transforms.tanh(ndArray).wrap() + override fun Tensor.atanh(): Tensor = Transforms.atanh(ndArray).wrap() + override fun Tensor.ceil(): Tensor = Transforms.ceil(ndArray).wrap() + override fun Tensor.floor(): Tensor = Transforms.floor(ndArray).wrap() + override fun Tensor.std(dim: Int, keepDim: Boolean): Tensor = ndArray.std(true, keepDim, dim).wrap() + override fun T.div(other: Tensor): Tensor = other.ndArray.rdiv(this).wrap() + override fun Tensor.div(value: T): Tensor = ndArray.div(value).wrap() + override fun Tensor.div(other: Tensor): Tensor = ndArray.div(other.ndArray).wrap() - public override fun Tensor.divAssign(value: T) { + override fun Tensor.divAssign(value: T) { ndArray.divi(value) } - public override fun Tensor.divAssign(other: Tensor) { + override fun Tensor.divAssign(other: Tensor) { ndArray.divi(other.ndArray) } - public override fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor = Nd4j.getExecutioner().exec(Variance(ndArray, true, true, dim)).wrap() private companion object { @@ -143,10 +143,10 @@ public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra * [Double] specialization of [Nd4jTensorAlgebra]. */ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { - public override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() @OptIn(PerformancePitfall::class) - public override val StructureND.ndArray: INDArray + override val StructureND.ndArray: INDArray get() = when (this) { is Nd4jArrayStructure -> ndArray else -> Nd4j.zeros(*shape).also { @@ -154,22 +154,22 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { } } - public override fun Tensor.valueOrNull(): Double? = + override fun Tensor.valueOrNull(): Double? = if (shape contentEquals intArrayOf(1)) ndArray.getDouble(0) else null // TODO rewrite @PerformancePitfall - public override fun diagonalEmbedding( + override fun diagonalEmbedding( diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int, ): Tensor = DoubleTensorAlgebra.diagonalEmbedding(diagonalEntries, offset, dim1, dim2) - public override fun Tensor.sum(): Double = ndArray.sumNumber().toDouble() - public override fun Tensor.min(): Double = ndArray.minNumber().toDouble() - public override fun Tensor.max(): Double = ndArray.maxNumber().toDouble() - public override fun Tensor.mean(): Double = ndArray.meanNumber().toDouble() - public override fun Tensor.std(): Double = ndArray.stdNumber().toDouble() - public override fun Tensor.variance(): Double = ndArray.varNumber().toDouble() + override fun Tensor.sum(): Double = ndArray.sumNumber().toDouble() + override fun Tensor.min(): Double = ndArray.minNumber().toDouble() + override fun Tensor.max(): Double = ndArray.maxNumber().toDouble() + override fun Tensor.mean(): Double = ndArray.meanNumber().toDouble() + override fun Tensor.std(): Double = ndArray.stdNumber().toDouble() + override fun Tensor.variance(): Double = ndArray.varNumber().toDouble() } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt index e3adcdc44..5a74a9a18 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt @@ -19,7 +19,7 @@ public interface Distribution : Sampler { */ public fun probability(arg: T): Double - public override fun sample(generator: RandomGenerator): Chain + override fun sample(generator: RandomGenerator): Chain /** * An empty companion. Distribution factories should be written as its extensions 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 04ec8b171..66e041f05 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 @@ -23,14 +23,14 @@ public class NormalDistribution(public val sampler: GaussianSampler) : Univariat normalized: NormalizedGaussianSampler = ZigguratNormalizedGaussianSampler, ) : this(GaussianSampler(mean, standardDeviation, normalized)) - public override fun probability(arg: Double): Double { + override fun probability(arg: Double): Double { val x1 = (arg - sampler.mean) / sampler.standardDeviation return exp(-0.5 * x1 * x1 - (ln(sampler.standardDeviation) + 0.5 * ln(2 * PI))) } - public override fun sample(generator: RandomGenerator): Chain = sampler.sample(generator) + override fun sample(generator: RandomGenerator): Chain = sampler.sample(generator) - public override fun cumulative(arg: Double): Double { + override fun cumulative(arg: Double): Double { val dev = arg - sampler.mean return when { 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 a231842df..77d29981f 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 @@ -24,7 +24,7 @@ public class AhrensDieterExponentialSampler(public val mean: Double) : Sampler 0) { "mean is not strictly positive: $mean" } } - public override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { + override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { override fun nextBlocking(): Double { // Step 1: var a = 0.0 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 2f32eee85..93605c7d8 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 @@ -113,8 +113,8 @@ public class AhrensDieterMarsagliaTsangGammaSampler private constructor( } } - public override fun sample(generator: RandomGenerator): Chain = delegate.sample(generator) - public override fun toString(): String = delegate.toString() + override fun sample(generator: RandomGenerator): Chain = delegate.sample(generator) + override fun toString(): String = delegate.toString() public companion object { public fun of( diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt index db4f598b7..36ddd3c8e 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt @@ -76,7 +76,7 @@ public open class AliasMethodDiscreteSampler private constructor( } } - public override fun sample(generator: RandomGenerator): Chain = generator.chain { + override fun sample(generator: RandomGenerator): Chain = generator.chain { // This implements the algorithm as per Vose (1991): // v = uniform() in [0, 1) // j = uniform(n) in [0, n) @@ -107,7 +107,7 @@ public open class AliasMethodDiscreteSampler private constructor( if (generator.nextLong() ushr 11 < probability[j]) j else alias[j] } - public override fun toString(): String = "Alias method" + override fun toString(): String = "Alias method" public companion object { private const val DEFAULT_ALPHA = 0 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt index d7d8e87b7..9219df43e 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt @@ -28,7 +28,7 @@ public class GaussianSampler( require(standardDeviation > 0.0) { "standard deviation is not strictly positive: $standardDeviation" } } - public override fun sample(generator: RandomGenerator): BlockingDoubleChain = normalized + override fun sample(generator: RandomGenerator): BlockingDoubleChain = normalized .sample(generator) .map { standardDeviation * it + mean } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt index 9bb48fe4e..14737decb 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt @@ -27,7 +27,7 @@ public class KempSmallMeanPoissonSampler internal constructor( private val p0: Double, private val mean: Double, ) : Sampler { - public override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { + override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { override fun nextBlocking(): Int { //TODO move to nextBufferBlocking // Note on the algorithm: @@ -60,7 +60,7 @@ public class KempSmallMeanPoissonSampler internal constructor( override suspend fun fork(): BlockingIntChain = sample(generator.fork()) } - public override fun toString(): String = "Kemp Small Mean Poisson deviate" + override fun toString(): String = "Kemp Small Mean Poisson deviate" } public fun KempSmallMeanPoissonSampler(mean: Double): KempSmallMeanPoissonSampler { diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt index e95778b9e..2177e41ab 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt @@ -58,7 +58,7 @@ public class SmallMeanPoissonSampler(public val mean: Double) : Sampler { throw IllegalArgumentException("No p(x=0) probability for mean: $mean") }.toInt() - public override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { + override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { override fun nextBlocking(): Int { var n = 0 var r = 1.0 @@ -76,7 +76,7 @@ public class SmallMeanPoissonSampler(public val mean: Double) : Sampler { override suspend fun fork(): BlockingIntChain = sample(generator.fork()) } - public override fun toString(): String = "Small Mean Poisson deviate" + override fun toString(): String = "Small Mean Poisson deviate" } @@ -113,7 +113,7 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { private val p1: Double = a1 / aSum private val p2: Double = a2 / aSum - public override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { + override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { override fun nextBlocking(): Int { val exponential = AhrensDieterExponentialSampler(1.0).sample(generator) val gaussian = ZigguratNormalizedGaussianSampler.sample(generator) @@ -197,7 +197,7 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { } private fun getFactorialLog(n: Int): Double = factorialLog.value(n) - public override fun toString(): String = "Large Mean Poisson deviate" + override fun toString(): String = "Large Mean Poisson deviate" public companion object { private const val MAX_MEAN: Double = 0.5 * Int.MAX_VALUE 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 9769146fb..ac2c2098f 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 @@ -27,13 +27,13 @@ public class Mean( override suspend fun evaluate(data: Buffer): T = super.evaluate(data) - public override suspend fun computeIntermediate(data: Buffer): Pair = + override suspend fun computeIntermediate(data: Buffer): Pair = evaluateBlocking(data) to data.size - public override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = + override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = group { first.first + second.first } to (first.second + second.second) - public override suspend fun toResult(intermediate: Pair): T = group { + override suspend fun toResult(intermediate: Pair): T = group { division(intermediate.first, intermediate.second) } 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 70754eab7..2cc867fb2 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 @@ -12,7 +12,7 @@ import space.kscience.kmath.structures.asSequence * Non-composable median */ public class Median(private val comparator: Comparator) : BlockingStatistic { - public override fun evaluateBlocking(data: Buffer): T = + override fun evaluateBlocking(data: Buffer): T = data.asSequence().sortedWith(comparator).toList()[data.size / 2] //TODO check if this is correct public companion object { diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt index 5041e7359..d4bc36b5b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt @@ -31,7 +31,7 @@ public fun RandomGenerator.chain(generator: suspend RandomGenerator.() -> R) * A type-specific double chunk random chain */ public class UniformDoubleChain(public val generator: RandomGenerator) : BlockingDoubleChain { - public override fun nextBufferBlocking(size: Int): DoubleBuffer = generator.nextDoubleBuffer(size) + override fun nextBufferBlocking(size: Int): DoubleBuffer = generator.nextDoubleBuffer(size) override suspend fun nextBuffer(size: Int): DoubleBuffer = nextBufferBlocking(size) override suspend fun fork(): UniformDoubleChain = UniformDoubleChain(generator.fork()) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt index 3ff12f383..5698f1a79 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt @@ -97,17 +97,17 @@ public interface RandomGenerator { * @property random the underlying [Random] object. */ public class DefaultGenerator(public val random: Random = Random) : RandomGenerator { - public override fun nextBoolean(): Boolean = random.nextBoolean() - public override fun nextDouble(): Double = random.nextDouble() - public override fun nextInt(): Int = random.nextInt() - public override fun nextInt(until: Int): Int = random.nextInt(until) - public override fun nextLong(): Long = random.nextLong() - public override fun nextLong(until: Long): Long = random.nextLong(until) + override fun nextBoolean(): Boolean = random.nextBoolean() + override fun nextDouble(): Double = random.nextDouble() + override fun nextInt(): Int = random.nextInt() + override fun nextInt(until: Int): Int = random.nextInt(until) + override fun nextLong(): Long = random.nextLong() + override fun nextLong(until: Long): Long = random.nextLong(until) - public override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { + override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { random.nextBytes(array, fromIndex, toIndex) } - public override fun nextBytes(size: Int): ByteArray = random.nextBytes(size) - public override fun fork(): RandomGenerator = RandomGenerator.default(random.nextLong()) + override fun nextBytes(size: Int): ByteArray = random.nextBytes(size) + override fun fork(): RandomGenerator = RandomGenerator.default(random.nextLong()) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt index 27465eff4..849cf152a 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt @@ -19,7 +19,7 @@ import space.kscience.kmath.operations.invoke * @property value the value to sample. */ public class ConstantSampler(public val value: T) : Sampler { - public override fun sample(generator: RandomGenerator): Chain = ConstantChain(value) + override fun sample(generator: RandomGenerator): Chain = ConstantChain(value) } /** @@ -28,7 +28,7 @@ public class ConstantSampler(public val value: T) : Sampler { * @property chainBuilder the provider of [Chain]. */ public class BasicSampler(public val chainBuilder: (RandomGenerator) -> Chain) : Sampler { - public override fun sample(generator: RandomGenerator): Chain = chainBuilder(generator) + override fun sample(generator: RandomGenerator): Chain = chainBuilder(generator) } /** @@ -39,17 +39,17 @@ public class BasicSampler(public val chainBuilder: (RandomGenerator public class SamplerSpace(public val algebra: S) : Group>, ScaleOperations> where S : Group, S : ScaleOperations { - public override val zero: Sampler = ConstantSampler(algebra.zero) + override val zero: Sampler = ConstantSampler(algebra.zero) - public override fun add(a: Sampler, b: Sampler): Sampler = BasicSampler { generator -> + override fun add(a: Sampler, b: Sampler): Sampler = BasicSampler { generator -> a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } } } - public override fun scale(a: Sampler, value: Double): Sampler = BasicSampler { generator -> + override fun scale(a: Sampler, value: Double): Sampler = BasicSampler { generator -> a.sample(generator).map { a -> algebra { a * value } } } - public override fun Sampler.unaryMinus(): Sampler = scale(this, -1.0) + override fun Sampler.unaryMinus(): Sampler = scale(this, -1.0) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt index f29b7415c..499dcac6a 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt @@ -44,7 +44,7 @@ public interface ComposableStatistic : Statistic { //Transform block to result public suspend fun toResult(intermediate: I): R - public override suspend fun evaluate(data: Buffer): R = toResult(computeIntermediate(data)) + override suspend fun evaluate(data: Buffer): R = toResult(computeIntermediate(data)) } @FlowPreview diff --git a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt index 1ff6481ac..7aaac7d32 100644 --- a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt +++ b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt @@ -17,19 +17,19 @@ public class RandomSourceGenerator internal constructor(public val source: Rando internal val random: UniformRandomProvider = seed?.let { RandomSource.create(source, seed) } ?: RandomSource.create(source) - public override fun nextBoolean(): Boolean = random.nextBoolean() - public override fun nextDouble(): Double = random.nextDouble() - public override fun nextInt(): Int = random.nextInt() - public override fun nextInt(until: Int): Int = random.nextInt(until) - public override fun nextLong(): Long = random.nextLong() - public override fun nextLong(until: Long): Long = random.nextLong(until) + override fun nextBoolean(): Boolean = random.nextBoolean() + override fun nextDouble(): Double = random.nextDouble() + override fun nextInt(): Int = random.nextInt() + override fun nextInt(until: Int): Int = random.nextInt(until) + override fun nextLong(): Long = random.nextLong() + override fun nextLong(until: Long): Long = random.nextLong(until) - public override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { + override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { require(toIndex > fromIndex) random.nextBytes(array, fromIndex, toIndex - fromIndex) } - public override fun fork(): RandomGenerator = RandomSourceGenerator(source, nextLong()) + override fun fork(): RandomGenerator = RandomSourceGenerator(source, nextLong()) } /** @@ -43,14 +43,14 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * * @return the next random value. */ - public override fun nextBoolean(): Boolean = generator.nextBoolean() + override fun nextBoolean(): Boolean = generator.nextBoolean() /** * Generates a [Float] value between 0 and 1. * * @return the next random value between 0 and 1. */ - public override fun nextFloat(): Float = generator.nextDouble().toFloat() + override fun nextFloat(): Float = generator.nextDouble().toFloat() /** * Generates [Byte] values and places them into a user-supplied array. @@ -59,7 +59,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * * @param bytes byte array in which to put the random bytes. */ - public override fun nextBytes(bytes: ByteArray): Unit = generator.fillBytes(bytes) + override fun nextBytes(bytes: ByteArray): Unit = generator.fillBytes(bytes) /** * Generates [Byte] values and places them into a user-supplied array. @@ -71,7 +71,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * @param start the index at which to start inserting the generated bytes. * @param len the number of bytes to insert. */ - public override fun nextBytes(bytes: ByteArray, start: Int, len: Int) { + override fun nextBytes(bytes: ByteArray, start: Int, len: Int) { generator.fillBytes(bytes, start, start + len) } @@ -80,7 +80,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * * @return the next random value. */ - public override fun nextInt(): Int = generator.nextInt() + override fun nextInt(): Int = generator.nextInt() /** * Generates an [Int] value between 0 (inclusive) and the specified value (exclusive). @@ -88,21 +88,21 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * @param n the bound on the random number to be returned. Must be positive. * @return a random integer between 0 (inclusive) and [n] (exclusive). */ - public override fun nextInt(n: Int): Int = generator.nextInt(n) + override fun nextInt(n: Int): Int = generator.nextInt(n) /** * Generates a [Double] value between 0 and 1. * * @return the next random value between 0 and 1. */ - public override fun nextDouble(): Double = generator.nextDouble() + override fun nextDouble(): Double = generator.nextDouble() /** * Generates a [Long] value. * * @return the next random value. */ - public override fun nextLong(): Long = generator.nextLong() + override fun nextLong(): Long = generator.nextLong() /** * Generates a [Long] value between 0 (inclusive) and the specified value (exclusive). @@ -110,7 +110,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * @param n Bound on the random number to be returned. Must be positive. * @return a random long value between 0 (inclusive) and [n] (exclusive). */ - public override fun nextLong(n: Long): Long = generator.nextLong(n) + override fun nextLong(n: Long): Long = generator.nextLong(n) } /** diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt index 88f0c941e..3067b5efb 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt @@ -30,9 +30,9 @@ public class SymjaExpression>( public val mst: MST, public val evaluator: ExprEvaluator = DEFAULT_EVALUATOR, ) : SpecialDifferentiableExpression> { - public override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) + override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) - public override fun derivativeOrNull(symbols: List): SymjaExpression = SymjaExpression( + override fun derivativeOrNull(symbols: List): SymjaExpression = SymjaExpression( algebra, symbols.map(Symbol::toIExpr).fold(mst.toIExpr(), F::D).toMst(evaluator), evaluator, 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 bbf502faf..c7f45c6da 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 @@ -10,15 +10,15 @@ import space.kscience.kmath.structures.MutableBuffer @Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") public class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { - public override val size: Int + override val size: Int get() = flatArray.size - public override inline fun get(index: Int): Double = flatArray[index] + override inline fun get(index: Int): Double = flatArray[index] - public override inline fun set(index: Int, value: Double) { + override inline fun set(index: Int, value: Double) { flatArray[index] = value } - public override fun copy(): MutableBuffer = ViktorBuffer(flatArray.copy().flatten()) - public override operator fun iterator(): Iterator = flatArray.data.iterator() + override fun copy(): MutableBuffer = ViktorBuffer(flatArray.copy().flatten()) + override operator fun iterator(): Iterator = flatArray.data.iterator() } 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 915637e2c..2be964017 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 @@ -16,16 +16,16 @@ import space.kscience.kmath.operations.ScaleOperations @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructureND { - public override val shape: IntArray get() = f64Buffer.shape + override val shape: IntArray get() = f64Buffer.shape - public override inline fun get(index: IntArray): Double = f64Buffer.get(*index) + override inline fun get(index: IntArray): Double = f64Buffer.get(*index) - public override inline fun set(index: IntArray, value: Double) { + override inline fun set(index: IntArray, value: Double) { f64Buffer.set(*index, value = value) } @PerformancePitfall - public override fun elements(): Sequence> = + override fun elements(): Sequence> = DefaultStrides(shape).indices().map { it to get(it) } } @@ -33,7 +33,7 @@ public fun F64Array.asStructure(): ViktorStructureND = ViktorStructureND(this) @OptIn(UnstableKMathAPI::class) @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public class ViktorFieldND(public override val shape: IntArray) : FieldND, +public class ViktorFieldND(override val shape: IntArray) : FieldND, NumbersAddOperations>, ExtendedField>, ScaleOperations> { @@ -47,30 +47,30 @@ public class ViktorFieldND(public override val shape: IntArray) : FieldND produce { this@f64Buffer[it] }.f64Buffer } - public override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } - public override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } + override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } + override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } private val strides: Strides = DefaultStrides(shape) - public override val elementContext: DoubleField get() = DoubleField + override val elementContext: DoubleField get() = DoubleField - public override fun produce(initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = + override fun produce(initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = F64Array(*shape).apply { this@ViktorFieldND.strides.indices().forEach { index -> set(value = DoubleField.initializer(index), indices = index) } }.asStructure() - public override fun StructureND.unaryMinus(): StructureND = -1 * this + override fun StructureND.unaryMinus(): StructureND = -1 * this - public override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = + override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = F64Array(*this@ViktorFieldND.shape).apply { this@ViktorFieldND.strides.indices().forEach { index -> set(value = DoubleField.transform(this@map[index]), indices = index) } }.asStructure() - public override fun StructureND.mapIndexed( + override fun StructureND.mapIndexed( transform: DoubleField.(index: IntArray, Double) -> Double, ): ViktorStructureND = F64Array(*this@ViktorFieldND.shape).apply { this@ViktorFieldND.strides.indices().forEach { index -> @@ -78,7 +78,7 @@ public class ViktorFieldND(public override val shape: IntArray) : FieldND, b: StructureND, transform: DoubleField.(Double, Double) -> Double, @@ -88,39 +88,39 @@ public class ViktorFieldND(public override val shape: IntArray) : FieldND, b: StructureND): ViktorStructureND = + override fun add(a: StructureND, b: StructureND): ViktorStructureND = (a.f64Buffer + b.f64Buffer).asStructure() - public override fun scale(a: StructureND, value: Double): ViktorStructureND = + override fun scale(a: StructureND, value: Double): ViktorStructureND = (a.f64Buffer * value).asStructure() - public override inline fun StructureND.plus(b: StructureND): ViktorStructureND = + override inline fun StructureND.plus(b: StructureND): ViktorStructureND = (f64Buffer + b.f64Buffer).asStructure() - public override inline fun StructureND.minus(b: StructureND): ViktorStructureND = + override inline fun StructureND.minus(b: StructureND): ViktorStructureND = (f64Buffer - b.f64Buffer).asStructure() - public override inline fun StructureND.times(k: Number): ViktorStructureND = + override inline fun StructureND.times(k: Number): ViktorStructureND = (f64Buffer * k.toDouble()).asStructure() - public override inline fun StructureND.plus(arg: Double): ViktorStructureND = + override inline fun StructureND.plus(arg: Double): ViktorStructureND = (f64Buffer.plus(arg)).asStructure() - public override fun number(value: Number): ViktorStructureND = + override fun number(value: Number): ViktorStructureND = F64Array.full(init = value.toDouble(), shape = shape).asStructure() - public override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } - public override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } - public override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } - public override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } - public override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } - public 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) } - public 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) } - public override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() + override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() - public override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() + override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() } public fun ViktorNDField(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) From bc2841295027760a1d8110df7fbda04c84c47810 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 21 Jul 2021 00:00:35 +0700 Subject: [PATCH 27/39] Update publish.yml --- .github/workflows/build.yml | 8 ++++---- .github/workflows/publish.yml | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2b611a46a..2eb9f34b3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,7 @@ name: Gradle build on: push: - branches: - - dev - - master + branches: [ dev, master ] pull_request: jobs: @@ -26,7 +24,9 @@ jobs: - name: Cache gradle uses: actions/cache@v2 with: - path: ~/.gradle/caches + path: | + ~/.gradle/caches + ~/.gradle/wrapper key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d1698d79b..13bbabbc9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -42,11 +42,13 @@ jobs: if: matrix.os == 'windows-latest' run: > ./gradlew release --no-daemon -Ppublishing.enabled=true - -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }} - -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }} + -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} + -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} + -Ppublishing.sonatype=false - name: Publish Mac Artifacts if: matrix.os == 'macOS-latest' run: > ./gradlew release --no-daemon -Ppublishing.enabled=true -Ppublishing.platform=macosX64 - -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }} - -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }} + -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} + -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} + -Ppublishing.sonatype=false From ec8f14a6e91035fc5f3e01a55edaa8d99975ab38 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 21 Jul 2021 00:00:35 +0700 Subject: [PATCH 28/39] Fix publish.yml --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 13bbabbc9..05c1c603e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -40,9 +40,9 @@ jobs: ${{ runner.os }}-gradle- - name: Publish Windows Artifacts if: matrix.os == 'windows-latest' + shell: cmd run: > - ./gradlew release --no-daemon -Ppublishing.enabled=true - -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} + ./gradlew release --no-daemon -Ppublishing.enabled=true -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} -Ppublishing.sonatype=false - name: Publish Mac Artifacts From 8b3298f7a888bee9682d4ba9276ffb1c81b141ef Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Jun 2021 17:57:33 +0700 Subject: [PATCH 29/39] Exact conversions from Long to Int, Int indexing of Dimension --- .../kmath/structures/typeSafeDimensions.kt | 2 +- .../commons/random/CMRandomGeneratorWrapper.kt | 3 ++- .../kotlin/space/kscience/kmath/misc/numbers.kt | 8 ++++++++ .../kotlin/space/kscience/kmath/misc/numbers.kt | 12 ++++++++++++ .../space/kscience/kmath/misc/numbersJVM.kt | 8 ++++++++ .../kotlin/space/kscience/kmath/misc/numbers.kt | 12 ++++++++++++ .../dimensions/{Dimensions.kt => Dimension.kt} | 16 ++++++++-------- .../space/kscience/kmath/dimensions/Wrappers.kt | 16 ++++++++-------- .../kmath/dimensions/{dimJs.kt => Dimension.kt} | 8 ++++---- .../kmath/dimensions/{dimJvm.kt => Dimension.kt} | 14 ++++++++------ .../dimensions/{dimNative.kt => Dimension.kt} | 8 ++++---- .../kotlin/space/kscience/kmath/nd4j/arrays.kt | 4 +++- .../kscience/kmath/samplers/PoissonSampler.kt | 5 +++-- .../ZigguratNormalizedGaussianSampler.kt | 3 ++- 14 files changed, 83 insertions(+), 36 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt create mode 100644 kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt create mode 100644 kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt create mode 100644 kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt rename kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/{Dimensions.kt => Dimension.kt} (67%) rename kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/{dimJs.kt => Dimension.kt} (62%) rename kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/{dimJvm.kt => Dimension.kt} (69%) rename kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/{dimNative.kt => Dimension.kt} (65%) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt index 955f86fa9..c28b566b9 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt @@ -19,7 +19,7 @@ private fun DMatrixContext.simple() { } private object D5 : Dimension { - override val dim: UInt = 5u + override val dim: Int = 5 } private fun DMatrixContext.custom() { diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt index afbfd9a24..6aeebb68c 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.commons.random import kotlinx.coroutines.runBlocking import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.samplers.GaussianSampler +import space.kscience.kmath.misc.toIntExact import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.next @@ -28,7 +29,7 @@ public class CMRandomGeneratorWrapper( } override fun setSeed(seed: Long) { - setSeed(seed.toInt()) + setSeed(seed.toIntExact()) } override fun nextBytes(bytes: ByteArray) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt new file mode 100644 index 000000000..f879a06d5 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -0,0 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.misc + +public expect fun Long.toIntExact(): Int diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt new file mode 100644 index 000000000..68a3c995b --- /dev/null +++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.misc + +public actual fun Long.toIntExact(): Int { + val i = toInt() + if (i.toLong() == this) throw ArithmeticException("integer overflow") + return i +} diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt new file mode 100644 index 000000000..5ba0dbc9b --- /dev/null +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt @@ -0,0 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.misc + +public actual fun Long.toIntExact(): Int = Math.toIntExact(this) diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt new file mode 100644 index 000000000..68a3c995b --- /dev/null +++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.misc + +public actual fun Long.toIntExact(): Int { + val i = toInt() + if (i.toLong() == this) throw ArithmeticException("integer overflow") + return i +} diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimensions.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt similarity index 67% rename from kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimensions.kt rename to kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 8b17d252f..e57c22834 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimensions.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -8,47 +8,47 @@ package space.kscience.kmath.dimensions import kotlin.reflect.KClass /** - * Represents a quantity of dimensions in certain structure. + * Represents a quantity of dimensions in certain structure. **This interface must be implemented only by objects.** * * @property dim The number of dimensions. */ public interface Dimension { - public val dim: UInt + public val dim: Int public companion object } -public fun KClass.dim(): UInt = Dimension.resolve(this).dim +public fun KClass.dim(): Int = Dimension.resolve(this).dim public expect fun Dimension.Companion.resolve(type: KClass): D /** * Finds or creates [Dimension] with [Dimension.dim] equal to [dim]. */ -public expect fun Dimension.Companion.of(dim: UInt): Dimension +public expect fun Dimension.Companion.of(dim: Int): Dimension /** * Finds [Dimension.dim] of given type [D]. */ -public inline fun Dimension.Companion.dim(): UInt = D::class.dim() +public inline fun Dimension.Companion.dim(): Int = D::class.dim() /** * Type representing 1 dimension. */ public object D1 : Dimension { - override val dim: UInt get() = 1U + override val dim: Int get() = 1 } /** * Type representing 2 dimensions. */ public object D2 : Dimension { - override val dim: UInt get() = 2U + override val dim: Int get() = 2 } /** * Type representing 3 dimensions. */ public object D3 : Dimension { - override val dim: UInt get() = 3U + override val dim: Int get() = 3 } diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt index a2ee14301..deb297913 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt @@ -23,11 +23,11 @@ public interface DMatrix : Structure2D { * Coerces a regular matrix to a matrix with type-safe dimensions and throws a error if coercion failed */ public inline fun coerce(structure: Structure2D): DMatrix { - require(structure.rowNum == Dimension.dim().toInt()) { + require(structure.rowNum == Dimension.dim()) { "Row number mismatch: expected ${Dimension.dim()} but found ${structure.rowNum}" } - require(structure.colNum == Dimension.dim().toInt()) { + require(structure.colNum == Dimension.dim()) { "Column number mismatch: expected ${Dimension.dim()} but found ${structure.colNum}" } @@ -61,7 +61,7 @@ public value class DMatrixWrapper( public interface DPoint : Point { public companion object { public inline fun coerce(point: Point): DPoint { - require(point.size == Dimension.dim().toInt()) { + require(point.size == Dimension.dim()) { "Vector dimension mismatch: expected ${Dimension.dim()}, but found ${point.size}" } @@ -92,11 +92,11 @@ public value class DPointWrapper(public val point: Point>(public val context: LinearSpace) { public inline fun Matrix.coerce(): DMatrix { - require(rowNum == Dimension.dim().toInt()) { + require(rowNum == Dimension.dim()) { "Row number mismatch: expected ${Dimension.dim()} but found $rowNum" } - require(colNum == Dimension.dim().toInt()) { + require(colNum == Dimension.dim()) { "Column number mismatch: expected ${Dimension.dim()} but found $colNum" } @@ -111,7 +111,7 @@ public value class DMatrixContext>(public val context: ): DMatrix { val rows = Dimension.dim() val cols = Dimension.dim() - return context.buildMatrix(rows.toInt(), cols.toInt(), initializer).coerce() + return context.buildMatrix(rows, cols, initializer).coerce() } public inline fun point(noinline initializer: A.(Int) -> T): DPoint { @@ -119,7 +119,7 @@ public value class DMatrixContext>(public val context: return DPoint.coerceUnsafe( context.buildVector( - size.toInt(), + size, initializer ) ) @@ -167,4 +167,4 @@ public inline fun DMatrixContext.on public inline fun DMatrixContext.zero(): DMatrix = produce { _, _ -> 0.0 - } \ No newline at end of file + } diff --git a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/dimJs.kt b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt similarity index 62% rename from kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/dimJs.kt rename to kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 27912f5bc..610e8b4c0 100644 --- a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/dimJs.kt +++ b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -7,17 +7,17 @@ package space.kscience.kmath.dimensions import kotlin.reflect.KClass -private val dimensionMap: MutableMap = hashMapOf(1u to D1, 2u to D2, 3u to D3) +private val dimensionMap: MutableMap = hashMapOf(1 to D1, 2 to D2, 3 to D3) @Suppress("UNCHECKED_CAST") public actual fun Dimension.Companion.resolve(type: KClass): D = dimensionMap .entries - .map(MutableMap.MutableEntry::value) + .map(MutableMap.MutableEntry::value) .find { it::class == type } as? D ?: error("Can't resolve dimension $type") -public actual fun Dimension.Companion.of(dim: UInt): Dimension = dimensionMap.getOrPut(dim) { +public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) { object : Dimension { - override val dim: UInt get() = dim + override val dim: Int get() = dim } } diff --git a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/dimJvm.kt b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt similarity index 69% rename from kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/dimJvm.kt rename to kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index f21a3e18f..e6d8b3b35 100644 --- a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/dimJvm.kt +++ b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:JvmName("DimensionJVM") + package space.kscience.kmath.dimensions import kotlin.reflect.KClass @@ -10,12 +12,12 @@ import kotlin.reflect.KClass public actual fun Dimension.Companion.resolve(type: KClass): D = type.objectInstance ?: error("No object instance for dimension class") -public actual fun Dimension.Companion.of(dim: UInt): Dimension = when (dim) { - 1u -> D1 - 2u -> D2 - 3u -> D3 +public actual fun Dimension.Companion.of(dim: Int): Dimension = when (dim) { + 1 -> D1 + 2 -> D2 + 3 -> D3 else -> object : Dimension { - override val dim: UInt get() = dim + override val dim: Int get() = dim } -} \ No newline at end of file +} diff --git a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/dimNative.kt b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt similarity index 65% rename from kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/dimNative.kt rename to kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 9aa58e64a..64edbe935 100644 --- a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/dimNative.kt +++ b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -9,17 +9,17 @@ import kotlin.native.concurrent.ThreadLocal import kotlin.reflect.KClass @ThreadLocal -private val dimensionMap: MutableMap = hashMapOf(1u to D1, 2u to D2, 3u to D3) +private val dimensionMap: MutableMap = hashMapOf(1 to D1, 2 to D2, 3 to D3) @Suppress("UNCHECKED_CAST") public actual fun Dimension.Companion.resolve(type: KClass): D = dimensionMap .entries - .map(MutableMap.MutableEntry::value) + .map(MutableMap.MutableEntry::value) .find { it::class == type } as? D ?: error("Can't resolve dimension $type") -public actual fun Dimension.Companion.of(dim: UInt): Dimension = dimensionMap.getOrPut(dim) { +public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) { object : Dimension { - override val dim: UInt get() = dim + override val dim: Int get() = dim } } diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt index 75a334ca7..3ca756600 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt @@ -5,4 +5,6 @@ package space.kscience.kmath.nd4j -internal fun LongArray.toIntArray(): IntArray = IntArray(size) { this[it].toInt() } +import space.kscience.kmath.misc.toIntExact + +internal fun LongArray.toIntArray(): IntArray = IntArray(size) { this[it].toIntExact() } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt index 2177e41ab..96131aa4b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingIntChain import space.kscience.kmath.internal.InternalUtils +import space.kscience.kmath.misc.toIntExact import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.Sampler import space.kscience.kmath.structures.IntBuffer @@ -119,7 +120,7 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { val gaussian = ZigguratNormalizedGaussianSampler.sample(generator) val smallMeanPoissonSampler = if (mean - lambda < Double.MIN_VALUE) { - null + null } else { KempSmallMeanPoissonSampler(mean - lambda).sample(generator) } @@ -188,7 +189,7 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { } } - return min(y2 + y.toLong(), Int.MAX_VALUE.toLong()).toInt() + return min(y2 + y.toLong(), Int.MAX_VALUE.toLong()).toIntExact() } override fun nextBufferBlocking(size: Int): IntBuffer = IntBuffer(size) { nextBlocking() } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt index 24148271d..81b8c3d4b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain +import space.kscience.kmath.misc.toIntExact import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.DoubleBuffer import kotlin.math.* @@ -58,7 +59,7 @@ public object ZigguratNormalizedGaussianSampler : NormalizedGaussianSampler { private fun sampleOne(generator: RandomGenerator): Double { val j = generator.nextLong() - val i = (j and LAST.toLong()).toInt() + val i = (j and LAST.toLong()).toIntExact() return if (abs(j) < K[i]) j * W[i] else fix(generator, j, i) } From ef50a4d963e94581ad636cc956ba7fba6c1203c1 Mon Sep 17 00:00:00 2001 From: Peter Klimai Date: Wed, 21 Jul 2021 12:33:45 +0300 Subject: [PATCH 30/39] Fix package name --- .../{kaceince => kscience}/kmath/real/DoubleMatrixTest.kt | 2 +- .../{kaceince => kscience}/kmath/real/DoubleVectorTest.kt | 2 +- .../kotlin/{kaceince => kscience}/kmath/real/GridTest.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename kmath-for-real/src/commonTest/kotlin/{kaceince => kscience}/kmath/real/DoubleMatrixTest.kt (99%) rename kmath-for-real/src/commonTest/kotlin/{kaceince => kscience}/kmath/real/DoubleVectorTest.kt (97%) rename kmath-for-real/src/commonTest/kotlin/{kaceince => kscience}/kmath/real/GridTest.kt (96%) diff --git a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleMatrixTest.kt similarity index 99% rename from kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt rename to kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleMatrixTest.kt index a9c5f9e1a..e7b8434c5 100644 --- a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleMatrixTest.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package kaceince.kmath.real +package kscience.kmath.real import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.matrix diff --git a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleVectorTest.kt similarity index 97% rename from kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt rename to kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleVectorTest.kt index 9de54381c..345013306 100644 --- a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleVectorTest.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package kaceince.kmath.real +package kscience.kmath.real import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.asMatrix diff --git a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/GridTest.kt b/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/GridTest.kt similarity index 96% rename from kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/GridTest.kt rename to kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/GridTest.kt index 0d3b80336..a59fdfca4 100644 --- a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/GridTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/GridTest.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package kaceince.kmath.real +package kscience.kmath.real import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.real.DoubleVector From c263b1acbe0a6de89bb45b9fa433c72c7323fc22 Mon Sep 17 00:00:00 2001 From: Peter Klimai Date: Wed, 21 Jul 2021 13:25:35 +0300 Subject: [PATCH 31/39] Fix package name again --- .../kotlin/{ => space}/kscience/kmath/real/DoubleMatrixTest.kt | 2 +- .../kotlin/{ => space}/kscience/kmath/real/DoubleVectorTest.kt | 2 +- .../kotlin/{ => space}/kscience/kmath/real/GridTest.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename kmath-for-real/src/commonTest/kotlin/{ => space}/kscience/kmath/real/DoubleMatrixTest.kt (99%) rename kmath-for-real/src/commonTest/kotlin/{ => space}/kscience/kmath/real/DoubleVectorTest.kt (97%) rename kmath-for-real/src/commonTest/kotlin/{ => space}/kscience/kmath/real/GridTest.kt (96%) diff --git a/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt similarity index 99% rename from kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleMatrixTest.kt rename to kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt index e7b8434c5..e3f015511 100644 --- a/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package kscience.kmath.real +package space.kscience.kmath.real import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.matrix diff --git a/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt similarity index 97% rename from kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleVectorTest.kt rename to kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt index 345013306..48e55ea01 100644 --- a/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/DoubleVectorTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package kscience.kmath.real +package space.kscience.kmath.real import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.asMatrix diff --git a/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/GridTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt similarity index 96% rename from kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/GridTest.kt rename to kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt index a59fdfca4..8fed8d10e 100644 --- a/kmath-for-real/src/commonTest/kotlin/kscience/kmath/real/GridTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package kscience.kmath.real +package space.kscience.kmath.real import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.real.DoubleVector From 2d3a5fb5c82bf47075596d4f13db2b9afb09d5b5 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 21 Jul 2021 00:45:29 +0700 Subject: [PATCH 32/39] Fix publish.yml --- .github/workflows/publish.yml | 2 -- README.md | 8 ++++---- kmath-kotlingrad/README.md | 4 ++-- settings.gradle.kts | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 05c1c603e..cbf13d03d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -44,11 +44,9 @@ jobs: run: > ./gradlew release --no-daemon -Ppublishing.enabled=true -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} - -Ppublishing.sonatype=false - name: Publish Mac Artifacts if: matrix.os == 'macOS-latest' run: > ./gradlew release --no-daemon -Ppublishing.enabled=true -Ppublishing.platform=macosX64 -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} - -Ppublishing.sonatype=false diff --git a/README.md b/README.md index 7645256d9..a15c4384f 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ KMath is a modular library. Different modules provide different features with di objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high performance calculations to code generation. > - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains -> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation +> - [autodiff](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
@@ -222,8 +222,8 @@ One can still use generic algebras though. > **Maturity**: EXPERIMENTAL > > **Features:** -> - [differentiable-mst-expression](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt) : MST based DifferentiableExpression. -> - [differentiable-mst-expression](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt) : Conversions between Kotlin∇'s SFun and MST +> - [differentiable-mst-expression](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression. +> - [scalars-adapters](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST
@@ -264,7 +264,7 @@ One can still use generic algebras though. > > **Features:** > - [tensor algebra](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) -> - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. +> - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. > - [linear algebra operations](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc.
diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 304a0639b..3b337460f 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -2,8 +2,8 @@ [Kotlin∇](https://www.htmlsymbols.xyz/unicode/U+2207) integration module. - - [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt) : MST based DifferentiableExpression. - - [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt) : Conversions between Kotlin∇'s SFun and MST + - [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression. + - [scalars-adapters](src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST ## Artifact: diff --git a/settings.gradle.kts b/settings.gradle.kts index 445f75c09..18f867df3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,7 +5,7 @@ pluginManagement { gradlePluginPortal() } - val toolsVersion = "0.10.1" + val toolsVersion = "0.10.2" val kotlinVersion = "1.5.21" plugins { From dd01c39cbe6dbd080078731b2c3741215119a6ad Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 21 Jul 2021 00:45:29 +0700 Subject: [PATCH 33/39] Fix publish.yml --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 3427a6d61..36a1ffd9e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -11,7 +11,7 @@ repositories { dependencies { api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") - api("ru.mipt.npm:gradle-tools:0.10.1") + api("ru.mipt.npm:gradle-tools:0.10.2") api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.3.1") } From fe21f0c954feeabacfe2aab976a533552a39a418 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 28 Jul 2021 05:52:23 +0700 Subject: [PATCH 34/39] Update plotly.kt and SLF4J --- examples/build.gradle.kts | 4 ++-- kmath-nd4j/build.gradle.kts | 2 +- kmath-symja/build.gradle.kts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 406b8f470..4cc6fecc0 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -41,9 +41,9 @@ dependencies { // } else implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - implementation("org.slf4j:slf4j-simple:1.7.30") + implementation("org.slf4j:slf4j-simple:1.7.31") // plotting - implementation("space.kscience:plotlykt-server:0.4.0") + implementation("space.kscience:plotlykt-server:0.4.2") //jafama implementation(project(":kmath-jafama")) } diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts index 6e890a937..dcb6f1b4a 100644 --- a/kmath-nd4j/build.gradle.kts +++ b/kmath-nd4j/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { api(project(":kmath-tensors")) api("org.nd4j:nd4j-api:1.0.0-M1") testImplementation("org.nd4j:nd4j-native-platform:1.0.0-M1") - testImplementation("org.slf4j:slf4j-simple:1.7.30") + testImplementation("org.slf4j:slf4j-simple:1.7.31") } readme { diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts index f305c03b8..65c329d52 100644 --- a/kmath-symja/build.gradle.kts +++ b/kmath-symja/build.gradle.kts @@ -34,7 +34,7 @@ dependencies { api("org.hipparchus:hipparchus-stat:1.8") api(project(":kmath-core")) - testImplementation("org.slf4j:slf4j-simple:1.7.30") + testImplementation("org.slf4j:slf4j-simple:1.7.31") } readme { From afd590878421093e4203aca8238f964900465a3e Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 7 May 2021 19:59:21 +0700 Subject: [PATCH 35/39] Revise grammar of KDoc comments, refresh documentation files --- README.md | 68 ++++++++------ docs/algebra.md | 83 +++++------------ docs/buffers.md | 17 ++-- docs/codestyle.md | 19 ++-- docs/contexts.md | 44 ++++----- docs/expressions.md | 23 ++--- docs/features.md | 14 --- docs/linear.md | 32 ++++--- docs/nd-structure.md | 18 ++-- docs/readme.md | 14 +++ docs/templates/README-TEMPLATE.md | 66 ++++++++------ .../kscience/kmath/ast/kotlingradSupport.kt | 4 +- .../space/kscience/kmath/ast/symjaSupport.kt | 4 +- .../kmath/commons/fit/fitWithAutoDiff.kt | 3 +- .../space/kscience/kmath/jafama/JafamaDemo.kt | 15 ++++ .../kscience/kmath/jafama/KMathaJafamaDemo.kt | 17 ---- .../kscience/kmath/stat/DistributionDemo.kt | 3 - .../kscience/kmath/structures/NDField.kt | 2 +- .../kmath/tensors/DataSetNormalization.kt | 4 +- .../tensors/LinearSystemSolvingWithLUP.kt | 2 +- .../kscience/kmath/tensors/NeuralNetwork.kt | 2 +- .../space/kscience/kmath/tensors/PCA.kt | 4 +- kmath-ast/README.md | 5 +- kmath-ast/docs/README-TEMPLATE.md | 5 +- .../kmath/ast/rendering/MathSyntax.kt | 4 +- .../kmath/ast/rendering/SyntaxRenderer.kt | 2 +- .../kscience/kmath/ast/rendering/features.kt | 8 +- .../kmath/asm/internal/codegenUtils.kt | 4 +- .../DerivativeStructureExpression.kt | 2 +- .../DerivativeStructureExpressionTest.kt | 2 +- .../commons/optimization/OptimizeTest.kt | 2 +- .../expressions/DifferentiableExpression.kt | 2 +- .../kscience/kmath/expressions/Expression.kt | 4 +- .../FunctionalExpressionAlgebra.kt | 2 +- .../kscience/kmath/linear/LinearSolver.kt | 4 +- .../kscience/kmath/linear/LinearSpace.kt | 4 +- .../kscience/kmath/linear/LupDecomposition.kt | 4 +- .../kscience/kmath/linear/MatrixFeatures.kt | 2 +- .../kscience/kmath/linear/MatrixWrapper.kt | 9 +- .../space/kscience/kmath/misc/annotations.kt | 6 +- .../space/kscience/kmath/nd/AlgebraND.kt | 26 +++--- .../space/kscience/kmath/nd/Structure1D.kt | 2 +- .../space/kscience/kmath/nd/Structure2D.kt | 5 +- .../space/kscience/kmath/nd/StructureND.kt | 10 +-- .../kscience/kmath/operations/Algebra.kt | 62 +++++++------ .../kmath/operations/AlgebraElements.kt | 2 +- .../space/kscience/kmath/operations/BigInt.kt | 4 +- .../kmath/operations/NumericAlgebra.kt | 32 +++---- .../kmath/operations/OptionalOperations.kt | 4 +- .../kscience/kmath/structures/DoubleBuffer.kt | 4 +- .../kmath/structures/FlaggedBuffer.kt | 2 +- .../kscience/kmath/structures/FloatBuffer.kt | 4 +- .../kscience/kmath/structures/IntBuffer.kt | 4 +- .../kscience/kmath/structures/LongBuffer.kt | 4 +- .../kscience/kmath/structures/ShortBuffer.kt | 4 +- .../space/kscience/kmath/chains/Chain.kt | 14 +-- .../kscience/kmath/streaming/BufferFlow.kt | 2 +- .../kscience/kmath/dimensions/Wrappers.kt | 4 +- kmath-for-real/build.gradle.kts | 2 +- .../space/kscience/kmath/real/RealVector.kt | 2 +- .../kotlin/space/kscience/kmath/real/grids.kt | 4 +- .../kscience/kmath/functions/Piecewise.kt | 10 +-- .../kmath/integration/GaussIntegrator.kt | 20 +++-- .../integration/GaussIntegratorRuleFactory.kt | 4 +- .../kmath/integration/SimpsonIntegrator.kt | 15 ++-- .../kmath/integration/SplineIntegrator.kt | 13 +-- .../kmath/integration/UnivariateIntegrand.kt | 4 +- .../kscience/kmath/histogram/Histogram.kt | 2 +- .../kmath/histogram/UnivariateHistogram.kt | 7 +- kmath-jafama/README.md | 20 +---- kmath-kotlingrad/README.md | 2 +- kmath-kotlingrad/docs/README-TEMPLATE.md | 2 +- .../space/kscience/kmath/memory/Memory.kt | 2 +- .../kscience/kmath/memory/DataViewMemory.kt | 2 +- .../kscience/kmath/memory/ByteBufferMemory.kt | 2 +- .../kscience/kmath/memory/NativeMemory.kt | 4 +- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 2 +- .../kscience/kmath/nd4j/Nd4jArrayStructure.kt | 2 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 2 +- .../kmath/distributions/Distribution.kt | 2 +- .../distributions/FactorizedDistribution.kt | 4 +- .../kscience/kmath/internal/InternalGamma.kt | 2 +- .../optimization/FunctionOptimization.kt | 15 ++-- .../NoDerivFunctionOptimization.kt | 2 +- .../kmath/optimization/Optimization.kt | 2 +- .../AhrensDieterMarsagliaTsangGammaSampler.kt | 4 +- .../samplers/AliasMethodDiscreteSampler.kt | 12 +-- .../samplers/KempSmallMeanPoissonSampler.kt | 5 +- .../kscience/kmath/samplers/PoissonSampler.kt | 8 +- .../kscience/kmath/stat/RandomGenerator.kt | 6 +- .../kscience/kmath/stat/SamplerAlgebra.kt | 2 +- .../space/kscience/kmath/stat/Statistic.kt | 7 +- .../kmath/stat/RandomSourceGenerator.kt | 2 +- .../tensors/api/LinearOpsTensorAlgebra.kt | 38 ++++---- .../kmath/tensors/api/TensorAlgebra.kt | 13 ++- .../api/TensorPartialDivisionAlgebra.kt | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 90 ++++++++++--------- .../kmath/tensors/core/internal/utils.kt | 4 +- 98 files changed, 523 insertions(+), 538 deletions(-) delete mode 100644 docs/features.md create mode 100644 docs/readme.md create mode 100644 examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt delete mode 100644 examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt diff --git a/README.md b/README.md index a15c4384f..db069d4e0 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ # KMath -Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to -Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture -designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could -be achieved with [kmath-for-real](/kmath-for-real) extension module. +Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based +analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior +architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like +experience could be achieved with [kmath-for-real](/kmath-for-real) extension module. [Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) @@ -21,26 +21,33 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module. # Goal -* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native). +* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native) + . * Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide bindings and wrappers with those abstractions for popular optimized platform libraries. ## Non-goals -* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API. +* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API. * Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. -* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like -for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better -experience for those, who want to work with specific types. +* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like + for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better + experience for those, who want to work with specific types. ## Features and stability -KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels: +KMath is a modular library. Different modules provide different features with different API stability guarantees. All +core modules are released with the same version, but with different API change policy. The features are described in +module definitions below. The module stability could have the following levels: -* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. -* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations. -* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. +* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could + break any moment. You can still use it, but be sure to fix the specific version. +* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked + with `@UnstableKmathAPI` or other stability warning annotations. +* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor + versions, but not in patch versions. API is protected + with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. @@ -161,7 +168,7 @@ performance calculations to code generation.
* ### [kmath-for-real](kmath-for-real) -> Extension module that should be used to achieve numpy-like behavior. +> Extension module that should be used to achieve numpy-like behavior. All operations are specialized to work with `Double` numbers without declaring algebraic contexts. One can still use generic algebras though. > @@ -278,30 +285,33 @@ One can still use generic algebras though. ## Multi-platform support -KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the -[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features -are delegated to platform-specific implementations even if they could be provided in the common module for performance -reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and +KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the +[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features +are delegated to platform-specific implementations even if they could be provided in the common module for performance +reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and feedback are also welcome. ## Performance -Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve -both performance and flexibility. +Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both +performance and flexibility. -We expect to focus on creating convenient universal API first and then work on increasing performance for specific -cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized -native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be +We expect to focus on creating convenient universal API first and then work on increasing performance for specific +cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized +native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. ## Requirements -KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance. +KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for +execution to get better performance. ### Repositories -Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of -[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: +Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) +repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of +[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could +be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: ```kotlin repositories { @@ -318,7 +328,7 @@ Gradle `6.0+` is required for multiplatform artifacts. ## Contributing -The project requires a lot of additional work. The most important thing we need is a feedback about what features are -required the most. Feel free to create feature requests. We are also welcome to code contributions, -especially in issues marked with +The project requires a lot of additional work. The most important thing we need is a feedback about what features are +required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues +marked with [waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. diff --git a/docs/algebra.md b/docs/algebra.md index 84693bb81..20158a125 100644 --- a/docs/algebra.md +++ b/docs/algebra.md @@ -1,85 +1,45 @@ # Algebraic Structures and Algebraic Elements -The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an -operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up, -say `Space`. Next one needs to run the actual operation in the context: +The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an +operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up, +say `Group`. Next one needs to run the actual operation in the context: ```kotlin import space.kscience.kmath.operations.* val a: T = ... val b: T = ... -val space: Space = ... +val group: Group = ... -val c = space { a + b } +val c = group { a + b } ``` -At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in -mathematics, one could draw up different operations on same objects. For example, one could use different types of +At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in +mathematics, one could draw up different operations on same objects. For example, one could use different types of geometry for vectors. ## Algebraic Structures -Mathematical contexts have the following hierarchy: +Primary mathematical contexts have the following hierarchy: -**Algebra** ← **Space** ← **Ring** ← **Field** +`Field <: Ring <: Group <: Algebra` These interfaces follow real algebraic structures: -- [Space](https://mathworld.wolfram.com/VectorSpace.html) defines addition, its neutral element (i.e. 0) and scalar -multiplication; -- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1); +- [Group](https://mathworld.wolfram.com/Group.html) defines addition, its identity element (i.e., 0) and additive + inverse (-x); +- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its identity element (i.e., 1); - [Field](http://mathworld.wolfram.com/Field.html) adds division operation. A typical implementation of `Field` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space`. In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate -interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot` -operation produces a matrix with new dimensions, which can be incompatible with initial matrix in terms of linear -operations. - -## Algebraic Element - -To achieve more familiar behavior (where you apply operations directly to mathematical objects), without involving -contexts KMath submits special type objects called `MathElement`. A `MathElement` is basically some object coupled to -a mathematical context. For example `Complex` is the pair of real numbers representing real and imaginary parts, -but it also holds reference to the `ComplexField` singleton, which allows performing direct operations on `Complex` -numbers without explicit involving the context like: - -```kotlin -import space.kscience.kmath.operations.* - -// Using elements -val c1 = Complex(1.0, 1.0) -val c2 = Complex(1.0, -1.0) -val c3 = c1 + c2 + 3.0.toComplex() - -// Using context -val c4 = ComplexField { c1 + i - 2.0 } -``` - -Both notations have their pros and cons. - -The hierarchy for algebraic elements follows the hierarchy for the corresponding algebraic structures. - -**MathElement** ← **SpaceElement** ← **RingElement** ← **FieldElement** - -`MathElement` is the generic common ancestor of the class with context. - -One major distinction between algebraic elements and algebraic contexts is that elements have three type -parameters: - -1. The type of elements, the field operates on. -2. The self-type of the element returned from operation (which has to be an algebraic element). -3. The type of the algebra over first type-parameter. - -The middle type is needed for of algebra members do not store context. For example, it is impossible to add a context -to regular `Double`. The element performs automatic conversions from context types and back. One should use context -operations in all performance-critical places. The performance of element operations is not guaranteed. +interface. Also, contexts may have operations, which produce elements outside the context. For example, `Matrix.dot` +operation produces a matrix with new dimensions, which can be incompatible with initial matrix in linear operations. ## Spaces and Fields -KMath submits both contexts and elements for builtin algebraic structures: +KMath introduces contexts for builtin algebraic structures: ```kotlin import space.kscience.kmath.operations.* @@ -102,13 +62,13 @@ val c2 = ComplexField { c1 - 1.0 } // Returns: Complex(re=0.0, im=2.0) val c3 = ComplexField { c1 - i * 2.0 } ``` -**Note**: In theory it is possible to add behaviors directly to the context, but as for now Kotlin does not support -that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and +**Note**: In theory it is possible to add behaviors directly to the context, but as for now Kotlin does not support +that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and [KEEP-176](https://github.com/Kotlin/KEEP/pull/176) for updates. ## Nested fields -Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex +Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex elements like so: ```kotlin @@ -118,8 +78,9 @@ val element = NDElement.complex(shape = intArrayOf(2, 2)) { index: IntArray -> ``` The `element` in this example is a member of the `Field` of 2D structures, each element of which is a member of its own -`ComplexField`. It is important one does not need to create a special n-d class to hold complex -numbers and implement operations on it, one just needs to provide a field for its elements. +`ComplexField`. It is important one does not need to create a special n-d class to hold complex numbers and implement +operations on it, one just needs to provide a field for its elements. -**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts like +**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts +like `MemorySpec`. diff --git a/docs/buffers.md b/docs/buffers.md index 679bd4e78..e7573497e 100644 --- a/docs/buffers.md +++ b/docs/buffers.md @@ -1,17 +1,20 @@ # Buffers -Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write (with `MutableBuffer`). -There are different types of buffers: +Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write ( +with `MutableBuffer`). There are different types of buffers: -* Primitive buffers wrapping like `RealBuffer` which are wrapping primitive arrays. +* Primitive buffers wrapping like `DoubleBuffer` which are wrapping primitive arrays. * Boxing `ListBuffer` wrapping a list * Functionally defined `VirtualBuffer` which does not hold a state itself, but provides a function to calculate value * `MemoryBuffer` allows direct allocation of objects in continuous memory block. -Some kmath features require a `BufferFactory` class to operate properly. A general convention is to use functions defined in -`Buffer` and `MutableBuffer` companion classes. For example factory `Buffer.Companion::auto` in most cases creates the most suitable -buffer for given reified type (for types with custom memory buffer it still better to use their own `MemoryBuffer.create()` factory). +Some kmath features require a `BufferFactory` class to operate properly. A general convention is to use functions +defined in +`Buffer` and `MutableBuffer` companion classes. For example factory `Buffer.Companion::auto` in most cases creates the +most suitable buffer for given reified type (for types with custom memory buffer it still better to use their +own `MemoryBuffer.create()` factory). ## Buffer performance -One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers instead +One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers +instead . diff --git a/docs/codestyle.md b/docs/codestyle.md index 541dc4973..73ba5f754 100644 --- a/docs/codestyle.md +++ b/docs/codestyle.md @@ -1,26 +1,20 @@ # Coding Conventions -KMath code follows general [Kotlin conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but -with a number of small changes and clarifications. +Generally, KMath code follows general [Kotlin coding conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but with a number of small changes and clarifications. ## Utility Class Naming -Filename should coincide with a name of one of the classes contained in the file or start with small letter and -describe its contents. +Filename should coincide with a name of one of the classes contained in the file or start with small letter and describe its contents. -The code convention [here](https://kotlinlang.org/docs/reference/coding-conventions.html#source-file-names) says that -file names should start with a capital letter even if file does not contain classes. Yet starting utility classes and -aggregators with a small letter seems to be a good way to visually separate those files. +The code convention [here](https://kotlinlang.org/docs/reference/coding-conventions.html#source-file-names) says that file names should start with a capital letter even if file does not contain classes. Yet starting utility classes and aggregators with a small letter seems to be a good way to visually separate those files. This convention could be changed in future in a non-breaking way. ## Private Variable Naming -Private variables' names may start with underscore `_` for of the private mutable variable is shadowed by the public -read-only value with the same meaning. +Private variables' names may start with underscore `_` for of the private mutable variable is shadowed by the public read-only value with the same meaning. -This rule does not permit underscores in names, but it is sometimes useful to "underscore" the fact that public and -private versions draw up the same entity. It is allowed only for private variables. +This rule does not permit underscores in names, but it is sometimes useful to "underscore" the fact that public and private versions draw up the same entity. It is allowed only for private variables. This convention could be changed in future in a non-breaking way. @@ -30,5 +24,4 @@ Use one-liners when they occupy single code window line both for functions and p `val b: String get() = "fff"`. The same should be performed with multiline expressions when they could be cleanly separated. -There is no universal consensus whenever use `fun a() = ...` or `fun a() { return ... }`. Yet from reader outlook -one-lines seem to better show that the property or function is easily calculated. +There is no universal consensus whenever use `fun a() = ...` or `fun a() { return ... }`. Yet from reader outlook one-lines seem to better show that the property or function is easily calculated. diff --git a/docs/contexts.md b/docs/contexts.md index 58b198046..c26333860 100644 --- a/docs/contexts.md +++ b/docs/contexts.md @@ -2,18 +2,17 @@ ## The problem -A known problem for implementing mathematics in statically-typed languages (but not only in them) is that different -sets of mathematical operators can be defined on the same mathematical objects. Sometimes there is no single way to -treat some operations, including basic arithmetic operations, on a Java/Kotlin `Number`. Sometimes there are different ways to -define the same structure, such as Euclidean and elliptic geometry vector spaces over real vectors. Another problem arises when -one wants to add some kind of behavior to an existing entity. In dynamic languages those problems are usually solved -by adding dynamic context-specific behaviors at runtime, but this solution has a lot of drawbacks. +A known problem for implementing mathematics in statically-typed languages (but not only in them) is that different sets +of mathematical operators can be defined on the same mathematical objects. Sometimes there is no single way to treat +some operations, including basic arithmetic operations, on a Java/Kotlin `Number`. Sometimes there are different ways to +define the same structure, such as Euclidean and elliptic geometry vector spaces over real vectors. Another problem +arises when one wants to add some kind of behavior to an existing entity. In dynamic languages those problems are +usually solved by adding dynamic context-specific behaviors at runtime, but this solution has a lot of drawbacks. ## Context-oriented approach -One possible solution to these problems is to divorce numerical representations from behaviors. -For example in Kotlin one can define a separate class which represents some entity without any operations, -ex. a complex number: +One possible solution to these problems is to divorce numerical representations from behaviors. For example in Kotlin +one can define a separate class representing some entity without any operations, ex. a complex number: ```kotlin data class Complex(val re: Double, val im: Double) @@ -28,9 +27,10 @@ object ComplexOperations { } ``` -In Java, applying such external operations could be very cumbersome, but Kotlin has a unique feature which allows us -implement this naturally: [extensions with receivers](https://kotlinlang.org/docs/reference/extensions.html#extension-functions). -In Kotlin, an operation on complex number could be implemented as: +In Java, applying such external operations could be cumbersome, but Kotlin has a unique feature that allows us +implement this +naturally: [extensions with receivers](https://kotlinlang.org/docs/reference/extensions.html#extension-functions). In +Kotlin, an operation on complex number could be implemented as: ```kotlin with(ComplexOperations) { c1 + c2 - c3 } @@ -52,20 +52,20 @@ In KMath, contexts are not only responsible for operations, but also for raw obj ### Type classes -An obvious candidate to get more or less the same functionality is the type class, which allows one to bind a behavior to -a specific type without modifying the type itself. On the plus side, type classes do not require explicit context +An obvious candidate to get more or less the same functionality is the type class, which allows one to bind a behavior +to a specific type without modifying the type itself. On the plus side, type classes do not require explicit context declaration, so the code looks cleaner. On the minus side, if there are different sets of behaviors for the same types, -it is impossible to combine them into one module. Also, unlike type classes, context can have parameters or even -state. For example in KMath, sizes and strides for `NDElement` or `Matrix` could be moved to context to optimize -performance in case of a large amount of structures. +it is impossible to combine them into one module. Also, unlike type classes, context can have parameters or even state. +For example in KMath, sizes and strides for `NDElement` or `Matrix` could be moved to context to optimize performance in +case of a large amount of structures. ### Wildcard imports and importing-on-demand -Sometimes, one may wish to use a single context throughout a file. In this case, is possible to import all members -from a package or file, via `import context.complex.*`. Effectively, this is the same as enclosing an entire file -with a single context. However when using multiple contexts, this technique can introduce operator ambiguity, due to -namespace pollution. If there are multiple scoped contexts which define the same operation, it is still possible to -to import specific operations as needed, without using an explicit context with extension functions, for example: +Sometimes, one may wish to use a single context throughout a file. In this case, is possible to import all members from +a package or file, via `import context.complex.*`. Effectively, this is the same as enclosing an entire file with a +single context. However, when using multiple contexts, this technique can introduce operator ambiguity, due to namespace +pollution. If there are multiple scoped contexts that define the same operation, it is still possible to import +specific operations as needed, without using an explicit context with extension functions, for example: ``` import context.complex.op1 diff --git a/docs/expressions.md b/docs/expressions.md index 1e05e5340..e6250110c 100644 --- a/docs/expressions.md +++ b/docs/expressions.md @@ -1,26 +1,21 @@ # Expressions -**Experimental: this API is in early stage and could change any time** - -Expressions is an experimental feature which allows to construct lazily or immediately calculated parametric mathematical -expressions. +Expressions is a feature, which allows constructing lazily or immediately calculated parametric mathematical expressions. The potential use-cases for it (so far) are following: -* Lazy evaluation (in general simple lambda is better, but there are some border cases) +* lazy evaluation (in general simple lambda is better, but there are some border cases); +* automatic differentiation in single-dimension and in multiple dimensions; +* generation of mathematical syntax trees with subsequent code generation for other languages; +* symbolic computations, especially differentiation (and some other actions with `kmath-symja` integration with Symja's `IExpr`—integration, simplification, and more); +* visualization with `kmath-jupyter`. -* Automatic differentiation in single-dimension and in multiple dimensions - -* Generation of mathematical syntax trees with subsequent code generation for other languages - -* Maybe symbolic computations (needs additional research) - -The workhorse of this API is `Expression` interface which exposes single `operator fun invoke(arguments: Map): T` -method. `ExpressionContext` is used to generate expressions and introduce variables. +The workhorse of this API is `Expression` interface, which exposes single `operator fun invoke(arguments: Map): T` +method. `ExpressionAlgebra` is used to generate expressions and introduce variables. Currently there are two implementations: * Generic `ExpressionField` in `kmath-core` which allows construction of custom lazy expressions -* Auto-differentiation expression in `kmath-commons` module allows to use full power of `DerivativeStructure` +* Auto-differentiation expression in `kmath-commons` module allows using full power of `DerivativeStructure` from commons-math. **TODO: add example** diff --git a/docs/features.md b/docs/features.md deleted file mode 100644 index 1068a4417..000000000 --- a/docs/features.md +++ /dev/null @@ -1,14 +0,0 @@ -# Features - -* [Algebra](algebra.md) - [Context-based](contexts.md) operations on different primitives and structures. - -* [NDStructures](nd-structure.md) - -* [Linear algebra](linear.md) - Matrices, operations and linear equations solving. To be moved to separate module. Currently supports basic -api and multiple library back-ends. - -* [Histograms](histograms.md) - Multidimensional histogram calculation and operations. - -* [Expressions](expressions.md) - -* Commons math integration diff --git a/docs/linear.md b/docs/linear.md index 6ccc6caac..2a05499ef 100644 --- a/docs/linear.md +++ b/docs/linear.md @@ -1,19 +1,31 @@ ## Basic linear algebra layout -KMath support for linear algebra organized in a context-oriented way. Meaning that operations are in most cases declared -in context classes, and are not the members of classes that store data. This allows more flexible approach to maintain multiple -back-ends. The new operations added as extensions to contexts instead of being member functions of data structures. +KMath support for linear algebra organized in a context-oriented way, which means that operations are in most cases declared in context classes, and are not the members of classes that store data. This allows more flexible approach to maintain multiple back-ends. The new operations added as extensions to contexts instead of being member functions of data structures. -Two major contexts used for linear algebra and hyper-geometry: +The main context for linear algebra over matrices and vectors is `LinearSpace`, which defines addition and dot products of matrices and vectors: -* `VectorSpace` forms a mathematical space on top of array-like structure (`Buffer` and its type alias `Point` used for geometry). +```kotlin +import space.kscience.kmath.linear.* -* `MatrixContext` forms a space-like context for 2d-structures. It does not store matrix size and therefore does not implement -`Space` interface (it is impossible to create zero element without knowing the matrix size). +LinearSpace.Companion.real { + val vec = buildVector(10) { i -> i.toDouble() } + val mat = buildMatrix(10, 10) { i, j -> i.toDouble() + j } -## Vector spaces + // Addition + vec + vec + mat + mat + // Multiplication by scalar + vec * 2.0 + mat * 2.0 -## Matrix operations + // Dot product + mat dot vec + mat dot mat +} +``` -## Back-end overview \ No newline at end of file +## Backends overview + +### EJML +### Commons Math diff --git a/docs/nd-structure.md b/docs/nd-structure.md index ab214094e..3e9203ec0 100644 --- a/docs/nd-structure.md +++ b/docs/nd-structure.md @@ -11,16 +11,16 @@ Let us consider following contexts: ```kotlin // automatically build context most suited for given type. val autoField = NDField.auto(DoubleField, dim, dim) - // specialized nd-field for Double. It works as generic Double field as well + // specialized nd-field for Double. It works as generic Double field as well. val specializedField = NDField.real(dim, dim) //A generic boxing field. It should be used for objects, not primitives. val genericField = NDField.buffered(DoubleField, dim, dim) ``` -Now let us perform several tests and see which implementation is best suited for each case: +Now let us perform several tests and see, which implementation is best suited for each case: ## Test case -In order to test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0` +To test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0` to it `n = 1000` times. ## Specialized @@ -35,8 +35,8 @@ The code to run this looks like: ``` The performance of this code is the best of all tests since it inlines all operations and is specialized for operation with doubles. We will measure everything else relative to this one, so time for this test will be `1x` (real time -on my computer is about 4.5 seconds). The only problem with this approach is that it requires to specify type -from the beginning. Everyone do so anyway, so it is the recommended approach. +on my computer is about 4.5 seconds). The only problem with this approach is that it requires specifying type +from the beginning. Everyone does so anyway, so it is the recommended approach. ## Automatic Let's do the same with automatic field inference: @@ -49,7 +49,7 @@ Let's do the same with automatic field inference: } ``` Ths speed of this operation is approximately the same as for specialized case since `NDField.auto` just -returns the same `RealNDField` in this case. Of course it is usually better to use specialized method to be sure. +returns the same `RealNDField` in this case. Of course, it is usually better to use specialized method to be sure. ## Lazy Lazy field does not produce a structure when asked, instead it generates an empty structure and fills it on-demand @@ -63,7 +63,7 @@ When one calls } } ``` -The result will be calculated almost immediately but the result will be empty. In order to get the full result +The result will be calculated almost immediately but the result will be empty. To get the full result structure one needs to call all its elements. In this case computation overhead will be huge. So this field never should be used if one expects to use the full result structure. Though if one wants only small fraction, it could save a lot of time. @@ -94,7 +94,7 @@ The boxing field produced by } } ``` -obviously is the slowest one, because it requires to box and unbox the `double` on each operation. It takes about +is the slowest one, because it requires boxing and unboxing the `double` on each operation. It takes about `15x` time (**TODO: there seems to be a problem here, it should be slow, but not that slow**). This field should never be used for primitives. @@ -123,6 +123,6 @@ for i in range(1000): ``` gives the completion time of about `1.1x`, which means that specialized kotlin code in fact is working faster (I think it is because better memory management). Of course if one writes `res += 1.0`, the performance will be different, -but it would be differenc case, because numpy overrides `+=` with in-place operations. In-place operations are +but it would be different case, because numpy overrides `+=` with in-place operations. In-place operations are available in `kmath` with `MutableNDStructure` but there is no field for it (one can still work with mapping functions). \ No newline at end of file diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 000000000..2953b7113 --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,14 @@ +# Documentation + +* [Algebra](algebra.md): [context-based](contexts.md) operations on different primitives and structures. + +* [NDStructures](nd-structure.md) + +* [Linear algebra](linear.md): matrices, operations and linear equations solving. To be moved to separate module. + Currently, supports basic API and multiple library back-ends. + +* [Histograms](histograms.md): multidimensional histogram calculation and operations. + +* [Expressions](expressions.md) + +* Commons math integration diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index bad11a31a..e75d4c5ed 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -6,10 +6,10 @@ # KMath -Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to -Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture -designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could -be achieved with [kmath-for-real](/kmath-for-real) extension module. +Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based +analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior +architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like +experience could be achieved with [kmath-for-real](/kmath-for-real) extension module. [Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) @@ -21,26 +21,33 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module. # Goal -* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native). +* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native) + . * Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide bindings and wrappers with those abstractions for popular optimized platform libraries. ## Non-goals -* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API. +* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API. * Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. -* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like -for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better -experience for those, who want to work with specific types. +* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like + for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better + experience for those, who want to work with specific types. ## Features and stability -KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels: +KMath is a modular library. Different modules provide different features with different API stability guarantees. All +core modules are released with the same version, but with different API change policy. The features are described in +module definitions below. The module stability could have the following levels: -* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. -* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations. -* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. +* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could + break any moment. You can still use it, but be sure to fix the specific version. +* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked + with `@UnstableKmathAPI` or other stability warning annotations. +* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor + versions, but not in patch versions. API is protected + with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. @@ -78,30 +85,33 @@ $modules ## Multi-platform support -KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the -[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features -are delegated to platform-specific implementations even if they could be provided in the common module for performance -reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and +KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the +[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features +are delegated to platform-specific implementations even if they could be provided in the common module for performance +reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and feedback are also welcome. ## Performance -Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve -both performance and flexibility. +Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both +performance and flexibility. -We expect to focus on creating convenient universal API first and then work on increasing performance for specific -cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized -native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be +We expect to focus on creating convenient universal API first and then work on increasing performance for specific +cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized +native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. ## Requirements -KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance. +KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for +execution to get better performance. ### Repositories -Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of -[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: +Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) +repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of +[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could +be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: ```kotlin repositories { @@ -118,7 +128,7 @@ Gradle `6.0+` is required for multiplatform artifacts. ## Contributing -The project requires a lot of additional work. The most important thing we need is a feedback about what features are -required the most. Feel free to create feature requests. We are also welcome to code contributions, -especially in issues marked with +The project requires a lot of additional work. The most important thing we need is a feedback about what features are +required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues +marked with [waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt index 6ceaa962a..dec3bfb81 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt @@ -13,8 +13,8 @@ import space.kscience.kmath.kotlingrad.toKotlingradExpression import space.kscience.kmath.operations.DoubleField /** - * In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with - * valid derivative in a certain point. + * In this example, *x2 − 4 x − 44* function is differentiated with Kotlin∇, and the + * derivation result is compared with valid derivative in a certain point. */ fun main() { val actualDerivative = "x^2-4*x-44" diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt index a9eca0500..7e09faeff 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt @@ -13,8 +13,8 @@ import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.symja.toSymjaExpression /** - * In this example, x^2-4*x-44 function is differentiated with Symja, and the autodiff result is compared with - * valid derivative in a certain point. + * In this example, *x2 − 4 x − 44* function is differentiated with Symja, and the + * derivation result is compared with valid derivative in a certain point. */ fun main() { val actualDerivative = "x^2-4*x-44" diff --git a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt index 5e64235e3..9118d09ae 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt @@ -25,8 +25,7 @@ import space.kscience.plotly.models.TraceValues import kotlin.math.pow import kotlin.math.sqrt -//Forward declaration of symbols that will be used in expressions. -// This declaration is required for +// Forward declaration of symbols that will be used in expressions. private val a by symbol private val b by symbol private val c by symbol diff --git a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt new file mode 100644 index 000000000..9c3d0fdbe --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.jafama + +import space.kscience.kmath.operations.invoke + +fun main() { + val a = 2.0 + val b = StrictJafamaDoubleField { exp(a) } + println(JafamaDoubleField { b + a }) + println(StrictJafamaDoubleField { ln(b) }) +} diff --git a/examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt deleted file mode 100644 index 879aab08f..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.jafama - -import net.jafama.FastMath - - -fun main(){ - val a = JafamaDoubleField.number(2.0) - val b = StrictJafamaDoubleField.power(FastMath.E,a) - - println(JafamaDoubleField.add(b,a)) - println(StrictJafamaDoubleField.ln(b)) -} 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 b319766e3..bde83cea9 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt @@ -10,9 +10,6 @@ import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.collectWithState import space.kscience.kmath.distributions.NormalDistribution -/** - * The state of distribution averager. - */ private data class AveragingChainState(var num: Int = 0, var value: Double = 0.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 501bf98db..e1621d477 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -32,7 +32,7 @@ fun main() { // automatically build context most suited for given type. val autoField = AlgebraND.auto(DoubleField, dim, dim) - // specialized nd-field for Double. It works as generic Double field as well + // specialized nd-field for Double. It works as generic Double field as well. val realField = AlgebraND.real(dim, dim) //A generic boxing field. It should be used for objects, not primitives. val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt index 74795cc68..ad6890b15 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt @@ -17,7 +17,7 @@ fun main() = BroadcastDoubleTensorAlgebra { // work in context with broadcast m dataset += fromArray( intArrayOf(5), - doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // rows means + doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // row means ) @@ -28,7 +28,7 @@ fun main() = BroadcastDoubleTensorAlgebra { // work in context with broadcast m println("Mean:\n$mean") println("Standard deviation:\n$std") - // also we can calculate other statistic as minimum and maximum of rows + // also, we can calculate other statistic as minimum and maximum of rows println("Minimum:\n${dataset.min(0, false)}") println("Maximum:\n${dataset.max(0, false)}") diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index 6453ca44e..3e6a60c31 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -42,7 +42,7 @@ fun main() = BroadcastDoubleTensorAlgebra {// work in context with linear operat // get P, L, U such that PA = LU val (p, l, u) = a.lu() - // check that P is permutation matrix + // check P is permutation matrix println("P:\n$p") // L is lower triangular matrix and U is upper triangular matrix println("L:\n$l") diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt index b262bee02..55a9aa67a 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt @@ -186,7 +186,7 @@ fun main() = BroadcastDoubleTensorAlgebra { x += fromArray( intArrayOf(5), - doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // rows means + doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // row means ) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt index 411e048d7..b973abdef 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -65,8 +65,8 @@ fun main(): Unit = BroadcastDoubleTensorAlgebra { // work in context with broad val datasetReduced = v dot stack(listOf(xScaled, yScaled)) println("Reduced data:\n$datasetReduced") - // we can restore original data from reduced data. - // for example, find 7th element of dataset + // we can restore original data from reduced data; + // for example, find 7th element of dataset. val n = 7 val restored = (datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean println("Original value:\n${dataset[n]}") diff --git a/kmath-ast/README.md b/kmath-ast/README.md index c3c4c38a1..686506f6f 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -106,7 +106,7 @@ var executable = function (constants, arguments) { }; ``` -JS also supports very experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. +JS also supports experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. Currently, only expressions inside `DoubleField` and `IntRing` are supported. ```kotlin @@ -161,7 +161,10 @@ public fun main() { Result LaTeX: +
+ ![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3}) +
Result MathML (can be used with MathJax or other renderers): diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md index b90f8ff08..9494af63a 100644 --- a/kmath-ast/docs/README-TEMPLATE.md +++ b/kmath-ast/docs/README-TEMPLATE.md @@ -77,7 +77,7 @@ var executable = function (constants, arguments) { }; ``` -JS also supports very experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. +JS also supports experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. Currently, only expressions inside `DoubleField` and `IntRing` are supported. ```kotlin @@ -132,7 +132,10 @@ public fun main() { Result LaTeX: +
+ ![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3}) +
Result MathML (can be used with MathJax or other renderers): diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt index 38450403d..ee23ab408 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.ast.rendering import space.kscience.kmath.misc.UnstableKMathAPI /** - * Mathematical typography syntax node. + * Syntax node for mathematical typography. * * @author Iaroslav Postovalov */ @@ -301,7 +301,7 @@ public data class BinaryPlusSyntax( } /** - * Represents binary, infix subtraction (*42 - 42*). + * Represents binary, infix subtraction (*42 − 42*). * * @param left The minuend. * @param right The subtrahend. diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt index fb2b3b66f..362c07d72 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI /** * Abstraction of writing [MathSyntax] as a string of an actual markup language. Typical implementation should - * involve traversal of MathSyntax with handling each its subtype. + * involve traversal of MathSyntax with handling each subtype. * * @author Iaroslav Postovalov */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt index 37e9a8c19..8a4804916 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt @@ -49,7 +49,7 @@ else NumberSyntax(string = s) /** - * Special printing for numeric types which are printed in form of + * Special printing for numeric types that are printed in form of * *('-'? (DIGIT+ ('.' DIGIT+)? ('E' '-'? DIGIT+)? | 'Infinity')) | 'NaN'*. * * @property types The suitable types. @@ -110,7 +110,7 @@ public class PrettyPrintFloats(public val types: Set>) : Rend } /** - * Special printing for numeric types which are printed in form of *'-'? DIGIT+*. + * Special printing for numeric types that are printed in form of *'-'? DIGIT+*. * * @property types The suitable types. * @author Iaroslav Postovalov @@ -155,7 +155,7 @@ public class PrettyPrintPi(public val symbols: Set) : RenderFeature { } /** - * Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is + * Abstract printing of unary operations that discards [MST] if their operation is not in [operations] or its type is * not [MST.Unary]. * * @param operations the allowed operations. If `null`, any operation is accepted. @@ -176,7 +176,7 @@ public abstract class Unary(public val operations: Collection?) : Render } /** - * Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is + * Abstract printing of unary operations that discards [MST] if their operation is not in [operations] or its type is * not [MST.Binary]. * * @property operations the allowed operations. If `null`, any operation is accepted. diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt index a84248f63..06e040e93 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt @@ -57,13 +57,13 @@ internal fun MethodVisitor.label(): Label = Label().also(::visitLabel) /** * Creates a class name for [Expression] subclassed to implement [mst] provided. * - * This methods helps to avoid collisions of class name to prevent loading several classes with the same name. If there + * These methods help to avoid collisions of class name to prevent loading several classes with the same name. If there * is a colliding class, change [collision] parameter or leave it `0` to check existing classes recursively. * * @author Iaroslav Postovalov */ internal tailrec fun buildName(mst: MST, collision: Int = 0): String { - val name = "space.kscience.kmath.asm.generated.AsmCompiledExpression_${mst.hashCode()}_$collision" + val name = "space.kscience.kmath.asm.generated.CompiledExpression_${mst.hashCode()}_$collision" try { Class.forName(name) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index 0925fee7e..d5473063a 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -31,7 +31,7 @@ public class DerivativeStructureField( override fun number(value: Number): DerivativeStructure = const(value.toDouble()) /** - * A class that implements both [DerivativeStructure] and a [Symbol] + * A class implementing both [DerivativeStructure] and [Symbol]. */ public inner class DerivativeStructureSymbol( size: Int, diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt index 0bf1d53f0..3c57f5467 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt @@ -34,7 +34,7 @@ internal class AutoDiffTest { println(z.derivative(x)) println(z.derivative(y, x)) assertEquals(z.derivative(x, y), z.derivative(y, x)) - //check that improper order cause failure + // check improper order cause failure assertFails { z.derivative(x, x, y) } } } diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt index 15c9120ec..b0e5d7904 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt @@ -27,7 +27,7 @@ internal class OptimizeTest { fun testGradientOptimization() { val result = normal.optimize(x, y) { initialGuess(x to 1.0, y to 1.0) - //no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function + // no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function. } println(result.point) println(result.value) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt index ce1265b2f..19befe6e6 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.expressions /** - * Represents expression which structure can be differentiated. + * Represents expression, which structure can be differentiated. * * @param T the type this expression takes as argument and returns. */ 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 84e66918f..5105c2bec 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 @@ -43,7 +43,7 @@ public operator fun Expression.invoke(vararg pairs: Pair): T = /** * Calls this expression from arguments. * - * @param pairs the pairs of arguments' names to values. + * @param pairs the pairs of arguments' names to value. * @return a value. */ @JvmName("callByString") @@ -60,7 +60,7 @@ public operator fun Expression.invoke(vararg pairs: Pair): T = public interface ExpressionAlgebra : Algebra { /** - * A constant expression which does not depend on arguments + * A constant expression that does not depend on arguments. */ public fun const(value: T): E } 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 5935424b6..838118339 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 @@ -18,7 +18,7 @@ public abstract class FunctionalExpressionAlgebra>( public val algebra: A, ) : ExpressionAlgebra> { /** - * Builds an Expression of constant expression which does not depend on arguments. + * Builds an Expression of constant expression that does not depend on arguments. */ override fun const(value: T): Expression = Expression { value } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt index 9c3ffd819..d63f141ba 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt @@ -8,8 +8,8 @@ package space.kscience.kmath.linear import space.kscience.kmath.nd.as1D /** - * A group of methods to solve for *X* in equation *X = A -1 · B*, where *A* and *B* are matrices or - * vectors. + * A group of methods to solve for *X* in equation *X = A−1 · B*, where *A* and *B* are + * matrices or vectors. * * @param T the type of items. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index badf2794e..63b881105 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt @@ -164,7 +164,7 @@ public interface LinearSpace> { public operator fun T.times(v: Point): Point = v * this /** - * Get a feature of the structure in this scope. Structure features take precedence other context features + * Get a feature of the structure in this scope. Structure features take precedence other context features. * * @param F the type of feature. * @param structure the structure. @@ -195,7 +195,7 @@ public interface LinearSpace> { } /** - * Get a feature of the structure in this scope. Structure features take precedence other context features + * Get a feature of the structure in this scope. Structure features take precedence other context features. * * @param T the type of items in the matrices. * @param F the type of feature. 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 f3653d394..25f53f65d 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 @@ -114,7 +114,7 @@ public fun > LinearSpace>.lup( for (i in 0 until col) sum -= luRow[i] * lu[i, col] luRow[col] = sum - // maintain best permutation choice + // maintain the best permutation choice if (abs(sum) > largest) { largest = abs(sum) max = row @@ -241,7 +241,7 @@ public fun LinearSpace.solveWithLup(a: Matrix, b: M } /** - * Inverses a square matrix using LUP decomposition. Non square matrix will throw a error. + * Inverses a square matrix using LUP decomposition. Non square matrix will throw an error. */ public fun LinearSpace.inverseWithLup(matrix: Matrix): Matrix = solveWithLup(matrix, one(matrix.rowNum, matrix.colNum)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt index e0d733a66..b70e9d8a9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt @@ -31,7 +31,7 @@ public object ZeroFeature : DiagonalFeature public object UnitFeature : DiagonalFeature /** - * Matrices with this feature can be inverted: [inverse] = `a`-1 where `a` is the owning matrix. + * Matrices with this feature can be inverted: *[inverse] = a−1* where *a* is the owning matrix. * * @param T the type of matrices' items. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt index 4b624b6a0..df3852d72 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt @@ -22,7 +22,8 @@ public class MatrixWrapper internal constructor( ) : Matrix by origin { /** - * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria + * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the + * criteria. */ @UnstableKMathAPI @Suppress("UNCHECKED_CAST") @@ -61,7 +62,7 @@ public operator fun Matrix.plus(newFeatures: Collection LinearSpace>.one( rows: Int, @@ -87,7 +88,7 @@ public class TransposedFeature(public val original: Matrix) : Ma * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` */ @OptIn(UnstableKMathAPI::class) -public fun Matrix.transpose(): Matrix = getFeature>()?.original ?: VirtualMatrix( +public fun Matrix.transpose(): Matrix = getFeature>()?.original ?: (VirtualMatrix( colNum, rowNum, -) { i, j -> get(j, i) } + TransposedFeature(this) \ No newline at end of file +) { i, j -> get(j, i) } + TransposedFeature(this)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt index e521e6237..99f959c86 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt @@ -7,8 +7,8 @@ package space.kscience.kmath.misc /** * Marks declarations that are still experimental in the KMath APIs, which means that the design of the corresponding - * declarations has open issues which may (or may not) lead to their changes in the future. Roughly speaking, there is - * a chance that those declarations will be deprecated in the near future or the semantics of their behavior may change + * declarations has open issues that may (or may not) lead to their changes in the future. Roughly speaking, there is + * a chance of those declarations will be deprecated in the near future or the semantics of their behavior may change * in some way that may break some code. */ @MustBeDocumented @@ -17,7 +17,7 @@ package space.kscience.kmath.misc public annotation class UnstableKMathAPI /** - * Marks API which could cause performance problems. The code, marked by this API is not necessary slow, but could cause + * Marks API that could cause performance problems. The code marked by this API is unnecessary slow but could cause * slow-down in some cases. Refer to the documentation and benchmark it to be sure. */ @MustBeDocumented diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt index 7b0b06a58..454a33e86 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt @@ -11,7 +11,7 @@ import space.kscience.kmath.structures.* import kotlin.reflect.KClass /** - * An exception is thrown when the expected ans actual shape of NDArray differs. + * An exception is thrown when the expected and actual shape of NDArray differ. * * @property expected the expected shape. * @property actual the actual shape. @@ -63,7 +63,7 @@ public interface AlgebraND> { structure.map { value -> this@invoke(value) } /** - * Get a feature of the structure in this scope. Structure features take precedence other context features + * Get a feature of the structure in this scope. Structure features take precedence other context features. * * @param F the type of feature. * @param structure the structure. @@ -79,7 +79,7 @@ public interface AlgebraND> { /** - * Get a feature of the structure in this scope. Structure features take precedence other context features + * Get a feature of the structure in this scope. Structure features take precedence other context features. * * @param T the type of items in the matrices. * @param F the type of feature. @@ -130,15 +130,6 @@ public interface GroupND> : Group>, AlgebraND override fun add(a: StructureND, b: StructureND): StructureND = combine(a, b) { aValue, bValue -> add(aValue, bValue) } -// /** -// * Element-wise multiplication by scalar. -// * -// * @param a the multiplicand. -// * @param k the multiplier. -// * @return the product. -// */ -// override fun multiply(a: NDStructure, k: Number): NDStructure = a.map { multiply(it, k) } - // TODO move to extensions after KEEP-176 /** @@ -226,7 +217,7 @@ public interface RingND> : Ring>, GroupND> : Field>, RingND, ScaleOperations> { +public interface FieldND> : Field>, RingND { /** * Element-wise division. * @@ -256,6 +247,15 @@ public interface FieldND> : Field>, RingND): StructureND = arg.map { divide(it, this@div) } + /** + * Element-wise scaling. + * + * @param a the multiplicand. + * @param value the multiplier. + * @return the product. + */ + override fun scale(a: StructureND, value: Double): StructureND = a.map { scale(it, value) } + // @ThreadLocal // public companion object { // private val realNDFieldCache: MutableMap = hashMapOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt index d916bc0d6..1af80149c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt @@ -110,7 +110,7 @@ internal class MutableBuffer1DWrapper(val buffer: MutableBuffer) : Mutable } /** - * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch + * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch. */ public fun StructureND.as1D(): Structure1D = this as? Structure1D ?: if (shape.size == 1) { when (this) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index cb69bdc00..293faaeda 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -144,13 +144,16 @@ private class MutableStructure2DWrapper(val structure: MutableStructureND) } /** - * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch + * Represents a [StructureND] as [Structure2D]. Throws runtime error in case of dimension mismatch. */ public fun StructureND.as2D(): Structure2D = this as? Structure2D ?: when (shape.size) { 2 -> Structure2DWrapper(this) else -> error("Can't create 2d-structure from ${shape.size}d-structure") } +/** + * Represents a [StructureND] as [Structure2D]. Throws runtime error in case of dimension mismatch. + */ public fun MutableStructureND.as2D(): MutableStructure2D = this as? MutableStructure2D ?: when (shape.size) { 2 -> MutableStructure2DWrapper(this) else -> error("Can't create 2d-structure from ${shape.size}d-structure") 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 1ad8289bc..716bd15f3 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 @@ -16,7 +16,7 @@ import kotlin.reflect.KClass public interface StructureFeature /** - * Represents n-dimensional structure, i.e. multidimensional container of items of the same type and size. The number + * Represents n-dimensional structure i.e., multidimensional container of items of the same type and size. The number * of dimensions and items in an array is defined by its shape, which is a sequence of non-negative integers that * specify the sizes of each dimension. * @@ -26,7 +26,7 @@ public interface StructureFeature */ public interface StructureND { /** - * 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 of * this structure. */ public val shape: IntArray @@ -53,8 +53,8 @@ public interface StructureND { public fun elements(): Sequence> /** - * Feature is some additional structure information which allows to access it special properties or hints. - * If the feature is not present, null is returned. + * Feature is some additional structure information that allows to access it special properties or hints. + * If the feature is not present, `null` is returned. */ @UnstableKMathAPI public fun getFeature(type: KClass): F? = null @@ -177,7 +177,7 @@ public inline fun MutableStructureND.mapInPlace(action: (IntArray, T) -> elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } /** - * A way to convert ND index to linear one and back. + * A way to convert ND indices to linear one and back. */ public interface Strides { /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt index cef34dce2..1009742e1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt @@ -23,15 +23,13 @@ public interface Algebra { * Wraps a raw string to [T] object. This method is designed for three purposes: * * 1. Mathematical constants (`e`, `pi`). - * 2. Variables for expression-like contexts (`a`, `b`, `c`...). - * 3. Literals (`{1, 2}`, (`(3; 4)`)). + * 1. Variables for expression-like contexts (`a`, `b`, `c`…). + * 1. Literals (`{1, 2}`, (`(3; 4)`)). * - * In case if algebra can't parse the string, this method must throw [kotlin.IllegalStateException]. - * - * Returns `null` if symbol could not be bound to the context + * If algebra can't parse the string, then this method must throw [kotlin.IllegalStateException]. * * @param value the raw string. - * @return an object. + * @return an object or `null` if symbol could not be bound to the context. */ public fun bindSymbolOrNull(value: String): T? = null @@ -42,13 +40,12 @@ public interface Algebra { bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this") /** - * Dynamically dispatches an unary operation with the certain name. + * Dynamically dispatches a unary operation with the certain name. * - * This function must has two features: + * Implementations must fulfil the following requirements: * - * 1. In case operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second `unaryOperation` overload: - * i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [unaryOperation]: for any `a` and `b`, `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. * * @param operation the name of operation. * @return an operation. @@ -57,13 +54,13 @@ public interface Algebra { error("Unary operation $operation not defined in $this") /** - * Dynamically invokes an unary operation with the certain name. + * Dynamically invokes a unary operation with the certain name. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [unaryOperationFunction] overload: - * i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [unaryOperationFunction]: i.e., for any `a` and `b`, + * `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. * * @param operation the name of operation. * @param arg the argument of operation. @@ -74,11 +71,11 @@ public interface Algebra { /** * Dynamically dispatches a binary operation with the certain name. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [binaryOperationFunction] overload: - * i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [binaryOperation]: for any `a`, `b`, and `c`, + * `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * * @param operation the name of operation. * @return an operation. @@ -89,11 +86,11 @@ public interface Algebra { /** * Dynamically invokes a binary operation with the certain name. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [binaryOperationFunction] overload: - * i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [binaryOperationFunction]: for any `a`, `b`, and `c`, + * `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -115,7 +112,7 @@ public fun Algebra.bindSymbol(symbol: Symbol): T = bindSymbol(symbol.iden public inline operator fun
, R> A.invoke(block: A.() -> R): R = run(block) /** - * Represents group without neutral element (also known as inverse semigroup), i.e. algebraic structure with + * Represents group without neutral element (also known as inverse semigroup) i.e., algebraic structure with * associative, binary operation [add]. * * @param T the type of element of this semispace. @@ -130,7 +127,7 @@ public interface GroupOperations : Algebra { */ public fun add(a: T, b: T): T - // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176 + // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176. /** * The negation of this element. @@ -192,7 +189,7 @@ public interface GroupOperations : Algebra { } /** - * Represents group, i.e. algebraic structure with associative, binary operation [add]. + * Represents group i.e., algebraic structure with associative, binary operation [add]. * * @param T the type of element of this semispace. */ @@ -204,7 +201,7 @@ public interface Group : GroupOperations { } /** - * Represents ring without multiplicative and additive identities, i.e. algebraic structure with + * Represents ring without multiplicative and additive identities i.e., algebraic structure with * associative, binary, commutative operation [add] and associative, operation [multiply] distributive over [add]. * * @param T the type of element of this semiring. @@ -240,7 +237,7 @@ public interface RingOperations : GroupOperations { } /** - * Represents ring, i.e. algebraic structure with two associative binary operations called "addition" and + * Represents ring i.e., algebraic structure with two associative binary operations called "addition" and * "multiplication" and their neutral elements. * * @param T the type of element of this ring. @@ -253,8 +250,9 @@ public interface Ring : Group, RingOperations { } /** - * Represents field without without multiplicative and additive identities, i.e. algebraic structure with associative, binary, commutative operations - * [add] and [multiply]; binary operation [divide] as multiplication of left operand by reciprocal of right one. + * Represents field without multiplicative and additive identities i.e., algebraic structure with associative, binary, + * commutative operations [add] and [multiply]; binary operation [divide] as multiplication of left operand by + * reciprocal of right one. * * @param T the type of element of this semifield. */ @@ -291,7 +289,7 @@ public interface FieldOperations : RingOperations { } /** - * Represents field, i.e. algebraic structure with three operations: associative, commutative addition and + * Represents field i.e., algebraic structure with three operations: associative, commutative addition and * multiplication, and division. **This interface differs from the eponymous mathematical definition: fields in KMath * also support associative multiplication by scalar.** * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt index 403a9c9b1..6b0e2cabd 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.operations import space.kscience.kmath.misc.UnstableKMathAPI /** - * The generic mathematics elements which is able to store its context + * The generic mathematics elements that is able to store its context * * @param C the type of mathematical context for this element. * @param T the type wrapped by this wrapper. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt index 4ccbfc531..8111691aa 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt @@ -121,7 +121,7 @@ public class BigInt internal constructor( var r = ZERO val bitSize = - (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: 0f + 1)).toInt() + (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: (0f + 1))).toInt() for (i in bitSize downTo 0) { r = r shl 1 @@ -442,7 +442,7 @@ public fun UIntArray.toBigInt(sign: Byte): BigInt { } /** - * Returns null if a valid number can not be read from a string + * Returns `null` if a valid number cannot be read from a string */ public fun String.parseBigInteger(): BigInt? { if (isEmpty()) return null diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt index 7a8fa5668..92070b33d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt @@ -26,11 +26,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically dispatches a binary operation with the certain name with numeric first argument. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [leftSideNumberOperation] overload: - * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. + * 1. If operation is not defined in the structure, then function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [leftSideNumberOperation]: for any `a`, `b`, and `c`, + * `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. * * @param operation the name of operation. * @return an operation. @@ -41,11 +41,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically invokes a binary operation with the certain name with numeric first argument. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [leftSideNumberOperation] overload: - * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [leftSideNumberOperation]: for any `a`, `b`, and `c`, + * `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -58,11 +58,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically dispatches a binary operation with the certain name with numeric first argument. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: - * i.e. `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [rightSideNumberOperation]: for any `a`, `b`, and `c`, + * `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @return an operation. @@ -73,11 +73,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically invokes a binary operation with the certain name with numeric second argument. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: - * i.e. `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [rightSideNumberOperationFunction]: for any `a`, `b`, and `c`, + * `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt index 86365394f..31bd47bc3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt @@ -330,13 +330,13 @@ public fun >> atanh(arg: T): */ public interface Norm { /** - * Computes the norm of [arg] (i.e. absolute value or vector length). + * Computes the norm of [arg] (i.e., absolute value or vector length). */ public fun norm(arg: T): R } /** - * Computes the norm of [arg] (i.e. absolute value or vector length). + * Computes the norm of [arg] (i.e., absolute value or vector length). */ @UnstableKMathAPI public fun >, R> norm(arg: T): R = arg.context.norm(arg) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt index b4ef37598..7a79663c4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt @@ -32,7 +32,7 @@ public value class DoubleBuffer(public val array: DoubleArray) : MutableBuffer Double): DoubleBuffer = DoubleBuffer(DoubleArray(size) { init(it) }) @@ -47,7 +47,7 @@ public fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(dou public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles) /** - * Returns a new [DoubleArray] containing all of the elements of this [Buffer]. + * Returns a new [DoubleArray] containing all the elements of this [Buffer]. */ public fun Buffer.toDoubleArray(): DoubleArray = when (this) { is DoubleBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt index 0b16a3afc..efb8504c2 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt @@ -51,7 +51,7 @@ public fun FlaggedBuffer<*>.hasFlag(index: Int, flag: ValueFlag): Boolean = (get public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, ValueFlag.MISSING) /** - * A real buffer which supports flags for each value like NaN or Missing + * A [Double] buffer that supports flags for each value like `NaN` or Missing. */ public class FlaggedDoubleBuffer(public val values: DoubleArray, public val flags: ByteArray) : FlaggedBuffer, Buffer { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt index 58b7c6aea..e7e98fc71 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt @@ -34,7 +34,7 @@ public value class FloatBuffer(public val array: FloatArray) : MutableBuffer Float): FloatBuffer = FloatBuffer(FloatArray(size) { init(it) }) @@ -44,7 +44,7 @@ public inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer = Fl public fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats) /** - * Returns a new [FloatArray] containing all of the elements of this [Buffer]. + * Returns a new [FloatArray] containing all the elements of this [Buffer]. */ public fun Buffer.toFloatArray(): FloatArray = when (this) { is FloatBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt index 57b6cfde3..35b722e2b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt @@ -33,7 +33,7 @@ public value class IntBuffer(public val array: IntArray) : MutableBuffer { * [init] function. * * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for an buffer element given its index. + * It should return the value for a buffer element given its index. */ public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffer(IntArray(size) { init(it) }) @@ -43,7 +43,7 @@ public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffe public fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints) /** - * Returns a new [IntArray] containing all of the elements of this [Buffer]. + * Returns a new [IntArray] containing all the elements of this [Buffer]. */ public fun Buffer.toIntArray(): IntArray = when (this) { is IntBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt index 57affa1c5..c69f4646d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt @@ -33,7 +33,7 @@ public value class LongBuffer(public val array: LongArray) : MutableBuffer * [init] function. * * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for an buffer element given its index. + * It should return the value for a buffer element given its index. */ public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongBuffer(LongArray(size) { init(it) }) @@ -43,7 +43,7 @@ public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongB public fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs) /** - * Returns a new [LongArray] containing all of the elements of this [Buffer]. + * Returns a new [LongArray] containing all the elements of this [Buffer]. */ public fun Buffer.toLongArray(): LongArray = when (this) { is LongBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt index 8dadecff7..20691511b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt @@ -31,7 +31,7 @@ public value class ShortBuffer(public val array: ShortArray) : MutableBuffer Short): ShortBuffer = ShortBuffer(ShortArray(size) { init(it) }) @@ -41,7 +41,7 @@ public inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer = Sh public fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts) /** - * Returns a new [ShortArray] containing all of the elements of this [Buffer]. + * Returns a new [ShortArray] containing all the elements of this [Buffer]. */ public fun Buffer.toShortArray(): ShortArray = when (this) { is ShortBuffer -> array.copyOf() diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt index 8523ac864..f8d2549e5 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt @@ -13,7 +13,7 @@ import kotlinx.coroutines.sync.withLock /** * A not-necessary-Markov chain of some type - * @param T - the chain element type + * @param T the chain element type */ public interface Chain : Flow { /** @@ -22,7 +22,7 @@ public interface Chain : Flow { public suspend fun next(): T /** - * Create a copy of current chain state. Consuming resulting chain does not affect initial chain + * Create a copy of current chain state. Consuming resulting chain does not affect initial chain. */ public suspend fun fork(): Chain @@ -62,9 +62,11 @@ public class MarkovChain(private val seed: suspend () -> R, private } /** - * A chain with possibly mutable state. The state must not be changed outside the chain. Two chins should never share the state - * @param S - the state of the chain - * @param forkState - the function to copy current state without modifying it + * A chain with possibly mutable state. The state must not be changed outside the chain. Two chins should never share + * the state. + * + * @param S the state of the chain. + * @param forkState the function to copy current state without modifying it. */ public class StatefulChain( private val state: S, @@ -96,7 +98,7 @@ public class ConstantChain(public val value: T) : Chain { /** * Map the chain result using suspended transformation. Initial chain result can no longer be safely consumed - * since mapped chain consumes tokens. Accepts regular transformation function + * since mapped chain consumes tokens. Accepts regular transformation function. */ public fun Chain.map(func: suspend (T) -> R): Chain = object : Chain { override suspend fun next(): R = func(this@map.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 0d6a1178a..4d4493aa4 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 @@ -76,7 +76,7 @@ public fun Flow.chunked(bufferSize: Int): Flow = flow { /** * Map a flow to a moving window buffer. The window step is one. - * In order to get different steps, one could use skip operation. + * To get different steps, one could use skip operation. */ public fun Flow.windowed(window: Int): Flow> = flow { require(window > 1) { "Window size must be more than one" } diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt index deb297913..eb099bd79 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt @@ -20,7 +20,7 @@ import kotlin.jvm.JvmInline public interface DMatrix : Structure2D { public companion object { /** - * Coerces a regular matrix to a matrix with type-safe dimensions and throws a error if coercion failed + * Coerces a regular matrix to a matrix with type-safe dimensions and throws an error if coercion failed */ public inline fun coerce(structure: Structure2D): DMatrix { require(structure.rowNum == Dimension.dim()) { @@ -35,7 +35,7 @@ public interface DMatrix : Structure2D { } /** - * The same as [DMatrix.coerce] but without dimension checks. Use with caution + * The same as [DMatrix.coerce] but without dimension checks. Use with caution. */ public fun coerceUnsafe(structure: Structure2D): DMatrix = DMatrixWrapper(structure) diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts index 25fdefaba..4cccaef5c 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -12,7 +12,7 @@ kotlin.sourceSets.commonMain { readme { description = """ - Extension module that should be used to achieve numpy-like behavior. + Extension module that should be used to achieve numpy-like behavior. All operations are specialized to work with `Double` numbers without declaring algebraic contexts. One can still use generic algebras though. """.trimIndent() diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt index d3867ea89..0508e9ca3 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt @@ -22,7 +22,7 @@ public typealias DoubleVector = Point public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer() /** - * Fill the vector of given [size] with given [value] + * Fill the vector with given [size] with given [value] */ @UnstableKMathAPI public fun Buffer.Companion.same(size: Int, value: Number): DoubleVector = double(size) { value.toDouble() } 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 c3556216d..1926ef02c 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 @@ -45,8 +45,8 @@ public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange> PiecewisePolynomial( } /** - * An optimized piecewise which uses not separate pieces, but a range separated by delimiters. - * The pieces search is logarithmic + * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. + * The pieces search is logarithmic. */ private class OrderedPiecewisePolynomial>( override val pieces: List, Polynomial>>, @@ -79,7 +79,7 @@ public class PiecewiseBuilder>(delimiter: T) { /** * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) * - * @param right new rightmost position. If is less then current rightmost position, an error is thrown. + * @param right new rightmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ public fun putRight(right: T, piece: Polynomial) { @@ -91,7 +91,7 @@ public class PiecewiseBuilder>(delimiter: T) { /** * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) * - * @param left the new leftmost position. If is less then current rightmost position, an error is thrown. + * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ public fun putLeft(left: T, piece: Polynomial) { @@ -114,7 +114,7 @@ public fun > PiecewisePolynomial( ): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() /** - * Return a value of polynomial function with given [ring] an given [arg] or null if argument is outside of piecewise + * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise * definition. */ public fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = 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 283f97557..278ef6abe 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 @@ -10,15 +10,17 @@ import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.indices - - /** * A simple one-pass integrator based on Gauss rule * Following integrand features are accepted: - * [GaussIntegratorRuleFactory] - A factory for computing the Gauss integration rule. By default uses [GaussLegendreRuleFactory] - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [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. - * [UnivariateIntegrandRanges] - Set of ranges and number of points per range. Defaults to given [IntegrationRange] and [IntegrandMaxCalls] + * + * * [GaussIntegratorRuleFactory]—a factory for computing the Gauss integration rule. By default, uses + * [GaussLegendreRuleFactory]. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. + * * [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. + * * [UnivariateIntegrandRanges]—set of ranges and number of points per range. Defaults to given + * [IntegrationRange] and [IntegrandMaxCalls]. */ public class GaussIntegrator( public val algebra: Field, @@ -71,14 +73,14 @@ public class GaussIntegrator( } /** - * Create a Gauss-Legendre integrator for this field + * Create a Gauss-Legendre integrator for this field. * @see [GaussIntegrator] */ -public val Field.gaussIntegrator: GaussIntegrator get() = GaussIntegrator(this) +public val Field.gaussIntegrator: GaussIntegrator get() = GaussIntegrator(this) /** - * Integrate using [intervals] segments with Gauss-Legendre rule of [order] order + * Integrate using [intervals] segments with Gauss-Legendre rule of [order] order. */ @UnstableKMathAPI public fun GaussIntegrator.integrate( 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 594ca9940..2eceec135 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 @@ -72,7 +72,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { } // Get previous rule. - // If it has not been computed yet it will trigger a recursive call + // If it has not been computed, yet it will trigger a recursive call // to this method. val previousPoints: Buffer = getOrBuildRule(numPoints - 1).first @@ -146,7 +146,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { } // If "numPoints" is odd, 0 is a root. // Note: as written, the test for oddness will work for negative - // integers too (although it is not necessary here), preventing + // integers too (although it is unnecessary here), preventing // a FindBugs warning. if (numPoints % 2 != 0) { var pmc = 1.0 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 baa9d4af8..c01c30ec2 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 @@ -13,9 +13,10 @@ import space.kscience.kmath.operations.sum /** * Use double pass Simpson rule integration with a fixed number of points. - * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls] - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [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. + * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls]. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. + * * [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. */ @UnstableKMathAPI public class SimpsonIntegrator( @@ -63,12 +64,12 @@ public val Field.simpsonIntegrator: SimpsonIntegrator get() = Si /** * Use double pass Simpson rule integration with a fixed number of points. - * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls] - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [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. + * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls]. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. + * * [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 { - private fun integrateRange( integrand: UnivariateIntegrand, range: ClosedRange, numPoints: Int, ): Double { 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 23d7bdd8d..07b37bd6a 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 @@ -45,8 +45,9 @@ public fun > PiecewisePolynomial.integrate( /** * A generic spline-interpolation-based analytic integration - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [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. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. + * * [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. */ @UnstableKMathAPI public class SplineIntegrator>( @@ -57,6 +58,7 @@ public class SplineIntegrator>( val range = integrand.getFeature()?.range ?: 0.0..1.0 val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { val numPoints = integrand.getFeature()?.maxCalls ?: 100 val step = (range.endInclusive - range.start) / (numPoints - 1) @@ -75,15 +77,16 @@ public class SplineIntegrator>( /** * A simplified double-based spline-interpolation-based analytic integration - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [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. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. + * * [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. */ @UnstableKMathAPI public object DoubleSplineIntegrator : UnivariateIntegrator { override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val range = integrand.getFeature()?.range ?: 0.0..1.0 - val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { val numPoints = integrand.getFeature()?.maxCalls ?: 100 val step = (range.endInclusive - range.start) / (numPoints - 1) 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 7f68284a7..9c8aeef1b 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 @@ -40,8 +40,8 @@ public class IntegrationRange(public val range: ClosedRange) : Integrand } /** - * Set of univariate integration ranges. First components correspond to ranges themselves, second components to number of - * integration nodes per range + * Set of univariate integration ranges. First components correspond to the ranges themselves, second components to + * number of integration nodes per range. */ public class UnivariateIntegrandRanges(public val ranges: List, Int>>) : IntegrandFeature { public constructor(vararg pairs: Pair, Int>) : this(pairs.toList()) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt index 31da4f392..4e803fc63 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt @@ -11,7 +11,7 @@ import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer /** - * The binned data element. Could be a histogram bin with a number of counts or an artificial construct + * The binned data element. Could be a histogram bin with a number of counts or an artificial construct. */ public interface Bin : Domain { /** diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt index f461ee4fa..ca37279c3 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt @@ -16,9 +16,10 @@ public val UnivariateDomain.center: Double get() = (range.endInclusive + range.start) / 2 /** - * A univariate bin based an a range - * @param value The value of histogram including weighting - * @param standardDeviation Standard deviation of the bin value. Zero or negative if not applicable + * A univariate bin based on a range + * + * @property value The value of histogram including weighting + * @property standardDeviation Standard deviation of the bin value. Zero or negative if not applicable */ @UnstableKMathAPI public class UnivariateBin( diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index 71097771d..3c5d4e19d 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -52,22 +52,4 @@ fun main() { According to KMath benchmarks on GraalVM, Jafama functions are slower than JDK math; however, there are indications that on Hotspot Jafama is a bit faster. -
- -Report for benchmark configuration jafamaDouble - - -* Run on OpenJDK 64-Bit Server VM (build 11.0.11+8-jvmci-21.1-b05) with Java process: - -``` -/home/commandertvis/graalvm-ce-java11/bin/java -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCIProduct -XX:-UnlockExperimentalVMOptions -XX:ThreadPriorityPolicy=1 -javaagent:/home/commandertvis/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core-jvm/1.5.0/d8cebccdcddd029022aa8646a5a953ff88b13ac8/kotlinx-coroutines-core-jvm-1.5.0.jar -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -ea -``` -* JMH 1.21 was used in `thrpt` mode with 1 warmup iteration by 1000 ms and 5 measurement iterations by 1000 ms. - -| Benchmark | Score | -|:---------:|:-----:| -|`space.kscience.kmath.benchmarks.JafamaBenchmark.core`|14.35014650168397 ± 0.9200669832937576 ops/s| -|`space.kscience.kmath.benchmarks.JafamaBenchmark.jafama`|12.048429204455887 ± 1.2882929181842269 ops/s| -|`space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafama`|12.977653357239152 ± 1.4122819627470866 ops/s| -
- +> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**. diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 3b337460f..aeb44ea13 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -1,6 +1,6 @@ # Module kmath-kotlingrad -[Kotlin∇](https://www.htmlsymbols.xyz/unicode/U+2207) integration module. +[Kotlin∇](https://github.com/breandan/kotlingrad) integration module. - [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression. - [scalars-adapters](src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST diff --git a/kmath-kotlingrad/docs/README-TEMPLATE.md b/kmath-kotlingrad/docs/README-TEMPLATE.md index ac38c849b..bc99bdf5f 100644 --- a/kmath-kotlingrad/docs/README-TEMPLATE.md +++ b/kmath-kotlingrad/docs/README-TEMPLATE.md @@ -1,6 +1,6 @@ # Module kmath-kotlingrad -[Kotlin∇](https://www.htmlsymbols.xyz/unicode/U+2207) integration module. +[Kotlin∇](https://github.com/breandan/kotlingrad) integration module. ${features} diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt index 930b21095..e8e51e9e2 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt @@ -156,6 +156,6 @@ public expect fun Memory.Companion.allocate(length: Int): Memory /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently from the resulting [Memory]. + * and could be mutated independently of the resulting [Memory]. */ public expect fun Memory.Companion.wrap(array: ByteArray): Memory diff --git a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt index 9a622ea36..6153743fc 100644 --- a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt +++ b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt @@ -95,7 +95,7 @@ public actual fun Memory.Companion.allocate(length: Int): Memory { /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently from the resulting [Memory]. + * and could be mutated independently of the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory { @Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array diff --git a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt index 944e8455b..aef68fd80 100644 --- a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt +++ b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt @@ -103,7 +103,7 @@ public actual fun Memory.Companion.allocate(length: Int): Memory = /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently from the resulting [Memory]. + * and could be mutated independently of the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory = ByteBufferMemory(checkNotNull(ByteBuffer.wrap(array))) diff --git a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt index d31c9e8f4..5146d9689 100644 --- a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt +++ b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt @@ -60,7 +60,7 @@ internal class NativeMemory( } override fun writeByte(offset: Int, value: Byte) { - array.set(position(offset), value) + array[position(offset)] = value } override fun writeShort(offset: Int, value: Short) { @@ -85,7 +85,7 @@ internal class NativeMemory( /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently from the resulting [Memory]. + * and could be mutated independently of the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory = NativeMemory(array) 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 7a650df3c..f69f831e8 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 @@ -35,7 +35,7 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND /** - * Unwraps to or acquires [INDArray] from [StructureND]. + * Unwraps to or get [INDArray] from [StructureND]. */ public val StructureND.ndArray: INDArray 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 97427d5c6..2a0fdc86c 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 @@ -17,7 +17,7 @@ import space.kscience.kmath.nd.StructureND */ public sealed class Nd4jArrayStructure : MutableStructureND { /** - * The wrapped [INDArray]. Since KMath uses [Int] indexes, assuming that the size of [INDArray] is less or equal to + * The wrapped [INDArray]. Since KMath uses [Int] indexes, assuming the size of [INDArray] is less or equal to * [Int.MAX_VALUE]. */ public abstract val ndArray: INDArray 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 0674c565e..1fdf845a6 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 @@ -29,7 +29,7 @@ public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra public fun INDArray.wrap(): Nd4jArrayStructure /** - * Unwraps to or acquires [INDArray] from [StructureND]. + * Unwraps to or gets [INDArray] from [StructureND]. */ public val StructureND.ndArray: INDArray diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt index 5a74a9a18..3d3f95f8f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt @@ -22,7 +22,7 @@ public interface Distribution : Sampler { override fun sample(generator: RandomGenerator): Chain /** - * An empty companion. Distribution factories should be written as its extensions + * An empty companion. Distribution factories should be written as its extensions. */ public companion object } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt index dde429244..1218f13c5 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt @@ -10,12 +10,12 @@ import space.kscience.kmath.chains.SimpleChain import space.kscience.kmath.stat.RandomGenerator /** - * A multivariate distribution which takes a map of parameters + * A multivariate distribution that takes a map of parameters. */ public interface NamedDistribution : Distribution> /** - * A multivariate distribution that has independent distributions for separate axis + * A multivariate distribution that has independent distributions for separate axis. */ public class FactorizedDistribution(public val distributions: Collection>) : NamedDistribution { diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt index a584af4f9..6e7eb039d 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt @@ -110,7 +110,7 @@ internal object InternalGamma { x <= 8.0 -> { val n = floor(x - 1.5).toInt() - val prod = (1..n).fold(1.0, { prod, i -> prod * (x - i) }) + val prod = (1..n).fold(1.0) { prod, i -> prod * (x - i) } logGamma1p(x - (n + 1)) + ln(prod) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index f54ba5723..997f1bbe3 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -11,27 +11,28 @@ import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.indices /** - * A likelihood function optimization problem with provided derivatives + * A likelihood function optimization problem with provided derivatives. */ public interface FunctionOptimization : Optimization { /** - * The optimization direction. If true search for function maximum, if false, search for the minimum + * The optimization direction. If true search for function maximum, if false, search for the minimum. */ public var maximize: Boolean /** - * Define the initial guess for the optimization problem + * Defines the initial guess for the optimization problem. */ public fun initialGuess(map: Map) /** - * Set a differentiable expression as objective function as function and gradient provider + * Set a differentiable expression as objective function as function and gradient provider. */ public fun diffFunction(expression: DifferentiableExpression) public companion object { /** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation + * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic + * differentiation. */ public fun chiSquared( autoDiff: AutoDiffProcessor>, @@ -61,7 +62,7 @@ public interface FunctionOptimization : Optimization { } /** - * Define a chi-squared-based objective function + * Defines a chi-squared-based objective function. */ public fun FunctionOptimization.chiSquared( autoDiff: AutoDiffProcessor>, @@ -76,7 +77,7 @@ public fun FunctionOptimization.chiSquared( } /** - * Optimize differentiable expression using specific [OptimizationProblemFactory] + * Optimizes differentiable expression using specific [OptimizationProblemFactory]. */ public fun > DifferentiableExpression.optimizeWith( factory: OptimizationProblemFactory, diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt index 0f2167549..44b66169f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt @@ -16,7 +16,7 @@ import kotlin.math.pow */ public interface NoDerivFunctionOptimization : Optimization { /** - * The optimization direction. If true search for function maximum, if false, search for the minimum + * The optimization direction. If `true` search for function maximum, search for the minimum otherwise. */ public var maximize: Boolean diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt index 15ae494f6..f85658d87 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt @@ -24,7 +24,7 @@ public operator fun OptimizationResult.plus( ): OptimizationResult = OptimizationResult(point, value, features + feature) /** - * An optimization problem builder over [T] variables + * A builder of optimization problems over [T] variables */ public interface Optimization { 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 93605c7d8..993215d41 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 @@ -14,9 +14,9 @@ import kotlin.math.* /** * Sampling from the [gamma distribution](http://mathworld.wolfram.com/GammaDistribution.html). - * - For 0 < alpha < 1: + * * For 0 < alpha < 1: * Ahrens, J. H. and Dieter, U., Computer methods for sampling from gamma, beta, Poisson and binomial distributions, Computing, 12, 223-246, 1974. - * - For alpha >= 1: + * * For alpha >= 1: * Marsaglia and Tsang, A Simple Method for Generating Gamma Variables. ACM Transactions on Mathematical Software, Volume 26 Issue 3, September, 2000. * * Based on Commons RNG implementation. diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt index 36ddd3c8e..5390a2e09 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt @@ -20,7 +20,7 @@ import kotlin.math.min * implements Vose's algorithm. * * Vose, M.D., A linear algorithm for generating random numbers with a given distribution, IEEE Transactions on - * Software Engineering, 17, 972-975, 1991. he algorithm will sample values in O(1) time after a pre-processing step + * Software Engineering, 17, 972-975, 1991. The algorithm will sample values in O(1) time after a pre-processing step * of O(n) time. * * The alias tables are constructed using fraction probabilities with an assumed denominator of 253. In the generic @@ -77,7 +77,7 @@ public open class AliasMethodDiscreteSampler private constructor( } override fun sample(generator: RandomGenerator): Chain = generator.chain { - // This implements the algorithm as per Vose (1991): + // This implements the algorithm in accordance with Vose (1991): // v = uniform() in [0, 1) // j = uniform(n) in [0, n) // if v < prob[j] then @@ -95,7 +95,7 @@ public open class AliasMethodDiscreteSampler private constructor( // p(j) == 1 => j // However it is assumed these edge cases are rare: // - // The probability table will be 1 for approximately 1/n samples, i.e. only the + // The probability table will be 1 for approximately 1/n samples i.e., only the // last unpaired probability. This is only worth checking for when the table size (n) // is small. But in that case the user should zero-pad the table for performance. // @@ -211,7 +211,7 @@ public open class AliasMethodDiscreteSampler private constructor( // c: 2=2/3; 6=1/3 (6 is the alias) // d: 1=1/3; 6=2/3 (6 is the alias) // - // The sample is obtained by randomly selecting a section, then choosing which category + // The sample is obtained by randomly selecting a section, then choosing, which category // from the pair based on a uniform random deviate. val sumProb = InternalUtils.validateProbabilities(probabilities) // Allow zero-padding @@ -241,9 +241,9 @@ public open class AliasMethodDiscreteSampler private constructor( val alias = IntArray(n) // This loop uses each large in turn to fill the alias table for small probabilities that - // do not reach the requirement to fill an entire section alone (i.e. p < mean). + // do not reach the requirement to fill an entire section alone (i.e., p < mean). // Since the sum of the small should be less than the sum of the large it should use up - // all the small first. However floating point round-off can result in + // all the small first. However, floating point round-off can result in // misclassification of items as small or large. The Vose algorithm handles this using // a while loop conditioned on the size of both sets and a subsequent loop to use // unpaired items. diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt index 14737decb..0105731c4 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt @@ -13,7 +13,7 @@ import kotlin.math.exp /** * Sampler for the Poisson distribution. - * - Kemp, A, W, (1981) Efficient Generation of Logarithmically Distributed Pseudo-Random Variables. Journal of the Royal Statistical Society. Vol. 30, No. 3, pp. 249-253. + * * Kemp, A, W, (1981) Efficient Generation of Logarithmically Distributed Pseudo-Random Variables. Journal of the Royal Statistical Society. Vol. 30, No. 3, pp. 249-253. * This sampler is suitable for mean < 40. For large means, LargeMeanPoissonSampler should be used instead. * * Note: The algorithm uses a recurrence relation to compute the Poisson probability and a rolling summation for the cumulative probability. When the mean is large the initial probability (Math.exp(-mean)) is zero and an exception is raised by the constructor. @@ -66,8 +66,7 @@ public class KempSmallMeanPoissonSampler internal constructor( public fun KempSmallMeanPoissonSampler(mean: Double): KempSmallMeanPoissonSampler { require(mean > 0) { "Mean is not strictly positive: $mean" } val p0 = exp(-mean) - // Probability must be positive. As mean increases then p(0) decreases. + // Probability must be positive. As mean increases, p(0) decreases. require(p0 > 0) { "No probability for mean: $mean" } return KempSmallMeanPoissonSampler(p0, mean) } - diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt index 96131aa4b..f0f94900e 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt @@ -18,11 +18,11 @@ private const val PIVOT = 40.0 /** * Sampler for the Poisson distribution. - * - For small means, a Poisson process is simulated using uniform deviates, as described in + * * For small means, a Poisson process is simulated using uniform deviates, as described in * Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3 * Important integer-valued distributions: The Poisson distribution. Addison Wesley. * The Poisson process (and hence, the returned value) is bounded by 1000 * mean. - * - For large means, we use the rejection algorithm described in + * * For large means, we use the rejection algorithm described in * Devroye, Luc. (1981). The Computer Generation of Poisson Random Variables Computing vol. 26 pp. 197-207. * * Based on Commons RNG implementation. @@ -35,10 +35,10 @@ public fun PoissonSampler(mean: Double): Sampler { /** * Sampler for the Poisson distribution. - * - For small means, a Poisson process is simulated using uniform deviates, as described in + * * For small means, a Poisson process is simulated using uniform deviates, as described in * Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3 Important * integer-valued distributions: The Poisson distribution. Addison Wesley. - * - The Poisson process (and hence, the returned value) is bounded by 1000 * mean. + * * The Poisson process (and hence, the returned value) is bounded by 1000 * mean. * This sampler is suitable for mean < 40. For large means, [LargeMeanPoissonSampler] should be used instead. * * Based on Commons RNG implementation. diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt index 5698f1a79..f280a78aa 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt @@ -23,7 +23,7 @@ public interface RandomGenerator { public fun nextDouble(): Double /** - * A chunk of doubles of given [size] + * A chunk of doubles of given [size]. */ public fun nextDoubleBuffer(size: Int): DoubleBuffer = DoubleBuffer(size) { nextDouble() } @@ -57,7 +57,7 @@ public interface RandomGenerator { public fun nextLong(until: Long): Long /** - * Fills a subrange of the specified byte [array] starting from [fromIndex] inclusive and ending [toIndex] exclusive + * Fills a subrange with the specified byte [array] starting from [fromIndex] inclusive and ending [toIndex] exclusive * with random bytes. * * @return [array] with the subrange filled with random bytes. @@ -70,7 +70,7 @@ public interface RandomGenerator { public fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) } /** - * Create a new generator which is independent from current generator (operations on new generator do not affect this one + * Create a new generator that is independent of current generator (operations on new generator do not affect this one * and vise versa). The statistical properties of new generator should be the same as for this one. * For pseudo-random generator, the fork is keeping the same sequence of numbers for given call order for each run. * diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt index 849cf152a..044e489b2 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt @@ -32,7 +32,7 @@ public class BasicSampler(public val chainBuilder: (RandomGenerator } /** - * A space of samplers. Allows to perform simple operations on distributions. + * A space of samplers. Allows performing simple operations on distributions. * * @property algebra the space to provide addition and scalar multiplication for [T]. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt index 499dcac6a..0af901fc9 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt @@ -30,9 +30,10 @@ public interface BlockingStatistic : Statistic { /** * A statistic tha could be computed separately on different blocks of data and then composed - * @param T - source type - * @param I - intermediate block type - * @param R - result type + * + * @param T the source type. + * @param I the intermediate block type. + * @param R the result type. */ public interface ComposableStatistic : Statistic { //compute statistic on a single block diff --git a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt index 7aaac7d32..202a1c8dd 100644 --- a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt +++ b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt @@ -55,7 +55,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un /** * Generates [Byte] values and places them into a user-supplied array. * - * The number of random bytes produced is equal to the length of the the byte array. + * The number of random bytes produced is equal to the length of the byte array. * * @param bytes byte array in which to put the random bytes. */ 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 6bdecfa85..af4ae8239 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 @@ -23,7 +23,7 @@ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { /** * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. * Given a square matrix `A`, return the matrix `AInv` satisfying - * `A dot AInv = AInv dot A = eye(a.shape[0])`. + * `A dot AInv == AInv dot A == eye(a.shape[0])`. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv * * @return the multiplicative inverse of a matrix. @@ -36,25 +36,27 @@ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { * Computes the Cholesky decomposition of a Hermitian (or symmetric for real-valued matrices) * positive-definite matrix or the Cholesky decompositions for a batch of such matrices. * Each decomposition has the form: - * Given a tensor `input`, return the tensor `L` satisfying `input = L dot L.H`, - * where L is a lower-triangular matrix and L.H is the conjugate transpose of L, + * Given a tensor `input`, return the tensor `L` satisfying `input = L dot LH`, + * where `L` is a lower-triangular matrix and `LH` is the conjugate transpose of `L`, * which is just a transpose for the case of real-valued input matrices. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky * - * @return the batch of L matrices. + * @receiver the `input`. + * @return the batch of `L` matrices. */ public fun Tensor.cholesky(): Tensor /** * QR decomposition. * - * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. - * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q dot R``, + * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `Q to R` of tensors. + * Given a tensor `input`, return tensors `Q to R` satisfying `input == Q dot R`, * with `Q` being an orthogonal matrix or batch of orthogonal matrices * and `R` being an upper triangular matrix or batch of upper triangular matrices. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr * - * @return pair of Q and R tensors. + * @receiver the `input`. + * @return pair of `Q` and `R` tensors. */ public fun Tensor.qr(): Pair, Tensor> @@ -67,7 +69,8 @@ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { * `L` being a lower triangular matrix or batch of matrices, * `U` being an upper triangular matrix or batch of matrices. * - * * @return triple of P, L and U tensors + * @receiver the `input`. + * @return triple of P, L and U tensors */ public fun Tensor.lu(): Triple, Tensor, Tensor> @@ -75,22 +78,25 @@ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { * Singular Value Decomposition. * * Computes the singular value decomposition of either a matrix or batch of matrices `input`. - * The singular value decomposition is represented as a triple `(U, S, V)`, - * such that `input = U dot diagonalEmbedding(S) dot V.H`, - * where V.H is the conjugate transpose of V. - * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. + * The singular value decomposition is represented as a triple `Triple(U, S, V)`, + * such that `input = U dot diagonalEmbedding(S) dot VH`, + * where `VH` is the conjugate transpose of V. + * If `input` is a batch of tensors, then `U`, `S`, and `VH` are also batched with the same batch dimensions as + * `input`. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd * - * @return triple `(U, S, V)`. + * @receiver the `input`. + * @return triple `Triple(U, S, V)`. */ public fun Tensor.svd(): Triple, Tensor, Tensor> /** - * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, - * represented by a pair (eigenvalues, eigenvectors). + * Returns eigenvalues and eigenvectors of a real symmetric matrix `input` or a batch of real symmetric matrices, + * represented by a pair `eigenvalues to eigenvectors`. * For more information: https://pytorch.org/docs/stable/generated/torch.symeig.html * - * @return a pair (eigenvalues, eigenvectors) + * @receiver the `input`. + * @return a pair `eigenvalues to eigenvectors` */ public fun Tensor.symEig(): Pair, Tensor> diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 62b8ef046..d48e7b1c9 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -14,7 +14,6 @@ import space.kscience.kmath.operations.Algebra * @param T the type of items in the tensors. */ public interface TensorAlgebra : Algebra> { - /** * Returns a single tensor value of unit dimension if tensor shape equals to [1]. * @@ -189,7 +188,7 @@ public interface TensorAlgebra : Algebra> { /** * View this tensor as the same size as [other]. - * ``this.viewAs(other) is equivalent to this.view(other.shape)``. + * `this.viewAs(other)` is equivalent to `this.view(other.shape)`. * For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html * * @param other the result tensor has the same size as other. @@ -217,14 +216,14 @@ public interface TensorAlgebra : Algebra> { * a 1 is prepended to its dimension for the purpose of the batched matrix multiply and removed after. * If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix * multiple and removed after. - * The non-matrix (i.e. batch) dimensions are broadcast (and thus must be broadcastable). + * The non-matrix (i.e., batch) dimensions are broadcast (and thus must be broadcastable). * For example, if `input` is a (j × 1 × n × n) tensor and `other` is a * (k × n × n) tensor, out will be a (j × k × n × n) tensor. * * For more information: https://pytorch.org/docs/stable/generated/torch.matmul.html * - * @param other tensor to be multiplied - * @return mathematical product of two tensors + * @param other tensor to be multiplied. + * @return a mathematical product of two tensors. */ public infix fun Tensor.dot(other: Tensor): Tensor @@ -234,7 +233,7 @@ public interface TensorAlgebra : Algebra> { * To facilitate creating batched diagonal matrices, * the 2D planes formed by the last two dimensions of the returned tensor are chosen by default. * - * The argument [offset] controls which diagonal to consider: + * The argument [offset] controls, which diagonal to consider: * 1. If [offset] = 0, it is the main diagonal. * 1. If [offset] > 0, it is above the main diagonal. * 1. If [offset] < 0, it is below the main diagonal. @@ -321,7 +320,7 @@ public interface TensorAlgebra : Algebra> { * * @param dim the dimension to reduce. * @param keepDim whether the output tensor has [dim] retained or not. - * @return the the index of maximum value of each row of the input tensor in the given dimension [dim]. + * @return the index of maximum value of each row of the input tensor in the given dimension [dim]. */ public fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index 02bf5415d..867d4b26e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -49,7 +49,7 @@ public interface TensorPartialDivisionAlgebra : TensorAlgebra { /** * Each element of this tensor is divided by each element of the [other] tensor. * - * @param other tensor to be divide by. + * @param other tensor to be divided by. */ public operator fun Tensor.divAssign(other: Tensor) } 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 d182558c5..d6ad8e8e2 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 @@ -90,37 +90,37 @@ public open class DoubleTensorAlgebra : } /** - * Returns a tensor filled with the scalar value 0.0, with the shape defined by the variable argument [shape]. + * Returns a tensor filled with the scalar value `0.0`, with the shape defined by the variable argument [shape]. * * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value 0.0, with the [shape] shape. + * @return tensor filled with the scalar value `0.0`, with the [shape] shape. */ public fun zeros(shape: IntArray): DoubleTensor = full(0.0, shape) /** - * Returns a tensor filled with the scalar value 0.0, with the same shape as a given array. + * Returns a tensor filled with the scalar value `0.0`, with the same shape as a given array. * - * @return tensor filled with the scalar value 0.0, with the same shape as `input` tensor. + * @return tensor filled with the scalar value `0.0`, with the same shape as `input` tensor. */ public fun Tensor.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) /** - * Returns a tensor filled with the scalar value 1.0, with the shape defined by the variable argument [shape]. + * Returns a tensor filled with the scalar value `1.0`, with the shape defined by the variable argument [shape]. * * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value 1.0, with the [shape] shape. + * @return tensor filled with the scalar value `1.0`, with the [shape] shape. */ public fun ones(shape: IntArray): DoubleTensor = full(1.0, shape) /** - * Returns a tensor filled with the scalar value 1.0, with the same shape as a given array. + * Returns a tensor filled with the scalar value `1.0`, with the same shape as a given array. * - * @return tensor filled with the scalar value 1.0, with the same shape as `input` tensor. + * @return tensor filled with the scalar value `1.0`, with the same shape as `input` tensor. */ public fun Tensor.onesLike(): DoubleTensor = tensor.fullLike(1.0) /** - * Returns a 2-D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. + * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. * * @param n the number of rows and columns * @return a 2-D tensor with ones on the diagonal and zeros elsewhere. @@ -311,7 +311,6 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun Tensor.view(shape: IntArray): DoubleTensor { checkView(tensor, shape) return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) @@ -444,7 +443,7 @@ public open class DoubleTensorAlgebra : /** * Compares element-wise two tensors. - * Comparison of two Double values occurs with 1e-5 precision. + * Comparison of two Double values occurs with `1e-5` precision. * * @param other the tensor to compare with `input` tensor. * @return true if two tensors have the same shape and elements, false otherwise. @@ -473,23 +472,24 @@ public open class DoubleTensorAlgebra : } /** - * Returns a tensor of random numbers drawn from normal distributions with 0.0 mean and 1.0 standard deviation. + * Returns a tensor of random numbers drawn from normal distributions with `0.0` mean and `1.0` standard deviation. * * @param shape the desired shape for the output tensor. * @param seed the random seed of the pseudo-random number generator. * @return tensor of a given shape filled with numbers from the normal distribution - * with 0.0 mean and 1.0 standard deviation. + * with `0.0` mean and `1.0` standard deviation. */ public fun randomNormal(shape: IntArray, seed: Long = 0): DoubleTensor = DoubleTensor(shape, getRandomNormals(shape.reduce(Int::times), seed)) /** * Returns a tensor with the same shape as `input` of random numbers drawn from normal distributions - * with 0.0 mean and 1.0 standard deviation. + * with `0.0` mean and `1.0` standard deviation. * + * @receiver the `input`. * @param seed the random seed of the pseudo-random number generator. - * @return tensor with the same shape as `input` filled with numbers from the normal distribution - * with 0.0 mean and 1.0 standard deviation. + * @return a tensor with the same shape as `input` filled with numbers from the normal distribution + * with `0.0` mean and `1.0` standard deviation. */ public fun Tensor.randomNormalLike(seed: Long = 0): DoubleTensor = DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) @@ -512,10 +512,10 @@ public open class DoubleTensorAlgebra : } /** - * Builds tensor from rows of input tensor + * Builds tensor from rows of the input tensor. * * @param indices the [IntArray] of 1-dimensional indices - * @return tensor with rows corresponding to rows by [indices] + * @return tensor with rows corresponding to row by [indices] */ public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) @@ -615,12 +615,12 @@ public open class DoubleTensorAlgebra : } /** - * Returns the covariance matrix M of given vectors. + * Returns the covariance matrix `M` of given vectors. * - * M[i, j] contains covariance of i-th and j-th given vectors + * `M[i, j]` contains covariance of `i`-th and `j`-th given vectors * * @param tensors the [List] of 1-dimensional tensors with same shape - * @return the covariance matrix + * @return `M`. */ public fun cov(tensors: List>): DoubleTensor { check(tensors.isNotEmpty()) { "List must have at least 1 element" } @@ -703,14 +703,14 @@ public open class DoubleTensorAlgebra : /** * Unpacks the data and pivots from a LU factorization of a tensor. - * Given a tensor [luTensor], return tensors (P, L, U) satisfying ``P * luTensor = L * U``, + * Given a tensor [luTensor], return tensors `Triple(P, L, U)` satisfying `P dot luTensor = L dot U`, * with `P` being a permutation matrix or batch of matrices, * `L` being a lower triangular matrix or batch of matrices, * `U` being an upper triangular matrix or batch of matrices. * * @param luTensor the packed LU factorization data * @param pivotsTensor the packed LU factorization pivots - * @return triple of P, L and U tensors + * @return triple of `P`, `L` and `U` tensors */ public fun luPivot( luTensor: Tensor, @@ -746,14 +746,15 @@ public open class DoubleTensorAlgebra : /** * QR decomposition. * - * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. - * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q * R``, + * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `Q to R` of tensors. + * Given a tensor `input`, return tensors `Q to R` satisfying `input == Q dot R`, * with `Q` being an orthogonal matrix or batch of orthogonal matrices * and `R` being an upper triangular matrix or batch of upper triangular matrices. * - * @param epsilon permissible error when comparing tensors for equality. + * @receiver the `input`. + * @param epsilon the permissible error when comparing tensors for equality. * Used when checking the positive definiteness of the input matrix or matrices. - * @return pair of Q and R tensors. + * @return a pair of `Q` and `R` tensors. */ public fun Tensor.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) @@ -793,13 +794,14 @@ public open class DoubleTensorAlgebra : * Singular Value Decomposition. * * Computes the singular value decomposition of either a matrix or batch of matrices `input`. - * The singular value decomposition is represented as a triple `(U, S, V)`, - * such that ``input = U.dot(diagonalEmbedding(S).dot(V.T))``. - * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. + * The singular value decomposition is represented as a triple `Triple(U, S, V)`, + * such that `input == U dot diagonalEmbedding(S) dot V.transpose()`. + * If `input` is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as `input. * - * @param epsilon permissible error when calculating the dot product of vectors, - * i.e. the precision with which the cosine approaches 1 in an iterative algorithm. - * @return triple `(U, S, V)`. + * @receiver the `input`. + * @param epsilon permissible error when calculating the dot product of vectors + * i.e., the precision with which the cosine approaches 1 in an iterative algorithm. + * @return a triple `Triple(U, S, V)`. */ public fun Tensor.svd(epsilon: Double): Triple { val size = tensor.dimension @@ -834,11 +836,11 @@ public open class DoubleTensorAlgebra : /** * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, - * represented by a pair (eigenvalues, eigenvectors). + * represented by a pair `eigenvalues to eigenvectors`. * - * @param epsilon permissible error when comparing tensors for equality + * @param epsilon the permissible error when comparing tensors for equality * and when the cosine approaches 1 in the SVD algorithm. - * @return a pair (eigenvalues, eigenvectors) + * @return a pair `eigenvalues to eigenvectors`. */ public fun Tensor.symEig(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) @@ -857,11 +859,11 @@ public open class DoubleTensorAlgebra : * Computes the determinant of a square matrix input, or of each square matrix in a batched input * using LU factorization algorithm. * - * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero + * @param epsilon the error in the LU algorithm—permissible error when comparing the determinant of a matrix + * with zero. * @return the determinant. */ public fun Tensor.detLU(epsilon: Double = 1e-9): DoubleTensor { - checkSquareMatrix(tensor.shape) val luTensor = tensor.copy() val pivotsTensor = tensor.setUpPivots() @@ -889,9 +891,9 @@ public open class DoubleTensorAlgebra : * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input * using LU factorization algorithm. * Given a square matrix `a`, return the matrix `aInv` satisfying - * ``a.dot(aInv) = aInv.dot(a) = eye(a.shape[0])``. + * `a dot aInv == aInv dot a == eye(a.shape[0])`. * - * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero + * @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 Tensor.invLU(epsilon: Double = 1e-9): DoubleTensor { @@ -908,16 +910,16 @@ public open class DoubleTensorAlgebra : } /** - * LUP decomposition + * LUP decomposition. * * Computes the LUP decomposition of a matrix or a batch of matrices. - * Given a tensor `input`, return tensors (P, L, U) satisfying ``P * input = L * U``, + * Given a tensor `input`, return tensors `Triple(P, L, U)` satisfying `P dot input == L dot U`, * with `P` being a permutation matrix or batch of matrices, * `L` being a lower triangular matrix or batch of matrices, * `U` being an upper triangular matrix or batch of matrices. * - * @param epsilon permissible error when comparing the determinant of a matrix with zero - * @return triple of P, L and U tensors + * @param epsilon permissible error when comparing the determinant of a matrix with zero. + * @return triple of `P`, `L` and `U` tensors. */ public fun Tensor.lu(epsilon: Double = 1e-9): Triple { val (lu, pivots) = tensor.luFactor(epsilon) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt index e337eeef9..ff89568ea 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt @@ -14,7 +14,7 @@ import space.kscience.kmath.tensors.core.DoubleTensor import kotlin.math.* /** - * Returns a reference to [IntArray] containing all of the elements of this [Buffer] or copy the data. + * Returns a reference to [IntArray] containing all the elements of this [Buffer] or copy the data. */ internal fun Buffer.array(): IntArray = when (this) { is IntBuffer -> array @@ -22,7 +22,7 @@ internal fun Buffer.array(): IntArray = when (this) { } /** - * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer] or copy the data. + * Returns a reference to [DoubleArray] containing all the elements of this [Buffer] or copy the data. */ @PublishedApi internal fun Buffer.array(): DoubleArray = when (this) { From 56fed6c16a9f721504e484547370bf721a5356fd Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Thu, 29 Jul 2021 23:55:27 +0700 Subject: [PATCH 36/39] Use Gradle caching --- .github/workflows/build.yml | 2 +- .github/workflows/pages.yml | 2 +- .github/workflows/publish.yml | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2eb9f34b3..78c1522c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,4 +38,4 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - name: Build - run: ./gradlew build --no-daemon --stacktrace + run: ./gradlew build --build-cache --no-daemon --stacktrace diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 1836287c8..86a0e130e 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -20,7 +20,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- - - run: ./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace + - run: ./gradlew dokkaHtmlMultiModule --build-cache --no-daemon --no-parallel --stacktrace - uses: JamesIves/github-pages-deploy-action@4.1.0 with: branch: gh-pages diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cbf13d03d..dbc4a9473 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -42,11 +42,12 @@ jobs: if: matrix.os == 'windows-latest' shell: cmd run: > - ./gradlew release --no-daemon -Ppublishing.enabled=true -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} + ./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true + -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} - name: Publish Mac Artifacts if: matrix.os == 'macOS-latest' run: > - ./gradlew release --no-daemon -Ppublishing.enabled=true -Ppublishing.platform=macosX64 + ./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true -Ppublishing.platform=macosX64 -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} From 8e766497c628b190fba9814d8b39c2556ddddd6c Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Thu, 5 Aug 2021 16:09:12 +0700 Subject: [PATCH 37/39] Extend CI timeout and update GraalVM --- .github/workflows/build.yml | 4 ++-- .github/workflows/pages.yml | 3 ++- .github/workflows/publish.yml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78c1522c7..cde58b6d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,14 +11,14 @@ jobs: matrix: os: [ macOS-latest, windows-latest ] runs-on: ${{matrix.os}} - timeout-minutes: 30 + timeout-minutes: 40 steps: - name: Checkout the repo uses: actions/checkout@v2 - name: Set up JDK 11 uses: DeLaGuardo/setup-graalvm@4.0 with: - graalvm: 21.1.0 + graalvm: 21.2.0 java: java11 arch: amd64 - name: Cache gradle diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 86a0e130e..23ed54357 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -7,11 +7,12 @@ on: jobs: build: runs-on: ubuntu-20.04 + timeout-minutes: 40 steps: - uses: actions/checkout@v2 - uses: DeLaGuardo/setup-graalvm@4.0 with: - graalvm: 21.1.0 + graalvm: 21.2.0 java: java11 arch: amd64 - uses: actions/cache@v2 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index dbc4a9473..c5075cb0f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,7 +19,7 @@ jobs: - name: Set up JDK 11 uses: DeLaGuardo/setup-graalvm@4.0 with: - graalvm: 21.1.0 + graalvm: 21.2.0 java: java11 arch: amd64 - name: Cache gradle From 86a45504e37d93be835e2d31da15a61acc074160 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Thu, 10 Jun 2021 01:02:57 +0700 Subject: [PATCH 38/39] Add contentEquals extension to ND algebra and LinearSpace --- .../kscience/kmath/linear/LinearSpace.kt | 2 +- .../space/kscience/kmath/nd/StructureND.kt | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index 63b881105..fdb5c2090 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt @@ -29,7 +29,7 @@ public typealias MutableMatrix = MutableStructure2D public typealias Point = Buffer /** - * Basic operations on matrices and vectors. Operates on [Matrix]. + * Basic operations on matrices and vectors. * * @param T the type of items in the matrices. * @param A the type of ring over [T]. 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 716bd15f3..cfb20f441 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 @@ -5,8 +5,11 @@ package space.kscience.kmath.nd +import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import kotlin.jvm.JvmName @@ -145,6 +148,44 @@ public interface StructureND { } } +/** + * Indicates whether some [StructureND] is equal to another one. + */ +@PerformancePitfall +public fun > AlgebraND>.contentEquals( + st1: StructureND, + st2: StructureND, +): Boolean = StructureND.contentEquals(st1, st2) + +/** + * Indicates whether some [StructureND] is equal to another one. + */ +@PerformancePitfall +public fun > LinearSpace>.contentEquals( + st1: StructureND, + st2: StructureND, +): Boolean = StructureND.contentEquals(st1, st2) + +/** + * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. + */ +@PerformancePitfall +public fun > GroupND>.contentEquals( + st1: StructureND, + st2: StructureND, + absoluteTolerance: T, +): Boolean = st1.elements().all { (index, value) -> elementContext { (value - st2[index]) } < absoluteTolerance } + +/** + * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. + */ +@PerformancePitfall +public fun > LinearSpace>.contentEquals( + st1: StructureND, + st2: StructureND, + absoluteTolerance: T, +): Boolean = st1.elements().all { (index, value) -> elementAlgebra { (value - st2[index]) } < absoluteTolerance } + /** * Returns the value at the specified indices. * From adff75bb6b616ec93d4e8ca1ce87e37fdbfc8648 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Thu, 5 Aug 2021 18:56:29 +0700 Subject: [PATCH 39/39] Avoid using kapt in kmath-jupyter #398 --- kmath-jupyter/build.gradle.kts | 4 ++++ settings.gradle.kts | 11 +++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/kmath-jupyter/build.gradle.kts b/kmath-jupyter/build.gradle.kts index 83a6a771a..5bd08c485 100644 --- a/kmath-jupyter/build.gradle.kts +++ b/kmath-jupyter/build.gradle.kts @@ -20,3 +20,7 @@ readme { kotlin.sourceSets.all { languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } + +tasks.processJupyterApiResources { + libraryProducers = listOf("space.kscience.kmath.jupyter.KMathJupyter") +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 18f867df3..f05092bb1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,18 +5,13 @@ pluginManagement { gradlePluginPortal() } - val toolsVersion = "0.10.2" val kotlinVersion = "1.5.21" plugins { - id("ru.mipt.npm.gradle.project") version toolsVersion - id("ru.mipt.npm.gradle.mpp") version toolsVersion - id("ru.mipt.npm.gradle.jvm") version toolsVersion - kotlin("multiplatform") version kotlinVersion - kotlin("jvm") version kotlinVersion - kotlin("plugin.allopen") version kotlinVersion id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - kotlin("jupyter.api") version "0.10.0-131-1" + id("ru.mipt.npm.gradle.project") version "0.10.2" + kotlin("multiplatform") version kotlinVersion + kotlin("plugin.allopen") version kotlinVersion } }