From 991ab907d87536c636f2ab6830a0f4a28886c386 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 10 Dec 2022 11:09:55 +0300 Subject: [PATCH 01/58] Encapsulate internal constants in Expression --- benchmarks/build.gradle.kts | 9 ++----- .../kscience/kmath/expressions/Expression.kt | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 9c8dc613a..5d2e4dac8 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -50,6 +50,8 @@ kotlin { val jvmMain by getting { dependencies { + implementation("org.openjdk.jmh:jmh-core:1.36") + implementation("org.openjdk.jmh:jmh-generator-annprocess:1.36") implementation(project(":kmath-commons")) implementation(project(":kmath-ejml")) implementation(project(":kmath-nd4j")) @@ -144,13 +146,6 @@ benchmark { } } -// Fix kotlinx-benchmarks bug -afterEvaluate { - val jvmBenchmarkJar by tasks.getting(org.gradle.jvm.tasks.Jar::class) { - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - } -} - kotlin.sourceSets.all { with(languageSettings) { optIn("kotlin.contracts.ExperimentalContracts") 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 9c769caa0..cf59efe71 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 @@ -48,6 +48,10 @@ public interface DoubleExpression : Expression { * @return the value. */ public operator fun invoke(arguments: DoubleArray): Double + + public companion object{ + internal val EMPTY_DOUBLE_ARRAY = DoubleArray(0) + } } /** @@ -73,6 +77,10 @@ public interface IntExpression : Expression { * @return the value. */ public operator fun invoke(arguments: IntArray): Int + + public companion object{ + internal val EMPTY_INT_ARRAY = IntArray(0) + } } /** @@ -98,6 +106,10 @@ public interface LongExpression : Expression { * @return the value. */ public operator fun invoke(arguments: LongArray): Long + + public companion object{ + internal val EMPTY_LONG_ARRAY = LongArray(0) + } } /** @@ -145,7 +157,7 @@ public operator fun Expression.invoke(vararg pairs: Pair): T = } ) -private val EMPTY_DOUBLE_ARRAY = DoubleArray(0) + /** * Calls this expression without providing any arguments. @@ -153,7 +165,7 @@ private val EMPTY_DOUBLE_ARRAY = DoubleArray(0) * @return a value. */ @UnstableKMathAPI -public operator fun DoubleExpression.invoke(): Double = this(EMPTY_DOUBLE_ARRAY) +public operator fun DoubleExpression.invoke(): Double = this(DoubleExpression.EMPTY_DOUBLE_ARRAY) /** * Calls this expression from arguments. @@ -164,15 +176,13 @@ public operator fun DoubleExpression.invoke(): Double = this(EMPTY_DOUBLE_ARRAY) @UnstableKMathAPI public operator fun DoubleExpression.invoke(vararg arguments: Double): Double = this(arguments) -private val EMPTY_INT_ARRAY = IntArray(0) - /** * Calls this expression without providing any arguments. * * @return a value. */ @UnstableKMathAPI -public operator fun IntExpression.invoke(): Int = this(EMPTY_INT_ARRAY) +public operator fun IntExpression.invoke(): Int = this(IntExpression.EMPTY_INT_ARRAY) /** * Calls this expression from arguments. @@ -183,15 +193,13 @@ public operator fun IntExpression.invoke(): Int = this(EMPTY_INT_ARRAY) @UnstableKMathAPI public operator fun IntExpression.invoke(vararg arguments: Int): Int = this(arguments) -private val EMPTY_LONG_ARRAY = LongArray(0) - /** * Calls this expression without providing any arguments. * * @return a value. */ @UnstableKMathAPI -public operator fun LongExpression.invoke(): Long = this(EMPTY_LONG_ARRAY) +public operator fun LongExpression.invoke(): Long = this(LongExpression.EMPTY_LONG_ARRAY) /** * Calls this expression from arguments. From 29977650f10d0d1168a4f218b2b71e371b567653 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 10 Dec 2022 12:21:56 +0300 Subject: [PATCH 02/58] Naive classifier notebook --- .gitignore | 3 +- examples/notebooks/Naive classifier.ipynb | 418 ++++++++++++++++++++++ 2 files changed, 419 insertions(+), 2 deletions(-) create mode 100644 examples/notebooks/Naive classifier.ipynb diff --git a/.gitignore b/.gitignore index 5ddd846a8..34ddf3fd9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,9 @@ build/ out/ .idea/ - - .vscode/ + # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar diff --git a/examples/notebooks/Naive classifier.ipynb b/examples/notebooks/Naive classifier.ipynb new file mode 100644 index 000000000..937f5b6c6 --- /dev/null +++ b/examples/notebooks/Naive classifier.ipynb @@ -0,0 +1,418 @@ +{ + "cells": [ + { + "cell_type": "code", + "source": [ + "%use kmath(0.3.1-dev-5)\n", + "%use plotly(0.5.0)\n", + "@file:DependsOn(\"space.kscience:kmath-commons:0.3.1-dev-5\")" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "lQbSB87rNAn9lV6poArVWW", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "code", + "source": [ + "//Uncomment to work in Jupyter classic or DataLore\n", + "//Plotly.jupyter.notebook()" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "0UP158hfccGgjQtHz0wAi6", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "markdown", + "source": [ + "# The model\n", + "\n", + "Defining the input data format, the statistic abstraction and the statistic implementation based on a weighted sum of elements." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "source": [ + "class XYValues(val xValues: DoubleArray, val yValues: DoubleArray) {\n", + " init {\n", + " require(xValues.size == yValues.size)\n", + " }\n", + "}\n", + "\n", + "fun interface XYStatistic {\n", + " operator fun invoke(values: XYValues): Double\n", + "}\n", + "\n", + "class ConvolutionalXYStatistic(val weights: DoubleArray) : XYStatistic {\n", + " override fun invoke(values: XYValues): Double {\n", + " require(weights.size == values.yValues.size)\n", + " val norm = values.yValues.sum()\n", + " return values.yValues.zip(weights) { value, weight -> value * weight }.sum()/norm\n", + " }\n", + "}" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "Zhgz1Ui91PWz0meJiQpHol", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "markdown", + "source": [ + "# Generator\n", + "Generate sample data for parabolas and hyperbolas" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "fun generateParabolas(xValues: DoubleArray, a: Double, b: Double, c: Double): XYValues {\n", + " val yValues = xValues.map { x -> a * x * x + b * x + c }.toDoubleArray()\n", + " return XYValues(xValues, yValues)\n", + "}\n", + "\n", + "fun generateHyperbols(xValues: DoubleArray, gamma: Double, x0: Double, y0: Double): XYValues {\n", + " val yValues = xValues.map { x -> y0 + gamma / (x - x0) }.toDoubleArray()\n", + " return XYValues(xValues, yValues)\n", + "}" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "source": [ + "val xValues = (1.0..10.0).step(1.0).toDoubleArray()\n", + "\n", + "val xy = generateHyperbols(xValues, 1.0, 0.0, 0.0)\n", + "\n", + "Plotly.plot {\n", + " scatter {\n", + " this.x.doubles = xValues\n", + " this.y.doubles = xy.yValues\n", + " }\n", + "}" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "ZE2atNvFzQsCvpAF8KK4ch", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Create a default statistic with uniform weights" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "source": [ + "val statistic = ConvolutionalXYStatistic(DoubleArray(xValues.size){1.0})\n", + "statistic(xy)" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "EA5HaydTddRKYrtAUwd29h", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "code", + "source": [ + "import kotlin.random.Random\n", + "\n", + "val random = Random(1288)\n", + "\n", + "val parabolas = buildList{\n", + " repeat(500){\n", + " add(\n", + " generateParabolas(\n", + " xValues, \n", + " random.nextDouble(), \n", + " random.nextDouble(), \n", + " random.nextDouble()\n", + " )\n", + " )\n", + " }\n", + "}\n", + "\n", + "val hyperbolas: List = buildList{\n", + " repeat(500){\n", + " add(\n", + " generateHyperbols(\n", + " xValues, \n", + " random.nextDouble()*10, \n", + " random.nextDouble(), \n", + " random.nextDouble()\n", + " )\n", + " )\n", + " }\n", + "}" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "t5t6IYmD7Q1ykeo9uijFfQ", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "code", + "source": [ + "Plotly.plot { \n", + " scatter { \n", + " x.doubles = xValues\n", + " y.doubles = parabolas[257].yValues\n", + " }\n", + " scatter { \n", + " x.doubles = xValues\n", + " y.doubles = hyperbolas[252].yValues\n", + " }\n", + " }" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "oXB8lmju7YVYjMRXITKnhO", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "code", + "source": [ + "Plotly.plot { \n", + " histogram { \n", + " name = \"parabolae\"\n", + " x.numbers = parabolas.map { statistic(it) }\n", + " }\n", + " histogram { \n", + " name = \"hyperbolae\"\n", + " x.numbers = hyperbolas.map { statistic(it) }\n", + " }\n", + "}" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "8EIIecUZrt2NNrOkhxG5P0", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "code", + "source": [ + "val lossFunction: (XYStatistic) -> Double = { statistic ->\n", + " - abs(parabolas.sumOf { statistic(it) } - hyperbolas.sumOf { statistic(it) })\n", + "}" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "h7UmglJW5zXkAfKHK40oIL", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Using commons-math optimizer to optimize weights" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "source": [ + "import org.apache.commons.math3.optim.*\n", + "import org.apache.commons.math3.optim.nonlinear.scalar.*\n", + "import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.*\n", + "\n", + "val optimizer = SimplexOptimizer(1e-1, Double.MAX_VALUE)\n", + "\n", + "val result = optimizer.optimize(\n", + " ObjectiveFunction { point ->\n", + " lossFunction(ConvolutionalXYStatistic(point))\n", + " },\n", + " NelderMeadSimplex(xValues.size),\n", + " InitialGuess(DoubleArray(xValues.size){ 1.0 }),\n", + " GoalType.MINIMIZE,\n", + " MaxEval(100000)\n", + ")" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "0EG3K4aCUciMlgGQKPvJ57", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Print resulting weights of optimization" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "source": [ + "result.point" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "LelUlY0ZSlJEO9yC6SLk5B", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "code", + "source": [ + "Plotly.plot { \n", + " scatter { \n", + " y.doubles = result.point\n", + " }\n", + "}" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "AuFOq5t9KpOIkGrOLsVXNf", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "markdown", + "source": [ + "# The resulting statistic distribution" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "source": [ + "val resultStatistic = ConvolutionalXYStatistic(result.point)\n", + "Plotly.plot { \n", + " histogram { \n", + " name = \"parabolae\"\n", + " x.numbers = parabolas.map { resultStatistic(it) }\n", + " }\n", + " histogram { \n", + " name = \"hyperbolae\"\n", + " x.numbers = hyperbolas.map { resultStatistic(it) }\n", + " }\n", + "}" + ], + "execution_count": null, + "outputs": [], + "metadata": { + "datalore": { + "node_id": "zvmq42DRdM5mZ3SpzviHwI", + "type": "CODE", + "hide_input_from_viewers": false, + "hide_output_from_viewers": false + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Kotlin", + "language": "kotlin", + "name": "kotlin" + }, + "datalore": { + "version": 1, + "computation_mode": "JUPYTER", + "package_manager": "pip", + "base_environment": "default", + "packages": [] + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 6d47c0ccecd4068cc4c6289741d5dc89931c4a13 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 10 Dec 2022 12:30:15 +0300 Subject: [PATCH 03/58] Ordered segments in trajectory --- .../kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt index 3fcf4365d..ffa23a537 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt @@ -102,7 +102,7 @@ public data class CircleTrajectory2D( } } -public open class CompositeTrajectory2D(public val segments: Collection) : Trajectory2D { +public open class CompositeTrajectory2D(public val segments: List) : Trajectory2D { override val length: Double get() = segments.sumOf { it.length } } From 3f4fe9e43ba488b5d5de65aaf9b916159023724e Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 31 Dec 2022 15:02:52 +0300 Subject: [PATCH 04/58] Migrate to 1.8. Use universal autodiffs --- benchmarks/build.gradle.kts | 4 +- build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 13 +++-- buildSrc/settings.gradle.kts | 2 +- .../kscience/kmath/benchmarks/JmhReport.kt | 5 -- .../benchmarks/addBenchmarkProperties.kt | 9 ++-- .../space/kscience/kmath/fit/chiSquared.kt | 4 +- .../kotlin/space/kscience/kmath/fit/qowFit.kt | 4 +- .../kmath/stat/DistributionBenchmark.kt | 4 +- gradle.properties | 3 +- gradle/wrapper/gradle-wrapper.properties | 2 +- ...ructureExpression.kt => CmDsExpression.kt} | 19 ++++--- .../DerivativeStructureExpressionTest.kt | 8 +-- .../commons/optimization/OptimizeTest.kt | 11 ++-- .../kscience/kmath/expressions/DSAlgebra.kt | 51 +++++++++++-------- .../kscience/kmath/expressions/DSCompiler.kt | 2 - .../kscience/kmath/expressions/DSTest.kt | 5 +- kmath-functions/build.gradle.kts | 2 +- kmath-histograms/build.gradle.kts | 2 +- kmath-optimization/build.gradle.kts | 2 +- kmath-stat/build.gradle.kts | 2 +- settings.gradle.kts | 2 +- 22 files changed, 84 insertions(+), 74 deletions(-) rename kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/{DerivativeStructureExpression.kt => CmDsExpression.kt} (91%) diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 5d2e4dac8..ea2349d91 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -5,7 +5,7 @@ import space.kscience.kmath.benchmarks.addBenchmarkProperties plugins { kotlin("multiplatform") - kotlin("plugin.allopen") + alias(spclibs.plugins.kotlin.plugin.allopen) id("org.jetbrains.kotlinx.benchmark") } @@ -44,7 +44,7 @@ kotlin { implementation(project(":kmath-tensors")) implementation(project(":kmath-multik")) implementation("org.jetbrains.kotlinx:multik-default:$multikVersion") - implementation(npmlibs.kotlinx.benchmark.runtime) + implementation(spclibs.kotlinx.benchmark.runtime) } } diff --git a/build.gradle.kts b/build.gradle.kts index e03bec9af..4efb6c802 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,7 @@ allprojects { } group = "space.kscience" - version = "0.3.1-dev-7" + version = "0.3.1-dev-8" } subprojects { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 0f95a7b3f..67df0aab4 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,7 +1,6 @@ plugins { `kotlin-dsl` `version-catalog` - kotlin("plugin.serialization") version "1.6.21" } java.targetCompatibility = JavaVersion.VERSION_11 @@ -13,18 +12,18 @@ repositories { gradlePluginPortal() } -val toolsVersion = npmlibs.versions.tools.get() -val kotlinVersion = npmlibs.versions.kotlin.asProvider().get() -val benchmarksVersion = npmlibs.versions.kotlinx.benchmark.get() +val toolsVersion = spclibs.versions.tools.get() +val kotlinVersion = spclibs.versions.kotlin.asProvider().get() +val benchmarksVersion = spclibs.versions.kotlinx.benchmark.get() dependencies { api("space.kscience:gradle-tools:$toolsVersion") - api(npmlibs.atomicfu.gradle) //plugins form benchmarks api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion") - api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") + //api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") //to be used inside build-script only - implementation(npmlibs.kotlinx.serialization.json) + //implementation(spclibs.kotlinx.serialization.json) + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.+") } kotlin.sourceSets.all { diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index 403e0f52c..02111ba37 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -26,7 +26,7 @@ dependencyResolutionManagement { } versionCatalogs { - create("npmlibs") { + create("spclibs") { from("space.kscience:version-catalog:$toolsVersion") } } diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt index 62cf44915..3a4fcdc79 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt @@ -5,9 +5,6 @@ package space.kscience.kmath.benchmarks -import kotlinx.serialization.Serializable - -@Serializable data class JmhReport( val jmhVersion: String, val benchmark: String, @@ -37,7 +34,6 @@ data class JmhReport( val scoreUnit: String } - @Serializable data class PrimaryMetric( override val score: Double, override val scoreError: Double, @@ -48,7 +44,6 @@ data class JmhReport( val rawData: List>? = null, ) : Metric - @Serializable data class SecondaryMetric( override val score: Double, override val scoreError: Double, 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 5c6a2ac83..61193790b 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -6,8 +6,8 @@ package space.kscience.kmath.benchmarks import kotlinx.benchmark.gradle.BenchmarksExtension -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue import org.gradle.api.Project import space.kscience.gradle.KScienceReadmeExtension import java.time.LocalDateTime @@ -45,6 +45,8 @@ private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run { private fun noun(number: Number, singular: String, plural: String) = if (number.toLong() == 1L) singular else plural +private val jsonMapper = jacksonObjectMapper() + fun Project.addBenchmarkProperties() { val benchmarksProject = this rootProject.subprojects.forEach { p -> @@ -60,8 +62,7 @@ fun Project.addBenchmarkProperties() { if (resDirectory == null || !(resDirectory.resolve("jvm.json")).exists()) { "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." } else { - val reports = - Json.decodeFromString>(resDirectory.resolve("jvm.json").readText()) + val reports: List = jsonMapper.readValue>(resDirectory.resolve("jvm.json")) buildString { appendLine("
") diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt index febf55283..c5f694ce0 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt @@ -7,9 +7,9 @@ package space.kscience.kmath.fit import kotlinx.html.br import kotlinx.html.h3 -import space.kscience.kmath.commons.expressions.DSProcessor import space.kscience.kmath.commons.optimization.CMOptimizer import space.kscience.kmath.distributions.NormalDistribution +import space.kscience.kmath.expressions.autodiff import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.asIterable @@ -67,7 +67,7 @@ suspend fun main() { val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma) // compute differentiable chi^2 sum for given model ax^2 + bx + c - val chi2 = DSProcessor.chiSquaredExpression(x, y, yErr) { arg -> + val chi2 = Double.autodiff.chiSquaredExpression(x, y, yErr) { arg -> //bind variables to autodiff context val a = bindSymbol(a) val b = bindSymbol(b) diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt index c7eefa6b9..9650fa630 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt @@ -7,10 +7,10 @@ package space.kscience.kmath.fit import kotlinx.html.br import kotlinx.html.h3 -import space.kscience.kmath.commons.expressions.DSProcessor import space.kscience.kmath.data.XYErrorColumnarData import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.autodiff import space.kscience.kmath.expressions.binding import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.asIterable @@ -63,7 +63,7 @@ suspend fun main() { val result = XYErrorColumnarData.of(x, y, yErr).fitWith( QowOptimizer, - DSProcessor, + Double.autodiff, mapOf(a to 0.9, b to 1.2, c to 2.0) ) { arg -> //bind variables to autodiff context diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt index 2576e9222..031955e15 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt @@ -36,7 +36,7 @@ private suspend fun runKMathChained(): Duration { return Duration.between(startTime, Instant.now()) } -private fun runApacheDirect(): Duration { +private fun runCMDirect(): Duration { val rng = RandomSource.create(RandomSource.MT, 123L) val sampler = CMGaussianSampler.of( @@ -65,7 +65,7 @@ private fun runApacheDirect(): Duration { * Comparing chain sampling performance with direct sampling performance */ fun main(): Unit = runBlocking(Dispatchers.Default) { - val directJob = async { runApacheDirect() } + val directJob = async { runCMDirect() } val chainJob = async { runKMathChained() } println("KMath Chained: ${chainJob.await()}") println("Apache Direct: ${directJob.await()}") diff --git a/gradle.properties b/gradle.properties index da5867ea4..3016246b2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,12 +5,11 @@ kotlin.code.style=official kotlin.mpp.stability.nowarn=true kotlin.native.ignoreDisabledTargets=true -kotlin.incremental.js.ir=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.13.1-kotlin-1.7.20 +toolsVersion=0.13.4-kotlin-1.8.0 org.gradle.parallel=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8049c684f..070cb702f 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.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists 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/CmDsExpression.kt similarity index 91% rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt rename to kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt index 6d756b15f..f2af49087 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/CmDsExpression.kt @@ -18,7 +18,8 @@ import space.kscience.kmath.operations.NumbersAddOps * @param bindings The map of bindings values. All bindings are considered free parameters */ @OptIn(UnstableKMathAPI::class) -public class DerivativeStructureField( +@Deprecated("Use generic DSAlgebra from the core") +public class CmDsField( public val order: Int, bindings: Map, ) : ExtendedField, ExpressionAlgebra, @@ -108,25 +109,27 @@ public class DerivativeStructureField( /** * Auto-diff processor based on Commons-math [DerivativeStructure] */ -public object DSProcessor : AutoDiffProcessor { +@Deprecated("Use generic DSAlgebra from the core") +public object CmDsProcessor : AutoDiffProcessor { override fun differentiate( - function: DerivativeStructureField.() -> DerivativeStructure, - ): DerivativeStructureExpression = DerivativeStructureExpression(function) + function: CmDsField.() -> DerivativeStructure, + ): CmDsExpression = CmDsExpression(function) } /** * A constructs that creates a derivative structure with required order on-demand */ -public class DerivativeStructureExpression( - public val function: DerivativeStructureField.() -> DerivativeStructure, +@Deprecated("Use generic DSAlgebra from the core") +public class CmDsExpression( + public val function: CmDsField.() -> DerivativeStructure, ) : DifferentiableExpression { override operator fun invoke(arguments: Map): Double = - DerivativeStructureField(0, arguments).function().value + CmDsField(0, arguments).function().value /** * Get the derivative expression with given orders */ override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> - with(DerivativeStructureField(symbols.size, arguments)) { function().derivative(symbols) } + with(CmDsField(symbols.size, arguments)) { function().derivative(symbols) } } } 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 40ba9fc7d..7c3c086ed 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 @@ -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("DEPRECATION") + package space.kscience.kmath.commons.expressions import space.kscience.kmath.expressions.* @@ -15,10 +17,10 @@ import kotlin.test.assertFails internal inline fun diff( order: Int, vararg parameters: Pair, - block: DerivativeStructureField.() -> Unit, + block: CmDsField.() -> Unit, ) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - DerivativeStructureField(order, mapOf(*parameters)).run(block) + CmDsField(order, mapOf(*parameters)).run(block) } internal class AutoDiffTest { @@ -41,7 +43,7 @@ internal class AutoDiffTest { @Test fun autoDifTest() { - val f = DerivativeStructureExpression { + val f = CmDsExpression { val x by binding val y by binding x.pow(2) + 2 * x * y + y.pow(2) + 1 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 7c8ba7d27..8b4631fca 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 @@ -6,22 +6,25 @@ package space.kscience.kmath.commons.optimization import kotlinx.coroutines.runBlocking -import space.kscience.kmath.commons.expressions.DSProcessor -import space.kscience.kmath.commons.expressions.DerivativeStructureExpression import space.kscience.kmath.distributions.NormalDistribution +import space.kscience.kmath.expressions.DSFieldExpression import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.Symbol.Companion.y +import space.kscience.kmath.expressions.autodiff import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleBufferOps.Companion.map +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.optimization.* import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer import kotlin.test.Test +@OptIn(UnstableKMathAPI::class) internal class OptimizeTest { - val normal = DerivativeStructureExpression { + val normal = DSFieldExpression(DoubleField) { exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y).pow(2) / 2) } @@ -60,7 +63,7 @@ internal class OptimizeTest { val yErr = DoubleBuffer(x.size) { sigma } - val chi2 = DSProcessor.chiSquaredExpression( + val chi2 = Double.autodiff.chiSquaredExpression( x, y, yErr ) { arg -> val cWithDefault = bindSymbolOrNull(c) ?: one diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt index e7ade4f66..9e91ff26b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt @@ -80,7 +80,6 @@ public abstract class DSAlgebra>( public val algebra: A, public val order: Int, bindings: Map, - public val valueBufferFactory: MutableBufferFactory = algebra.bufferFactory, ) : ExpressionAlgebra>, SymbolIndexer { /** @@ -116,7 +115,6 @@ public abstract class DSAlgebra>( newCache[p][o] = DSCompiler( algebra, - valueBufferFactory, p, o, valueCompiler, @@ -141,7 +139,7 @@ public abstract class DSAlgebra>( override val symbols: List = bindings.map { it.key } private fun bufferForVariable(index: Int, value: T): Buffer { - val buffer = valueBufferFactory(compiler.size) { algebra.zero } + val buffer = algebra.bufferFactory(compiler.size) { algebra.zero } buffer[0] = value if (compiler.order > 0) { // the derivative of the variable with respect to itself is 1. @@ -207,7 +205,7 @@ public abstract class DSAlgebra>( } public override fun const(value: T): DS { - val buffer = valueBufferFactory(compiler.size) { algebra.zero } + val buffer = algebra.bufferFactory(compiler.size) { algebra.zero } buffer[0] = value return DS(buffer) @@ -245,11 +243,14 @@ public open class DSRing( algebra: A, order: Int, bindings: Map, - valueBufferFactory: MutableBufferFactory, -) : DSAlgebra(algebra, order, bindings, valueBufferFactory), - Ring>, ScaleOperations>, +) : DSAlgebra(algebra, order, bindings), + Ring>, + ScaleOperations>, NumericAlgebra>, - NumbersAddOps> where A : Ring, A : NumericAlgebra, A : ScaleOperations { + NumbersAddOps> + where A : Ring, A : NumericAlgebra, A : ScaleOperations { + + public val elementBufferFactory: MutableBufferFactory = algebra.bufferFactory override fun bindSymbolOrNull(value: String): DSSymbol? = super.bindSymbolOrNull(value) @@ -261,14 +262,14 @@ public open class DSRing( */ protected inline fun DS.transformDataBuffer(block: A.(MutableBuffer) -> Unit): DS { require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - val newData = valueBufferFactory(compiler.size) { data[it] } + val newData = elementBufferFactory(compiler.size) { data[it] } algebra.block(newData) return DS(newData) } protected fun DS.mapData(block: A.(T) -> T): DS { require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - val newData: Buffer = data.mapToBuffer(valueBufferFactory) { + val newData: Buffer = data.mapToBuffer(elementBufferFactory) { algebra.block(it) } return DS(newData) @@ -276,7 +277,7 @@ public open class DSRing( protected fun DS.mapDataIndexed(block: (Int, T) -> T): DS { require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - val newData: Buffer = data.mapIndexedToBuffer(valueBufferFactory, block) + val newData: Buffer = data.mapIndexedToBuffer(elementBufferFactory, block) return DS(newData) } @@ -329,22 +330,21 @@ public class DerivativeStructureRingExpression( public val function: DSRing.() -> DS, ) : DifferentiableExpression where A : Ring, A : ScaleOperations, A : NumericAlgebra { override operator fun invoke(arguments: Map): T = - DSRing(algebra, 0, arguments, elementBufferFactory).function().value + DSRing(algebra, 0, arguments).function().value override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> with( DSRing( algebra, symbols.size, - arguments, - elementBufferFactory + arguments ) ) { function().derivative(symbols) } } } /** - * A field over commons-math [DerivativeStructure]. + * A field over [DS]. * * @property order The derivation order. * @param bindings The map of bindings values. All bindings are considered free parameters. @@ -354,8 +354,7 @@ public class DSField>( algebra: A, order: Int, bindings: Map, - valueBufferFactory: MutableBufferFactory, -) : DSRing(algebra, order, bindings, valueBufferFactory), ExtendedField> { +) : DSRing(algebra, order, bindings), ExtendedField> { override fun number(value: Number): DS = const(algebra.number(value)) override fun divide(left: DS, right: DS): DS = left.transformDataBuffer { result -> @@ -414,6 +413,7 @@ public class DSField>( is Int -> arg.transformDataBuffer { result -> compiler.pow(arg.data, 0, pow, result, 0) } + else -> arg.transformDataBuffer { result -> compiler.pow(arg.data, 0, pow.toDouble(), result, 0) } @@ -439,18 +439,29 @@ public class DSField>( @UnstableKMathAPI public class DSFieldExpression>( public val algebra: A, - private val valueBufferFactory: MutableBufferFactory = algebra.bufferFactory, public val function: DSField.() -> DS, ) : DifferentiableExpression { override operator fun invoke(arguments: Map): T = - DSField(algebra, 0, arguments, valueBufferFactory).function().value + DSField(algebra, 0, arguments).function().value override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> DSField( algebra, symbols.size, arguments, - valueBufferFactory, ).run { function().derivative(symbols) } } } + + +@UnstableKMathAPI +public class DSFieldProcessor>( + public val algebra: A, +) : AutoDiffProcessor, DSField> { + override fun differentiate( + function: DSField.() -> DS, + ): DifferentiableExpression = DSFieldExpression(algebra, function) +} + +@UnstableKMathAPI +public val Double.Companion.autodiff: DSFieldProcessor get() = DSFieldProcessor(DoubleField) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt index 6ab9b3d44..1da151d46 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt @@ -9,7 +9,6 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableBufferFactory import kotlin.math.min internal fun MutableBuffer.fill(element: T, fromIndex: Int = 0, toIndex: Int = size) { @@ -56,7 +55,6 @@ internal fun MutableBuffer.fill(element: T, fromIndex: Int = 0, toIndex: */ public class DSCompiler> internal constructor( public val algebra: A, - public val bufferFactory: MutableBufferFactory, public val freeParameters: Int, public val order: Int, valueCompiler: DSCompiler?, diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt index f46f3023d..0bfcb04a7 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt @@ -9,7 +9,6 @@ package space.kscience.kmath.expressions import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.DoubleBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.test.Test @@ -22,7 +21,7 @@ internal inline fun diff( block: DSField.() -> Unit, ) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - DSField(DoubleField, order, mapOf(*parameters), ::DoubleBuffer).block() + DSField(DoubleField, order, mapOf(*parameters)).block() } internal class DSTest { @@ -45,7 +44,7 @@ internal class DSTest { @Test fun dsExpressionTest() { - val f = DSFieldExpression(DoubleField, ::DoubleBuffer) { + val f = DSFieldExpression(DoubleField) { val x by binding val y by binding x.pow(2) + 2 * x * y + y.pow(2) + 1 diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 2e7b023c1..9c2cd8352 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -17,7 +17,7 @@ kotlin.sourceSets { } dependencies { - dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${npmlibs.versions.dokka.get()}") + dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${spclibs.versions.dokka.get()}") } readme { diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index d31526a74..9d7ac33e4 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -12,7 +12,7 @@ kotlin.sourceSets { commonMain { dependencies { api(project(":kmath-core")) - api(npmlibs.atomicfu) + api(spclibs.atomicfu) } } commonTest { diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts index f4256b9aa..ba49d49bf 100644 --- a/kmath-optimization/build.gradle.kts +++ b/kmath-optimization/build.gradle.kts @@ -14,7 +14,7 @@ kotlin.sourceSets { commonMain { dependencies { api(project(":kmath-coroutines")) - api(npmlibs.atomicfu) + api(spclibs.atomicfu) } } } diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index f6ca54e17..bc98129a9 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -10,7 +10,7 @@ kotlin.sourceSets { commonMain { dependencies { api(project(":kmath-coroutines")) - implementation(npmlibs.atomicfu) + implementation(spclibs.atomicfu) } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 23af18d31..7d92dc36e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,7 +13,7 @@ dependencyResolutionManagement { } versionCatalogs { - create("npmlibs") { + create("spclibs") { from("space.kscience:version-catalog:$toolsVersion") } } From 2e4be2aa3a3678ee5fed7de029106bb793ed4c32 Mon Sep 17 00:00:00 2001 From: darksnake Date: Tue, 24 Jan 2023 11:36:53 +0300 Subject: [PATCH 05/58] A minor change to XYfit arguments --- .../kscience/kmath/optimization/XYFit.kt | 67 ++++++++++++------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt index d2182e91f..bba7a7113 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -30,7 +30,7 @@ public interface PointToCurveDistance : OptimizationFeature { return object : DifferentiableExpression { override fun derivativeOrNull( - symbols: List + symbols: List, ): Expression? = problem.model.derivativeOrNull(symbols)?.let { derivExpression -> Expression { arguments -> derivExpression.invoke(arguments + (Symbol.x to x)) @@ -93,24 +93,15 @@ public fun XYFit.withFeature(vararg features: OptimizationFeature): XYFit { return XYFit(data, model, this.features.with(*features), pointToCurveDistance, pointWeight) } -/** - * Fit given dta with - */ -public suspend fun XYColumnarData.fitWith( +public suspend fun XYColumnarData.fitWith( optimizer: Optimizer, - processor: AutoDiffProcessor, + modelExpression: DifferentiableExpression, startingPoint: Map, vararg features: OptimizationFeature = emptyArray(), xSymbol: Symbol = Symbol.x, pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, pointWeight: PointWeight = PointWeight.byYSigma, - model: A.(I) -> I -): XYFit where A : ExtendedField, A : ExpressionAlgebra { - val modelExpression = processor.differentiate { - val x = bindSymbol(xSymbol) - model(x) - } - +): XYFit { var actualFeatures = FeatureSet.of(*features, OptimizationStartPoint(startingPoint)) if (actualFeatures.getFeature() == null) { @@ -127,20 +118,50 @@ public suspend fun XYColumnarData.fitWith( return optimizer.optimize(problem) } +/** + * Fit given data with a model provided as an expression + */ +public suspend fun XYColumnarData.fitWith( + optimizer: Optimizer, + processor: AutoDiffProcessor, + startingPoint: Map, + vararg features: OptimizationFeature = emptyArray(), + xSymbol: Symbol = Symbol.x, + pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, + pointWeight: PointWeight = PointWeight.byYSigma, + model: A.(I) -> I, +): XYFit where A : ExtendedField, A : ExpressionAlgebra { + val modelExpression: DifferentiableExpression = processor.differentiate { + val x = bindSymbol(xSymbol) + model(x) + } + + return fitWith( + optimizer = optimizer, + modelExpression = modelExpression, + startingPoint = startingPoint, + features = features, + xSymbol = xSymbol, + pointToCurveDistance = pointToCurveDistance, + pointWeight = pointWeight + ) +} + /** * Compute chi squared value for completed fit. Return null for incomplete fit */ -public val XYFit.chiSquaredOrNull: Double? get() { - val result = resultPointOrNull ?: return null +public val XYFit.chiSquaredOrNull: Double? + get() { + val result = resultPointOrNull ?: return null - return data.indices.sumOf { index-> + return data.indices.sumOf { index -> - val x = data.x[index] - val y = data.y[index] - val yErr = data[Symbol.yError]?.get(index) ?: 1.0 + val x = data.x[index] + val y = data.y[index] + val yErr = data[Symbol.yError]?.get(index) ?: 1.0 - val mu = model.invoke(result + (xSymbol to x) ) + val mu = model.invoke(result + (xSymbol to x)) - ((y - mu)/yErr).pow(2) - } -} \ No newline at end of file + ((y - mu) / yErr).pow(2) + } + } \ No newline at end of file From 7f4f4c7703275e80cb51e38af3a28a7672dbbf5f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 24 Jan 2023 21:01:26 +0300 Subject: [PATCH 06/58] Update of symbolic operations --- CHANGELOG.md | 2 + build.gradle.kts | 2 +- .../space/kscience/kmath/fit/chiSquared.kt | 2 +- .../kotlin/space/kscience/kmath/fit/qowFit.kt | 21 ++-- .../expressions/ExpressionWithDefault.kt | 31 +++++ .../kscience/kmath/expressions/NamedMatrix.kt | 37 ++++++ .../kmath/optimization/OptimizationProblem.kt | 17 ++- .../kmath/optimization/QowOptimizer.kt | 116 ++++++++++-------- .../kscience/kmath/optimization/XYFit.kt | 7 +- .../kmath/stat/chiSquaredExpression.kt | 7 +- 10 files changed, 173 insertions(+), 69 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt => kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt (87%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b3ab75fd..b8cb0d976 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] ### Added +- `NamedMatrix` - matrix with symbol-based indexing +- `Expression` with default arguments - Type-aliases for numbers like `Float64` - 2D optimal trajectory computation in a separate module `kmath-trajectory` - Autodiff for generic algebra elements in core! diff --git a/build.gradle.kts b/build.gradle.kts index 4efb6c802..8731dbc70 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,7 @@ allprojects { } group = "space.kscience" - version = "0.3.1-dev-8" + version = "0.3.1-dev-9" } subprojects { diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt index c5f694ce0..258ed0c84 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt @@ -10,7 +10,6 @@ import kotlinx.html.h3 import space.kscience.kmath.commons.optimization.CMOptimizer import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.expressions.autodiff -import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.asIterable import space.kscience.kmath.operations.toList @@ -22,6 +21,7 @@ import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.real.DoubleVector import space.kscience.kmath.real.map import space.kscience.kmath.real.step +import space.kscience.kmath.stat.chiSquaredExpression import space.kscience.plotly.* import space.kscience.plotly.models.ScatterMode import space.kscience.plotly.models.TraceValues diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt index 9650fa630..fe7f48b72 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt @@ -15,10 +15,7 @@ import space.kscience.kmath.expressions.binding import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.asIterable import space.kscience.kmath.operations.toList -import space.kscience.kmath.optimization.QowOptimizer -import space.kscience.kmath.optimization.chiSquaredOrNull -import space.kscience.kmath.optimization.fitWith -import space.kscience.kmath.optimization.resultPoint +import space.kscience.kmath.optimization.* import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.real.map import space.kscience.kmath.real.step @@ -32,6 +29,8 @@ import kotlin.math.sqrt private val a by symbol private val b by symbol private val c by symbol +private val d by symbol +private val e by symbol /** @@ -64,16 +63,22 @@ suspend fun main() { val result = XYErrorColumnarData.of(x, y, yErr).fitWith( QowOptimizer, Double.autodiff, - mapOf(a to 0.9, b to 1.2, c to 2.0) + mapOf(a to 0.9, b to 1.2, c to 2.0, e to 1.0, d to 1.0, e to 0.0), + OptimizationParameters(a, b, c, d) ) { arg -> //bind variables to autodiff context val a by binding val b by binding //Include default value for c if it is not provided as a parameter val c = bindSymbolOrNull(c) ?: one - a * arg.pow(2) + b * arg + c + val d by binding + val e by binding + + a * arg.pow(2) + b * arg + c + d * arg.pow(3) + e / arg } + println("Resulting chi2/dof: ${result.chiSquaredOrNull}/${result.dof}") + //display a page with plot and numerical results val page = Plotly.page { plot { @@ -89,7 +94,7 @@ suspend fun main() { scatter { mode = ScatterMode.lines x(x) - y(x.map { result.model(result.resultPoint + (Symbol.x to it)) }) + y(x.map { result.model(result.startPoint + result.resultPoint + (Symbol.x to it)) }) name = "fit" } } @@ -98,7 +103,7 @@ suspend fun main() { +"Fit result: ${result.resultPoint}" } h3 { - +"Chi2/dof = ${result.chiSquaredOrNull!! / (x.size - 3)}" + +"Chi2/dof = ${result.chiSquaredOrNull!! / result.dof}" } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt new file mode 100644 index 000000000..c802fe04c --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.expressions + +public class ExpressionWithDefault( + private val origin: Expression, + private val defaultArgs: Map, +) : Expression { + override fun invoke(arguments: Map): T = origin.invoke(defaultArgs + arguments) +} + +public fun Expression.withDefaultArgs(defaultArgs: Map): ExpressionWithDefault = + ExpressionWithDefault(this, defaultArgs) + + +public class DiffExpressionWithDefault( + private val origin: DifferentiableExpression, + private val defaultArgs: Map, +) : DifferentiableExpression { + + override fun invoke(arguments: Map): T = origin.invoke(defaultArgs + arguments) + + override fun derivativeOrNull(symbols: List): Expression? = + origin.derivativeOrNull(symbols)?.withDefaultArgs(defaultArgs) +} + +public fun DifferentiableExpression.withDefaultArgs(defaultArgs: Map): DiffExpressionWithDefault = + DiffExpressionWithDefault(this, defaultArgs) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt new file mode 100644 index 000000000..f0b27ffa2 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:OptIn(UnstableKMathAPI::class) + +package space.kscience.kmath.expressions + +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.structures.getOrNull + +public class NamedMatrix(public val values: Matrix, public val indexer: SymbolIndexer) : Matrix by values { + public operator fun get(i: Symbol, j: Symbol): T = get(indexer.indexOf(i), indexer.indexOf(j)) + + public companion object { + + public fun toStringWithSymbols(values: Matrix<*>, indexer: SymbolIndexer): String = buildString { + appendLine(indexer.symbols.joinToString(separator = "\t", prefix = "\t\t")) + indexer.symbols.forEach { i -> + append(i.identity + "\t") + values.rows.getOrNull(indexer.indexOf(i))?.let { row -> + indexer.symbols.forEach { j -> + append(row.getOrNull(indexer.indexOf(j)).toString()) + append("\t") + } + appendLine() + } + } + } + } +} + +public fun Matrix.named(indexer: SymbolIndexer): NamedMatrix = NamedMatrix(this, indexer) + +public fun Matrix.named(symbols: List): NamedMatrix = named(SimpleSymbolIndexer(symbols)) \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt index db154be42..9fdcfc53d 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -6,8 +6,8 @@ package space.kscience.kmath.optimization import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.NamedMatrix import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.linear.Matrix import space.kscience.kmath.misc.* import kotlin.reflect.KClass @@ -32,7 +32,10 @@ public interface OptimizationPrior : OptimizationFeature, DifferentiableExpre override val key: FeatureKey get() = OptimizationPrior::class } -public class OptimizationCovariance(public val covariance: Matrix) : OptimizationFeature { +/** + * Covariance matrix for + */ +public class OptimizationCovariance(public val covariance: NamedMatrix) : OptimizationFeature { override fun toString(): String = "Covariance($covariance)" } @@ -57,10 +60,20 @@ public class OptimizationLog(private val loggable: Loggable) : Loggable by logga override fun toString(): String = "Log($loggable)" } +/** + * Free parameters of the optimization + */ public class OptimizationParameters(public val symbols: List) : OptimizationFeature { public constructor(vararg symbols: Symbol) : this(listOf(*symbols)) override fun toString(): String = "Parameters($symbols)" } +/** + * Maximum allowed number of iterations + */ +public class OptimizationIterations(public val maxIterations: Int) : OptimizationFeature { + override fun toString(): String = "Iterations($maxIterations)" +} + diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt index 669860934..bbebec6af 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt @@ -5,10 +5,7 @@ package space.kscience.kmath.optimization -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.SymbolIndexer -import space.kscience.kmath.expressions.derivative +import space.kscience.kmath.expressions.* import space.kscience.kmath.linear.* import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.log @@ -16,6 +13,7 @@ import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleL2Norm import space.kscience.kmath.operations.algebra import space.kscience.kmath.structures.DoubleBuffer +import kotlin.math.abs public class QowRuns(public val runs: Int) : OptimizationFeature { @@ -40,18 +38,24 @@ public object QowOptimizer : Optimizer { @OptIn(UnstableKMathAPI::class) private class QoWeight( val problem: XYFit, - val parameters: Map, - ) : Map by parameters, SymbolIndexer { - override val symbols: List = parameters.keys.toList() + val freeParameters: Map, + ) : SymbolIndexer { + val size get() = freeParameters.size + + override val symbols: List = freeParameters.keys.toList() val data get() = problem.data + val allParameters by lazy { + problem.startPoint + freeParameters + } + /** * Derivatives of the spectrum over parameters. First index in the point number, second one - index of parameter */ val derivs: Matrix by lazy { linearSpace.buildMatrix(problem.data.size, symbols.size) { d, s -> - problem.distance(d).derivative(symbols[s])(parameters) + problem.distance(d).derivative(symbols[s]).invoke(allParameters) } } @@ -60,29 +64,31 @@ public object QowOptimizer : Optimizer { */ val dispersion: Point by lazy { DoubleBuffer(problem.data.size) { d -> - 1.0/problem.weight(d).invoke(parameters) + 1.0 / problem.weight(d).invoke(allParameters) } } - val prior: DifferentiableExpression? get() = problem.getFeature>() + val prior: DifferentiableExpression? + get() = problem.getFeature>()?.withDefaultArgs(allParameters) - override fun toString(): String = parameters.toString() + override fun toString(): String = freeParameters.toString() } /** * The signed distance from the model to the [d]-th point of data. */ - private fun QoWeight.distance(d: Int, parameters: Map): Double = problem.distance(d)(parameters) + private fun QoWeight.distance(d: Int, parameters: Map): Double = + problem.distance(d)(allParameters + parameters) /** * The derivative of [distance] */ private fun QoWeight.distanceDerivative(symbol: Symbol, d: Int, parameters: Map): Double = - problem.distance(d).derivative(symbol)(parameters) + problem.distance(d).derivative(symbol).invoke(allParameters + parameters) /** - * Теоретическая ковариация весовых функций. + * Theoretical covariance of weight functions * * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 */ @@ -92,7 +98,7 @@ public object QowOptimizer : Optimizer { } /** - * Экспериментальная ковариация весов. Формула (22) из + * Experimental covariance Eq (22) from * http://arxiv.org/abs/physics/0604127 */ private fun QoWeight.covarFExp(theta: Map): Matrix = @@ -115,10 +121,9 @@ public object QowOptimizer : Optimizer { * Equation derivatives for Newton run */ private fun QoWeight.getEqDerivValues( - theta: Map = parameters, + theta: Map = freeParameters, ): Matrix = with(linearSpace) { - //Возвращает производную k-того Eq по l-тому параметру - //val res = Array(fitDim) { DoubleArray(fitDim) } + //Derivative of k Eq over l parameter val sderiv = buildMatrix(data.size, size) { d, s -> distanceDerivative(symbols[s], d, theta) } @@ -140,16 +145,15 @@ public object QowOptimizer : Optimizer { /** - * Значения уравнений метода квазиоптимальных весов + * Quasi optimal weights equations values */ - private fun QoWeight.getEqValues(theta: Map = this): Point { + private fun QoWeight.getEqValues(theta: Map): Point { val distances = DoubleBuffer(data.size) { d -> distance(d, theta) } - return DoubleBuffer(size) { s -> val base = (0 until data.size).sumOf { d -> distances[d] * derivs[d, s] / dispersion[d] } - //Поправка на априорную вероятность + //Prior probability correction prior?.let { prior -> - base - prior.derivative(symbols[s])(theta) / prior(theta) + base - prior.derivative(symbols[s]).invoke(theta) / prior(theta) } ?: base } } @@ -157,15 +161,13 @@ public object QowOptimizer : Optimizer { private fun QoWeight.newtonianStep( theta: Map, - eqvalues: Point, + eqValues: Point, ): QoWeight = linearSpace { - with(this@newtonianStep) { - val start = theta.toPoint() - val invJacob = solver.inverse(this@newtonianStep.getEqDerivValues(theta)) + val start = theta.toPoint() + val invJacob = solver.inverse(getEqDerivValues(theta)) - val step = invJacob.dot(eqvalues) - return QoWeight(problem, theta + (start - step).toMap()) - } + val step = invJacob.dot(eqValues) + return QoWeight(problem, theta + (start - step).toMap()) } private fun QoWeight.newtonianRun( @@ -177,10 +179,10 @@ public object QowOptimizer : Optimizer { val logger = problem.getFeature() var dis: Double //discrepancy value - // Working with the full set of parameters - var par = problem.startPoint - logger?.log { "Starting newtonian iteration from: \n\t$par" } + var par = freeParameters + + logger?.log { "Starting newtonian iteration from: \n\t$allParameters" } var eqvalues = getEqValues(par) //Values of the weight functions @@ -193,48 +195,48 @@ public object QowOptimizer : Optimizer { logger?.log { "Starting step number $i" } val currentSolution = if (fast) { - //Берет значения матрицы в той точке, где считается вес - newtonianStep(this, eqvalues) + //Matrix values in the point of weight computation + newtonianStep(freeParameters, eqvalues) } else { - //Берет значения матрицы в точке par + //Matrix values in a current point newtonianStep(par, eqvalues) } // здесь должен стоять учет границ параметров logger?.log { "Parameter values after step are: \n\t$currentSolution" } - eqvalues = getEqValues(currentSolution) - val currentDis = DoubleL2Norm.norm(eqvalues)// невязка после шага + eqvalues = getEqValues(currentSolution.freeParameters) + val currentDis = DoubleL2Norm.norm(eqvalues)// discrepancy after the step logger?.log { "The discrepancy after step is: $currentDis." } if (currentDis >= dis && i > 1) { - //дополнительно проверяем, чтобы был сделан хотя бы один шаг + //Check if one step is made flag = true logger?.log { "The discrepancy does not decrease. Stopping iteration." } + } else if (abs(dis - currentDis) <= tolerance) { + flag = true + par = currentSolution.freeParameters + logger?.log { "Relative discrepancy tolerance threshold is reached. Stopping iteration." } } else { - par = currentSolution + par = currentSolution.freeParameters dis = currentDis } if (i >= maxSteps) { flag = true logger?.log { "Maximum number of iterations reached. Stopping iteration." } } - if (dis <= tolerance) { - flag = true - logger?.log { "Tolerance threshold is reached. Stopping iteration." } - } } return QoWeight(problem, par) } - private fun QoWeight.covariance(): Matrix { + private fun QoWeight.covariance(): NamedMatrix { val logger = problem.getFeature() logger?.log { """ - Starting errors estimation using quasioptimal weights method. The starting weight is: - ${problem.startPoint} + Starting errors estimation using quasi-optimal weights method. The starting weight is: + $allParameters """.trimIndent() } @@ -248,19 +250,27 @@ public object QowOptimizer : Optimizer { // valid = false // } // } - return covar + logger?.log { + "Covariance matrix:" + "\n" + NamedMatrix.toStringWithSymbols(covar, this) + } + return covar.named(symbols) } override suspend fun optimize(problem: XYFit): XYFit { val qowRuns = problem.getFeature()?.runs ?: 2 + val iterations = problem.getFeature()?.maxIterations ?: 50 + val freeParameters: Map = problem.getFeature()?.let { op -> + problem.startPoint.filterKeys { it in op.symbols } + } ?: problem.startPoint - var qow = QoWeight(problem, problem.startPoint) - var res = qow.newtonianRun() + var qow = QoWeight(problem, freeParameters) + var res = qow.newtonianRun(maxSteps = iterations) repeat(qowRuns - 1) { - qow = QoWeight(problem, res.parameters) - res = qow.newtonianRun() + qow = QoWeight(problem, res.freeParameters) + res = qow.newtonianRun(maxSteps = iterations) } - return res.problem.withFeature(OptimizationResult(res.parameters)) + val covariance = res.covariance() + return res.problem.withFeature(OptimizationResult(res.freeParameters), OptimizationCovariance(covariance)) } } \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt index bba7a7113..5c28826ee 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -152,7 +152,7 @@ public suspend fun XYColumnarData.fitWith( */ public val XYFit.chiSquaredOrNull: Double? get() { - val result = resultPointOrNull ?: return null + val result = startPoint + (resultPointOrNull ?: return null) return data.indices.sumOf { index -> @@ -164,4 +164,7 @@ public val XYFit.chiSquaredOrNull: Double? ((y - mu) / yErr).pow(2) } - } \ No newline at end of file + } + +public val XYFit.dof: Int + get() = data.size - (getFeature()?.symbols?.size ?: startPoint.size) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt similarity index 87% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt rename to kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt index 59dfeb8ea..ca9755ad5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt @@ -1,10 +1,13 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2023 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.expressions +package space.kscience.kmath.stat +import space.kscience.kmath.expressions.AutoDiffProcessor +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.ExpressionAlgebra import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.asIterable import space.kscience.kmath.structures.Buffer From d97888f1350250e07d8c186714d58e05484a06a5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 24 Jan 2023 21:22:25 +0300 Subject: [PATCH 07/58] Fix test --- .../space/kscience/kmath/commons/optimization/OptimizeTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8b4631fca..03b1426f5 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 @@ -11,13 +11,13 @@ import space.kscience.kmath.expressions.DSFieldExpression import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.Symbol.Companion.y import space.kscience.kmath.expressions.autodiff -import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleBufferOps.Companion.map import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.optimization.* import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.chiSquaredExpression import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer import kotlin.test.Test From db3091354225a8a054de7acc281216ef7f569d04 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 3 Feb 2023 19:32:53 +0300 Subject: [PATCH 08/58] Move to build tools 0.14 --- benchmarks/build.gradle.kts | 7 +- .../kmath/benchmarks/IntegrationBenchmark.kt | 40 +++++++++ build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 2 +- .../kscience/kmath/functions/integrate.kt | 13 +++ .../kmath/functions/matrixIntegration.kt | 32 ++++--- .../kscience/kmath/linear/dotPerformance.kt | 6 +- .../space/kscience/kmath/series/analyzeDif.kt | 2 +- gradle.properties | 2 +- kmath-ast/build.gradle.kts | 89 +++++++++---------- .../commons/expressions/CmDsExpression.kt | 2 + kmath-complex/build.gradle.kts | 10 +-- .../space/kscience/kmath/complex/Complex.kt | 2 + kmath-core/build.gradle.kts | 4 +- .../kscience/kmath/expressions/NamedMatrix.kt | 2 + .../kmath/operations/algebraExtensions.kt | 11 +++ kmath-coroutines/build.gradle.kts | 25 ++---- .../kmath/coroutines/coroutinesExtra.kt | 2 + .../kscience/kmath/streaming/BufferFlow.kt | 3 + kmath-dimensions/build.gradle.kts | 24 +++-- kmath-for-real/build.gradle.kts | 6 +- kmath-functions/build.gradle.kts | 2 + kmath-geometry/build.gradle.kts | 6 +- kmath-histograms/build.gradle.kts | 2 + kmath-jupyter/build.gradle.kts | 5 +- kmath-memory/build.gradle.kts | 2 + kmath-multik/build.gradle.kts | 5 ++ kmath-optimization/build.gradle.kts | 2 + kmath-stat/build.gradle.kts | 4 +- kmath-tensors/build.gradle.kts | 3 + kmath-trajectory/build.gradle.kts | 6 +- test-utils/build.gradle.kts | 2 + 32 files changed, 205 insertions(+), 120 deletions(-) create mode 100644 benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index ea2349d91..3a985cbb4 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -50,8 +50,6 @@ kotlin { val jvmMain by getting { dependencies { - implementation("org.openjdk.jmh:jmh-core:1.36") - implementation("org.openjdk.jmh:jmh-generator-annprocess:1.36") implementation(project(":kmath-commons")) implementation(project(":kmath-ejml")) implementation(project(":kmath-nd4j")) @@ -144,6 +142,11 @@ benchmark { commonConfiguration() include("ViktorLogBenchmark") } + + configurations.register("integration") { + commonConfiguration() + include("IntegrationBenchmark") + } } kotlin.sourceSets.all { diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt new file mode 100644 index 000000000..6cc649fe9 --- /dev/null +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State +import org.openjdk.jmh.infra.Blackhole +import space.kscience.kmath.complex.Complex +import space.kscience.kmath.complex.algebra +import space.kscience.kmath.integration.gaussIntegrator +import space.kscience.kmath.integration.integrate +import space.kscience.kmath.integration.value +import space.kscience.kmath.operations.algebra + + +@State(Scope.Benchmark) +internal class IntegrationBenchmark { + + @Benchmark + fun doubleIntegration(blackhole: Blackhole) { + val res = Double.algebra.gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double -> + //sin(1 / x) + 1/x + }.value + blackhole.consume(res) + } + + @Benchmark + fun complexIntegration(blackhole: Blackhole) = with(Complex.algebra) { + val res = gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double -> +// sin(1 / x) + i * cos(1 / x) + 1/x - i/x + }.value + blackhole.consume(res) + } +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 8731dbc70..9b1101a22 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,7 @@ allprojects { } group = "space.kscience" - version = "0.3.1-dev-9" + version = "0.3.1-dev-10" } subprojects { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 67df0aab4..afa36ed1e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -19,7 +19,7 @@ val benchmarksVersion = spclibs.versions.kotlinx.benchmark.get() dependencies { api("space.kscience:gradle-tools:$toolsVersion") //plugins form benchmarks - api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion") + api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.4.7") //api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") //to be used inside build-script only //implementation(spclibs.kotlinx.serialization.json) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt index 28169f15a..e8534d002 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt @@ -5,6 +5,11 @@ package space.kscience.kmath.functions +import space.kscience.kmath.complex.Complex +import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.complex.ComplexField.div +import space.kscience.kmath.complex.ComplexField.minus +import space.kscience.kmath.complex.algebra import space.kscience.kmath.integration.gaussIntegrator import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value @@ -20,4 +25,12 @@ fun main() { //the value is nullable because in some cases the integration could not succeed println(result.value) + + + repeat(100000) { + Complex.algebra.gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double -> +// sin(1 / x) + i * cos(1 / x) + 1 / x - ComplexField.i / x + }.value + } } \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt index 1b578626d..baba2eb28 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -12,23 +12,21 @@ import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.structureND import space.kscience.kmath.nd.withNdAlgebra import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.invoke +import kotlin.math.pow -fun main(): Unit = Double.algebra { - withNdAlgebra(2, 2) { +fun main(): Unit = Double.algebra.withNdAlgebra(2, 2) { - //Produce a diagonal StructureND - fun diagonal(v: Double) = structureND { (i, j) -> - if (i == j) v else 0.0 - } - - //Define a function in a nd space - val function: (Double) -> StructureND = { x: Double -> 3 * x.pow(2) + 2 * diagonal(x) + 1 } - - //get the result of the integration - val result = gaussIntegrator.integrate(0.0..10.0, function = function) - - //the value is nullable because in some cases the integration could not succeed - println(result.value) + //Produce a diagonal StructureND + fun diagonal(v: Double) = structureND { (i, j) -> + if (i == j) v else 0.0 } -} \ No newline at end of file + + //Define a function in a nd space + val function: (Double) -> StructureND = { x: Double -> 3 * x.pow(2) + 2 * diagonal(x) + 1 } + + //get the result of the integration + val result = gaussIntegrator.integrate(0.0..10.0, function = function) + + //the value is nullable because in some cases the integration could not succeed + println(result.value) +} diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt index d9c3281f2..79eddc6c3 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt @@ -7,8 +7,10 @@ package space.kscience.kmath.linear import space.kscience.kmath.operations.algebra import kotlin.random.Random -import kotlin.system.measureTimeMillis +import kotlin.time.ExperimentalTime +import kotlin.time.measureTime +@OptIn(ExperimentalTime::class) fun main() { val random = Random(12224) val dim = 1000 @@ -21,7 +23,7 @@ fun main() { if (i <= j) random.nextDouble() else 0.0 } - val time = measureTimeMillis { + val time = measureTime { with(Double.algebra.linearSpace) { repeat(10) { matrix1 dot matrix2 diff --git a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt b/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt index c1b0c056e..c94cb0e71 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt @@ -37,7 +37,7 @@ fun main() = with(Double.algebra.bufferAlgebra.seriesAlgebra()) { val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 val s4 = DoubleBufferOps.ln(s3) - val kmTest: KMComparisonResult = ksComparisonStatistic(s1, s2) + @Suppress("UNUSED_VARIABLE") val kmTest: KMComparisonResult = ksComparisonStatistic(s1, s2) Plotly.page { h1 { +"This is my plot" } diff --git a/gradle.properties b/gradle.properties index 3016246b2..16cdd3551 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin.native.ignoreDisabledTargets=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.13.4-kotlin-1.8.0 +toolsVersion=0.14.0-kotlin-1.8.10 org.gradle.parallel=true diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 7fd0f43f7..c60977862 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -3,65 +3,58 @@ plugins { } kscience{ + jvm() + js() native() + + dependencies { + api(projects.kmathCore) + api("com.github.h0tk3y.betterParse:better-parse:0.4.4") + } + + testDependencies { + implementation(projects.kmathComplex) + } + + dependencies(jsMain) { + implementation(npm("astring", "1.7.5")) + implementation(npm("binaryen", "101.0.0")) + implementation(npm("js-base64", "3.6.1")) + } + + dependencies(jvmMain){ + implementation("org.ow2.asm:asm-commons:9.2") + } + } -kotlin.js { - nodejs { - testTask { - useMocha().timeout = "0" +kotlin { + js { + nodejs { + testTask { + useMocha().timeout = "0" + } + } + + browser { + testTask { + useMocha().timeout = "0" + } } } - browser { - testTask { - useMocha().timeout = "0" - } + sourceSets { + filter { it.name.contains("test", true) } + .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) + .forEach { it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") } } } -kotlin.sourceSets { - filter { it.name.contains("test", true) } - .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) - .forEach { it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") } - - commonMain { - dependencies { - api("com.github.h0tk3y.betterParse:better-parse:0.4.4") - api(project(":kmath-core")) - } - } - - commonTest { - dependencies { - implementation(project(":kmath-complex")) - } - } - - jsMain { - dependencies { - implementation(npm("astring", "1.7.5")) - implementation(npm("binaryen", "101.0.0")) - implementation(npm("js-base64", "3.6.1")) - } - } - - jvmMain { - dependencies { - implementation("org.ow2.asm:asm-commons:9.2") - } - } -} - -//Workaround for https://github.com/Kotlin/dokka/issues/1455 -tasks.dokkaHtml { - dependsOn(tasks.build) -} - -if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") - tasks.jvmTest { +if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") { + tasks.withType { jvmArgs("-Dspace.kscience.kmath.ast.dump.generated.classes=1") } +} readme { maturity = space.kscience.gradle.Maturity.EXPERIMENTAL diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt index f2af49087..cb7fb543f 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.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("DEPRECATION") + package space.kscience.kmath.commons.expressions import org.apache.commons.math3.analysis.differentiation.DerivativeStructure diff --git a/kmath-complex/build.gradle.kts b/kmath-complex/build.gradle.kts index b63def0a7..76d5a4c9a 100644 --- a/kmath-complex/build.gradle.kts +++ b/kmath-complex/build.gradle.kts @@ -3,14 +3,12 @@ plugins { } kscience { + jvm() + js() native() -} -kotlin.sourceSets { - commonMain { - dependencies { - api(project(":kmath-core")) - } + dependencies { + api(projects.kmathCore) } } 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 7bf8af4e8..bb580989b 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 @@ -80,6 +80,8 @@ public object ComplexField : override fun add(left: Complex, right: Complex): Complex = Complex(left.re + right.re, left.im + right.im) // override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble()) +// override fun Complex.minus(arg: Complex): Complex = Complex(re - arg.re, im - arg.im) + override fun multiply(left: Complex, right: Complex): Complex = Complex(left.re * right.re - left.im * right.im, left.re * right.im + left.im * right.re) diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index f33d33324..0e4646bed 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -3,10 +3,12 @@ plugins { } kscience{ + jvm() + js() native() dependencies { - api(project(":kmath-memory")) + api(projects.kmathMemory) } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt index f0b27ffa2..24bdfce7e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.expressions import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.getOrNull @@ -16,6 +17,7 @@ public class NamedMatrix(public val values: Matrix, public val indexer: Sy public companion object { + @OptIn(PerformancePitfall::class) public fun toStringWithSymbols(values: Matrix<*>, indexer: SymbolIndexer): String = buildString { appendLine(indexer.symbols.joinToString(separator = "\t", prefix = "\t\t")) indexer.symbols.forEach { i -> diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt index f05ddafb8..84fb2ea41 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt @@ -92,6 +92,17 @@ public fun > Group.abs(value: T): T = if (value > zero) val */ public fun Iterable.sumWith(group: Group): T = group.sum(this) +/** + * Sum extracted elements of [Iterable] with given [group] + * + * @receiver the collection to sum up. + * @param group tha algebra that provides addition + * @param extractor the (inline) lambda function to extract value + */ +public inline fun Iterable.sumWithGroupOf(group: Group, extractor: (T) -> R): R = this.fold(group.zero) { left: R, right: T -> + group.add(left, extractor(right)) +} + /** * Returns the sum of all elements in the sequence in provided space. * diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts index 529084619..9d5cfabe4 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -2,25 +2,14 @@ plugins { id("space.kscience.gradle.mpp") } -kscience{ +kscience { + jvm() + js() native() -} - -kotlin.sourceSets { - all { - with(languageSettings) { - optIn("kotlinx.coroutines.InternalCoroutinesApi") - optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") - optIn("kotlinx.coroutines.FlowPreview") - } - } - - commonMain { - dependencies { - api(project(":kmath-core")) - api(project(":kmath-complex")) - api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${space.kscience.gradle.KScienceVersions.coroutinesVersion}") - } + dependencies { + api(project(":kmath-core")) + api(project(":kmath-complex")) + api(spclibs.kotlinx.coroutines.core) } } 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 7bae388a8..2fd4f0057 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 @@ -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:OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class) + package space.kscience.kmath.coroutines import kotlinx.coroutines.* 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 8aa5a937c..ccd329064 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 @@ -3,8 +3,11 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:OptIn(FlowPreview::class) + package space.kscience.kmath.streaming +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.flatMapConcat diff --git a/kmath-dimensions/build.gradle.kts b/kmath-dimensions/build.gradle.kts index 29c0eccb6..be1fc65a0 100644 --- a/kmath-dimensions/build.gradle.kts +++ b/kmath-dimensions/build.gradle.kts @@ -3,25 +3,21 @@ plugins { } kscience{ + jvm() + js() native() + + dependencies{ + api(projects.kmathCore) + } + + dependencies(jvmMain) { + api(kotlin("reflect")) + } } description = "A proof of concept module for adding type-safe dimensions to structures" -kotlin.sourceSets { - commonMain { - dependencies { - api(project(":kmath-core")) - } - } - - jvmMain { - dependencies { - api(kotlin("reflect")) - } - } -} - readme { maturity = space.kscience.gradle.Maturity.PROTOTYPE } diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts index 1e964d99c..99ce5903f 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -3,11 +3,15 @@ plugins { } kscience { + jvm() + js() native() + dependencies { api(projects.kmathCore) } - dependencies("commonTest") { + + testDependencies { implementation(projects.testUtils) } } diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 9c2cd8352..08e76aef0 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -3,6 +3,8 @@ plugins { } kscience{ + jvm() + js() native() } diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index 52d76d5d2..f248a1717 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -3,8 +3,12 @@ plugins { } kscience{ + jvm() + js() native() - withContextReceivers() + + useContextReceivers() + useSerialization() dependencies{ api(projects.kmath.kmathComplex) } diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 9d7ac33e4..33704c29e 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -3,6 +3,8 @@ plugins { } kscience{ + jvm() + js() native() } diff --git a/kmath-jupyter/build.gradle.kts b/kmath-jupyter/build.gradle.kts index d92b6ca0d..a600261b3 100644 --- a/kmath-jupyter/build.gradle.kts +++ b/kmath-jupyter/build.gradle.kts @@ -4,15 +4,12 @@ plugins { } dependencies { + api(spclibs.kotlinx.html) api(project(":kmath-ast")) api(project(":kmath-complex")) api(project(":kmath-for-real")) } -kscience { - useHtml() -} - readme { maturity = space.kscience.gradle.Maturity.PROTOTYPE } diff --git a/kmath-memory/build.gradle.kts b/kmath-memory/build.gradle.kts index 50eb448a7..4f0f996b9 100644 --- a/kmath-memory/build.gradle.kts +++ b/kmath-memory/build.gradle.kts @@ -3,6 +3,8 @@ plugins { } kscience { + jvm() + js() native() } diff --git a/kmath-multik/build.gradle.kts b/kmath-multik/build.gradle.kts index 39c03ab9b..fc51d2c21 100644 --- a/kmath-multik/build.gradle.kts +++ b/kmath-multik/build.gradle.kts @@ -6,6 +6,11 @@ description = "JetBrains Multik connector" val multikVersion: String by rootProject.extra +kscience { + jvm() + js() +} + kotlin{ sourceSets{ commonMain{ diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts index ba49d49bf..0a8e47728 100644 --- a/kmath-optimization/build.gradle.kts +++ b/kmath-optimization/build.gradle.kts @@ -3,6 +3,8 @@ plugins { } kscience{ + jvm() + js() native() } diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index bc98129a9..267bfd0f3 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -3,6 +3,8 @@ plugins { } kscience{ + jvm() + js() native() } @@ -14,7 +16,7 @@ kotlin.sourceSets { } } - jvmMain { + getByName("jvmMain") { dependencies { api("org.apache.commons:commons-rng-sampling:1.3") api("org.apache.commons:commons-rng-simple:1.3") diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index 1060b37b4..d27faeeef 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -3,7 +3,10 @@ plugins { } kscience{ + jvm() + js() native() + dependencies { api(projects.kmathCore) api(projects.kmathStat) diff --git a/kmath-trajectory/build.gradle.kts b/kmath-trajectory/build.gradle.kts index 16a84b691..689c3265b 100644 --- a/kmath-trajectory/build.gradle.kts +++ b/kmath-trajectory/build.gradle.kts @@ -3,8 +3,12 @@ plugins { } kscience{ + jvm() + js() native() - withContextReceivers() + + useContextReceivers() + useSerialization() dependencies { api(projects.kmath.kmathGeometry) } diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts index 98bd7328d..b860a62ec 100644 --- a/test-utils/build.gradle.kts +++ b/test-utils/build.gradle.kts @@ -3,6 +3,8 @@ plugins { } kscience{ + jvm() + js() native() } From 0366a69123fc45690d5b6983d83a3c90929d1084 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 3 Feb 2023 19:33:22 +0300 Subject: [PATCH 09/58] Refactor trajectory --- .../space/kscience/kmath/geometry/Circle2D.kt | 4 +- .../kmath/geometry/Euclidean2DSpace.kt | 21 +++ .../kmath/geometry/Euclidean3DSpace.kt | 22 +++ .../space/kscience/kmath/geometry/Line.kt | 11 ++ .../kscience/kmath/trajectory/DubinsPath.kt | 173 ++++++++++-------- .../kscience/kmath/trajectory/DubinsPose2D.kt | 41 ++++- .../kscience/kmath/trajectory/Trajectory2D.kt | 13 +- .../space/kscience/kmath/trajectory/route.kt | 16 -- .../kmath/trajectory/dubins/DubinsTests.kt | 34 ++-- 9 files changed, 217 insertions(+), 118 deletions(-) delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt index 162130908..8beef6fee 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -5,13 +5,15 @@ package space.kscience.kmath.geometry +import kotlinx.serialization.Serializable import kotlin.math.PI /** * A circle in 2D space */ +@Serializable public data class Circle2D( - public val center: DoubleVector2D, + @Serializable(Euclidean2DSpace.VectorSerializer::class) public val center: DoubleVector2D, public val radius: Double ) 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 a8310503c..3df8dba7b 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 @@ -5,6 +5,12 @@ package space.kscience.kmath.geometry +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder import space.kscience.kmath.linear.Point import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.ScaleOperations @@ -33,6 +39,7 @@ public operator fun Vector2D.component1(): T = x public operator fun Vector2D.component2(): T = y public typealias DoubleVector2D = Vector2D +public typealias Float64Vector2D = Vector2D public val Vector2D.r: Double get() = Euclidean2DSpace.norm(this) @@ -44,11 +51,25 @@ public object Euclidean2DSpace : GeometrySpace, ScaleOperations, Norm { + @Serializable + @SerialName("Float64Vector2D") private data class Vector2DImpl( override val x: Double, override val y: Double, ) : DoubleVector2D + public object VectorSerializer : KSerializer { + private val proxySerializer = Vector2DImpl.serializer() + override val descriptor: SerialDescriptor get() = proxySerializer.descriptor + + override fun deserialize(decoder: Decoder): DoubleVector2D = decoder.decodeSerializableValue(proxySerializer) + + override fun serialize(encoder: Encoder, value: DoubleVector2D) { + val vector = value as? Vector2DImpl ?: Vector2DImpl(value.x, value.y) + encoder.encodeSerializableValue(proxySerializer, vector) + } + } + public fun vector(x: Number, y: Number): DoubleVector2D = Vector2DImpl(x.toDouble(), y.toDouble()) override val zero: DoubleVector2D by lazy { vector(0.0, 0.0) } 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 d214e4edf..cc641a3f1 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 @@ -5,6 +5,12 @@ package space.kscience.kmath.geometry +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder import space.kscience.kmath.linear.Point import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.ScaleOperations @@ -45,17 +51,33 @@ public fun Buffer.asVector3D(): Vector3D = object : Vector3D { } public typealias DoubleVector3D = Vector3D +public typealias Float64Vector3D = Vector3D public val DoubleVector3D.r: Double get() = Euclidean3DSpace.norm(this) public object Euclidean3DSpace : GeometrySpace, ScaleOperations, Norm { + + @Serializable + @SerialName("Float64Vector3D") private data class Vector3DImpl( override val x: Double, override val y: Double, override val z: Double, ) : DoubleVector3D + public object VectorSerializer : KSerializer { + private val proxySerializer = Vector3DImpl.serializer() + override val descriptor: SerialDescriptor get() = proxySerializer.descriptor + + override fun deserialize(decoder: Decoder): DoubleVector3D = decoder.decodeSerializableValue(proxySerializer) + + override fun serialize(encoder: Encoder, value: DoubleVector3D) { + val vector = value as? Vector3DImpl ?: Vector3DImpl(value.x, value.y, value.z) + encoder.encodeSerializableValue(proxySerializer, vector) + } + } + public fun vector(x: Number, y: Number, z: Number): DoubleVector3D = Vector3DImpl(x.toDouble(), y.toDouble(), z.toDouble()) 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 bf14d6d4a..ab322ddca 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,10 +5,13 @@ package space.kscience.kmath.geometry +import kotlinx.serialization.Serializable + /** * A line formed by [base] vector of start and a [direction] vector. Direction vector is not necessarily normalized, * but its length does not affect line properties */ +@Serializable public data class Line(val base: V, val direction: V) public typealias Line2D = Line @@ -17,4 +20,12 @@ public typealias Line3D = Line /** * A directed line segment between [begin] and [end] */ +@Serializable public data class LineSegment(val begin: V, val end: V) + +public fun LineSegment.line(algebra: GeometrySpace): Line = with(algebra) { + Line(begin, end - begin) +} + +public typealias LineSegment2D = LineSegment +public typealias LineSegment3D = LineSegment diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index 1ba9936ee..6bbf3e55b 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -57,7 +57,11 @@ internal fun leftInnerTangent(base: Circle2D, direction: Circle2D): StraightTraj internal fun rightInnerTangent(base: Circle2D, direction: Circle2D): StraightTrajectory2D? = innerTangent(base, direction, CircleTrajectory2D.Direction.RIGHT) -private fun innerTangent(base: Circle2D, direction: Circle2D, side: CircleTrajectory2D.Direction): StraightTrajectory2D? = +private fun innerTangent( + base: Circle2D, + direction: Circle2D, + side: CircleTrajectory2D.Direction, +): StraightTrajectory2D? = with(Euclidean2DSpace) { val centers = StraightTrajectory2D(base.center, direction.center) if (centers.length < base.radius * 2) return null @@ -76,43 +80,49 @@ private fun innerTangent(base: Circle2D, direction: Circle2D, side: CircleTrajec internal fun theta(theta: Double): Double = (theta + (2 * PI)) % (2 * PI) + @Suppress("DuplicatedCode") -public class DubinsPath( - public val a: CircleTrajectory2D, - public val b: Trajectory2D, - public val c: CircleTrajectory2D, -) : CompositeTrajectory2D(listOf(a, b, c)) { +public object DubinsPath { - public val type: TYPE = TYPE.valueOf( - arrayOf( - a.direction.name[0], - if (b is CircleTrajectory2D) b.direction.name[0] else 'S', - c.direction.name[0] - ).toCharArray().concatToString() - ) - - public enum class TYPE { + public enum class Type { RLR, LRL, RSR, LSL, RSL, LSR } - public companion object { - public fun all( - start: DubinsPose2D, - end: DubinsPose2D, - turningRadius: Double, - ): List = listOfNotNull( - rlr(start, end, turningRadius), - lrl(start, end, turningRadius), - rsr(start, end, turningRadius), - lsl(start, end, turningRadius), - rsl(start, end, turningRadius), - lsr(start, end, turningRadius) + /** + * Return Dubins trajectory type or null if trajectory is not a Dubins path + */ + public fun trajectoryTypeOf(trajectory2D: CompositeTrajectory2D): Type?{ + if(trajectory2D.segments.size != 3) return null + val a = trajectory2D.segments.first() as? CircleTrajectory2D ?: return null + val b = trajectory2D.segments[1] + val c = trajectory2D.segments.last() as? CircleTrajectory2D ?: return null + return Type.valueOf( + arrayOf( + a.direction.name[0], + if (b is CircleTrajectory2D) b.direction.name[0] else 'S', + c.direction.name[0] + ).toCharArray().concatToString() ) + } - public fun shortest(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): DubinsPath = - all(start, end, turningRadius).minBy { it.length } + public fun all( + start: DubinsPose2D, + end: DubinsPose2D, + turningRadius: Double, + ): List = listOfNotNull( + rlr(start, end, turningRadius), + lrl(start, end, turningRadius), + rsr(start, end, turningRadius), + lsl(start, end, turningRadius), + rsl(start, end, turningRadius), + lsr(start, end, turningRadius) + ) - public fun rlr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): DubinsPath? = with(Euclidean2DSpace) { + public fun shortest(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D = + all(start, end, turningRadius).minBy { it.length } + + public fun rlr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? = + with(Euclidean2DSpace) { val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) val centers = StraightTrajectory2D(c1.center, c2.center) @@ -132,7 +142,7 @@ public class DubinsPath( val a1 = CircleTrajectory2D.of(c1.center, start, p1, CircleTrajectory2D.Direction.RIGHT) val a2 = CircleTrajectory2D.of(e.center, p1, p2, CircleTrajectory2D.Direction.LEFT) val a3 = CircleTrajectory2D.of(c2.center, p2, end, CircleTrajectory2D.Direction.RIGHT) - DubinsPath(a1, a2, a3) + CompositeTrajectory2D(a1, a2, a3) } val secondVariant = run { @@ -149,13 +159,14 @@ public class DubinsPath( val a1 = CircleTrajectory2D.of(c1.center, start, p1, CircleTrajectory2D.Direction.RIGHT) val a2 = CircleTrajectory2D.of(e.center, p1, p2, CircleTrajectory2D.Direction.LEFT) val a3 = CircleTrajectory2D.of(c2.center, p2, end, CircleTrajectory2D.Direction.RIGHT) - DubinsPath(a1, a2, a3) + CompositeTrajectory2D(a1, a2, a3) } return if (firstVariant.length < secondVariant.length) firstVariant else secondVariant } - public fun lrl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): DubinsPath? = with(Euclidean2DSpace) { + public fun lrl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? = + with(Euclidean2DSpace) { val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) val centers = StraightTrajectory2D(c1.center, c2.center) @@ -175,10 +186,10 @@ public class DubinsPath( val a1 = CircleTrajectory2D.of(c1.center, start, p1, CircleTrajectory2D.Direction.LEFT) val a2 = CircleTrajectory2D.of(e.center, p1, p2, CircleTrajectory2D.Direction.RIGHT) val a3 = CircleTrajectory2D.of(c2.center, p2, end, CircleTrajectory2D.Direction.LEFT) - DubinsPath(a1, a2, a3) + CompositeTrajectory2D(a1, a2, a3) } - val secondVariant = run{ + val secondVariant = run { var theta = theta(centers.bearing - acos(centers.length / (turningRadius * 4))) var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) @@ -192,50 +203,60 @@ public class DubinsPath( val a1 = CircleTrajectory2D.of(c1.center, start, p1, CircleTrajectory2D.Direction.LEFT) val a2 = CircleTrajectory2D.of(e.center, p1, p2, CircleTrajectory2D.Direction.RIGHT) val a3 = CircleTrajectory2D.of(c2.center, p2, end, CircleTrajectory2D.Direction.LEFT) - DubinsPath(a1, a2, a3) + CompositeTrajectory2D(a1, a2, a3) } return if (firstVariant.length < secondVariant.length) firstVariant else secondVariant } - public fun rsr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): DubinsPath { - val c1 = start.getRightCircle(turningRadius) - val c2 = end.getRightCircle(turningRadius) - val s = leftOuterTangent(c1, c2) - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.RIGHT) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.RIGHT) - return DubinsPath(a1, s, a3) - } - - public fun lsl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): DubinsPath { - val c1 = start.getLeftCircle(turningRadius) - val c2 = end.getLeftCircle(turningRadius) - val s = rightOuterTangent(c1, c2) - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.LEFT) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.LEFT) - return DubinsPath(a1, s, a3) - } - - public fun rsl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): DubinsPath? { - val c1 = start.getRightCircle(turningRadius) - val c2 = end.getLeftCircle(turningRadius) - val s = rightInnerTangent(c1, c2) - if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.RIGHT) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.LEFT) - return DubinsPath(a1, s, a3) - } - - public fun lsr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): DubinsPath? { - val c1 = start.getLeftCircle(turningRadius) - val c2 = end.getRightCircle(turningRadius) - val s = leftInnerTangent(c1, c2) - if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.LEFT) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.RIGHT) - return DubinsPath(a1, s, a3) - } + public fun rsr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D { + val c1 = start.getRightCircle(turningRadius) + val c2 = end.getRightCircle(turningRadius) + val s = leftOuterTangent(c1, c2) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.RIGHT) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.RIGHT) + return CompositeTrajectory2D(a1, s, a3) } -} \ No newline at end of file + + public fun lsl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D { + val c1 = start.getLeftCircle(turningRadius) + val c2 = end.getLeftCircle(turningRadius) + val s = rightOuterTangent(c1, c2) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.LEFT) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.LEFT) + return CompositeTrajectory2D(a1, s, a3) + } + + public fun rsl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? { + val c1 = start.getRightCircle(turningRadius) + val c2 = end.getLeftCircle(turningRadius) + val s = rightInnerTangent(c1, c2) + if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null + + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.RIGHT) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.LEFT) + return CompositeTrajectory2D(a1, s, a3) + } + + public fun lsr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? { + val c1 = start.getLeftCircle(turningRadius) + val c2 = end.getRightCircle(turningRadius) + val s = leftInnerTangent(c1, c2) + if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null + + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.LEFT) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.RIGHT) + return CompositeTrajectory2D(a1, s, a3) + } +} + +public fun interface MaxCurvature { + public fun compute(startPoint: PhaseVector2D): Double +} + +public fun DubinsPath.shortest( + start: PhaseVector2D, + end: PhaseVector2D, + maxCurvature: MaxCurvature, +): CompositeTrajectory2D = shortest(start, end, maxCurvature.compute(start)) + diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt index 5aa8c1455..ff2198bbb 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt @@ -2,35 +2,62 @@ * Copyright 2018-2022 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. */ - +@file:UseSerializers(Euclidean2DSpace.VectorSerializer::class) package space.kscience.kmath.trajectory +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder import space.kscience.kmath.geometry.DoubleVector2D +import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.Vector import kotlin.math.atan2 /** * Combination of [Vector] and its view angle (clockwise from positive y-axis direction) */ +@Serializable(DubinsPose2DSerializer::class) public interface DubinsPose2D : DoubleVector2D { - public val coordinate: DoubleVector2D + public val coordinates: DoubleVector2D public val bearing: Double } +@Serializable public class PhaseVector2D( - override val coordinate: DoubleVector2D, + override val coordinates: DoubleVector2D, public val velocity: DoubleVector2D, -) : DubinsPose2D, DoubleVector2D by coordinate { +) : DubinsPose2D, DoubleVector2D by coordinates { override val bearing: Double get() = atan2(velocity.x, velocity.y) } +@Serializable +@SerialName("DubinsPose2D") private class DubinsPose2DImpl( - override val coordinate: DoubleVector2D, + override val coordinates: DoubleVector2D, override val bearing: Double, -) : DubinsPose2D, DoubleVector2D by coordinate{ +) : DubinsPose2D, DoubleVector2D by coordinates{ - override fun toString(): String = "Pose2D(x=$x, y=$y, bearing=$bearing)" + override fun toString(): String = "DubinsPose2D(x=$x, y=$y, bearing=$bearing)" } +public object DubinsPose2DSerializer: KSerializer{ + private val proxySerializer = DubinsPose2DImpl.serializer() + + override val descriptor: SerialDescriptor + get() = proxySerializer.descriptor + + override fun deserialize(decoder: Decoder): DubinsPose2D { + return decoder.decodeSerializableValue(proxySerializer) + } + + override fun serialize(encoder: Encoder, value: DubinsPose2D) { + val pose = value as? DubinsPose2DImpl ?: DubinsPose2DImpl(value.coordinates, value.bearing) + encoder.encodeSerializableValue(proxySerializer, pose) + } +} public fun DubinsPose2D(coordinate: DoubleVector2D, theta: Double): DubinsPose2D = DubinsPose2DImpl(coordinate, theta) \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt index ffa23a537..120bedf90 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt @@ -2,15 +2,19 @@ * Copyright 2018-2022 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. */ - +@file:UseSerializers(Euclidean2DSpace.VectorSerializer::class) package space.kscience.kmath.trajectory +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.DoubleVector2D +import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import kotlin.math.PI import kotlin.math.atan2 +@Serializable public sealed interface Trajectory2D { public val length: Double } @@ -18,6 +22,7 @@ public sealed interface Trajectory2D { /** * Straight path segment. The order of start and end defines the direction */ +@Serializable public data class StraightTrajectory2D( public val start: DoubleVector2D, public val end: DoubleVector2D, @@ -30,6 +35,7 @@ public data class StraightTrajectory2D( /** * An arc segment */ +@Serializable public data class CircleTrajectory2D( public val circle: Circle2D, public val start: DubinsPose2D, @@ -102,7 +108,10 @@ public data class CircleTrajectory2D( } } -public open class CompositeTrajectory2D(public val segments: List) : Trajectory2D { +@Serializable +public class CompositeTrajectory2D(public val segments: List) : Trajectory2D { override val length: Double get() = segments.sumOf { it.length } } +public fun CompositeTrajectory2D(vararg segments: Trajectory2D): CompositeTrajectory2D = CompositeTrajectory2D(segments.toList()) + diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt deleted file mode 100644 index 56350835d..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2018-2022 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.trajectory - -public fun interface MaxCurvature { - public fun compute(startPoint: PhaseVector2D): Double -} - -public fun DubinsPath.Companion.shortest( - start: PhaseVector2D, - end: PhaseVector2D, - maxCurvature: MaxCurvature, -): DubinsPath = shortest(start, end, maxCurvature.compute(start)) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 5bbf8c294..0e14ae736 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -28,31 +28,33 @@ class DubinsTests { println("Absolute distance: $absoluteDistance") val expectedLengths = mapOf( - DubinsPath.TYPE.RLR to 13.067681939031397, - DubinsPath.TYPE.RSR to 12.28318530717957, - DubinsPath.TYPE.LSL to 32.84955592153878, - DubinsPath.TYPE.RSL to 23.37758938854081, - DubinsPath.TYPE.LSR to 23.37758938854081 + DubinsPath.Type.RLR to 13.067681939031397, + DubinsPath.Type.RSR to 12.28318530717957, + DubinsPath.Type.LSL to 32.84955592153878, + DubinsPath.Type.RSL to 23.37758938854081, + DubinsPath.Type.LSR to 23.37758938854081 ) expectedLengths.forEach { - val path = dubins.find { p -> p.type === it.key } + val path = dubins.find { p -> DubinsPath.trajectoryTypeOf(p) === it.key } assertNotNull(path, "Path ${it.key} not found") println("${it.key}: ${path.length}") assertTrue(it.value.equalFloat(path.length)) - assertTrue(start.equalsFloat(path.a.start)) - assertTrue(end.equalsFloat(path.c.end)) + val a = path.segments[0] as CircleTrajectory2D + val b = path.segments[1] + val c = path.segments[2] as CircleTrajectory2D + + assertTrue(start.equalsFloat(a.start)) + assertTrue(end.equalsFloat(c.end)) // Not working, theta double precision inaccuracy - if (path.b is CircleTrajectory2D) { - val b = path.b as CircleTrajectory2D - assertTrue(path.a.end.equalsFloat(b.start)) - assertTrue(path.c.start.equalsFloat(b.end)) - } else if (path.b is StraightTrajectory2D) { - val b = path.b as StraightTrajectory2D - assertTrue(path.a.end.equalsFloat(DubinsPose2D(b.start, b.bearing))) - assertTrue(path.c.start.equalsFloat(DubinsPose2D(b.end, b.bearing))) + if (b is CircleTrajectory2D) { + assertTrue(a.end.equalsFloat(b.start)) + assertTrue(c.start.equalsFloat(b.end)) + } else if (b is StraightTrajectory2D) { + assertTrue(a.end.equalsFloat(DubinsPose2D(b.start, b.bearing))) + assertTrue(c.start.equalsFloat(DubinsPose2D(b.end, b.bearing))) } } } From 2c6d1e89c512627f79c579e7305197d3a3ae98db Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 5 Feb 2023 20:05:53 +0300 Subject: [PATCH 10/58] Update type-safe angles --- CHANGELOG.md | 1 + .../space/kscience/kmath/geometry/angles.kt | 53 +++++++++++-------- .../kscience/kmath/geometry/AngleTest.kt | 16 ++++++ .../kscience/kmath/trajectory/DubinsPath.kt | 39 ++++++-------- .../kscience/kmath/trajectory/DubinsPose2D.kt | 12 ++--- .../kscience/kmath/trajectory/Trajectory2D.kt | 42 +++++++-------- .../space/kscience/kmath/trajectory/math.kt | 8 +-- .../kmath/trajectory/segments/ArcTests.kt | 6 +-- .../kmath/trajectory/segments/LineTests.kt | 12 ++--- 9 files changed, 104 insertions(+), 85 deletions(-) create mode 100644 kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index b8cb0d976..404366a03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Algebra now has an obligatory `bufferFactory` (#477). ### Changed +- Trajectory use type-safe angles - Tensor operations switched to prefix notation - Row-wise and column-wise ND shapes in the core - Shape is read-only diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt index e7b0afcda..45022ad05 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt @@ -7,8 +7,9 @@ package space.kscience.kmath.geometry import kotlin.jvm.JvmInline import kotlin.math.PI +import kotlin.math.floor -public sealed interface Angle { +public sealed interface Angle : Comparable { public fun toRadians(): Radians public fun toDegrees(): Degrees @@ -17,7 +18,15 @@ public sealed interface Angle { public operator fun times(other: Number): Angle public operator fun div(other: Number): Angle + public operator fun div(other: Angle): Double public operator fun unaryMinus(): Angle + + public companion object { + public val zero: Radians = Radians(0.0) + public val pi: Radians = Radians(PI) + public val piTimes2: Radians = Radians(PI * 2) + public val piDiv2: Radians = Radians(PI / 2) + } } /** @@ -28,12 +37,16 @@ public value class Radians(public val value: Double) : Angle { override fun toRadians(): Radians = this override fun toDegrees(): Degrees = Degrees(value * 180 / PI) - public override fun plus(other: Angle): Radians = Radians(value + other.toRadians().value) - public override fun minus(other: Angle): Radians = Radians(value - other.toRadians().value) + public override fun plus(other: Angle): Radians = Radians(value + other.radians) + public override fun minus(other: Angle): Radians = Radians(value - other.radians) - public override fun times(other: Number): Radians = Radians(value + other.toDouble()) + public override fun times(other: Number): Radians = Radians(value * other.toDouble()) public override fun div(other: Number): Radians = Radians(value / other.toDouble()) + override fun div(other: Angle): Double = value / other.radians + public override fun unaryMinus(): Radians = Radians(-value) + + override fun compareTo(other: Angle): Int = value.compareTo(other.radians) } public fun sin(angle: Angle): Double = kotlin.math.sin(angle.toRadians().value) @@ -42,6 +55,8 @@ public fun tan(angle: Angle): Double = kotlin.math.tan(angle.toRadians().value) public val Number.radians: Radians get() = Radians(toDouble()) +public val Angle.radians: Double get() = toRadians().value + /** * Type safe degrees */ @@ -50,30 +65,26 @@ public value class Degrees(public val value: Double) : Angle { override fun toRadians(): Radians = Radians(value * PI / 180) override fun toDegrees(): Degrees = this - public override fun plus(other: Angle): Degrees = Degrees(value + other.toDegrees().value) - public override fun minus(other: Angle): Degrees = Degrees(value - other.toDegrees().value) + public override fun plus(other: Angle): Degrees = Degrees(value + other.degrees) + public override fun minus(other: Angle): Degrees = Degrees(value - other.degrees) - public override fun times(other: Number): Degrees = Degrees(value + other.toDouble()) + public override fun times(other: Number): Degrees = Degrees(value * other.toDouble()) public override fun div(other: Number): Degrees = Degrees(value / other.toDouble()) + override fun div(other: Angle): Double = value / other.degrees + public override fun unaryMinus(): Degrees = Degrees(-value) + + override fun compareTo(other: Angle): Int = value.compareTo(other.degrees) } public val Number.degrees: Degrees get() = Degrees(toDouble()) +public val Angle.degrees: Double get() = toDegrees().value + /** - * A holder class for Pi representation in radians and degrees + * Normalized angle 2 PI range symmetric around [center]. By default, uses (0, 2PI) range. */ -public object Pi { - public val radians: Radians = Radians(PI) - public val degrees: Degrees = radians.toDegrees() -} +public fun Angle.normalized(center: Angle = Angle.pi): Angle = + this - Angle.piTimes2 * floor((radians + PI - center.radians) / PI / 2) -public object PiTimes2 { - public val radians: Radians = Radians(2 * PI) - public val degrees: Degrees = radians.toDegrees() -} - -public object PiDiv2 { - public val radians: Radians = Radians(PI / 2) - public val degrees: Degrees = radians.toDegrees() -} \ No newline at end of file +public fun abs(angle: Angle): Angle = if (angle < Angle.zero) -angle else angle \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt new file mode 100644 index 000000000..b8086eb75 --- /dev/null +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt @@ -0,0 +1,16 @@ +package space.kscience.kmath.geometry + +import kotlin.test.Test +import kotlin.test.assertEquals + +class AngleTest { + @Test + fun normalization() { + assertEquals(30.degrees, 390.degrees.normalized()) + assertEquals(30.degrees, (-330).degrees.normalized()) + assertEquals(200.degrees, 200.degrees.normalized()) + assertEquals(30.degrees, 390.degrees.normalized(Angle.zero)) + assertEquals(30.degrees, (-330).degrees.normalized(Angle.zero)) + assertEquals((-160).degrees, 200.degrees.normalized(Angle.zero)) + } +} \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index 6bbf3e55b..568ef691a 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -5,13 +5,9 @@ package space.kscience.kmath.trajectory -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.* import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import kotlin.math.PI import kotlin.math.acos -import kotlin.math.cos -import kotlin.math.sin internal fun DubinsPose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first @@ -65,12 +61,11 @@ private fun innerTangent( with(Euclidean2DSpace) { val centers = StraightTrajectory2D(base.center, direction.center) if (centers.length < base.radius * 2) return null - val angle = theta( - when (side) { - CircleTrajectory2D.Direction.LEFT -> centers.bearing + acos(base.radius * 2 / centers.length) - CircleTrajectory2D.Direction.RIGHT -> centers.bearing - acos(base.radius * 2 / centers.length) - } - ) + val angle = when (side) { + CircleTrajectory2D.Direction.LEFT -> centers.bearing + acos(base.radius * 2 / centers.length).radians + CircleTrajectory2D.Direction.RIGHT -> centers.bearing - acos(base.radius * 2 / centers.length).radians + }.normalized() + val dX = base.radius * sin(angle) val dY = base.radius * cos(angle) val p1 = vector(base.center.x + dX, base.center.y + dY) @@ -78,8 +73,6 @@ private fun innerTangent( return StraightTrajectory2D(p1, p2) } -internal fun theta(theta: Double): Double = (theta + (2 * PI)) % (2 * PI) - @Suppress("DuplicatedCode") public object DubinsPath { @@ -91,8 +84,8 @@ public object DubinsPath { /** * Return Dubins trajectory type or null if trajectory is not a Dubins path */ - public fun trajectoryTypeOf(trajectory2D: CompositeTrajectory2D): Type?{ - if(trajectory2D.segments.size != 3) return null + public fun trajectoryTypeOf(trajectory2D: CompositeTrajectory2D): Type? { + if (trajectory2D.segments.size != 3) return null val a = trajectory2D.segments.first() as? CircleTrajectory2D ?: return null val b = trajectory2D.segments[1] val c = trajectory2D.segments.last() as? CircleTrajectory2D ?: return null @@ -129,13 +122,13 @@ public object DubinsPath { if (centers.length > turningRadius * 4) return null val firstVariant = run { - var theta = theta(centers.bearing - acos(centers.length / (turningRadius * 4))) + var theta = (centers.bearing - acos(centers.length / (turningRadius * 4)).radians).normalized() var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) val e = Circle2D(p, turningRadius) val p1 = vector(c1.center.x + dX, c1.center.y + dY) - theta = theta(centers.bearing + acos(centers.length / (turningRadius * 4))) + theta = (centers.bearing + acos(centers.length / (turningRadius * 4)).radians).normalized() dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) @@ -146,13 +139,13 @@ public object DubinsPath { } val secondVariant = run { - var theta = theta(centers.bearing + acos(centers.length / (turningRadius * 4))) + var theta = (centers.bearing + acos(centers.length / (turningRadius * 4)).radians).normalized() var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) val e = Circle2D(p, turningRadius) val p1 = vector(c1.center.x + dX, c1.center.y + dY) - theta = theta(centers.bearing - acos(centers.length / (turningRadius * 4))) + theta = (centers.bearing - acos(centers.length / (turningRadius * 4)).radians).normalized() dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) @@ -173,13 +166,13 @@ public object DubinsPath { if (centers.length > turningRadius * 4) return null val firstVariant = run { - var theta = theta(centers.bearing + acos(centers.length / (turningRadius * 4))) + var theta = (centers.bearing + acos(centers.length / (turningRadius * 4)).radians).normalized() var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) val e = Circle2D(p, turningRadius) val p1 = vector(c1.center.x + dX, c1.center.y + dY) - theta = theta(centers.bearing - acos(centers.length / (turningRadius * 4))) + theta = (centers.bearing - acos(centers.length / (turningRadius * 4)).radians).normalized() dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) @@ -190,13 +183,13 @@ public object DubinsPath { } val secondVariant = run { - var theta = theta(centers.bearing - acos(centers.length / (turningRadius * 4))) + var theta = (centers.bearing - acos(centers.length / (turningRadius * 4)).radians).normalized() var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) val e = Circle2D(p, turningRadius) val p1 = vector(c1.center.x + dX, c1.center.y + dY) - theta = theta(centers.bearing + acos(centers.length / (turningRadius * 4))) + theta = (centers.bearing + acos(centers.length / (turningRadius * 4)).radians).normalized() dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt index ff2198bbb..8362d0cb5 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt @@ -12,9 +12,7 @@ import kotlinx.serialization.UseSerializers import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import space.kscience.kmath.geometry.DoubleVector2D -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.Vector +import space.kscience.kmath.geometry.* import kotlin.math.atan2 /** @@ -23,7 +21,7 @@ import kotlin.math.atan2 @Serializable(DubinsPose2DSerializer::class) public interface DubinsPose2D : DoubleVector2D { public val coordinates: DoubleVector2D - public val bearing: Double + public val bearing: Angle } @Serializable @@ -31,14 +29,14 @@ public class PhaseVector2D( override val coordinates: DoubleVector2D, public val velocity: DoubleVector2D, ) : DubinsPose2D, DoubleVector2D by coordinates { - override val bearing: Double get() = atan2(velocity.x, velocity.y) + override val bearing: Angle get() = atan2(velocity.x, velocity.y).radians } @Serializable @SerialName("DubinsPose2D") private class DubinsPose2DImpl( override val coordinates: DoubleVector2D, - override val bearing: Double, + override val bearing: Angle, ) : DubinsPose2D, DoubleVector2D by coordinates{ override fun toString(): String = "DubinsPose2D(x=$x, y=$y, bearing=$bearing)" @@ -60,4 +58,4 @@ public object DubinsPose2DSerializer: KSerializer{ } } -public fun DubinsPose2D(coordinate: DoubleVector2D, theta: Double): DubinsPose2D = DubinsPose2DImpl(coordinate, theta) \ No newline at end of file +public fun DubinsPose2D(coordinate: DoubleVector2D, theta: Angle): DubinsPose2D = DubinsPose2DImpl(coordinate, theta) \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt index 120bedf90..b8916e748 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt @@ -3,15 +3,13 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:UseSerializers(Euclidean2DSpace.VectorSerializer::class) + package space.kscience.kmath.trajectory import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.DoubleVector2D -import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.* import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import kotlin.math.PI import kotlin.math.atan2 @Serializable @@ -29,7 +27,7 @@ public data class StraightTrajectory2D( ) : Trajectory2D { override val length: Double get() = start.distanceTo(end) - public val bearing: Double get() = theta(atan2(end.x - start.x, end.y - start.y)) + public val bearing: Angle get() = (atan2(end.x - start.x, end.y - start.y).radians).normalized() } /** @@ -49,26 +47,25 @@ public data class CircleTrajectory2D( /** * Arc length in radians */ - val arcLength: Double - get() = theta( - if (direction == Direction.LEFT) { - start.bearing - end.bearing - } else { - end.bearing - start.bearing - } - ) + val arcLength: Angle + get() = if (direction == Direction.LEFT) { + start.bearing - end.bearing + } else { + end.bearing - start.bearing + }.normalized() + override val length: Double by lazy { - circle.radius * arcLength + circle.radius * arcLength.radians } public val direction: Direction by lazy { if (start.y < circle.center.y) { - if (start.bearing > PI) Direction.RIGHT else Direction.LEFT + if (start.bearing > Angle.pi) Direction.RIGHT else Direction.LEFT } else if (start.y > circle.center.y) { - if (start.bearing < PI) Direction.RIGHT else Direction.LEFT + if (start.bearing < Angle.pi) Direction.RIGHT else Direction.LEFT } else { - if (start.bearing == 0.0) { + if (start.bearing == Angle.zero) { if (start.x < circle.center.x) Direction.RIGHT else Direction.LEFT } else { if (start.x > circle.center.x) Direction.RIGHT else Direction.LEFT @@ -85,13 +82,13 @@ public data class CircleTrajectory2D( ): CircleTrajectory2D { fun calculatePose( vector: DoubleVector2D, - theta: Double, + theta: Angle, direction: Direction, ): DubinsPose2D = DubinsPose2D( vector, when (direction) { - Direction.LEFT -> theta(theta - PI / 2) - Direction.RIGHT -> theta(theta + PI / 2) + Direction.LEFT -> (theta - Angle.piDiv2).normalized() + Direction.RIGHT -> (theta + Angle.piDiv2).normalized() } ) @@ -100,7 +97,7 @@ public data class CircleTrajectory2D( val pose1 = calculatePose(start, s1.bearing, direction) val pose2 = calculatePose(end, s2.bearing, direction) val trajectory = CircleTrajectory2D(Circle2D(center, s1.length), pose1, pose2) - if(trajectory.direction != direction){ + if (trajectory.direction != direction) { error("Trajectory direction mismatch") } return trajectory @@ -113,5 +110,6 @@ public class CompositeTrajectory2D(public val segments: List) : Tr override val length: Double get() = segments.sumOf { it.length } } -public fun CompositeTrajectory2D(vararg segments: Trajectory2D): CompositeTrajectory2D = CompositeTrajectory2D(segments.toList()) +public fun CompositeTrajectory2D(vararg segments: Trajectory2D): CompositeTrajectory2D = + CompositeTrajectory2D(segments.toList()) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt index 4599f30f8..c69ad24f1 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt @@ -6,19 +6,21 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.radians +import space.kscience.kmath.geometry.sin import kotlin.math.PI import kotlin.math.abs -import kotlin.math.sin const val maxFloatDelta = 0.000001 fun Double.radiansToDegrees() = this * 180 / PI fun Double.equalFloat(other: Double) = abs(this - other) < maxFloatDelta -fun DubinsPose2D.equalsFloat(other: DubinsPose2D) = x.equalFloat(other.x) && y.equalFloat(other.y) && bearing.equalFloat(other.bearing) +fun DubinsPose2D.equalsFloat(other: DubinsPose2D) = + x.equalFloat(other.x) && y.equalFloat(other.y) && bearing.radians.equalFloat(other.bearing.radians) fun StraightTrajectory2D.inverse() = StraightTrajectory2D(end, start) -fun StraightTrajectory2D.shift(shift: Int, width: Double): StraightTrajectory2D = with(Euclidean2DSpace){ +fun StraightTrajectory2D.shift(shift: Int, width: Double): StraightTrajectory2D = with(Euclidean2DSpace) { val dX = width * sin(inverse().bearing) val dY = width * sin(bearing) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index af1444ade..643f9eaaa 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -8,8 +8,8 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.circumference +import space.kscience.kmath.geometry.degrees import space.kscience.kmath.trajectory.CircleTrajectory2D -import space.kscience.kmath.trajectory.radiansToDegrees import kotlin.test.Test import kotlin.test.assertEquals @@ -20,7 +20,7 @@ class ArcTests { val circle = Circle2D(vector(0.0, 0.0), 2.0) val arc = CircleTrajectory2D.of(circle.center, vector(-2.0, 0.0), vector(0.0, 2.0), CircleTrajectory2D.Direction.RIGHT) assertEquals(circle.circumference / 4, arc.length, 1.0) - assertEquals(0.0, arc.start.bearing.radiansToDegrees()) - assertEquals(90.0, arc.end.bearing.radiansToDegrees()) + assertEquals(0.0, arc.start.bearing.degrees) + assertEquals(90.0, arc.end.bearing.degrees) } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt index 03320a3df..54deb2193 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt @@ -6,8 +6,8 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.degrees import space.kscience.kmath.trajectory.StraightTrajectory2D -import space.kscience.kmath.trajectory.radiansToDegrees import kotlin.math.pow import kotlin.math.sqrt import kotlin.test.Test @@ -19,19 +19,19 @@ class LineTests { fun lineTest() = with(Euclidean2DSpace){ val straight = StraightTrajectory2D(vector(0.0, 0.0), vector(100.0, 100.0)) assertEquals(sqrt(100.0.pow(2) + 100.0.pow(2)), straight.length) - assertEquals(45.0, straight.bearing.radiansToDegrees()) + assertEquals(45.0, straight.bearing.degrees) } @Test fun lineAngleTest() = with(Euclidean2DSpace){ //val zero = Vector2D(0.0, 0.0) val north = StraightTrajectory2D(zero, vector(0.0, 2.0)) - assertEquals(0.0, north.bearing.radiansToDegrees()) + assertEquals(0.0, north.bearing.degrees) val east = StraightTrajectory2D(zero, vector(2.0, 0.0)) - assertEquals(90.0, east.bearing.radiansToDegrees()) + assertEquals(90.0, east.bearing.degrees) val south = StraightTrajectory2D(zero, vector(0.0, -2.0)) - assertEquals(180.0, south.bearing.radiansToDegrees()) + assertEquals(180.0, south.bearing.degrees) val west = StraightTrajectory2D(zero, vector(-2.0, 0.0)) - assertEquals(270.0, west.bearing.radiansToDegrees()) + assertEquals(270.0, west.bearing.degrees) } } From 6deeaf057e64d0ccaba0abb3cab32c64a8e76455 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 11 Feb 2023 21:51:19 +0300 Subject: [PATCH 11/58] Add angle serializer --- .../space/kscience/kmath/geometry/angles.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt index 45022ad05..3855514fb 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt @@ -5,10 +5,17 @@ package space.kscience.kmath.geometry +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder import kotlin.jvm.JvmInline import kotlin.math.PI import kotlin.math.floor +@Serializable(AngleSerializer::class) public sealed interface Angle : Comparable { public fun toRadians(): Radians public fun toDegrees(): Degrees @@ -29,9 +36,21 @@ public sealed interface Angle : Comparable { } } + +public object AngleSerializer : KSerializer { + override val descriptor: SerialDescriptor get() = Double.serializer().descriptor + + override fun deserialize(decoder: Decoder): Angle = decoder.decodeDouble().degrees + + override fun serialize(encoder: Encoder, value: Angle) { + encoder.encodeDouble(value.degrees) + } +} + /** * Type safe radians */ +@Serializable @JvmInline public value class Radians(public val value: Double) : Angle { override fun toRadians(): Radians = this From 784d397ab12103bae441d770b8ee6c2f8e0c03c3 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 12 Feb 2023 10:40:53 +0300 Subject: [PATCH 12/58] Fix serial names for trajectory serializers --- .../kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt index b8916e748..7e0a8c1c0 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.trajectory +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers import space.kscience.kmath.geometry.* @@ -21,6 +22,7 @@ public sealed interface Trajectory2D { * Straight path segment. The order of start and end defines the direction */ @Serializable +@SerialName("straight") public data class StraightTrajectory2D( public val start: DoubleVector2D, public val end: DoubleVector2D, @@ -34,6 +36,7 @@ public data class StraightTrajectory2D( * An arc segment */ @Serializable +@SerialName("arc") public data class CircleTrajectory2D( public val circle: Circle2D, public val start: DubinsPose2D, @@ -106,6 +109,7 @@ public data class CircleTrajectory2D( } @Serializable +@SerialName("composite") public class CompositeTrajectory2D(public val segments: List) : Trajectory2D { override val length: Double get() = segments.sumOf { it.length } } From 50579f4712695629d477eb1031f1a36e0d34f9af Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Mon, 13 Feb 2023 23:17:13 +0300 Subject: [PATCH 13/58] added tangent between two circles --- .../space/kscience/kmath/geometry/Tangent.kt | 77 +++++++++++++++++++ .../kscience/kmath/geometry/TangentTest.kt | 39 ++++++++++ 2 files changed, 116 insertions(+) create mode 100644 kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt create mode 100644 kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt new file mode 100644 index 000000000..889debecb --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.geometry + +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.linear.DoubleLinearSpace.plus +import space.kscience.kmath.linear.Point +import kotlin.math.absoluteValue +import kotlin.math.atan2 +import kotlin.math.pow +import kotlin.math.sign +import kotlin.math.sin +import kotlin.math.cos +import space.kscience.kmath.geometry.Euclidean2DSpace.vector +import space.kscience.kmath.geometry.Euclidean2DSpace.dot +import space.kscience.kmath.geometry.Euclidean2DSpace.scale +import space.kscience.kmath.geometry.Euclidean2DSpace.add + + +public class Segment( + public val startPoint: DoubleVector2D, + public val terminalPoint: DoubleVector2D, + public val length: Double = startPoint.distanceTo(terminalPoint) +) { + public override operator fun equals(other: Any?): Boolean { + return if (other is Segment) { + startPoint.x.equalFloat(other.startPoint.x) && startPoint.y.equalFloat(other.startPoint.y) && + terminalPoint.x.equalFloat(other.terminalPoint.x) && terminalPoint.y.equalFloat(other.terminalPoint.y) + } else { + false + } + } +} + +public const val maxFloatDelta: Double = 0.000001 +public fun Double.equalFloat(other: Double): Boolean = kotlin.math.abs(this - other) < maxFloatDelta + + + +public fun tangentsToCircles( + startCircle: Circle2D, + terminalCircle: Circle2D +): kotlin.collections.MutableMap { + val R1 = startCircle.radius + val R2 = terminalCircle.radius + val d = Segment(startCircle.center, terminalCircle.center).length + val angle1 = atan2(terminalCircle.center.x - startCircle.center.x, terminalCircle.center.y - startCircle.center.y) + var r: Double + var angle2: Double + val routes = mapOf("RSR" to Pair(R1, R2), + "RSL" to Pair(R1, -R2), + "LSR" to Pair(-R1, R2), + "LSL" to Pair(-R1, -R2)) + val segments = mutableMapOf() + for ((route, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + val L = (d * d - r * r).pow(0.5) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, L) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, L) + } + val W = vector(-cos(angle2), sin(angle2)) + segments[route] = Segment(add(startCircle.center, scale(W, r1)), + add(terminalCircle.center, scale(W, r2))) + } + return segments +} \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt new file mode 100644 index 000000000..beac8d15f --- /dev/null +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.geometry + +import space.kscience.kmath.geometry.Euclidean2DSpace.vector +import kotlin.test.Test +import kotlin.test.assertEquals + +class TangentTest { + @Test + fun tangent() { + val c1 = Circle2D(vector(0.0, 0.0), 1.0) + val c2 = Circle2D(vector(4.0, 0.0), 1.0) + val routes = arrayListOf("RSR", "RSL", "LSR", "LSL") + val segments = arrayListOf( + Segment(startPoint = vector(0.0, 1.0), + terminalPoint = vector(4.0, 1.0)), + Segment(startPoint = vector(0.5, 0.8660254), + terminalPoint = vector(3.5, -0.8660254)), + Segment(startPoint = vector(0.5, -0.8660254), + terminalPoint = vector(3.5, 0.8660254)), + Segment(startPoint = vector(0.0, -1.0), + terminalPoint = vector(4.0, -1.0)) + ) + + val tangentMap = tangentsToCircles(c1, c2) + val tangentMapKeys = tangentMap.keys.toList() + val tangentMapValues = tangentMap.values.toList() + + assertEquals(routes, tangentMapKeys) + for (i in segments.indices) { + assertEquals(segments[i], tangentMapValues[i]) + } +// assertEquals(segments, tangentMapValues) + } +} \ No newline at end of file From bef317677c9a1c3496595dca8999a06ead1c3f85 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Wed, 15 Feb 2023 14:36:58 +0300 Subject: [PATCH 14/58] tangentsToCircle fixed --- .../space/kscience/kmath/geometry/Circle2D.kt | 39 ++++++- .../space/kscience/kmath/geometry/Line.kt | 10 ++ .../space/kscience/kmath/geometry/Tangent.kt | 108 +++++++++--------- .../kscience/kmath/geometry/TangentTest.kt | 24 ++-- .../kscience/kmath/geometry/testUtils.kt | 3 + 5 files changed, 116 insertions(+), 68 deletions(-) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt index 8beef6fee..a26a592da 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -6,7 +6,8 @@ package space.kscience.kmath.geometry import kotlinx.serialization.Serializable -import kotlin.math.PI +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import kotlin.math.* /** * A circle in 2D space @@ -17,4 +18,40 @@ public data class Circle2D( public val radius: Double ) +public fun Circle2D.tangentsToCircle(other: Circle2D): kotlin.collections.MutableMap> { + val R1 = this.radius + val R2 = other.radius + val line = LineSegment(this.center, other.center) + val d = line.begin.distanceTo(line.end) + val angle1 = atan2(other.center.x - this.center.x, other.center.y - this.center.y) + var r: Double + var angle2: Double + val routes = mapOf("RSR" to Pair(R1, R2), + "RSL" to Pair(R1, -R2), + "LSR" to Pair(-R1, R2), + "LSL" to Pair(-R1, -R2)) + val segments = mutableMapOf>() + for ((route, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + val L = (d * d - r * r).pow(0.5) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, L) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, L) + } + val W = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) + segments[route] = LineSegment( + Euclidean2DSpace.add(this.center, Euclidean2DSpace.scale(W, r1)), + Euclidean2DSpace.add(other.center, Euclidean2DSpace.scale(W, r2)) + ) + } + return segments +} + public val Circle2D.circumference: Double get() = radius * 2 * PI 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 ab322ddca..bb03b5a93 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 @@ -27,5 +27,15 @@ public fun LineSegment.line(algebra: GeometrySpace): Line Line(begin, end - begin) } +public fun equalLineSegments(line1: LineSegment, line2: LineSegment): Boolean { + val maxFloatDelta = 0.000001 + return line1.begin.x.equalFloat(line2.begin.x) && line1.begin.y.equalFloat(line2.begin.y) && + line1.end.x.equalFloat(line2.end.x) && line1.end.y.equalFloat(line2.end.y) +// return line1.begin == line2.begin && line1.end == line2.end +} + +public fun Double.equalFloat(other: Double, maxFloatDelta: Double = 0.000001): + Boolean = kotlin.math.abs(this - other) < maxFloatDelta + public typealias LineSegment2D = LineSegment public typealias LineSegment3D = LineSegment diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt index 889debecb..cfcb78115 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt @@ -5,9 +5,6 @@ package space.kscience.kmath.geometry -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.linear.DoubleLinearSpace.plus -import space.kscience.kmath.linear.Point import kotlin.math.absoluteValue import kotlin.math.atan2 import kotlin.math.pow @@ -15,63 +12,64 @@ import kotlin.math.sign import kotlin.math.sin import kotlin.math.cos import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import space.kscience.kmath.geometry.Euclidean2DSpace.dot import space.kscience.kmath.geometry.Euclidean2DSpace.scale import space.kscience.kmath.geometry.Euclidean2DSpace.add +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -public class Segment( - public val startPoint: DoubleVector2D, - public val terminalPoint: DoubleVector2D, - public val length: Double = startPoint.distanceTo(terminalPoint) -) { - public override operator fun equals(other: Any?): Boolean { - return if (other is Segment) { - startPoint.x.equalFloat(other.startPoint.x) && startPoint.y.equalFloat(other.startPoint.y) && - terminalPoint.x.equalFloat(other.terminalPoint.x) && terminalPoint.y.equalFloat(other.terminalPoint.y) - } else { - false - } - } -} +//public class Segment( +// public val startPoint: DoubleVector2D, +// public val terminalPoint: DoubleVector2D, +// public val length: Double = startPoint.distanceTo(terminalPoint) +//) { +// public override operator fun equals(other: Any?): Boolean { +// return if (other is Segment) { +// startPoint.x.equalFloat(other.startPoint.x) && startPoint.y.equalFloat(other.startPoint.y) && +// terminalPoint.x.equalFloat(other.terminalPoint.x) && terminalPoint.y.equalFloat(other.terminalPoint.y) +// } else { +// false +// } +// } +//} -public const val maxFloatDelta: Double = 0.000001 -public fun Double.equalFloat(other: Double): Boolean = kotlin.math.abs(this - other) < maxFloatDelta +//public const val maxFloatDelta: Double = 0.000001 +//public fun Double.equalFloat(other: Double): Boolean = kotlin.math.abs(this - other) < maxFloatDelta -public fun tangentsToCircles( - startCircle: Circle2D, - terminalCircle: Circle2D -): kotlin.collections.MutableMap { - val R1 = startCircle.radius - val R2 = terminalCircle.radius - val d = Segment(startCircle.center, terminalCircle.center).length - val angle1 = atan2(terminalCircle.center.x - startCircle.center.x, terminalCircle.center.y - startCircle.center.y) - var r: Double - var angle2: Double - val routes = mapOf("RSR" to Pair(R1, R2), - "RSL" to Pair(R1, -R2), - "LSR" to Pair(-R1, R2), - "LSL" to Pair(-R1, -R2)) - val segments = mutableMapOf() - for ((route, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - val L = (d * d - r * r).pow(0.5) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, L) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, L) - } - val W = vector(-cos(angle2), sin(angle2)) - segments[route] = Segment(add(startCircle.center, scale(W, r1)), - add(terminalCircle.center, scale(W, r2))) - } - return segments -} \ No newline at end of file +//public fun tangentsToCircles( +// startCircle: Circle2D, +// terminalCircle: Circle2D +//): kotlin.collections.MutableMap> { +// val R1 = startCircle.radius +// val R2 = terminalCircle.radius +// val line = LineSegment(startCircle.center, terminalCircle.center) +// val d = line.begin.distanceTo(line.end) +// val angle1 = atan2(terminalCircle.center.x - startCircle.center.x, terminalCircle.center.y - startCircle.center.y) +// var r: Double +// var angle2: Double +// val routes = mapOf("RSR" to Pair(R1, R2), +// "RSL" to Pair(R1, -R2), +// "LSR" to Pair(-R1, R2), +// "LSL" to Pair(-R1, -R2)) +// val segments = mutableMapOf>() +// for ((route, r1r2) in routes) { +// val r1 = r1r2.first +// val r2 = r1r2.second +// r = if (r1.sign == r2.sign) { +// r1.absoluteValue - r2.absoluteValue +// } else { +// r1.absoluteValue + r2.absoluteValue +// } +// val L = (d * d - r * r).pow(0.5) +// angle2 = if (r1.absoluteValue > r2.absoluteValue) { +// angle1 + r1.sign * atan2(r.absoluteValue, L) +// } else { +// angle1 - r2.sign * atan2(r.absoluteValue, L) +// } +// val W = vector(-cos(angle2), sin(angle2)) +// segments[route] = LineSegment(add(startCircle.center, scale(W, r1)), +// add(terminalCircle.center, scale(W, r2))) +// } +// return segments +//} \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt index beac8d15f..fd3002e19 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.geometry import space.kscience.kmath.geometry.Euclidean2DSpace.vector import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertTrue class TangentTest { @Test @@ -15,25 +16,24 @@ class TangentTest { val c1 = Circle2D(vector(0.0, 0.0), 1.0) val c2 = Circle2D(vector(4.0, 0.0), 1.0) val routes = arrayListOf("RSR", "RSL", "LSR", "LSL") - val segments = arrayListOf( - Segment(startPoint = vector(0.0, 1.0), - terminalPoint = vector(4.0, 1.0)), - Segment(startPoint = vector(0.5, 0.8660254), - terminalPoint = vector(3.5, -0.8660254)), - Segment(startPoint = vector(0.5, -0.8660254), - terminalPoint = vector(3.5, 0.8660254)), - Segment(startPoint = vector(0.0, -1.0), - terminalPoint = vector(4.0, -1.0)) + val segments = arrayListOf>( + LineSegment(begin = vector(0.0, 1.0), + end = vector(4.0, 1.0)), + LineSegment(begin = vector(0.5, 0.8660254), + end = vector(3.5, -0.8660254)), + LineSegment(begin = vector(0.5, -0.8660254), + end = vector(3.5, 0.8660254)), + LineSegment(begin = vector(0.0, -1.0), + end = vector(4.0, -1.0)) ) - val tangentMap = tangentsToCircles(c1, c2) + val tangentMap = c1.tangentsToCircle(c2) val tangentMapKeys = tangentMap.keys.toList() val tangentMapValues = tangentMap.values.toList() assertEquals(routes, tangentMapKeys) for (i in segments.indices) { - assertEquals(segments[i], tangentMapValues[i]) + assertTrue(equalLineSegments(segments[i], tangentMapValues[i])) } -// assertEquals(segments, tangentMapValues) } } \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt index 89db22d45..c62af3cd3 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt @@ -44,3 +44,6 @@ fun GeometrySpace.isCollinear(a: V, b: V, absoluteTolerance: Dou fun GeometrySpace.isOrthogonal(a: V, b: V, absoluteTolerance: Double = 1e-6): Boolean = abs(a dot b) < absoluteTolerance + +fun Double.equalFloat(other: Double, maxFloatDelta: Double = 0.000001): + Boolean = kotlin.math.abs(this - other) < maxFloatDelta \ No newline at end of file From d535a2155f3171b538a2f6019dffad9ef83f2001 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Wed, 15 Feb 2023 15:06:47 +0300 Subject: [PATCH 15/58] tangentsToCircle fixed --- .../space/kscience/kmath/geometry/Circle2D.kt | 17 +++-- .../kmath/geometry/Euclidean2DSpace.kt | 7 ++ .../space/kscience/kmath/geometry/Line.kt | 6 -- .../space/kscience/kmath/geometry/Tangent.kt | 75 ------------------- .../kscience/kmath/geometry/TangentTest.kt | 8 +- 5 files changed, 25 insertions(+), 88 deletions(-) delete mode 100644 kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt index a26a592da..df25dcbea 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -18,7 +18,11 @@ public data class Circle2D( public val radius: Double ) -public fun Circle2D.tangentsToCircle(other: Circle2D): kotlin.collections.MutableMap> { +public enum class DubinsRoutes { + RSR, RSL, LSR, LSL +} + +public fun Circle2D.tangentsToCircle(other: Circle2D): Map> { val R1 = this.radius val R2 = other.radius val line = LineSegment(this.center, other.center) @@ -26,11 +30,12 @@ public fun Circle2D.tangentsToCircle(other: Circle2D): kotlin.collections.Mutabl val angle1 = atan2(other.center.x - this.center.x, other.center.y - this.center.y) var r: Double var angle2: Double - val routes = mapOf("RSR" to Pair(R1, R2), - "RSL" to Pair(R1, -R2), - "LSR" to Pair(-R1, R2), - "LSL" to Pair(-R1, -R2)) - val segments = mutableMapOf>() + val routes = mapOf( + DubinsRoutes.RSR to Pair(R1, R2), + DubinsRoutes.RSL to Pair(R1, -R2), + DubinsRoutes.LSR to Pair(-R1, R2), + DubinsRoutes.LSL to Pair(-R1, -R2)) + val segments = mutableMapOf>() for ((route, r1r2) in routes) { val r1 = r1r2.first val r2 = r1r2.second 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 3df8dba7b..dc05f6648 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 @@ -85,6 +85,13 @@ public object Euclidean2DSpace : GeometrySpace, override fun scale(a: DoubleVector2D, value: Double): DoubleVector2D = vector(a.x * value, a.y * value) override fun DoubleVector2D.dot(other: DoubleVector2D): Double = x * other.x + y * other.y + public fun equalLineSegments(line1: LineSegment, line2: LineSegment): Boolean { + val maxFloatDelta = 0.000001 + return line1.begin.x.equalFloat(line2.begin.x) && line1.begin.y.equalFloat(line2.begin.y) && + line1.end.x.equalFloat(line2.end.x) && line1.end.y.equalFloat(line2.end.y) + } + + public val xAxis: DoubleVector2D = vector(1.0, 0.0) public val yAxis: DoubleVector2D = vector(0.0, 1.0) } 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 bb03b5a93..6413edce9 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 @@ -27,12 +27,6 @@ public fun LineSegment.line(algebra: GeometrySpace): Line Line(begin, end - begin) } -public fun equalLineSegments(line1: LineSegment, line2: LineSegment): Boolean { - val maxFloatDelta = 0.000001 - return line1.begin.x.equalFloat(line2.begin.x) && line1.begin.y.equalFloat(line2.begin.y) && - line1.end.x.equalFloat(line2.end.x) && line1.end.y.equalFloat(line2.end.y) -// return line1.begin == line2.begin && line1.end == line2.end -} public fun Double.equalFloat(other: Double, maxFloatDelta: Double = 0.000001): Boolean = kotlin.math.abs(this - other) < maxFloatDelta diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt deleted file mode 100644 index cfcb78115..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Tangent.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import kotlin.math.absoluteValue -import kotlin.math.atan2 -import kotlin.math.pow -import kotlin.math.sign -import kotlin.math.sin -import kotlin.math.cos -import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import space.kscience.kmath.geometry.Euclidean2DSpace.scale -import space.kscience.kmath.geometry.Euclidean2DSpace.add -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo - - -//public class Segment( -// public val startPoint: DoubleVector2D, -// public val terminalPoint: DoubleVector2D, -// public val length: Double = startPoint.distanceTo(terminalPoint) -//) { -// public override operator fun equals(other: Any?): Boolean { -// return if (other is Segment) { -// startPoint.x.equalFloat(other.startPoint.x) && startPoint.y.equalFloat(other.startPoint.y) && -// terminalPoint.x.equalFloat(other.terminalPoint.x) && terminalPoint.y.equalFloat(other.terminalPoint.y) -// } else { -// false -// } -// } -//} - -//public const val maxFloatDelta: Double = 0.000001 -//public fun Double.equalFloat(other: Double): Boolean = kotlin.math.abs(this - other) < maxFloatDelta - - - -//public fun tangentsToCircles( -// startCircle: Circle2D, -// terminalCircle: Circle2D -//): kotlin.collections.MutableMap> { -// val R1 = startCircle.radius -// val R2 = terminalCircle.radius -// val line = LineSegment(startCircle.center, terminalCircle.center) -// val d = line.begin.distanceTo(line.end) -// val angle1 = atan2(terminalCircle.center.x - startCircle.center.x, terminalCircle.center.y - startCircle.center.y) -// var r: Double -// var angle2: Double -// val routes = mapOf("RSR" to Pair(R1, R2), -// "RSL" to Pair(R1, -R2), -// "LSR" to Pair(-R1, R2), -// "LSL" to Pair(-R1, -R2)) -// val segments = mutableMapOf>() -// for ((route, r1r2) in routes) { -// val r1 = r1r2.first -// val r2 = r1r2.second -// r = if (r1.sign == r2.sign) { -// r1.absoluteValue - r2.absoluteValue -// } else { -// r1.absoluteValue + r2.absoluteValue -// } -// val L = (d * d - r * r).pow(0.5) -// angle2 = if (r1.absoluteValue > r2.absoluteValue) { -// angle1 + r1.sign * atan2(r.absoluteValue, L) -// } else { -// angle1 - r2.sign * atan2(r.absoluteValue, L) -// } -// val W = vector(-cos(angle2), sin(angle2)) -// segments[route] = LineSegment(add(startCircle.center, scale(W, r1)), -// add(terminalCircle.center, scale(W, r2))) -// } -// return segments -//} \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt index fd3002e19..214495dfe 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.geometry +import space.kscience.kmath.geometry.Euclidean2DSpace.equalLineSegments import space.kscience.kmath.geometry.Euclidean2DSpace.vector import kotlin.test.Test import kotlin.test.assertEquals @@ -15,7 +16,12 @@ class TangentTest { fun tangent() { val c1 = Circle2D(vector(0.0, 0.0), 1.0) val c2 = Circle2D(vector(4.0, 0.0), 1.0) - val routes = arrayListOf("RSR", "RSL", "LSR", "LSL") + val routes = arrayListOf( + DubinsRoutes.RSR, + DubinsRoutes.RSL, + DubinsRoutes.LSR, + DubinsRoutes.LSL + ) val segments = arrayListOf>( LineSegment(begin = vector(0.0, 1.0), end = vector(4.0, 1.0)), From c342c5cd7835c92a7ccd26d07872b8018f7980f2 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Wed, 15 Feb 2023 17:53:32 +0300 Subject: [PATCH 16/58] tangentsToCircle fixed --- .../space/kscience/kmath/geometry/Circle2D.kt | 40 ---------- .../kscience/kmath/geometry/TangentTest.kt | 80 +++++++++---------- .../kscience/kmath/trajectory/Tangent.kt | 55 +++++++++++++ .../kmath/trajectory/segments/TangentTest.kt | 48 +++++++++++ 4 files changed, 143 insertions(+), 80 deletions(-) create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt create mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt index df25dcbea..d37ed45c0 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -18,45 +18,5 @@ public data class Circle2D( public val radius: Double ) -public enum class DubinsRoutes { - RSR, RSL, LSR, LSL -} - -public fun Circle2D.tangentsToCircle(other: Circle2D): Map> { - val R1 = this.radius - val R2 = other.radius - val line = LineSegment(this.center, other.center) - val d = line.begin.distanceTo(line.end) - val angle1 = atan2(other.center.x - this.center.x, other.center.y - this.center.y) - var r: Double - var angle2: Double - val routes = mapOf( - DubinsRoutes.RSR to Pair(R1, R2), - DubinsRoutes.RSL to Pair(R1, -R2), - DubinsRoutes.LSR to Pair(-R1, R2), - DubinsRoutes.LSL to Pair(-R1, -R2)) - val segments = mutableMapOf>() - for ((route, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - val L = (d * d - r * r).pow(0.5) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, L) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, L) - } - val W = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) - segments[route] = LineSegment( - Euclidean2DSpace.add(this.center, Euclidean2DSpace.scale(W, r1)), - Euclidean2DSpace.add(other.center, Euclidean2DSpace.scale(W, r2)) - ) - } - return segments -} public val Circle2D.circumference: Double get() = radius * 2 * PI diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt index 214495dfe..4ffd4dcab 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt @@ -3,43 +3,43 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.geometry - -import space.kscience.kmath.geometry.Euclidean2DSpace.equalLineSegments -import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class TangentTest { - @Test - fun tangent() { - val c1 = Circle2D(vector(0.0, 0.0), 1.0) - val c2 = Circle2D(vector(4.0, 0.0), 1.0) - val routes = arrayListOf( - DubinsRoutes.RSR, - DubinsRoutes.RSL, - DubinsRoutes.LSR, - DubinsRoutes.LSL - ) - val segments = arrayListOf>( - LineSegment(begin = vector(0.0, 1.0), - end = vector(4.0, 1.0)), - LineSegment(begin = vector(0.5, 0.8660254), - end = vector(3.5, -0.8660254)), - LineSegment(begin = vector(0.5, -0.8660254), - end = vector(3.5, 0.8660254)), - LineSegment(begin = vector(0.0, -1.0), - end = vector(4.0, -1.0)) - ) - - val tangentMap = c1.tangentsToCircle(c2) - val tangentMapKeys = tangentMap.keys.toList() - val tangentMapValues = tangentMap.values.toList() - - assertEquals(routes, tangentMapKeys) - for (i in segments.indices) { - assertTrue(equalLineSegments(segments[i], tangentMapValues[i])) - } - } -} \ No newline at end of file +//package space.kscience.kmath.geometry +// +//import space.kscience.kmath.geometry.Euclidean2DSpace.equalLineSegments +//import space.kscience.kmath.geometry.Euclidean2DSpace.vector +//import kotlin.test.Test +//import kotlin.test.assertEquals +//import kotlin.test.assertTrue +// +//class TangentTest { +// @Test +// fun tangent() { +// val c1 = Circle2D(vector(0.0, 0.0), 1.0) +// val c2 = Circle2D(vector(4.0, 0.0), 1.0) +// val routes = arrayListOf( +// DubinsRoutes.RSR, +// DubinsRoutes.RSL, +// DubinsRoutes.LSR, +// DubinsRoutes.LSL +// ) +// val segments = arrayListOf>( +// LineSegment(begin = vector(0.0, 1.0), +// end = vector(4.0, 1.0)), +// LineSegment(begin = vector(0.5, 0.8660254), +// end = vector(3.5, -0.8660254)), +// LineSegment(begin = vector(0.5, -0.8660254), +// end = vector(3.5, 0.8660254)), +// LineSegment(begin = vector(0.0, -1.0), +// end = vector(4.0, -1.0)) +// ) +// +// val tangentMap = c1.tangentsToCircle(c2) +// val tangentMapKeys = tangentMap.keys.toList() +// val tangentMapValues = tangentMap.values.toList() +// +// assertEquals(routes, tangentMapKeys) +// for (i in segments.indices) { +// assertTrue(equalLineSegments(segments[i], tangentMapValues[i])) +// } +// } +//} \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt new file mode 100644 index 000000000..9546a8d64 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.trajectory + +import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.DoubleVector2D +import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.LineSegment +import kotlin.math.* + +public enum class DubinsRoutes { + RSR, RSL, LSR, LSL +} + +public fun Circle2D.tangentsToCircle(other: Circle2D): Map> { + val R1 = this.radius + val R2 = other.radius + val line = LineSegment(this.center, other.center) + val d = line.begin.distanceTo(line.end) + val angle1 = atan2(other.center.x - this.center.x, other.center.y - this.center.y) + var r: Double + var angle2: Double + val routes = mapOf( + DubinsRoutes.RSR to Pair(R1, R2), + DubinsRoutes.RSL to Pair(R1, -R2), + DubinsRoutes.LSR to Pair(-R1, R2), + DubinsRoutes.LSL to Pair(-R1, -R2) + ) + val segments = mutableMapOf>() + for ((route, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + val L = (d * d - r * r).pow(0.5) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, L) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, L) + } + val W = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) + segments[route] = LineSegment( + Euclidean2DSpace.add(this.center, Euclidean2DSpace.scale(W, r1)), + Euclidean2DSpace.add(other.center, Euclidean2DSpace.scale(W, r2)) + ) + } + return segments +} \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt new file mode 100644 index 000000000..cfa2fa52b --- /dev/null +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.trajectory + +import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.DoubleVector2D +import space.kscience.kmath.geometry.Euclidean2DSpace.equalLineSegments +import space.kscience.kmath.geometry.Euclidean2DSpace.vector +import space.kscience.kmath.geometry.LineSegment +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class TangentTest { + @Test + fun tangent() { + val c1 = Circle2D(vector(0.0, 0.0), 1.0) + val c2 = Circle2D(vector(4.0, 0.0), 1.0) + val routes = arrayListOf( + DubinsRoutes.RSR, + DubinsRoutes.RSL, + DubinsRoutes.LSR, + DubinsRoutes.LSL + ) + val segments = arrayListOf>( + LineSegment(begin = vector(0.0, 1.0), + end = vector(4.0, 1.0)), + LineSegment(begin = vector(0.5, 0.8660254), + end = vector(3.5, -0.8660254)), + LineSegment(begin = vector(0.5, -0.8660254), + end = vector(3.5, 0.8660254)), + LineSegment(begin = vector(0.0, -1.0), + end = vector(4.0, -1.0)) + ) + + val tangentMap = c1.tangentsToCircle(c2) + val tangentMapKeys = tangentMap.keys.toList() + val tangentMapValues = tangentMap.values.toList() + + assertEquals(routes, tangentMapKeys) + for (i in segments.indices) { + assertTrue(equalLineSegments(segments[i], tangentMapValues[i])) + } + } +} \ No newline at end of file From 8998a394b34e6946f820d27521b40cd67ba3a33f Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Wed, 15 Feb 2023 17:55:39 +0300 Subject: [PATCH 17/58] tangentsToCircle fixed --- .../space/kscience/kmath/geometry/Line.kt | 1 - .../kscience/kmath/geometry/TangentTest.kt | 45 ------------------- 2 files changed, 46 deletions(-) delete mode 100644 kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt 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 6413edce9..adc3a8b85 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 @@ -27,7 +27,6 @@ public fun LineSegment.line(algebra: GeometrySpace): Line Line(begin, end - begin) } - public fun Double.equalFloat(other: Double, maxFloatDelta: Double = 0.000001): Boolean = kotlin.math.abs(this - other) < maxFloatDelta diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt deleted file mode 100644 index 4ffd4dcab..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -//package space.kscience.kmath.geometry -// -//import space.kscience.kmath.geometry.Euclidean2DSpace.equalLineSegments -//import space.kscience.kmath.geometry.Euclidean2DSpace.vector -//import kotlin.test.Test -//import kotlin.test.assertEquals -//import kotlin.test.assertTrue -// -//class TangentTest { -// @Test -// fun tangent() { -// val c1 = Circle2D(vector(0.0, 0.0), 1.0) -// val c2 = Circle2D(vector(4.0, 0.0), 1.0) -// val routes = arrayListOf( -// DubinsRoutes.RSR, -// DubinsRoutes.RSL, -// DubinsRoutes.LSR, -// DubinsRoutes.LSL -// ) -// val segments = arrayListOf>( -// LineSegment(begin = vector(0.0, 1.0), -// end = vector(4.0, 1.0)), -// LineSegment(begin = vector(0.5, 0.8660254), -// end = vector(3.5, -0.8660254)), -// LineSegment(begin = vector(0.5, -0.8660254), -// end = vector(3.5, 0.8660254)), -// LineSegment(begin = vector(0.0, -1.0), -// end = vector(4.0, -1.0)) -// ) -// -// val tangentMap = c1.tangentsToCircle(c2) -// val tangentMapKeys = tangentMap.keys.toList() -// val tangentMapValues = tangentMap.values.toList() -// -// assertEquals(routes, tangentMapKeys) -// for (i in segments.indices) { -// assertTrue(equalLineSegments(segments[i], tangentMapValues[i])) -// } -// } -//} \ No newline at end of file From 7d897ad8cb6758b57d9bc08d3ec7250caae944dc Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 16 Feb 2023 10:29:12 +0300 Subject: [PATCH 18/58] Cleanup after circle tangent changes --- .../kmath/geometry/Euclidean2DSpace.kt | 7 --- .../space/kscience/kmath/geometry/Line.kt | 3 - .../kscience/kmath/geometry/floatPrecision.kt | 38 +++++++++++++ .../kscience/kmath/trajectory/Tangent.kt | 55 ------------------ .../kscience/kmath/trajectory/tangent.kt | 53 ++++++++++++++++++ .../kscience/kmath/trajectory/TangentTest.kt | 56 +++++++++++++++++++ .../kmath/trajectory/segments/TangentTest.kt | 48 ---------------- 7 files changed, 147 insertions(+), 113 deletions(-) create mode 100644 kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt create mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt delete mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt 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 dc05f6648..3df8dba7b 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 @@ -85,13 +85,6 @@ public object Euclidean2DSpace : GeometrySpace, override fun scale(a: DoubleVector2D, value: Double): DoubleVector2D = vector(a.x * value, a.y * value) override fun DoubleVector2D.dot(other: DoubleVector2D): Double = x * other.x + y * other.y - public fun equalLineSegments(line1: LineSegment, line2: LineSegment): Boolean { - val maxFloatDelta = 0.000001 - return line1.begin.x.equalFloat(line2.begin.x) && line1.begin.y.equalFloat(line2.begin.y) && - line1.end.x.equalFloat(line2.end.x) && line1.end.y.equalFloat(line2.end.y) - } - - public val xAxis: DoubleVector2D = vector(1.0, 0.0) public val yAxis: DoubleVector2D = vector(0.0, 1.0) } 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 adc3a8b85..ab322ddca 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 @@ -27,8 +27,5 @@ public fun LineSegment.line(algebra: GeometrySpace): Line Line(begin, end - begin) } -public fun Double.equalFloat(other: Double, maxFloatDelta: Double = 0.000001): - Boolean = kotlin.math.abs(this - other) < maxFloatDelta - public typealias LineSegment2D = LineSegment public typealias LineSegment3D = LineSegment diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt new file mode 100644 index 000000000..023355a0f --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.geometry + +internal const val defaultPrecision = 1e-6 + +public fun Double.equalsFloat(other: Double, precision: Double = defaultPrecision): Boolean = + kotlin.math.abs(this - other) < precision + +public fun Double.equalsFloat(other: Float, precision: Double = defaultPrecision): Boolean = + kotlin.math.abs(this - other) < precision + +public fun V.equalsVector( + space: GeometrySpace, + other: V, + precision: Double = defaultPrecision, +): Boolean = with(space) { + norm(this@equalsVector - other) < precision +} + +public fun Float64Vector2D.equalsVector( + other: Float64Vector2D, + precision: Double = defaultPrecision, +): Boolean = equalsVector(Euclidean2DSpace, other, precision) + +public fun Float64Vector3D.equalsVector( + other: Float64Vector3D, + precision: Double = defaultPrecision, +): Boolean = equalsVector(Euclidean3DSpace, other, precision) + +public fun LineSegment.equalsLine( + space: GeometrySpace, + other: LineSegment, + precision: Double = defaultPrecision, +): Boolean = begin.equalsVector(space, other.begin, precision) && end.equalsVector(space, other.end, precision) \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt deleted file mode 100644 index 9546a8d64..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.trajectory - -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.DoubleVector2D -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.LineSegment -import kotlin.math.* - -public enum class DubinsRoutes { - RSR, RSL, LSR, LSL -} - -public fun Circle2D.tangentsToCircle(other: Circle2D): Map> { - val R1 = this.radius - val R2 = other.radius - val line = LineSegment(this.center, other.center) - val d = line.begin.distanceTo(line.end) - val angle1 = atan2(other.center.x - this.center.x, other.center.y - this.center.y) - var r: Double - var angle2: Double - val routes = mapOf( - DubinsRoutes.RSR to Pair(R1, R2), - DubinsRoutes.RSL to Pair(R1, -R2), - DubinsRoutes.LSR to Pair(-R1, R2), - DubinsRoutes.LSL to Pair(-R1, -R2) - ) - val segments = mutableMapOf>() - for ((route, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - val L = (d * d - r * r).pow(0.5) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, L) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, L) - } - val W = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) - segments[route] = LineSegment( - Euclidean2DSpace.add(this.center, Euclidean2DSpace.scale(W, r1)), - Euclidean2DSpace.add(other.center, Euclidean2DSpace.scale(W, r2)) - ) - } - return segments -} \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt new file mode 100644 index 000000000..70a1ac696 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.trajectory + +import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.DoubleVector2D +import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.LineSegment +import kotlin.math.* + +public fun Circle2D.tangentsToCircle( + other: Circle2D, +): Map> = with(Euclidean2DSpace) { + val line = LineSegment(center, other.center) + val d = line.begin.distanceTo(line.end) + val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) + var r: Double + var angle2: Double + val routes = mapOf( + DubinsPath.Type.RSR to Pair(radius, other.radius), + DubinsPath.Type.RSL to Pair(radius, -other.radius), + DubinsPath.Type.LSR to Pair(-radius, other.radius), + DubinsPath.Type.LSL to Pair(-radius, -other.radius) + ) + return buildMap { + for ((route, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + val l = (d * d - r * r).pow(0.5) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = vector(-cos(angle2), sin(angle2)) + put( + route, + LineSegment( + center + w * r1, + other.center + w * r2 + ) + ) + } + } +} \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt new file mode 100644 index 000000000..c1cf2f800 --- /dev/null +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.trajectory + +import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.Euclidean2DSpace.vector +import space.kscience.kmath.geometry.LineSegment +import space.kscience.kmath.geometry.equalsLine +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class TangentTest { + @Test + fun tangent() { + val c1 = Circle2D(vector(0.0, 0.0), 1.0) + val c2 = Circle2D(vector(4.0, 0.0), 1.0) + val routes = listOf( + DubinsPath.Type.RSR, + DubinsPath.Type.RSL, + DubinsPath.Type.LSR, + DubinsPath.Type.LSL + ) + val segments = listOf( + LineSegment( + begin = vector(0.0, 1.0), + end = vector(4.0, 1.0) + ), + LineSegment( + begin = vector(0.5, 0.8660254), + end = vector(3.5, -0.8660254) + ), + LineSegment( + begin = vector(0.5, -0.8660254), + end = vector(3.5, 0.8660254) + ), + LineSegment( + begin = vector(0.0, -1.0), + end = vector(4.0, -1.0) + ) + ) + + val tangentMap = c1.tangentsToCircle(c2) + val tangentMapKeys = tangentMap.keys.toList() + val tangentMapValues = tangentMap.values.toList() + + assertEquals(routes, tangentMapKeys) + for (i in segments.indices) { + assertTrue(segments[i].equalsLine(Euclidean2DSpace, tangentMapValues[i])) + } + } +} \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt deleted file mode 100644 index cfa2fa52b..000000000 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.trajectory - -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.DoubleVector2D -import space.kscience.kmath.geometry.Euclidean2DSpace.equalLineSegments -import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import space.kscience.kmath.geometry.LineSegment -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class TangentTest { - @Test - fun tangent() { - val c1 = Circle2D(vector(0.0, 0.0), 1.0) - val c2 = Circle2D(vector(4.0, 0.0), 1.0) - val routes = arrayListOf( - DubinsRoutes.RSR, - DubinsRoutes.RSL, - DubinsRoutes.LSR, - DubinsRoutes.LSL - ) - val segments = arrayListOf>( - LineSegment(begin = vector(0.0, 1.0), - end = vector(4.0, 1.0)), - LineSegment(begin = vector(0.5, 0.8660254), - end = vector(3.5, -0.8660254)), - LineSegment(begin = vector(0.5, -0.8660254), - end = vector(3.5, 0.8660254)), - LineSegment(begin = vector(0.0, -1.0), - end = vector(4.0, -1.0)) - ) - - val tangentMap = c1.tangentsToCircle(c2) - val tangentMapKeys = tangentMap.keys.toList() - val tangentMapValues = tangentMap.values.toList() - - assertEquals(routes, tangentMapKeys) - for (i in segments.indices) { - assertTrue(equalLineSegments(segments[i], tangentMapValues[i])) - } - } -} \ No newline at end of file From 67316c4a70cee2814ef2e65dece45077bef7c894 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 16 Feb 2023 10:39:25 +0300 Subject: [PATCH 19/58] Add documentation after circle tangent changes --- .../kscience/kmath/geometry/GeometrySpace.kt | 7 ++++ .../kscience/kmath/geometry/floatPrecision.kt | 32 +++++++++++++++---- .../kscience/kmath/trajectory/tangent.kt | 4 +++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt index 854d84b65..d6d7e5725 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt @@ -21,4 +21,11 @@ public interface GeometrySpace : Group, ScaleOperations, Norm< * Scalar product */ public infix fun V.dot(other: V): Double + + public companion object{ + /** + * Default precision for geometry objects comparison + */ + internal const val DEFAULT_PRECISION = 1e-6 + } } \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt index 023355a0f..ea46ab90f 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt @@ -5,34 +5,52 @@ package space.kscience.kmath.geometry -internal const val defaultPrecision = 1e-6 +import space.kscience.kmath.geometry.GeometrySpace.Companion.DEFAULT_PRECISION -public fun Double.equalsFloat(other: Double, precision: Double = defaultPrecision): Boolean = +/** + * Float equality within given [precision] + */ +public fun Double.equalsFloat(other: Double, precision: Double = DEFAULT_PRECISION): Boolean = kotlin.math.abs(this - other) < precision -public fun Double.equalsFloat(other: Float, precision: Double = defaultPrecision): Boolean = +/** + * Float equality within given [precision] + */ +public fun Double.equalsFloat(other: Float, precision: Double = DEFAULT_PRECISION): Boolean = kotlin.math.abs(this - other) < precision +/** + * Vector equality within given [precision] (using [GeometrySpace.norm] provided by the space + */ public fun V.equalsVector( space: GeometrySpace, other: V, - precision: Double = defaultPrecision, + precision: Double = DEFAULT_PRECISION, ): Boolean = with(space) { norm(this@equalsVector - other) < precision } +/** + * Vector equality using Euclidian L2 norm and given [precision] + */ public fun Float64Vector2D.equalsVector( other: Float64Vector2D, - precision: Double = defaultPrecision, + precision: Double = DEFAULT_PRECISION, ): Boolean = equalsVector(Euclidean2DSpace, other, precision) +/** + * Vector equality using Euclidian L2 norm and given [precision] + */ public fun Float64Vector3D.equalsVector( other: Float64Vector3D, - precision: Double = defaultPrecision, + precision: Double = DEFAULT_PRECISION, ): Boolean = equalsVector(Euclidean3DSpace, other, precision) +/** + * Line equality using [GeometrySpace.norm] provided by the [space] and given [precision] + */ public fun LineSegment.equalsLine( space: GeometrySpace, other: LineSegment, - precision: Double = defaultPrecision, + precision: Double = DEFAULT_PRECISION, ): Boolean = begin.equalsVector(space, other.begin, precision) && end.equalsVector(space, other.end, precision) \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt index 70a1ac696..cf5bcd11d 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt @@ -11,6 +11,10 @@ import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.LineSegment import kotlin.math.* +/** + * Create inner and outer tangents between two circles. + * This method returns a map of segments using [DubinsPath] connection type notation. + */ public fun Circle2D.tangentsToCircle( other: Circle2D, ): Map> = with(Euclidean2DSpace) { From ed4aa47913c2cc982e9a325e3635774d00d01dec Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 16 Feb 2023 10:57:24 +0300 Subject: [PATCH 20/58] Minor refactoring of tangents --- .../space/kscience/kmath/trajectory/Trajectory2D.kt | 4 +--- .../space/kscience/kmath/trajectory/TangentTest.kt | 2 +- .../kscience/kmath/trajectory/dubins/DubinsTests.kt | 3 ++- .../kotlin/space/kscience/kmath/trajectory/math.kt | 10 +++------- .../kscience/kmath/trajectory/segments/ArcTests.kt | 7 ++++++- .../kscience/kmath/trajectory/segments/CircleTests.kt | 3 +-- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt index 7e0a8c1c0..e5f60e025 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt @@ -100,9 +100,7 @@ public data class CircleTrajectory2D( val pose1 = calculatePose(start, s1.bearing, direction) val pose2 = calculatePose(end, s2.bearing, direction) val trajectory = CircleTrajectory2D(Circle2D(center, s1.length), pose1, pose2) - if (trajectory.direction != direction) { - error("Trajectory direction mismatch") - } + if (trajectory.direction != direction) error("Trajectory direction mismatch") return trajectory } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt index c1cf2f800..42442a55f 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt @@ -16,7 +16,7 @@ import kotlin.test.assertTrue class TangentTest { @Test - fun tangent() { + fun tangents() { val c1 = Circle2D(vector(0.0, 0.0), 1.0) val c2 = Circle2D(vector(4.0, 0.0), 1.0) val routes = listOf( diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 0e14ae736..481ea4786 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.trajectory.dubins import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.equalsFloat import space.kscience.kmath.trajectory.* import kotlin.test.Test import kotlin.test.assertNotNull @@ -39,7 +40,7 @@ class DubinsTests { val path = dubins.find { p -> DubinsPath.trajectoryTypeOf(p) === it.key } assertNotNull(path, "Path ${it.key} not found") println("${it.key}: ${path.length}") - assertTrue(it.value.equalFloat(path.length)) + assertTrue(it.value.equalsFloat(path.length)) val a = path.segments[0] as CircleTrajectory2D val b = path.segments[1] diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt index c69ad24f1..24685f528 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt @@ -6,20 +6,16 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.equalsFloat import space.kscience.kmath.geometry.radians import space.kscience.kmath.geometry.sin -import kotlin.math.PI -import kotlin.math.abs -const val maxFloatDelta = 0.000001 -fun Double.radiansToDegrees() = this * 180 / PI - -fun Double.equalFloat(other: Double) = abs(this - other) < maxFloatDelta fun DubinsPose2D.equalsFloat(other: DubinsPose2D) = - x.equalFloat(other.x) && y.equalFloat(other.y) && bearing.radians.equalFloat(other.bearing.radians) + x.equalsFloat(other.x) && y.equalsFloat(other.y) && bearing.radians.equalsFloat(other.bearing.radians) fun StraightTrajectory2D.inverse() = StraightTrajectory2D(end, start) + fun StraightTrajectory2D.shift(shift: Int, width: Double): StraightTrajectory2D = with(Euclidean2DSpace) { val dX = width * sin(inverse().bearing) val dY = width * sin(bearing) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index 643f9eaaa..7594aa046 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -18,7 +18,12 @@ class ArcTests { @Test fun arcTest() = with(Euclidean2DSpace){ val circle = Circle2D(vector(0.0, 0.0), 2.0) - val arc = CircleTrajectory2D.of(circle.center, vector(-2.0, 0.0), vector(0.0, 2.0), CircleTrajectory2D.Direction.RIGHT) + val arc = CircleTrajectory2D.of( + circle.center, + vector(-2.0, 0.0), + vector(0.0, 2.0), + CircleTrajectory2D.Direction.RIGHT + ) assertEquals(circle.circumference / 4, arc.length, 1.0) assertEquals(0.0, arc.start.bearing.degrees) assertEquals(90.0, arc.end.bearing.degrees) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt index 5321fb1a1..27434b874 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt @@ -8,7 +8,6 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.circumference -import space.kscience.kmath.trajectory.maxFloatDelta import kotlin.test.Test import kotlin.test.assertEquals @@ -20,6 +19,6 @@ class CircleTests { val radius = 2.0 val expectedCircumference = 12.56637 val circle = Circle2D(center, radius) - assertEquals(expectedCircumference, circle.circumference, maxFloatDelta) + assertEquals(expectedCircumference, circle.circumference) } } From cc0fb2a718a3981332328b75ce2a86b4610b161d Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Thu, 16 Feb 2023 18:47:42 +0300 Subject: [PATCH 21/58] non-existence of tangents throws exception --- .../kscience/kmath/trajectory/tangent.kt | 31 +++++++++++-------- .../kscience/kmath/trajectory/TangentTest.kt | 25 +++++++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt index cf5bcd11d..945b140c2 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt @@ -38,20 +38,25 @@ public fun Circle2D.tangentsToCircle( } else { r1.absoluteValue + r2.absoluteValue } - val l = (d * d - r * r).pow(0.5) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, l) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, l) - } - val w = vector(-cos(angle2), sin(angle2)) - put( - route, - LineSegment( - center + w * r1, - other.center + w * r2 + if (d * d > r * r) { + val l = (d * d - r * r).pow(0.5) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = vector(-cos(angle2), sin(angle2)) + put( + route, + LineSegment( + center + w * r1, + other.center + w * r2 + ) ) - ) + } + else { + throw Exception("Circles should not be") + } } } } \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt index 42442a55f..3e87b47de 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt @@ -13,6 +13,7 @@ import space.kscience.kmath.geometry.equalsLine import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue +import kotlin.test.assertFailsWith class TangentTest { @Test @@ -53,4 +54,28 @@ class TangentTest { assertTrue(segments[i].equalsLine(Euclidean2DSpace, tangentMapValues[i])) } } + + @Test + fun nonExistingTangents() { + assertFailsWith { + val c1 = Circle2D(vector(0.0, 0.0), 10.0) + val c2 = Circle2D(vector(0.0, 0.0), 1.0) + val segments = c1.tangentsToCircle(c2) + } + assertFailsWith { + val c1 = Circle2D(vector(0.0, 0.0), 1.0) + val c2 = Circle2D(vector(0.0, 0.0), 10.0) + val segments = c1.tangentsToCircle(c2) + } + assertFailsWith { + val c1 = Circle2D(vector(0.0, 0.0), 1.0) + val c2 = Circle2D(vector(2.0, 0.0), 1.0) + val segments = c1.tangentsToCircle(c2) + } + assertFailsWith { + val c1 = Circle2D(vector(0.0, 0.0), 1.0) + val c2 = Circle2D(vector(0.5, 0.0), 1.0) + val segments = c1.tangentsToCircle(c2) + } + } } \ No newline at end of file From 04127fc3f2b781a2e66b95b8b2d63629dca15220 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 18 Feb 2023 18:53:03 +0300 Subject: [PATCH 22/58] Fix tests --- gradle.properties | 2 +- .../kscience/kmath/trajectory/tangent.kt | 48 +++++++++---------- .../kscience/kmath/trajectory/TangentTest.kt | 40 +++++++--------- .../kmath/trajectory/segments/CircleTests.kt | 2 +- 4 files changed, 43 insertions(+), 49 deletions(-) diff --git a/gradle.properties b/gradle.properties index 16cdd3551..cc44b5b02 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin.native.ignoreDisabledTargets=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.14.0-kotlin-1.8.10 +toolsVersion=0.14.1-kotlin-1.8.10 org.gradle.parallel=true diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt index 945b140c2..d3165e162 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt @@ -5,10 +5,7 @@ package space.kscience.kmath.trajectory -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.DoubleVector2D -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.LineSegment +import space.kscience.kmath.geometry.* import kotlin.math.* /** @@ -18,10 +15,14 @@ import kotlin.math.* public fun Circle2D.tangentsToCircle( other: Circle2D, ): Map> = with(Euclidean2DSpace) { + //return empty map for concentric circles + if(center.equalsVector(other.center)) return@tangentsToCircle emptyMap() + + // A line connecting centers val line = LineSegment(center, other.center) - val d = line.begin.distanceTo(line.end) + // Distance between centers + val distance = line.begin.distanceTo(line.end) val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) - var r: Double var angle2: Double val routes = mapOf( DubinsPath.Type.RSR to Pair(radius, other.radius), @@ -33,30 +34,27 @@ public fun Circle2D.tangentsToCircle( for ((route, r1r2) in routes) { val r1 = r1r2.first val r2 = r1r2.second - r = if (r1.sign == r2.sign) { + val r = if (r1.sign == r2.sign) { r1.absoluteValue - r2.absoluteValue } else { r1.absoluteValue + r2.absoluteValue } - if (d * d > r * r) { - val l = (d * d - r * r).pow(0.5) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, l) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, l) - } - val w = vector(-cos(angle2), sin(angle2)) - put( - route, - LineSegment( - center + w * r1, - other.center + w * r2 - ) + if (distance <= r) TODO("Intersecting circles are not supported yet") + val l = sqrt(distance * distance - r * r) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = vector(-cos(angle2), sin(angle2)) + put( + route, + LineSegment( + center + w * r1, + other.center + w * r2 ) - } - else { - throw Exception("Circles should not be") - } + ) + } } } \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt index 3e87b47de..6d4493124 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt @@ -13,7 +13,6 @@ import space.kscience.kmath.geometry.equalsLine import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -import kotlin.test.assertFailsWith class TangentTest { @Test @@ -56,26 +55,23 @@ class TangentTest { } @Test - fun nonExistingTangents() { - assertFailsWith { - val c1 = Circle2D(vector(0.0, 0.0), 10.0) - val c2 = Circle2D(vector(0.0, 0.0), 1.0) - val segments = c1.tangentsToCircle(c2) - } - assertFailsWith { - val c1 = Circle2D(vector(0.0, 0.0), 1.0) - val c2 = Circle2D(vector(0.0, 0.0), 10.0) - val segments = c1.tangentsToCircle(c2) - } - assertFailsWith { - val c1 = Circle2D(vector(0.0, 0.0), 1.0) - val c2 = Circle2D(vector(2.0, 0.0), 1.0) - val segments = c1.tangentsToCircle(c2) - } - assertFailsWith { - val c1 = Circle2D(vector(0.0, 0.0), 1.0) - val c2 = Circle2D(vector(0.5, 0.0), 1.0) - val segments = c1.tangentsToCircle(c2) - } + fun concentric(){ + val c1 = Circle2D(vector(0.0, 0.0), 10.0) + val c2 = Circle2D(vector(0.0, 0.0), 1.0) + assertEquals(emptyMap(), c1.tangentsToCircle(c2)) } +// +// @Test +// fun nonExistingTangents() { +// assertFailsWith { +// val c1 = Circle2D(vector(0.0, 0.0), 1.0) +// val c2 = Circle2D(vector(2.0, 0.0), 1.0) +// c1.tangentsToCircle(c2) +// } +// assertFailsWith { +// val c1 = Circle2D(vector(0.0, 0.0), 1.0) +// val c2 = Circle2D(vector(0.5, 0.0), 1.0) +// c1.tangentsToCircle(c2) +// } +// } } \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt index 27434b874..c3fca06ec 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt @@ -19,6 +19,6 @@ class CircleTests { val radius = 2.0 val expectedCircumference = 12.56637 val circle = Circle2D(center, radius) - assertEquals(expectedCircumference, circle.circumference) + assertEquals(expectedCircumference, circle.circumference, 1e-4) } } From db61f7144089056ae184fd1b28c1dd0db2c5fd6f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 18 Feb 2023 19:04:07 +0300 Subject: [PATCH 23/58] update build tools --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index cc44b5b02..c3f070c2d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin.native.ignoreDisabledTargets=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.14.1-kotlin-1.8.10 +toolsVersion=0.14.2-kotlin-1.8.10 org.gradle.parallel=true From 2c13386646a6f3f38523e9546eccf38343251163 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Wed, 1 Mar 2023 10:40:54 +0300 Subject: [PATCH 24/58] search for shortest path algorithm --- .../space/kscience/kmath/geometry/Line.kt | 1 + .../kmath/trajectory/DubinsObstacle.kt | 413 ++++++++++++++++++ .../kscience/kmath/trajectory/DubinsPath.kt | 110 +++++ .../kscience/kmath/trajectory/tangent.kt | 66 ++- 4 files changed, 583 insertions(+), 7 deletions(-) create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt 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 ab322ddca..e593150f1 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 @@ -6,6 +6,7 @@ package space.kscience.kmath.geometry import kotlinx.serialization.Serializable +import space.kscience.kmath.operations.DoubleField.pow /** * A line formed by [base] vector of start and a [direction] vector. Direction vector is not necessarily normalized, diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt new file mode 100644 index 000000000..56aa88e4a --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt @@ -0,0 +1,413 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.trajectory + +import space.kscience.kmath.geometry.* +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.Euclidean2DSpace.minus +import space.kscience.kmath.geometry.Euclidean2DSpace.plus +import space.kscience.kmath.geometry.Euclidean2DSpace.times +import space.kscience.kmath.geometry.Euclidean2DSpace.vector +import space.kscience.kmath.geometry.Euclidean2DSpace.norm +import space.kscience.kmath.operations.DoubleField.pow +import kotlin.math.* + +public fun LineSegment2D.length(): Double { + return ((end.y - begin.y).pow(2.0) + (end.x - begin.x).pow(2.0)).pow(0.5) +} +public class DubinsObstacle( + public val circles: List +) { + public val tangents: List = boundaryTangents().first + public val boundaryRoute: DubinsPath.Type = boundaryTangents().second + public val center: Vector2D = + vector(this.circles.sumOf{it.center.x} / this.circles.size, + this.circles.sumOf{it.center.y} / this.circles.size) + private fun boundaryTangents(): Pair, DubinsPath.Type> { + // outer tangents for a polygon circles can be either lsl or rsr + + fun Circle2D.dubinsTangentsToCircles( + other: Circle2D, + ): Map = with(Euclidean2DSpace) { + val line = LineSegment(center, other.center) + val d = line.begin.distanceTo(line.end) + val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) + var r: Double + var angle2: Double + val routes = mapOf( + DubinsPath.Type.RSR to Pair(radius, other.radius), + DubinsPath.Type.RSL to Pair(radius, -other.radius), + DubinsPath.Type.LSR to Pair(-radius, other.radius), + DubinsPath.Type.LSL to Pair(-radius, -other.radius) + ) + return buildMap { + for ((route, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + if (d * d > r * r) { + val l = (d * d - r * r).pow(0.5) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = vector(-cos(angle2), sin(angle2)) + put(route, DubinsTangent(Circle2D(center, radius), + other, + this@DubinsObstacle, + this@DubinsObstacle, + LineSegment2D( + center + w * r1, + other.center + w * r2 + ), + DubinsPath.toSimpleTypes(route)) + ) + } else { + throw Exception("Circles should not intersect") + } + } + } + } + val firstCircles = this.circles.slice(-this.circles.size..-1) + val secondCircles = this.circles.slice(-this.circles.size+1..0) + val lslTangents = firstCircles.zip(secondCircles) + {a, b -> a.dubinsTangentsToCircles(b)[DubinsPath.Type.LSL]!!} + val rsrTangents = firstCircles.zip(secondCircles) + {a, b -> a.dubinsTangentsToCircles(b)[DubinsPath.Type.RSR]!!} + val center = vector( + this.circles.sumOf { it.center.x } / this.circles.size, + this.circles.sumOf { it.center.y } / this.circles.size + ) + val lslToCenter = lslTangents.sumOf { it.lineSegment.begin.distanceTo(center) } + + lslTangents.sumOf { it.lineSegment.end.distanceTo(center) } + val rsrToCenter = rsrTangents.sumOf { it.lineSegment.begin.distanceTo(center) } + + rsrTangents.sumOf { it.lineSegment.end.distanceTo(center) } + return if (rsrToCenter >= lslToCenter) { + Pair(rsrTangents, DubinsPath.Type.RSR) + } else { + Pair(lslTangents, DubinsPath.Type.LSL) + } + } + + public fun nextTangent(circle: Circle2D, route: DubinsPath.Type): DubinsTangent { + if (route == this.boundaryRoute) { + for (i in this.circles.indices) { + if (this.circles[i] == circle) { + return this.tangents[i] + } + } + } + else { + for (i in this.circles.indices) { + if (this.circles[i] == circle) { + return DubinsTangent(this.circles[i], + this.circles[i-1], + this, + this, + LineSegment2D(this.tangents[i-1].lineSegment.end, + this.tangents[i-1].lineSegment.begin), + DubinsPath.toSimpleTypes(route)) + } + } + } + + error("next tangent not found") + } + + public fun equals(other: DubinsObstacle): Boolean { + return this.circles == other.circles + } +} + +public data class DubinsTangent(val startCircle: Circle2D, + val endCircle: Circle2D, + val startObstacle: DubinsObstacle, + val endObstacle: DubinsObstacle, + val lineSegment: LineSegment2D, + val route: PathTypes) + +public fun LineSegment2D.intersectSegment(other: LineSegment2D): Boolean { + fun crossProduct(v1: DoubleVector2D, v2: DoubleVector2D): Double { + return v1.x * v2.y - v1.y * v2.x + } + if (crossProduct(other.begin - this.begin, other.end - this.begin).sign == + crossProduct(other.begin - this.end, other.end - this.end).sign) { + return false + } + if (crossProduct(this.begin - other.begin, this.end - other.begin).sign == + crossProduct(this.begin - other.end, this.end - other.end).sign) { + return false + } + return true +} + +public fun LineSegment2D.intersectCircle(circle: Circle2D): Boolean { + val a = (this.begin.x - this.end.x).pow(2.0) + (this.begin.y - this.end.y).pow(2.0) + val b = 2 * ((this.begin.x - this.end.x) * (this.end.x - circle.center.x) + + (this.begin.y - this.end.y) * (this.end.y - circle.center.y)) + val c = (this.end.x - circle.center.x).pow(2.0) + (this.end.y - circle.center.y) - + circle.radius.pow(2.0) + val d = b.pow(2.0) - 4 * a * c + if (d < 1e-6) { + return false + } + else { + val t1 = (-b - d.pow(0.5)) * 0.5 / a + val t2 = (-b + d.pow(0.5)) * 0.5 / a + if (((0 < t1) and (t1 < 1)) or ((0 < t2) and (t2 < 1))) { + return true + } + } + return false +} + +public fun DubinsTangent.intersectObstacle(obstacle: DubinsObstacle): Boolean { + for (tangent in obstacle.tangents) { + if (this.lineSegment.intersectSegment(tangent.lineSegment)) { + return true + } + } + for (circle in obstacle.circles) { + if (this.lineSegment.intersectCircle(circle)) { + return true + } + } + return false +} + +public fun outerTangents(first: DubinsObstacle, second: DubinsObstacle): MutableMap { + return buildMap { + for (circle1 in first.circles) { + for (circle2 in second.circles) { + for (tangent in dubinsTangentsToCircles(circle1, circle2, first, second)) { + if (!(tangent.value.intersectObstacle(first)) + and !(tangent.value.intersectObstacle(second))) { + put( + tangent.key, + tangent.value + ) + } + } + } + } + }.toMutableMap() +} + +public fun arcLength(circle: Circle2D, + point1: DoubleVector2D, + point2: DoubleVector2D, + route: DubinsPath.SimpleType): Double { + val phi1 = atan2(point1.y - circle.center.y, point1.x - circle.center.x) + val phi2 = atan2(point2.y - circle.center.y, point2.x - circle.center.x) + var angle = 0.0 + when (route) { + DubinsPath.SimpleType.L -> { + angle = if (phi2 >= phi1) { + phi2 - phi1 + } else { + 2 * PI + phi2 - phi1 + } + } + DubinsPath.SimpleType.R -> { + angle = if (phi2 >= phi1) { + 2 * PI - (phi2 - phi1) + } else { + -(phi2 - phi1) + } + } + DubinsPath.SimpleType.S -> { + error("L or R route is expected") + } + } + return circle.radius * angle +} + +public fun normalVectors(v: DoubleVector2D, r: Double): Pair { + return Pair( + r * vector(v.y / norm(v), -v.x / norm(v)), + r * vector(-v.y / norm(v), v.x / norm(v)) + ) +} + +public fun constructTangentCircles(point: DoubleVector2D, + direction: DoubleVector2D, + r: Double): Map { + val center1 = point + normalVectors(direction, r).first + val center2 = point + normalVectors(direction, r).second + val p1 = center1 - point + val p2 = center2 - point + return if (atan2(p1.y, p1.x) - atan2(p2.y, p2.x) in listOf(PI/2, -3*PI/2)) { + mapOf(DubinsPath.SimpleType.L to Circle2D(center1, r), + DubinsPath.SimpleType.R to Circle2D(center2, r)) + } + else { + mapOf(DubinsPath.SimpleType.L to Circle2D(center2, r), + DubinsPath.SimpleType.R to Circle2D(center1, r)) + } +} + +public fun sortedObstacles(currentObstacle: DubinsObstacle, + obstacles: List): List { + return obstacles.sortedBy {norm(it.center - currentObstacle.center)}.reversed() +} + +public fun tangentsAlongTheObstacle(initialCircle: Circle2D, + initialRoute: DubinsPath.Type, + finalCircle: Circle2D, + obstacle: DubinsObstacle): MutableList { + val dubinsTangents = mutableListOf() + var tangent = obstacle.nextTangent(initialCircle, initialRoute) + dubinsTangents.add(tangent) + while (tangent.endCircle != finalCircle) { + tangent = obstacle.nextTangent(tangent.endCircle, initialRoute) + dubinsTangents.add(tangent) + } + return dubinsTangents +} + +public fun allFinished(paths: List>, + finalObstacle: DubinsObstacle): Boolean { + for (path in paths) { + if (path[-1].endObstacle != finalObstacle) { + return false + } + } + return true +} + +public fun pathLength(path: List): Double { + val tangentsLength = path.sumOf{norm(it.lineSegment.end - it.lineSegment.begin)} + val arcsLength = buildList{ + for (i in 1..path.size) { + add(arcLength(path[i].startCircle, + path[i-1].lineSegment.end, + path[i].lineSegment.begin, + path[i].route[0])) + } + }.sum() + return tangentsLength + arcsLength +} + +public fun shortestPath(path: List>): List> { + return path.sortedBy { pathLength(it) } +} + +public typealias Path = List +public fun findAllPaths( + startingPoint: DoubleVector2D, + startingDirection: DoubleVector2D, + startingRadius: Double, + finalPoint: DoubleVector2D, + finalDirection: DoubleVector2D, + finalRadius: Double, + obstacles: List +) { + val initialCircles = constructTangentCircles( + startingPoint, + startingDirection, + startingRadius) + val finalCircles = constructTangentCircles( + finalPoint, + finalDirection, + finalRadius) + var outputTangents = mutableMapOf>() + for (i in listOf(DubinsPath.SimpleType.L, DubinsPath.SimpleType.R)) { + for (j in listOf(DubinsPath.SimpleType.L, DubinsPath.SimpleType.R)) { + val finalCircle = finalCircles[j]!! + val finalObstacle = DubinsObstacle(listOf(finalCircle)) + outputTangents[listOf(i, + DubinsPath.SimpleType.S, + j)] = listOf( + listOf(DubinsTangent( + initialCircles[i]!!, + initialCircles[i]!!, + DubinsObstacle(listOf(initialCircles[i]!!)), + DubinsObstacle(listOf(initialCircles[i]!!)), + LineSegment2D(startingPoint, startingPoint), + listOf(i, DubinsPath.SimpleType.S, i) + ))) + var currentObstacle = DubinsObstacle(listOf(initialCircles[i]!!)) + while (!allFinished(outputTangents[listOf(i, + DubinsPath.SimpleType.S, + j)]!!, finalObstacle)) { + var newOutputTangents = listOf() + for (line in outputTangents[listOf(i, + DubinsPath.SimpleType.S, + j)]!!) { + var currentCircle = line[-1].endCircle + var currentDirection = line[-1].route[-1] + var currentObstacle = line[-1].endObstacle + var nextObstacle = DubinsObstacle(listOf()) + if (currentObstacle != finalObstacle) { + var tangentToFinal = outerTangents(currentObstacle, finalObstacle)[DubinsPath.toType(listOf( + currentDirection, + DubinsPath.SimpleType.S, + j) + )] + for (obstacle in sortedObstacles(currentObstacle, obstacles)) { + if (tangentToFinal!!.intersectObstacle(obstacle)) { + nextObstacle = obstacle + break + } + } + if (nextObstacle == DubinsObstacle(listOf())) { + nextObstacle = finalObstacle + } + var nextTangents = outerTangents(currentObstacle, nextObstacle) +// for (pathType in listOf( +// listOf(DubinsPath.SimpleType.L, +// DubinsPath.SimpleType.S, +// DubinsPath.SimpleType.L), +// listOf(DubinsPath.SimpleType.L, +// DubinsPath.SimpleType.S, +// DubinsPath.SimpleType.R), +// listOf(DubinsPath.SimpleType.R, +// DubinsPath.SimpleType.S, +// DubinsPath.SimpleType.L), +// listOf(DubinsPath.SimpleType.R, +// DubinsPath.SimpleType.S, +// DubinsPath.SimpleType.R) +// )) { + for (pathType in nextTangents.keys) { + for (obstacle in obstacles) { + // in Python code here try/except was used, but seems unneeded + if (nextTangents[pathType]!!.intersectObstacle(obstacle)) { + nextTangents.remove(pathType) + } + + } + } + if (nextObstacle == finalObstacle) { + nextTangents = + nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection) and + (DubinsPath.toSimpleTypes(it.key)[0] == j)} + as MutableMap + } + else { + nextTangents = + nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection)} + as MutableMap + } + TODO("rewrite fragment from Python") + } + } + } + } + } +} + + + + + + + + diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index 568ef691a..5654d10ae 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -77,10 +77,118 @@ private fun innerTangent( @Suppress("DuplicatedCode") public object DubinsPath { +// public class ArcType(private val type: Type){ +// public val first: SimpleType +// get() { +// if (this.type in listOf(Type.RSR, Type.RSL, Type.RLR)) { +// return SimpleType.R +// } +// else if (type in listOf(Type.LSL, Type.LSR, Type.LRL)) { +// return SimpleType.L +// } +// error("Wrong DubinsPath.Type") +// } +// +// public val last: SimpleType +// get() { +// if (type in listOf(Type.RSR, Type.LSR, Type.RLR)) { +// return SimpleType.R +// } +// else if (type in listOf(Type.LSL, Type.RSL, Type.LRL)) { +// return SimpleType.L +// } +// error("Wrong DubinsPath.Type") +// } +// public val intermediate: SimpleType +// get() { +// if (type == Type.RLR) { +// return SimpleType.L +// } +// else if (type == Type.LRL) { +// return SimpleType.R +// } +// error("This DubinsPath.Type doesn't contain intermediate arc") +// } +// } + + public enum class SimpleType { + R, S, L + } + public enum class Type { RLR, LRL, RSR, LSL, RSL, LSR } + public fun toSimpleTypes(type: Type): List { + when (type) { + Type.RLR -> { + return listOf(SimpleType.R, SimpleType.L, SimpleType.R) + } + Type.LRL -> { + return listOf(SimpleType.L, SimpleType.R, SimpleType.L) + } + Type.RSR -> { + return listOf(SimpleType.R, SimpleType.S, SimpleType.R) + } + Type.LSL -> { + return listOf(SimpleType.L, SimpleType.S, SimpleType.L) + } + Type.RSL -> { + return listOf(SimpleType.R, SimpleType.S, SimpleType.L) + } + Type.LSR -> { + return listOf(SimpleType.L, SimpleType.S, SimpleType.R) + } + else -> error("This type doesn't exist") + } + } + + public fun toType(types: List): Type { + when (types) { + listOf(SimpleType.R, SimpleType.L, SimpleType.R) -> { + return Type.RLR + } + listOf(SimpleType.L, SimpleType.R, SimpleType.L) -> { + return Type.LRL + } + listOf(SimpleType.R, SimpleType.S, SimpleType.R) -> { + return Type.RSR + } + listOf(SimpleType.L, SimpleType.S, SimpleType.L) -> { + return Type.LSL + } + listOf(SimpleType.R, SimpleType.S, SimpleType.L) -> { + return Type.RSL + } + listOf(SimpleType.L, SimpleType.S, SimpleType.R) -> { + return Type.LSR + } + else -> error("This type doesn't exist") + } + } + +// public class PathTypes(private val inputTypes: List) { +// public val type: Type +// get() { +// when (this.inputTypes) { +// listOf(SimpleType.R, SimpleType.S, SimpleType.R) -> { +// return Type.RSR +// } +// listOf(SimpleType.R, SimpleType.S, SimpleType.L) -> { +// return Type.RSL +// } +// listOf(SimpleType.L, SimpleType.S, SimpleType.R) -> { +// return Type.LSR +// } +// listOf(SimpleType.L, SimpleType.S, SimpleType.L) -> { +// return Type.LSL +// } +// else -> error("Wrong list of SimpleTypes") +// } +// } +// public val chain: List = this.inputTypes +// } + /** * Return Dubins trajectory type or null if trajectory is not a Dubins path */ @@ -243,6 +351,8 @@ public object DubinsPath { } } +public typealias PathTypes = List + public fun interface MaxCurvature { public fun compute(startPoint: PhaseVector2D): Double } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt index 945b140c2..2d935aa00 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt @@ -5,10 +5,10 @@ package space.kscience.kmath.trajectory -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.DoubleVector2D -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.LineSegment +import space.kscience.kmath.geometry.* +import space.kscience.kmath.geometry.Euclidean2DSpace.plus +import space.kscience.kmath.geometry.Euclidean2DSpace.times +import space.kscience.kmath.operations.DoubleField.pow import kotlin.math.* /** @@ -17,7 +17,7 @@ import kotlin.math.* */ public fun Circle2D.tangentsToCircle( other: Circle2D, -): Map> = with(Euclidean2DSpace) { +): Map = with(Euclidean2DSpace) { val line = LineSegment(center, other.center) val d = line.begin.distanceTo(line.end) val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) @@ -48,14 +48,66 @@ public fun Circle2D.tangentsToCircle( val w = vector(-cos(angle2), sin(angle2)) put( route, - LineSegment( + LineSegment2D( center + w * r1, other.center + w * r2 ) ) } else { - throw Exception("Circles should not be") + throw Exception("Circles should not intersect") + } + } + } +} + +public fun dubinsTangentsToCircles( + firstCircle: Circle2D, + secondCircle: Circle2D, + firstObstacle: DubinsObstacle, + secondObstacle: DubinsObstacle +): Map = with(Euclidean2DSpace) { + val line = LineSegment(firstCircle.center, secondCircle.center) + val d = line.begin.distanceTo(line.end) + val angle1 = atan2(secondCircle.center.x - firstCircle.center.x, + secondCircle.center.y - firstCircle.center.y) + var r: Double + var angle2: Double + val routes = mapOf( + DubinsPath.Type.RSR to Pair(firstCircle.radius, secondCircle.radius), + DubinsPath.Type.RSL to Pair(firstCircle.radius, -secondCircle.radius), + DubinsPath.Type.LSR to Pair(-firstCircle.radius, secondCircle.radius), + DubinsPath.Type.LSL to Pair(-firstCircle.radius, -secondCircle.radius) + ) + return buildMap { + for ((route, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + if (d * d > r * r) { + val l = (d * d - r * r).pow(0.5) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) + put(route, DubinsTangent(Circle2D(firstCircle.center, firstCircle.radius), + secondCircle, + firstObstacle, + secondObstacle, + LineSegment2D( + firstCircle.center + w * r1, + secondCircle.center + w * r2 + ), + DubinsPath.toSimpleTypes(route)) + ) + } else { + throw Exception("Circles should not intersect") } } } From 61d43ae5faa05f8c9d90d6519897a7f0ebd6b77a Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Sat, 4 Mar 2023 21:31:06 +0300 Subject: [PATCH 25/58] search for shortest path algorithm --- .../kmath/trajectory/DubinsObstacle.kt | 144 ++++++++++++++---- .../kscience/kmath/trajectory/tangent.kt | 82 ++++++++-- .../kscience/kmath/trajectory/DubinsTest.kt | 39 +++++ 3 files changed, 225 insertions(+), 40 deletions(-) create mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt index 56aa88e4a..e1c967e2a 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt @@ -276,7 +276,7 @@ public fun tangentsAlongTheObstacle(initialCircle: Circle2D, public fun allFinished(paths: List>, finalObstacle: DubinsObstacle): Boolean { for (path in paths) { - if (path[-1].endObstacle != finalObstacle) { + if (path.last().endObstacle != finalObstacle) { return false } } @@ -296,8 +296,8 @@ public fun pathLength(path: List): Double { return tangentsLength + arcsLength } -public fun shortestPath(path: List>): List> { - return path.sortedBy { pathLength(it) } +public fun shortestPath(path: List>): List { + return path.sortedBy { pathLength(it) }[0] } public typealias Path = List @@ -309,7 +309,7 @@ public fun findAllPaths( finalDirection: DoubleVector2D, finalRadius: Double, obstacles: List -) { +): List> { val initialCircles = constructTangentCircles( startingPoint, startingDirection, @@ -318,15 +318,15 @@ public fun findAllPaths( finalPoint, finalDirection, finalRadius) - var outputTangents = mutableMapOf>() + var outputTangents = mutableMapOf>>() for (i in listOf(DubinsPath.SimpleType.L, DubinsPath.SimpleType.R)) { for (j in listOf(DubinsPath.SimpleType.L, DubinsPath.SimpleType.R)) { val finalCircle = finalCircles[j]!! val finalObstacle = DubinsObstacle(listOf(finalCircle)) outputTangents[listOf(i, DubinsPath.SimpleType.S, - j)] = listOf( - listOf(DubinsTangent( + j)] = mutableListOf( + mutableListOf(DubinsTangent( initialCircles[i]!!, initialCircles[i]!!, DubinsObstacle(listOf(initialCircles[i]!!)), @@ -338,13 +338,13 @@ public fun findAllPaths( while (!allFinished(outputTangents[listOf(i, DubinsPath.SimpleType.S, j)]!!, finalObstacle)) { - var newOutputTangents = listOf() + var newOutputTangents = mutableListOf>() for (line in outputTangents[listOf(i, DubinsPath.SimpleType.S, j)]!!) { - var currentCircle = line[-1].endCircle - var currentDirection = line[-1].route[-1] - var currentObstacle = line[-1].endObstacle + var currentCircle = line.last().endCircle + var currentDirection = line.last().route.last() + var currentObstacle = line.last().endObstacle var nextObstacle = DubinsObstacle(listOf()) if (currentObstacle != finalObstacle) { var tangentToFinal = outerTangents(currentObstacle, finalObstacle)[DubinsPath.toType(listOf( @@ -362,20 +362,7 @@ public fun findAllPaths( nextObstacle = finalObstacle } var nextTangents = outerTangents(currentObstacle, nextObstacle) -// for (pathType in listOf( -// listOf(DubinsPath.SimpleType.L, -// DubinsPath.SimpleType.S, -// DubinsPath.SimpleType.L), -// listOf(DubinsPath.SimpleType.L, -// DubinsPath.SimpleType.S, -// DubinsPath.SimpleType.R), -// listOf(DubinsPath.SimpleType.R, -// DubinsPath.SimpleType.S, -// DubinsPath.SimpleType.L), -// listOf(DubinsPath.SimpleType.R, -// DubinsPath.SimpleType.S, -// DubinsPath.SimpleType.R) -// )) { + for (pathType in nextTangents.keys) { for (obstacle in obstacles) { // in Python code here try/except was used, but seems unneeded @@ -396,12 +383,117 @@ public fun findAllPaths( nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection)} as MutableMap } - TODO("rewrite fragment from Python") + val tangentsAlong = mutableListOf() + for (tangent in nextTangents.values) { + if (tangent.startCircle == line.last().endCircle) { + val lengthMaxPossible = arcLength( + tangent.startCircle, + line.last().lineSegment.end, + tangent.startObstacle.nextTangent( + tangent.startCircle, + DubinsPath.toType(listOf(currentDirection, DubinsPath.SimpleType.S, currentDirection)), + ).lineSegment.begin, + currentDirection + ) + val lengthCalculated = arcLength( + tangent.startCircle, + line.last().lineSegment.end, + tangent.lineSegment.begin, + currentDirection) + if (lengthCalculated > lengthMaxPossible) { + val tangentsAlong = tangentsAlongTheObstacle( + currentCircle, + DubinsPath.toType(listOf( + currentDirection, + DubinsPath.SimpleType.S, + currentDirection)), + tangent.startCircle, + currentObstacle + ) + } + else { + val tangentsAlong = mutableListOf() + } + } + else { + val tangentsAlong = tangentsAlongTheObstacle( + currentCircle, + DubinsPath.toType(listOf( + currentDirection, + DubinsPath.SimpleType.S, + currentDirection)), + tangent.startCircle, + currentObstacle + ) + } + newOutputTangents.add((line + tangentsAlong + listOf(tangent)).toMutableList()) + } + outputTangents[listOf( + i, + DubinsPath.SimpleType.S, + j + )] = newOutputTangents + } + else { + // minor changes from Python code + newOutputTangents.add(line) + outputTangents[listOf( + i, + DubinsPath.SimpleType.S, + j + )] = newOutputTangents } } } + for (lineId in outputTangents[listOf( + i, + DubinsPath.SimpleType.S, + j + )]!!.indices) { + val lastDirection = outputTangents[listOf( + i, + DubinsPath.SimpleType.S, + j + )]!![lineId].last().route[2] + outputTangents[listOf( + i, + DubinsPath.SimpleType.S, + j + )]!![lineId].add(DubinsTangent( + finalCircles[j]!!, + finalCircles[j]!!, + DubinsObstacle( + listOf(finalCircles[j]!!) + ), + DubinsObstacle( + listOf(finalCircles[j]!!) + ), + LineSegment2D(finalPoint, finalPoint), + listOf( + lastDirection, + DubinsPath.SimpleType.S, + j + ) + )) + } } } + return outputTangents[listOf( + DubinsPath.SimpleType.L, + DubinsPath.SimpleType.S, + DubinsPath.SimpleType.L + )]!! + outputTangents[listOf( + DubinsPath.SimpleType.L, + DubinsPath.SimpleType.S, + DubinsPath.SimpleType.R + )]!! + outputTangents[listOf( + DubinsPath.SimpleType.R, + DubinsPath.SimpleType.S, + DubinsPath.SimpleType.L + )]!! + outputTangents[listOf( + DubinsPath.SimpleType.R, + DubinsPath.SimpleType.S, + DubinsPath.SimpleType.L)]!! } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt index d3165e162..1a58d64cc 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt @@ -39,22 +39,76 @@ public fun Circle2D.tangentsToCircle( } else { r1.absoluteValue + r2.absoluteValue } - if (distance <= r) TODO("Intersecting circles are not supported yet") - val l = sqrt(distance * distance - r * r) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, l) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, l) - } - val w = vector(-cos(angle2), sin(angle2)) - put( - route, - LineSegment( - center + w * r1, - other.center + w * r2 + if (distance * distance >= r * r) { + val l = sqrt(distance * distance - r * r) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) + put( + route, + LineSegment( + center + w * r1, + other.center + w * r2 + ) ) - ) + } else { + throw Exception("Circles should not intersect") + } + } + } +} +public fun dubinsTangentsToCircles( + firstCircle: Circle2D, + secondCircle: Circle2D, + firstObstacle: DubinsObstacle, + secondObstacle: DubinsObstacle +): Map = with(Euclidean2DSpace) { + val line = LineSegment(firstCircle.center, secondCircle.center) + val distance = line.begin.distanceTo(line.end) + val angle1 = atan2(secondCircle.center.x - firstCircle.center.x, + secondCircle.center.y - firstCircle.center.y) + var r: Double + var angle2: Double + val routes = mapOf( + DubinsPath.Type.RSR to Pair(firstCircle.radius, secondCircle.radius), + DubinsPath.Type.RSL to Pair(firstCircle.radius, -secondCircle.radius), + DubinsPath.Type.LSR to Pair(-firstCircle.radius, secondCircle.radius), + DubinsPath.Type.LSL to Pair(-firstCircle.radius, -secondCircle.radius) + ) + return buildMap { + for ((route, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + if (distance * distance >= r * r) { + val l = sqrt(distance * distance - r * r) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) + put(route, DubinsTangent(Circle2D(firstCircle.center, firstCircle.radius), + secondCircle, + firstObstacle, + secondObstacle, + LineSegment2D( + firstCircle.center + w * r1, + secondCircle.center + w * r2 + ), + DubinsPath.toSimpleTypes(route)) + ) + } else { + throw Exception("Circles should not intersect") + } } } } \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt new file mode 100644 index 000000000..3eefbdaeb --- /dev/null +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.trajectory + +import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.DoubleVector2D +import space.kscience.kmath.geometry.Euclidean2DSpace.vector +import kotlin.test.Test +import kotlin.test.assertTrue + +class DubinsTest { + @Test + fun firstPath() { + val startPoint = vector(-5.0, -1.0) + val startDirection = vector(1.0, 1.0) + val startRadius = 0.5 + val finalPoint = vector(20.0, 4.0) + val finalDirection = vector(1.0, -1.0) + val finalRadius = 0.5 + + val obstacles = listOf(DubinsObstacle(listOf( + Circle2D(vector(7.0, 1.0), 5.0)))) + + val outputTangents = findAllPaths( + startPoint, + startDirection, + startRadius, + finalPoint, + finalDirection, + finalRadius, + obstacles) + val length = pathLength(shortestPath(outputTangents)) + TODO("fix negative indices in boundaryTangents and accomplish test") + assertTrue(false) + } +} \ No newline at end of file From 1b6a41c728150bb9374625b06045c06f8073c524 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Thu, 9 Mar 2023 08:39:20 +0300 Subject: [PATCH 26/58] search for shortest path algorithm --- .../kmath/trajectory/DubinsObstacle.kt | 30 ++++++++--------- .../kscience/kmath/trajectory/tangent.kt | 2 +- .../kscience/kmath/trajectory/DubinsTest.kt | 33 +++++++++++++++++++ 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt index e1c967e2a..d3ab13f26 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt @@ -39,8 +39,8 @@ public class DubinsObstacle( var angle2: Double val routes = mapOf( DubinsPath.Type.RSR to Pair(radius, other.radius), - DubinsPath.Type.RSL to Pair(radius, -other.radius), - DubinsPath.Type.LSR to Pair(-radius, other.radius), +// DubinsPath.Type.RSL to Pair(radius, -other.radius), +// DubinsPath.Type.LSR to Pair(-radius, other.radius), DubinsPath.Type.LSL to Pair(-radius, -other.radius) ) return buildMap { @@ -52,7 +52,7 @@ public class DubinsObstacle( } else { r1.absoluteValue + r2.absoluteValue } - if (d * d > r * r) { + if (d * d >= r * r) { val l = (d * d - r * r).pow(0.5) angle2 = if (r1.absoluteValue > r2.absoluteValue) { angle1 + r1.sign * atan2(r.absoluteValue, l) @@ -76,8 +76,11 @@ public class DubinsObstacle( } } } - val firstCircles = this.circles.slice(-this.circles.size..-1) - val secondCircles = this.circles.slice(-this.circles.size+1..0) +// val firstCircles = this.circles.slice(-this.circles.size..-1) +// val secondCircles = this.circles.slice(-this.circles.size+1..0) + val firstCircles = this.circles + val secondCircles = this.circles.slice(1..this.circles.lastIndex) + + this.circles[0] val lslTangents = firstCircles.zip(secondCircles) {a, b -> a.dubinsTangentsToCircles(b)[DubinsPath.Type.LSL]!!} val rsrTangents = firstCircles.zip(secondCircles) @@ -345,7 +348,7 @@ public fun findAllPaths( var currentCircle = line.last().endCircle var currentDirection = line.last().route.last() var currentObstacle = line.last().endObstacle - var nextObstacle = DubinsObstacle(listOf()) + var nextObstacle: DubinsObstacle? = null if (currentObstacle != finalObstacle) { var tangentToFinal = outerTangents(currentObstacle, finalObstacle)[DubinsPath.toType(listOf( currentDirection, @@ -358,7 +361,7 @@ public fun findAllPaths( break } } - if (nextObstacle == DubinsObstacle(listOf())) { + if (nextObstacle == null) { nextObstacle = finalObstacle } var nextTangents = outerTangents(currentObstacle, nextObstacle) @@ -372,16 +375,13 @@ public fun findAllPaths( } } - if (nextObstacle == finalObstacle) { - nextTangents = - nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection) and + nextTangents = if (nextObstacle == finalObstacle) { + nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection) and (DubinsPath.toSimpleTypes(it.key)[0] == j)} as MutableMap - } - else { - nextTangents = - nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection)} - as MutableMap + } else { + nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection)} + as MutableMap } val tangentsAlong = mutableListOf() for (tangent in nextTangents.values) { diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt index 1a58d64cc..fb1c3927b 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt @@ -95,7 +95,7 @@ public fun dubinsTangentsToCircles( } else { angle1 - r2.sign * atan2(r.absoluteValue, l) } - val w = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) + val w = vector(-cos(angle2), sin(angle2)) put(route, DubinsTangent(Circle2D(firstCircle.center, firstCircle.radius), secondCircle, firstObstacle, diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt index 3eefbdaeb..a0697c59c 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt @@ -36,4 +36,37 @@ class DubinsTest { TODO("fix negative indices in boundaryTangents and accomplish test") assertTrue(false) } + @Test + fun outerTangentsTest1() { + // works incorrectly + val circles1 = listOf( + Circle2D(vector(0.0, 0.0), 1.0)) + val circles2 = listOf( + Circle2D(vector(5.0, 5.0), 1.0) + ) + println(outerTangents(DubinsObstacle(circles1), DubinsObstacle(circles2))) + assertTrue(false) + } + @Test + fun outerTangentsTest2() { + // works incorrectly + val circles1 = listOf( + Circle2D(vector(0.0, 0.0), 1.0), + Circle2D(vector( 2.0, 0.0), 1.0)) + val circles2 = listOf( + Circle2D(vector(5.0, 5.0), 1.0), + Circle2D(vector(7.0, 5.0), 1.0) + ) + println(outerTangents(DubinsObstacle(circles1), DubinsObstacle(circles2))) + + for (circle1 in circles1) { + for (circle2 in circles2) { + for (tangent in dubinsTangentsToCircles(circle1, circle2, + DubinsObstacle(circles1), DubinsObstacle(circles2))) { + println(tangent) + } + } + } + assertTrue(false) + } } \ No newline at end of file From 2bce369c5dcdae8b4ba16f498fd19d31807b29df Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Thu, 9 Mar 2023 16:03:48 +0300 Subject: [PATCH 27/58] search for shortest path algorithm --- .../kmath/trajectory/DubinsObstacle.kt | 38 ++++++++++++------- .../kscience/kmath/trajectory/DubinsTest.kt | 37 +++++++++++++++++- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt index d3ab13f26..6b247e55b 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt @@ -111,13 +111,24 @@ public class DubinsObstacle( else { for (i in this.circles.indices) { if (this.circles[i] == circle) { - return DubinsTangent(this.circles[i], - this.circles[i-1], - this, - this, - LineSegment2D(this.tangents[i-1].lineSegment.end, - this.tangents[i-1].lineSegment.begin), - DubinsPath.toSimpleTypes(route)) + if (i > 0) { + return DubinsTangent(this.circles[i], + this.circles[i-1], + this, + this, + LineSegment2D(this.tangents[i-1].lineSegment.end, + this.tangents[i-1].lineSegment.begin), + DubinsPath.toSimpleTypes(route)) + } + else { + return DubinsTangent(this.circles[0], + this.circles.last(), + this, + this, + LineSegment2D(this.tangents.last().lineSegment.end, + this.tangents.last().lineSegment.begin), + DubinsPath.toSimpleTypes(route)) + } } } } @@ -156,7 +167,7 @@ public fun LineSegment2D.intersectCircle(circle: Circle2D): Boolean { val a = (this.begin.x - this.end.x).pow(2.0) + (this.begin.y - this.end.y).pow(2.0) val b = 2 * ((this.begin.x - this.end.x) * (this.end.x - circle.center.x) + (this.begin.y - this.end.y) * (this.end.y - circle.center.y)) - val c = (this.end.x - circle.center.x).pow(2.0) + (this.end.y - circle.center.y) - + val c = (this.end.x - circle.center.x).pow(2.0) + (this.end.y - circle.center.y).pow(2.0) - circle.radius.pow(2.0) val d = b.pow(2.0) - 4 * a * c if (d < 1e-6) { @@ -289,7 +300,7 @@ public fun allFinished(paths: List>, public fun pathLength(path: List): Double { val tangentsLength = path.sumOf{norm(it.lineSegment.end - it.lineSegment.begin)} val arcsLength = buildList{ - for (i in 1..path.size) { + for (i in 1..path.lastIndex) { add(arcLength(path[i].startCircle, path[i-1].lineSegment.end, path[i].lineSegment.begin, @@ -366,13 +377,14 @@ public fun findAllPaths( } var nextTangents = outerTangents(currentObstacle, nextObstacle) - for (pathType in nextTangents.keys) { + for (pathType in DubinsPath.Type.values()) { for (obstacle in obstacles) { // in Python code here try/except was used, but seems unneeded - if (nextTangents[pathType]!!.intersectObstacle(obstacle)) { - nextTangents.remove(pathType) + if (nextTangents.containsKey(pathType)) { + if (nextTangents[pathType]!!.intersectObstacle(obstacle)) { + nextTangents.remove(pathType) + } } - } } nextTangents = if (nextObstacle == finalObstacle) { diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt index a0697c59c..16d77c84d 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt @@ -33,8 +33,41 @@ class DubinsTest { finalRadius, obstacles) val length = pathLength(shortestPath(outputTangents)) - TODO("fix negative indices in boundaryTangents and accomplish test") - assertTrue(false) + println(length) + } + + @Test + fun secondPath() { + val startPoint = vector(-5.0, -1.0) + val startDirection = vector(1.0, 1.0) + val startRadius = 0.5 + val finalPoint = vector(20.0, 4.0) + val finalDirection = vector(1.0, -1.0) + val finalRadius = 0.5 + + val obstacles = listOf( + DubinsObstacle(listOf( + Circle2D(vector(1.0, 6.5), 0.5), + Circle2D(vector(2.0, 1.0), 0.5), + Circle2D(vector(6.0, 0.0), 0.5), + Circle2D(vector(5.0, 5.0), 0.5) + )), DubinsObstacle(listOf( + Circle2D(vector(10.0, 1.0), 0.5), + Circle2D(vector(16.0, 0.0), 0.5), + Circle2D(vector(14.0, 6.0), 0.5), + Circle2D(vector(9.0, 4.0), 0.5) + )) + ) + val outputTangents = findAllPaths( + startPoint, + startDirection, + startRadius, + finalPoint, + finalDirection, + finalRadius, + obstacles) + val length = pathLength(shortestPath(outputTangents)) + println(length) } @Test fun outerTangentsTest1() { From 4871baf0e5f4d45bf3c7d31916d4b84be187b689 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 10 Mar 2023 12:01:08 +0300 Subject: [PATCH 28/58] Add vector product to Euclidean3DSpace --- gradle.properties | 2 +- .../kmath/geometry/Euclidean3DSpace.kt | 47 ++++++++++++++++++- .../kmath/geometry/Euclidean3DSpaceTest.kt | 46 ++++++++++++------ 3 files changed, 78 insertions(+), 17 deletions(-) diff --git a/gradle.properties b/gradle.properties index c3f070c2d..048c9c9f3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin.native.ignoreDisabledTargets=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.14.2-kotlin-1.8.10 +toolsVersion=0.14.3-kotlin-1.8.20-RC org.gradle.parallel=true 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 cc641a3f1..f1cf0bad2 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 @@ -78,8 +78,11 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations< } } + public fun vector(x: Double, y: Double, z: Double): DoubleVector3D = + Vector3DImpl(x, y, z) + public fun vector(x: Number, y: Number, z: Number): DoubleVector3D = - Vector3DImpl(x.toDouble(), y.toDouble(), z.toDouble()) + vector(x.toDouble(), y.toDouble(), z.toDouble()) override val zero: DoubleVector3D by lazy { vector(0.0, 0.0, 0.0) } @@ -100,6 +103,48 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations< override fun DoubleVector3D.dot(other: DoubleVector3D): Double = x * other.x + y * other.y + z * other.z + private fun leviCivita(i: Int, j: Int, k: Int): Int = when { + // even permutation + i == 0 && j == 1 && k == 2 -> 1 + i == 1 && j == 2 && k == 0 -> 1 + i == 2 && j == 0 && k == 1 -> 1 + // odd permutations + i == 2 && j == 1 && k == 0 -> -1 + i == 0 && j == 2 && k == 1 -> -1 + i == 1 && j == 0 && k == 2 -> -1 + + else -> 0 + } + + /** + * Compute vector product of [first] and [second]. The basis assumed to be right-handed if [rightBasis] is true and + * left-handed otherwise + */ + public fun vectorProduct( + first: DoubleVector3D, + second: DoubleVector3D, + rightBasis: Boolean = true, + ): DoubleVector3D { + var x = 0.0 + var y = 0.0 + var z = 0.0 + + for (j in (0..2)) { + for (k in (0..2)) { + x += leviCivita(0, j, k) * first[j] * second[k] + y += leviCivita(1, j, k) * first[j] * second[k] + z += leviCivita(2, j, k) * first[j] * second[k] + } + } + + return vector(x, y, z) * (if (rightBasis) 1 else -1) + } + + /** + * Vector product with right basis + */ + public infix fun DoubleVector3D.cross(other: DoubleVector3D): Vector3D = vectorProduct(this, other) + public val xAxis: DoubleVector3D = vector(1.0, 0.0, 0.0) public val yAxis: DoubleVector3D = vector(0.0, 1.0, 0.0) public val zAxis: DoubleVector3D = vector(0.0, 0.0, 1.0) diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt index 6d9a169eb..291b0ad47 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt @@ -57,23 +57,39 @@ internal class Euclidean3DSpaceTest { } @Test - fun add() { - with(Euclidean3DSpace) { - assertVectorEquals( - vector(1.0, -2.0, 0.001), - vector(1.0, -2.0, 0.001) + zero - ) - assertVectorEquals( - vector(8.0, -3.0, 3.001), - vector(1.0, 2.0, 3.0) + vector(7.0, -5.0, 0.001) - ) - } + fun add() = with(Euclidean3DSpace) { + assertVectorEquals( + vector(1.0, -2.0, 0.001), + vector(1.0, -2.0, 0.001) + zero + ) + assertVectorEquals( + vector(8.0, -3.0, 3.001), + vector(1.0, 2.0, 3.0) + vector(7.0, -5.0, 0.001) + ) } @Test - fun multiply() { - with(Euclidean3DSpace) { - assertVectorEquals(vector(2.0, -4.0, 0.0), vector(1.0, -2.0, 0.0) * 2) - } + fun multiply() = with(Euclidean3DSpace) { + assertVectorEquals(vector(2.0, -4.0, 0.0), vector(1.0, -2.0, 0.0) * 2) } + + @Test + fun vectorProduct() = with(Euclidean3DSpace) { + assertVectorEquals(zAxis, vectorProduct(xAxis, yAxis)) + assertVectorEquals(zAxis, xAxis cross yAxis) + assertVectorEquals(-zAxis, vectorProduct(yAxis, xAxis)) + assertVectorEquals(zAxis, vectorProduct(yAxis, xAxis, rightBasis = false)) + } + + @Test + fun doubleVectorProduct() = with(Euclidean3DSpace) { + val a = vector(1, 2, -3) + val b = vector(-1, 0, 1) + val c = vector(4, 5, 6) + + val res = a cross (b cross c) + val expected = b * (a dot c) - c * (a dot b) + assertVectorEquals(expected, res) + } + } From a3963ac4f50b7042cf21c51c8b5f97c36877249e Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 10 Mar 2023 21:40:14 +0300 Subject: [PATCH 29/58] Refactor series naming and docs --- .../kscience/kmath/series/SeriesAlgebra.kt | 79 +++++++++++-------- .../kscience/kmath/series/seriesExtensions.kt | 32 ++++---- 2 files changed, 62 insertions(+), 49 deletions(-) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt index 3cd2212f6..45e392693 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt @@ -6,6 +6,7 @@ import space.kscience.kmath.operations.RingOps import space.kscience.kmath.stat.StatisticalAlgebra import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferView +import space.kscience.kmath.structures.getOrNull import kotlin.math.max import kotlin.math.min @@ -33,8 +34,6 @@ public interface Series : Buffer { public val position: Int } -public val Series.absoluteIndices: IntRange get() = position until position + size - /** * A [BufferView] with index offset (both positive and negative) and possible size change */ @@ -60,54 +59,68 @@ public class SeriesAlgebra, out BA : BufferAlgebra, L>( private val labelResolver: (Int) -> L, ) : RingOps>, StatisticalAlgebra { - public val Buffer.indices: IntRange + /** + * A range of valid offset indices. In general, does not start with zero. + */ + public val Buffer.offsetIndices: IntRange get() = if (this is Series) { - absoluteIndices + position until position + size } else { 0 until size } /** - * Get the value by absolute index in the series algebra or return null if index is out of range + * Get the value by absolute offset in the series algebra or return null if index is out of range */ - public fun Buffer.getAbsoluteOrNull(index: Int): T? = when { - index !in indices -> null - this is Series -> origin[index - position] - else -> get(index) + public fun Buffer.getByOffsetOrNull(index: Int): T? = when { + index !in offsetIndices -> null + this is Series -> origin.getOrNull(index - position) + else -> getOrNull(index) } /** * Get the value by absolute index in the series algebra or throw [IndexOutOfBoundsException] if index is out of range */ - public fun Buffer.getAbsolute(index: Int): T = - getAbsoluteOrNull(index) ?: throw IndexOutOfBoundsException("Index $index is not in $indices") + public fun Buffer.getByOffset(index: Int): T = + getByOffsetOrNull(index) ?: throw IndexOutOfBoundsException("Index $index is not in $offsetIndices") /** - * Create an offset series with index starting point at [index] + * Zero-copy move [Buffer] or [Series] to given [position] ignoring series offset if it is present. */ - public fun Buffer.moveTo(index: Int): Series = if (this is Series) { - SeriesImpl(origin, index, size) + public fun Buffer.moveTo(position: Int): Series = if (this is Series) { + SeriesImpl(origin, position, size) } else { - SeriesImpl(this, index, size) + SeriesImpl(this, position, size) } - public val Buffer.offset: Int get() = if (this is Series) position else 0 + /** + * Zero-copy move [Buffer] or [Series] by given [offset]. If it is [Series], sum intrinsic series position and the [offset]. + */ + public fun Buffer.moveBy(offset: Int): Series = if (this is Series) { + SeriesImpl(origin, position + offset, size) + } else { + SeriesImpl(this, offset, size) + } /** - * Build a new series + * An offset of the buffer start relative to [SeriesAlgebra] zero offset */ - public fun series(size: Int, fromIndex: Int = 0, block: A.(label: L) -> T): Series { + public val Buffer.startOffset: Int get() = if (this is Series) position else 0 + + /** + * Build a new series positioned at [startOffset]. + */ + public fun series(size: Int, startOffset: Int = 0, block: A.(label: L) -> T): Series { return elementAlgebra.bufferFactory(size) { - val index = it + fromIndex + val index = it + startOffset elementAlgebra.block(labelResolver(index)) - }.moveTo(fromIndex) + }.moveTo(startOffset) } /** * Get a label buffer for given buffer. */ - public val Buffer.labels: List get() = indices.map(labelResolver) - + public val Buffer.labels: List get() = offsetIndices.map(labelResolver) /** * Try to resolve element by label and return null if element with a given label is not found @@ -115,7 +128,7 @@ public class SeriesAlgebra, out BA : BufferAlgebra, L>( public operator fun Buffer.get(label: L): T? { val index = labels.indexOf(label) if (index == -1) return null - return getAbsolute(index + offset) + return getByOffset(index + startOffset) } /** @@ -123,9 +136,9 @@ public class SeriesAlgebra, out BA : BufferAlgebra, L>( */ public inline fun Buffer.map(crossinline transform: A.(T) -> T): Series { val buf = elementAlgebra.bufferFactory(size) { - elementAlgebra.transform(getAbsolute(it)) + elementAlgebra.transform(getByOffset(it)) } - return buf.moveTo(indices.first) + return buf.moveTo(offsetIndices.first) } /** @@ -134,22 +147,22 @@ public class SeriesAlgebra, out BA : BufferAlgebra, L>( public inline fun Buffer.mapWithLabel(crossinline transform: A.(arg: T, label: L) -> T): Series { val labels = labels val buf = elementAlgebra.bufferFactory(size) { - elementAlgebra.transform(getAbsolute(it), labels[it]) + elementAlgebra.transform(getByOffset(it), labels[it]) } - return buf.moveTo(indices.first) + return buf.moveTo(offsetIndices.first) } public inline fun Buffer.fold(initial: R, operation: A.(acc: R, T) -> R): R { var accumulator = initial - for (index in this.indices) accumulator = elementAlgebra.operation(accumulator, getAbsolute(index)) + for (index in this.offsetIndices) accumulator = elementAlgebra.operation(accumulator, getByOffset(index)) return accumulator } public inline fun Buffer.foldWithLabel(initial: R, operation: A.(acc: R, arg: T, label: L) -> R): R { val labels = labels var accumulator = initial - for (index in this.indices) accumulator = - elementAlgebra.operation(accumulator, getAbsolute(index), labels[index]) + for (index in this.offsetIndices) accumulator = + elementAlgebra.operation(accumulator, getByOffset(index), labels[index]) return accumulator } @@ -160,11 +173,11 @@ public class SeriesAlgebra, out BA : BufferAlgebra, L>( other: Buffer, crossinline operation: A.(left: T, right: T) -> T, ): Series { - val newRange = indices.intersect(other.indices) + val newRange = offsetIndices.intersect(other.offsetIndices) return elementAlgebra.bufferFactory(newRange.size) { elementAlgebra.operation( - getAbsolute(it), - other.getAbsolute(it) + getByOffset(it), + other.getByOffset(it) ) }.moveTo(newRange.first) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt index 882fa2c46..fa5e0addd 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt @@ -12,32 +12,32 @@ import space.kscience.kmath.structures.Buffer public fun SeriesAlgebra.sin( arg: Buffer, ): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.sin(arg).moveTo(arg.offset) + bufferAlgebra.sin(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.cos( arg: Buffer, ): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.cos(arg).moveTo(arg.offset) + bufferAlgebra.cos(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.tan( arg: Buffer, ): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.tan(arg).moveTo(arg.offset) + bufferAlgebra.tan(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.asin( arg: Buffer, ): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.asin(arg).moveTo(arg.offset) + bufferAlgebra.asin(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.acos( arg: Buffer, ): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.acos(arg).moveTo(arg.offset) + bufferAlgebra.acos(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.atan( arg: Buffer, ): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.atan(arg).moveTo(arg.offset) + bufferAlgebra.atan(arg).moveTo(arg.startOffset) //exponential @@ -45,42 +45,42 @@ public fun SeriesAlgebra.atan( public fun SeriesAlgebra.exp( arg: Buffer, ): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.exp(arg).moveTo(arg.offset) + bufferAlgebra.exp(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.ln( arg: Buffer, ): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.ln(arg).moveTo(arg.offset) + bufferAlgebra.ln(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.sinh( arg: Buffer, ): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.sinh(arg).moveTo(arg.offset) + bufferAlgebra.sinh(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.cosh( arg: Buffer, ): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.cosh(arg).moveTo(arg.offset) + bufferAlgebra.cosh(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.tanh( arg: Buffer, ): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.tanh(arg).moveTo(arg.offset) + bufferAlgebra.tanh(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.asinh( arg: Buffer, ): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.asinh(arg).moveTo(arg.offset) + bufferAlgebra.asinh(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.acosh( arg: Buffer, ): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.acosh(arg).moveTo(arg.offset) + bufferAlgebra.acosh(arg).moveTo(arg.startOffset) public fun SeriesAlgebra.atanh( arg: Buffer, ): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.atanh(arg).moveTo(arg.offset) + bufferAlgebra.atanh(arg).moveTo(arg.startOffset) //power @@ -89,9 +89,9 @@ public fun SeriesAlgebra.power( arg: Buffer, pow: Number, ): Series where BA : BufferAlgebra, BA : PowerOperations> = - bufferAlgebra.power(arg, pow).moveTo(arg.offset) + bufferAlgebra.power(arg, pow).moveTo(arg.startOffset) public fun SeriesAlgebra.sqrt( arg: Buffer, ): Series where BA : BufferAlgebra, BA : PowerOperations> = - bufferAlgebra.sqrt(arg).moveTo(arg.offset) \ No newline at end of file + bufferAlgebra.sqrt(arg).moveTo(arg.startOffset) \ No newline at end of file From 72c70302974a1cc568f32a6c6242d7180c77a9fd Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 10 Mar 2023 22:50:41 +0300 Subject: [PATCH 30/58] Add time series example stub --- examples/build.gradle.kts | 9 ++-- .../kscience/kmath/stat/DateTimeSeries.kt | 19 ++++++++ .../kmath/series/MonotonicSeriesAlgebra.kt | 47 +++++++++++++++++++ .../kscience/kmath/series/SeriesAlgebra.kt | 16 +++++-- 4 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/stat/DateTimeSeries.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index da645f012..f7b7794f3 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile + plugins { kotlin("jvm") } @@ -33,6 +35,8 @@ dependencies { implementation(project(":kmath-multik")) implementation("org.jetbrains.kotlinx:multik-default:$multikVersion") + //datetime + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") implementation("org.nd4j:nd4j-native:1.0.0-beta7") @@ -46,9 +50,6 @@ dependencies { // } else implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - // multik implementation - implementation("org.jetbrains.kotlinx:multik-default:0.1.0") - implementation("org.slf4j:slf4j-simple:1.7.32") // plotting implementation("space.kscience:plotlykt-server:0.5.0") @@ -62,7 +63,7 @@ kotlin.sourceSets.all { } } -tasks.withType { +tasks.withType { kotlinOptions { jvmTarget = "11" freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DateTimeSeries.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DateTimeSeries.kt new file mode 100644 index 000000000..9836db6ea --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DateTimeSeries.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.stat + +import kotlinx.datetime.Instant +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.bufferAlgebra +import space.kscience.kmath.series.MonotonicSeriesAlgebra +import space.kscience.kmath.series.SeriesAlgebra +import kotlin.time.Duration + +fun SeriesAlgebra.Companion.time(zero: Instant, step: Duration) = MonotonicSeriesAlgebra( + bufferAlgebra = Double.algebra.bufferAlgebra, + offsetToLabel = { zero + step * it }, + labelToOffset = { (it - zero) / step } +) \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt new file mode 100644 index 000000000..2bc363934 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.series + +import space.kscience.kmath.operations.BufferAlgebra +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.structures.Buffer +import kotlin.math.ceil +import kotlin.math.floor + +/** + * A [SeriesAlgebra] with reverse label to index transformation. + * + * @param [labelToOffset] returns floating point number that is used for index resolution. + */ +public class MonotonicSeriesAlgebra, out BA : BufferAlgebra, L : Comparable>( + bufferAlgebra: BA, + offsetToLabel: (Int) -> L, + private val labelToOffset: (L) -> Double, +) : SeriesAlgebra(bufferAlgebra, offsetToLabel) { + + public val Buffer.labelRange: ClosedRange get() = offsetToLabel(startOffset)..offsetToLabel(startOffset + size) + + /** + * An offset of the given [label] rounded down + */ + public fun floorOffset(label: L): Int = floor(labelToOffset(label)).toInt() + + /** + * An offset of the given [label] rounded up + */ + public fun ceilOffset(label: L): Int = ceil(labelToOffset(label)).toInt() + + /** + * Get value by label (rounded down) or return null if the value is outside series boundaries. + */ + public fun Buffer.getByLabelOrNull(label: L): T? = getByOffsetOrNull(floorOffset(label)) + + /** + * Get value by label (rounded down) or throw [IndexOutOfBoundsException] if the value is outside series boundaries. + */ + public fun Buffer.getByLabel(label: L): T = getByLabelOrNull(label) + ?: throw IndexOutOfBoundsException("Label $label is not in $labelRange") +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt index 45e392693..1847e33b6 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt @@ -24,7 +24,9 @@ internal operator fun IntRange.contains(other: IntRange): Boolean = (other.first //TODO add permutation sort //TODO check rank statistics - +/** + * A [Buffer] with an offset relative to the [SeriesAlgebra] zero. + */ public interface Series : Buffer { public val origin: Buffer @@ -54,9 +56,9 @@ private class SeriesImpl( /** * A scope to operation on series */ -public class SeriesAlgebra, out BA : BufferAlgebra, L>( +public open class SeriesAlgebra, out BA : BufferAlgebra, L>( override val bufferAlgebra: BA, - private val labelResolver: (Int) -> L, + public val offsetToLabel: (Int) -> L, ) : RingOps>, StatisticalAlgebra { /** @@ -107,20 +109,22 @@ public class SeriesAlgebra, out BA : BufferAlgebra, L>( */ public val Buffer.startOffset: Int get() = if (this is Series) position else 0 + public val Buffer.startLabel: L get() = offsetToLabel(startOffset) + /** * Build a new series positioned at [startOffset]. */ public fun series(size: Int, startOffset: Int = 0, block: A.(label: L) -> T): Series { return elementAlgebra.bufferFactory(size) { val index = it + startOffset - elementAlgebra.block(labelResolver(index)) + elementAlgebra.block(offsetToLabel(index)) }.moveTo(startOffset) } /** * Get a label buffer for given buffer. */ - public val Buffer.labels: List get() = offsetIndices.map(labelResolver) + public val Buffer.labels: List get() = offsetIndices.map(offsetToLabel) /** * Try to resolve element by label and return null if element with a given label is not found @@ -187,6 +191,8 @@ public class SeriesAlgebra, out BA : BufferAlgebra, L>( override fun add(left: Buffer, right: Buffer): Series = left.zip(right) { l, r -> l + r } override fun multiply(left: Buffer, right: Buffer): Buffer = left.zip(right) { l, r -> l * r } + + public companion object } public fun , BA : BufferAlgebra, L> BA.seriesAlgebra(labels: Iterable): SeriesAlgebra { From 4c1ffdb6d9db3ea37ff159ad95958184bb8fd517 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Tue, 14 Mar 2023 13:50:42 +0300 Subject: [PATCH 31/58] search for shortest path algorithm --- .../kmath/trajectory/DubinsObstacle.kt | 24 +++++++----- .../kscience/kmath/trajectory/DubinsTest.kt | 39 ++++++++++++++++++- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt index 6b247e55b..3aea139ec 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt @@ -136,7 +136,8 @@ public class DubinsObstacle( error("next tangent not found") } - public fun equals(other: DubinsObstacle): Boolean { + override fun equals(other: Any?): Boolean { + if (other == null || other !is DubinsObstacle) return false return this.circles == other.circles } } @@ -258,7 +259,7 @@ public fun constructTangentCircles(point: DoubleVector2D, val center2 = point + normalVectors(direction, r).second val p1 = center1 - point val p2 = center2 - point - return if (atan2(p1.y, p1.x) - atan2(p2.y, p2.x) in listOf(PI/2, -3*PI/2)) { + return if (atan2(p1.y, p1.x) - atan2(direction.y, direction.x) in listOf(PI/2, -3*PI/2)) { mapOf(DubinsPath.SimpleType.L to Circle2D(center1, r), DubinsPath.SimpleType.R to Circle2D(center2, r)) } @@ -270,7 +271,7 @@ public fun constructTangentCircles(point: DoubleVector2D, public fun sortedObstacles(currentObstacle: DubinsObstacle, obstacles: List): List { - return obstacles.sortedBy {norm(it.center - currentObstacle.center)}.reversed() + return obstacles.sortedBy {norm(it.center - currentObstacle.center)}//.reversed() } public fun tangentsAlongTheObstacle(initialCircle: Circle2D, @@ -389,13 +390,13 @@ public fun findAllPaths( } nextTangents = if (nextObstacle == finalObstacle) { nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection) and - (DubinsPath.toSimpleTypes(it.key)[0] == j)} + (DubinsPath.toSimpleTypes(it.key)[2] == j)} as MutableMap } else { nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection)} as MutableMap } - val tangentsAlong = mutableListOf() + var tangentsAlong = mutableListOf() for (tangent in nextTangents.values) { if (tangent.startCircle == line.last().endCircle) { val lengthMaxPossible = arcLength( @@ -413,7 +414,7 @@ public fun findAllPaths( tangent.lineSegment.begin, currentDirection) if (lengthCalculated > lengthMaxPossible) { - val tangentsAlong = tangentsAlongTheObstacle( + tangentsAlong = tangentsAlongTheObstacle( currentCircle, DubinsPath.toType(listOf( currentDirection, @@ -424,11 +425,11 @@ public fun findAllPaths( ) } else { - val tangentsAlong = mutableListOf() + tangentsAlong = mutableListOf() } } else { - val tangentsAlong = tangentsAlongTheObstacle( + tangentsAlong = tangentsAlongTheObstacle( currentCircle, DubinsPath.toType(listOf( currentDirection, @@ -456,6 +457,11 @@ public fun findAllPaths( )] = newOutputTangents } } + outputTangents[listOf( + i, + DubinsPath.SimpleType.S, + j + )] = newOutputTangents } for (lineId in outputTangents[listOf( i, @@ -505,7 +511,7 @@ public fun findAllPaths( )]!! + outputTangents[listOf( DubinsPath.SimpleType.R, DubinsPath.SimpleType.S, - DubinsPath.SimpleType.L)]!! + DubinsPath.SimpleType.R)]!! } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt index 16d77c84d..b26b21737 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt @@ -7,6 +7,8 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.DoubleVector2D +import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.Euclidean2DSpace.minus import space.kscience.kmath.geometry.Euclidean2DSpace.vector import kotlin.test.Test import kotlin.test.assertTrue @@ -68,6 +70,18 @@ class DubinsTest { obstacles) val length = pathLength(shortestPath(outputTangents)) println(length) + for (path in outputTangents) { + println(pathLength(path)) + println(path.size) + for (tangent in path) { +// println(tangent.route) +// println(tangent.startCircle) +// println(tangent.endCircle) +// println(Euclidean2DSpace.norm(tangent.lineSegment.end - tangent.lineSegment.begin)) + } + println() + println() + } } @Test fun outerTangentsTest1() { @@ -78,7 +92,6 @@ class DubinsTest { Circle2D(vector(5.0, 5.0), 1.0) ) println(outerTangents(DubinsObstacle(circles1), DubinsObstacle(circles2))) - assertTrue(false) } @Test fun outerTangentsTest2() { @@ -100,6 +113,28 @@ class DubinsTest { } } } - assertTrue(false) + } + @Test + fun tangentsTest() { + val circle1 = Circle2D(vector(1.0, 6.5), 0.5) + val circle2 = Circle2D(vector(1.0, 6.5), 0.5) + val obstacle1 = DubinsObstacle(listOf(circle1)) + val obstacle2 = DubinsObstacle(listOf(circle2)) + val tangent = dubinsTangentsToCircles(circle1, circle2, obstacle1, obstacle2) + println(tangent) + } + @Test + fun equalCircles() { + val circle1 = Circle2D(vector(1.0, 6.5), 0.5) + val circle2 = Circle2D(vector(1.0, 6.5), 0.5) + println(circle1 == circle2) + } + @Test + fun equalObstacles() { + val circle1 = Circle2D(vector(1.0, 6.5), 0.5) + val circle2 = Circle2D(vector(1.0, 6.5), 0.5) + val obstacle1 = DubinsObstacle(listOf(circle1)) + val obstacle2 = DubinsObstacle(listOf(circle2)) + println(obstacle1 == obstacle2) } } \ No newline at end of file From 28b85b0f53ba5d6e5e82777ffa8d57a770860baa Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 14 Mar 2023 20:13:34 +0300 Subject: [PATCH 32/58] Remove the choice of left-handed product. Refactor `vectorProduct`. Remove `leviChivita` function. --- .../kmath/geometry/Euclidean3DSpace.kt | 34 +++---------------- 1 file changed, 5 insertions(+), 29 deletions(-) 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 f1cf0bad2..38c252bc0 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 @@ -103,45 +103,21 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations< override fun DoubleVector3D.dot(other: DoubleVector3D): Double = x * other.x + y * other.y + z * other.z - private fun leviCivita(i: Int, j: Int, k: Int): Int = when { - // even permutation - i == 0 && j == 1 && k == 2 -> 1 - i == 1 && j == 2 && k == 0 -> 1 - i == 2 && j == 0 && k == 1 -> 1 - // odd permutations - i == 2 && j == 1 && k == 0 -> -1 - i == 0 && j == 2 && k == 1 -> -1 - i == 1 && j == 0 && k == 2 -> -1 - - else -> 0 - } - /** - * Compute vector product of [first] and [second]. The basis assumed to be right-handed if [rightBasis] is true and - * left-handed otherwise + * Compute vector product of [first] and [second]. The basis assumed to be right-handed. */ public fun vectorProduct( first: DoubleVector3D, second: DoubleVector3D, - rightBasis: Boolean = true, ): DoubleVector3D { - var x = 0.0 - var y = 0.0 - var z = 0.0 + val (x1, y1, z1) = first + val (x2, y2, z2) = second - for (j in (0..2)) { - for (k in (0..2)) { - x += leviCivita(0, j, k) * first[j] * second[k] - y += leviCivita(1, j, k) * first[j] * second[k] - z += leviCivita(2, j, k) * first[j] * second[k] - } - } - - return vector(x, y, z) * (if (rightBasis) 1 else -1) + return vector(y1 * z2 - y2 * z2, z1 * x2 - z2 * x2, x1 * y2 - x2 * y2) } /** - * Vector product with right basis + * Vector product with a right basis */ public infix fun DoubleVector3D.cross(other: DoubleVector3D): Vector3D = vectorProduct(this, other) From cd2ade881add23d4ac9b3f4b4d5ea594b6ad6d63 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 16 Mar 2023 09:33:17 +0300 Subject: [PATCH 33/58] Revert "Remove the choice of left-handed product. Refactor `vectorProduct`. Remove `leviChivita` function." This reverts commit 28b85b0f53ba5d6e5e82777ffa8d57a770860baa. --- .../kmath/geometry/Euclidean3DSpace.kt | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) 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 38c252bc0..f1cf0bad2 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 @@ -103,21 +103,45 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations< override fun DoubleVector3D.dot(other: DoubleVector3D): Double = x * other.x + y * other.y + z * other.z + private fun leviCivita(i: Int, j: Int, k: Int): Int = when { + // even permutation + i == 0 && j == 1 && k == 2 -> 1 + i == 1 && j == 2 && k == 0 -> 1 + i == 2 && j == 0 && k == 1 -> 1 + // odd permutations + i == 2 && j == 1 && k == 0 -> -1 + i == 0 && j == 2 && k == 1 -> -1 + i == 1 && j == 0 && k == 2 -> -1 + + else -> 0 + } + /** - * Compute vector product of [first] and [second]. The basis assumed to be right-handed. + * Compute vector product of [first] and [second]. The basis assumed to be right-handed if [rightBasis] is true and + * left-handed otherwise */ public fun vectorProduct( first: DoubleVector3D, second: DoubleVector3D, + rightBasis: Boolean = true, ): DoubleVector3D { - val (x1, y1, z1) = first - val (x2, y2, z2) = second + var x = 0.0 + var y = 0.0 + var z = 0.0 - return vector(y1 * z2 - y2 * z2, z1 * x2 - z2 * x2, x1 * y2 - x2 * y2) + for (j in (0..2)) { + for (k in (0..2)) { + x += leviCivita(0, j, k) * first[j] * second[k] + y += leviCivita(1, j, k) * first[j] * second[k] + z += leviCivita(2, j, k) * first[j] * second[k] + } + } + + return vector(x, y, z) * (if (rightBasis) 1 else -1) } /** - * Vector product with a right basis + * Vector product with right basis */ public infix fun DoubleVector3D.cross(other: DoubleVector3D): Vector3D = vectorProduct(this, other) From ef336af87ddb6df9acc8029e9633234ae5fe6851 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 16 Mar 2023 09:37:03 +0300 Subject: [PATCH 34/58] Fix vector product --- .gitignore | 3 ++- CHANGELOG.md | 1 + examples/build.gradle.kts | 14 +++++----- gradle.properties | 2 +- .../space/kscience/kmath/nd/BufferND.kt | 26 +++++++++++++++++++ .../integration/GaussIntegratorRuleFactory.kt | 2 -- .../kmath/geometry/Euclidean3DSpace.kt | 6 ++--- .../kmath/geometry/Euclidean3DSpaceTest.kt | 1 - 8 files changed, 40 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 34ddf3fd9..7713a9f96 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ out/ !/.idea/copyright/ !/.idea/scopes/ -/kotlin-js-store/yarn.lock +/gradle/yarn.lock + diff --git a/CHANGELOG.md b/CHANGELOG.md index 404366a03..c5fa3f372 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [Unreleased] ### Added +- Generic builders for `BufferND` and `MutableBufferND` - `NamedMatrix` - matrix with symbol-based indexing - `Expression` with default arguments - Type-aliases for numbers like `Float64` diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index f7b7794f3..50708eaa9 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -55,17 +55,19 @@ dependencies { implementation("space.kscience:plotlykt-server:0.5.0") } -kotlin.sourceSets.all { - with(languageSettings) { - optIn("kotlin.contracts.ExperimentalContracts") - optIn("kotlin.ExperimentalUnsignedTypes") - optIn("space.kscience.kmath.misc.UnstableKMathAPI") +kotlin { + jvmToolchain(11) + sourceSets.all { + with(languageSettings) { + optIn("kotlin.contracts.ExperimentalContracts") + optIn("kotlin.ExperimentalUnsignedTypes") + optIn("space.kscience.kmath.misc.UnstableKMathAPI") + } } } tasks.withType { kotlinOptions { - jvmTarget = "11" freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" } } diff --git a/gradle.properties b/gradle.properties index 048c9c9f3..cded5934c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin.native.ignoreDisabledTargets=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.14.3-kotlin-1.8.20-RC +toolsVersion=0.14.4-kotlin-1.8.20-RC org.gradle.parallel=true diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt index 55e8bbcf8..a6bab8be1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt @@ -7,7 +7,9 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.structures.MutableBufferFactory /** * Represents [StructureND] over [Buffer]. @@ -29,6 +31,18 @@ public open class BufferND( override fun toString(): String = StructureND.toString(this) } +/** + * Create a generic [BufferND] using provided [initializer] + */ +public fun BufferND( + shape: ShapeND, + bufferFactory: BufferFactory = BufferFactory.boxing(), + initializer: (IntArray) -> T, +): BufferND { + val strides = Strides(shape) + return BufferND(strides, bufferFactory(strides.linearSize) { initializer(strides.index(it)) }) +} + ///** // * Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferND] // */ @@ -67,6 +81,18 @@ public open class MutableBufferND( } } +/** + * Create a generic [BufferND] using provided [initializer] + */ +public fun MutableBufferND( + shape: ShapeND, + bufferFactory: MutableBufferFactory = MutableBufferFactory.boxing(), + initializer: (IntArray) -> T, +): MutableBufferND { + val strides = Strides(shape) + return MutableBufferND(strides, bufferFactory(strides.linearSize) { initializer(strides.index(it)) }) +} + ///** // * Transform structure to a new structure using provided [MutableBufferFactory] and optimizing if argument is [MutableBufferND] // */ 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 fc76ea819..4ed4965c9 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 @@ -9,7 +9,6 @@ import space.kscience.kmath.operations.mapToBuffer import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer -import kotlin.jvm.Synchronized import kotlin.math.ulp import kotlin.native.concurrent.ThreadLocal @@ -57,7 +56,6 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { private val cache = HashMap, Buffer>>() - @Synchronized private fun getOrBuildRule(numPoints: Int): Pair, Buffer> = cache.getOrPut(numPoints) { buildRule(numPoints) } 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 f1cf0bad2..3059cefe6 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 @@ -117,13 +117,11 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations< } /** - * Compute vector product of [first] and [second]. The basis assumed to be right-handed if [rightBasis] is true and - * left-handed otherwise + * Compute vector product of [first] and [second]. The basis assumed to be right-handed. */ public fun vectorProduct( first: DoubleVector3D, second: DoubleVector3D, - rightBasis: Boolean = true, ): DoubleVector3D { var x = 0.0 var y = 0.0 @@ -137,7 +135,7 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations< } } - return vector(x, y, z) * (if (rightBasis) 1 else -1) + return vector(x, y, z) } /** diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt index 291b0ad47..20e112ad1 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt @@ -78,7 +78,6 @@ internal class Euclidean3DSpaceTest { assertVectorEquals(zAxis, vectorProduct(xAxis, yAxis)) assertVectorEquals(zAxis, xAxis cross yAxis) assertVectorEquals(-zAxis, vectorProduct(yAxis, xAxis)) - assertVectorEquals(zAxis, vectorProduct(yAxis, xAxis, rightBasis = false)) } @Test From c36af3515e08adb3595a95a6470309eb149fc0c9 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 19 Mar 2023 18:39:27 +0300 Subject: [PATCH 35/58] Update trajectory description --- kmath-trajectory/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-trajectory/build.gradle.kts b/kmath-trajectory/build.gradle.kts index 689c3265b..32b87bb06 100644 --- a/kmath-trajectory/build.gradle.kts +++ b/kmath-trajectory/build.gradle.kts @@ -15,7 +15,7 @@ kscience{ } readme { - description = "Path and trajectory optimization" - maturity = space.kscience.gradle.Maturity.PROTOTYPE + description = "Path and trajectory optimization (to be moved to a separate project)" + maturity = space.kscience.gradle.Maturity.DEPRECATED propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) } From 62c8610a9ebb45d5c450ef283ce21ec5e0d4de3c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 19 Mar 2023 19:16:46 +0300 Subject: [PATCH 36/58] Update publishing CD --- .github/workflows/publish.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 794881b09..8087195c2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,7 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v3.0.0 - - uses: actions/setup-java@v3.0.0 + - uses: actions/setup-java@v3.10.0 with: java-version: 11 distribution: liberica @@ -26,26 +26,24 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- - - uses: gradle/wrapper-validation-action@v1.0.4 - name: Publish Windows Artifacts if: matrix.os == 'windows-latest' - uses: gradle/gradle-build-action@v2.1.5 + uses: gradle/gradle-build-action@v2.4.0 with: arguments: | - releaseAll + publishAllPublicationsToSpaceRepository -Ppublishing.enabled=true - -Ppublishing.sonatype=false -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} - name: Publish Mac Artifacts if: matrix.os == 'macOS-latest' - uses: gradle/gradle-build-action@v2.1.5 + uses: gradle/gradle-build-action@v2.4.0 with: arguments: | - releaseMacosX64 - releaseIosArm64 - releaseIosX64 + publishMacosX64PublicationsToSpaceRepository + publishIosX64PublicationsToSpaceRepository + publishIosArm64PublicationsToSpaceRepository + publishIosSimulatorArm64PublicationsToSpaceRepository -Ppublishing.enabled=true - -Ppublishing.sonatype=false -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} From c442eb7e94ff562688b171cfcdf7deb829b71d47 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 19 Mar 2023 19:41:31 +0300 Subject: [PATCH 37/58] Fix publish task names --- .github/workflows/publish.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8087195c2..0ac8805e0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -40,10 +40,10 @@ jobs: uses: gradle/gradle-build-action@v2.4.0 with: arguments: | - publishMacosX64PublicationsToSpaceRepository - publishIosX64PublicationsToSpaceRepository - publishIosArm64PublicationsToSpaceRepository - publishIosSimulatorArm64PublicationsToSpaceRepository + publishMacosX64PublicationToSpaceRepository + publishIosX64PublicationToSpaceRepository + publishIosArm64PublicationToSpaceRepository + publishIosSimulatorArm64PublicationToSpaceRepository -Ppublishing.enabled=true -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} From 81213eb94340fc87ae6958d30e598d234439dc35 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Tue, 21 Mar 2023 12:04:27 +0300 Subject: [PATCH 38/58] search for shortest path algorithm --- .../kmath/trajectory/DubinsObstacle.kt | 87 +++++++++---------- .../kscience/kmath/trajectory/DubinsTest.kt | 50 +---------- 2 files changed, 45 insertions(+), 92 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt index 3aea139ec..896803fba 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt @@ -39,8 +39,6 @@ public class DubinsObstacle( var angle2: Double val routes = mapOf( DubinsPath.Type.RSR to Pair(radius, other.radius), -// DubinsPath.Type.RSL to Pair(radius, -other.radius), -// DubinsPath.Type.LSR to Pair(-radius, other.radius), DubinsPath.Type.LSL to Pair(-radius, -other.radius) ) return buildMap { @@ -76,8 +74,7 @@ public class DubinsObstacle( } } } -// val firstCircles = this.circles.slice(-this.circles.size..-1) -// val secondCircles = this.circles.slice(-this.circles.size+1..0) + val firstCircles = this.circles val secondCircles = this.circles.slice(1..this.circles.lastIndex) + this.circles[0] @@ -149,7 +146,7 @@ public data class DubinsTangent(val startCircle: Circle2D, val lineSegment: LineSegment2D, val route: PathTypes) -public fun LineSegment2D.intersectSegment(other: LineSegment2D): Boolean { +private fun LineSegment2D.intersectSegment(other: LineSegment2D): Boolean { fun crossProduct(v1: DoubleVector2D, v2: DoubleVector2D): Double { return v1.x * v2.y - v1.y * v2.x } @@ -164,7 +161,7 @@ public fun LineSegment2D.intersectSegment(other: LineSegment2D): Boolean { return true } -public fun LineSegment2D.intersectCircle(circle: Circle2D): Boolean { +private fun LineSegment2D.intersectCircle(circle: Circle2D): Boolean { val a = (this.begin.x - this.end.x).pow(2.0) + (this.begin.y - this.end.y).pow(2.0) val b = 2 * ((this.begin.x - this.end.x) * (this.end.x - circle.center.x) + (this.begin.y - this.end.y) * (this.end.y - circle.center.y)) @@ -184,7 +181,7 @@ public fun LineSegment2D.intersectCircle(circle: Circle2D): Boolean { return false } -public fun DubinsTangent.intersectObstacle(obstacle: DubinsObstacle): Boolean { +private fun DubinsTangent.intersectObstacle(obstacle: DubinsObstacle): Boolean { for (tangent in obstacle.tangents) { if (this.lineSegment.intersectSegment(tangent.lineSegment)) { return true @@ -198,7 +195,7 @@ public fun DubinsTangent.intersectObstacle(obstacle: DubinsObstacle): Boolean { return false } -public fun outerTangents(first: DubinsObstacle, second: DubinsObstacle): MutableMap { +private fun outerTangents(first: DubinsObstacle, second: DubinsObstacle): MutableMap { return buildMap { for (circle1 in first.circles) { for (circle2 in second.circles) { @@ -216,7 +213,7 @@ public fun outerTangents(first: DubinsObstacle, second: DubinsObstacle): Mutable }.toMutableMap() } -public fun arcLength(circle: Circle2D, +private fun arcLength(circle: Circle2D, point1: DoubleVector2D, point2: DoubleVector2D, route: DubinsPath.SimpleType): Double { @@ -245,14 +242,14 @@ public fun arcLength(circle: Circle2D, return circle.radius * angle } -public fun normalVectors(v: DoubleVector2D, r: Double): Pair { +private fun normalVectors(v: DoubleVector2D, r: Double): Pair { return Pair( r * vector(v.y / norm(v), -v.x / norm(v)), r * vector(-v.y / norm(v), v.x / norm(v)) ) } -public fun constructTangentCircles(point: DoubleVector2D, +private fun constructTangentCircles(point: DoubleVector2D, direction: DoubleVector2D, r: Double): Map { val center1 = point + normalVectors(direction, r).first @@ -269,12 +266,12 @@ public fun constructTangentCircles(point: DoubleVector2D, } } -public fun sortedObstacles(currentObstacle: DubinsObstacle, +private fun sortedObstacles(currentObstacle: DubinsObstacle, obstacles: List): List { return obstacles.sortedBy {norm(it.center - currentObstacle.center)}//.reversed() } -public fun tangentsAlongTheObstacle(initialCircle: Circle2D, +private fun tangentsAlongTheObstacle(initialCircle: Circle2D, initialRoute: DubinsPath.Type, finalCircle: Circle2D, obstacle: DubinsObstacle): MutableList { @@ -288,7 +285,7 @@ public fun tangentsAlongTheObstacle(initialCircle: Circle2D, return dubinsTangents } -public fun allFinished(paths: List>, +private fun allFinished(paths: List>, finalObstacle: DubinsObstacle): Boolean { for (path in paths) { if (path.last().endObstacle != finalObstacle) { @@ -333,28 +330,28 @@ public fun findAllPaths( finalPoint, finalDirection, finalRadius) - var outputTangents = mutableMapOf>>() + var path = mutableMapOf>>() for (i in listOf(DubinsPath.SimpleType.L, DubinsPath.SimpleType.R)) { for (j in listOf(DubinsPath.SimpleType.L, DubinsPath.SimpleType.R)) { val finalCircle = finalCircles[j]!! val finalObstacle = DubinsObstacle(listOf(finalCircle)) - outputTangents[listOf(i, - DubinsPath.SimpleType.S, - j)] = mutableListOf( - mutableListOf(DubinsTangent( - initialCircles[i]!!, - initialCircles[i]!!, - DubinsObstacle(listOf(initialCircles[i]!!)), - DubinsObstacle(listOf(initialCircles[i]!!)), - LineSegment2D(startingPoint, startingPoint), - listOf(i, DubinsPath.SimpleType.S, i) - ))) - var currentObstacle = DubinsObstacle(listOf(initialCircles[i]!!)) - while (!allFinished(outputTangents[listOf(i, + path[listOf(i, + DubinsPath.SimpleType.S, + j)] = mutableListOf( + mutableListOf(DubinsTangent( + initialCircles[i]!!, + initialCircles[i]!!, + DubinsObstacle(listOf(initialCircles[i]!!)), + DubinsObstacle(listOf(initialCircles[i]!!)), + LineSegment2D(startingPoint, startingPoint), + listOf(i, DubinsPath.SimpleType.S, i) + ))) + //var currentObstacle = DubinsObstacle(listOf(initialCircles[i]!!)) + while (!allFinished(path[listOf(i, DubinsPath.SimpleType.S, j)]!!, finalObstacle)) { - var newOutputTangents = mutableListOf>() - for (line in outputTangents[listOf(i, + var newPaths = mutableListOf>() + for (line in path[listOf(i, DubinsPath.SimpleType.S, j)]!!) { var currentCircle = line.last().endCircle @@ -439,41 +436,41 @@ public fun findAllPaths( currentObstacle ) } - newOutputTangents.add((line + tangentsAlong + listOf(tangent)).toMutableList()) + newPaths.add((line + tangentsAlong + listOf(tangent)).toMutableList()) } - outputTangents[listOf( + path[listOf( i, DubinsPath.SimpleType.S, j - )] = newOutputTangents + )] = newPaths } else { // minor changes from Python code - newOutputTangents.add(line) - outputTangents[listOf( + newPaths.add(line) + path[listOf( i, DubinsPath.SimpleType.S, j - )] = newOutputTangents + )] = newPaths } } - outputTangents[listOf( + path[listOf( i, DubinsPath.SimpleType.S, j - )] = newOutputTangents + )] = newPaths } - for (lineId in outputTangents[listOf( + for (lineId in path[listOf( i, DubinsPath.SimpleType.S, j )]!!.indices) { - val lastDirection = outputTangents[listOf( + val lastDirection = path[listOf( i, DubinsPath.SimpleType.S, j )]!![lineId].last().route[2] - outputTangents[listOf( + path[listOf( i, DubinsPath.SimpleType.S, j @@ -496,19 +493,19 @@ public fun findAllPaths( } } } - return outputTangents[listOf( + return path[listOf( DubinsPath.SimpleType.L, DubinsPath.SimpleType.S, DubinsPath.SimpleType.L - )]!! + outputTangents[listOf( + )]!! + path[listOf( DubinsPath.SimpleType.L, DubinsPath.SimpleType.S, DubinsPath.SimpleType.R - )]!! + outputTangents[listOf( + )]!! + path[listOf( DubinsPath.SimpleType.R, DubinsPath.SimpleType.S, DubinsPath.SimpleType.L - )]!! + outputTangents[listOf( + )]!! + path[listOf( DubinsPath.SimpleType.R, DubinsPath.SimpleType.S, DubinsPath.SimpleType.R)]!! diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt index b26b21737..a78a5317d 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt @@ -6,12 +6,8 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.DoubleVector2D -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.Euclidean2DSpace.minus import space.kscience.kmath.geometry.Euclidean2DSpace.vector import kotlin.test.Test -import kotlin.test.assertTrue class DubinsTest { @Test @@ -60,7 +56,7 @@ class DubinsTest { Circle2D(vector(9.0, 4.0), 0.5) )) ) - val outputTangents = findAllPaths( + val paths = findAllPaths( startPoint, startDirection, startRadius, @@ -68,9 +64,9 @@ class DubinsTest { finalDirection, finalRadius, obstacles) - val length = pathLength(shortestPath(outputTangents)) + val length = pathLength(shortestPath(paths)) println(length) - for (path in outputTangents) { + for (path in paths) { println(pathLength(path)) println(path.size) for (tangent in path) { @@ -84,46 +80,6 @@ class DubinsTest { } } @Test - fun outerTangentsTest1() { - // works incorrectly - val circles1 = listOf( - Circle2D(vector(0.0, 0.0), 1.0)) - val circles2 = listOf( - Circle2D(vector(5.0, 5.0), 1.0) - ) - println(outerTangents(DubinsObstacle(circles1), DubinsObstacle(circles2))) - } - @Test - fun outerTangentsTest2() { - // works incorrectly - val circles1 = listOf( - Circle2D(vector(0.0, 0.0), 1.0), - Circle2D(vector( 2.0, 0.0), 1.0)) - val circles2 = listOf( - Circle2D(vector(5.0, 5.0), 1.0), - Circle2D(vector(7.0, 5.0), 1.0) - ) - println(outerTangents(DubinsObstacle(circles1), DubinsObstacle(circles2))) - - for (circle1 in circles1) { - for (circle2 in circles2) { - for (tangent in dubinsTangentsToCircles(circle1, circle2, - DubinsObstacle(circles1), DubinsObstacle(circles2))) { - println(tangent) - } - } - } - } - @Test - fun tangentsTest() { - val circle1 = Circle2D(vector(1.0, 6.5), 0.5) - val circle2 = Circle2D(vector(1.0, 6.5), 0.5) - val obstacle1 = DubinsObstacle(listOf(circle1)) - val obstacle2 = DubinsObstacle(listOf(circle2)) - val tangent = dubinsTangentsToCircles(circle1, circle2, obstacle1, obstacle2) - println(tangent) - } - @Test fun equalCircles() { val circle1 = Circle2D(vector(1.0, 6.5), 0.5) val circle2 = Circle2D(vector(1.0, 6.5), 0.5) From 56bba749c026863a02ed6eb461d85d29d56e81e6 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 22 Mar 2023 10:54:24 +0300 Subject: [PATCH 39/58] Update publishing --- .github/workflows/publish.yml | 4 ++-- gradle.properties | 2 +- .../kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0ac8805e0..471388364 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -32,7 +32,7 @@ jobs: with: arguments: | publishAllPublicationsToSpaceRepository - -Ppublishing.enabled=true + -Ppublishing.targets=all -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} - name: Publish Mac Artifacts @@ -44,6 +44,6 @@ jobs: publishIosX64PublicationToSpaceRepository publishIosArm64PublicationToSpaceRepository publishIosSimulatorArm64PublicationToSpaceRepository - -Ppublishing.enabled=true + -Ppublishing.targets=all -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} diff --git a/gradle.properties b/gradle.properties index cded5934c..262bcabfb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin.native.ignoreDisabledTargets=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.14.4-kotlin-1.8.20-RC +toolsVersion=0.14.5-kotlin-1.8.20-RC org.gradle.parallel=true 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 2fd4f0057..48be93b87 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 @@ -8,6 +8,7 @@ package space.kscience.kmath.coroutines import kotlinx.coroutines.* +import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.produce import kotlinx.coroutines.flow.* @@ -57,7 +58,7 @@ public suspend fun AsyncFlow.collect(concurrency: Int, collector: FlowCol coroutineScope { //Starting up to N deferred coroutines ahead of time - val channel = produce(capacity = concurrency - 1) { + val channel: ReceiveChannel> = produce(capacity = concurrency - 1) { deferredFlow.collect { value -> value.start(this@coroutineScope) send(value) From d87eefcaa359f92a9a35c34784e196f767aa2836 Mon Sep 17 00:00:00 2001 From: SPC-code <112205870+SPC-code@users.noreply.github.com> Date: Wed, 22 Mar 2023 18:04:16 +0300 Subject: [PATCH 40/58] Add macOsArm64 to publish.yml --- .github/workflows/publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 471388364..ab9243f15 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -41,6 +41,7 @@ jobs: with: arguments: | publishMacosX64PublicationToSpaceRepository + publishMacosArm64PublicationToSpaceRepository publishIosX64PublicationToSpaceRepository publishIosArm64PublicationToSpaceRepository publishIosSimulatorArm64PublicationToSpaceRepository From ea5305c8d878e910128543f44453fe7e20294164 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Fri, 24 Mar 2023 10:28:02 +0300 Subject: [PATCH 41/58] search for shortest path algorithm --- .../kscience/kmath/trajectory/DubinsTest.kt | 18 ++++-------------- .../kscience/kmath/trajectory/TangentTest.kt | 15 +-------------- 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt index a78a5317d..fdc3bd3c7 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt @@ -7,7 +7,9 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace.vector +import space.kscience.kmath.geometry.equalsFloat import kotlin.test.Test +import kotlin.test.assertTrue class DubinsTest { @Test @@ -31,7 +33,7 @@ class DubinsTest { finalRadius, obstacles) val length = pathLength(shortestPath(outputTangents)) - println(length) + assertTrue(length.equalsFloat(27.2113183)) } @Test @@ -65,19 +67,7 @@ class DubinsTest { finalRadius, obstacles) val length = pathLength(shortestPath(paths)) - println(length) - for (path in paths) { - println(pathLength(path)) - println(path.size) - for (tangent in path) { -// println(tangent.route) -// println(tangent.startCircle) -// println(tangent.endCircle) -// println(Euclidean2DSpace.norm(tangent.lineSegment.end - tangent.lineSegment.begin)) - } - println() - println() - } + assertTrue(length.equalsFloat(28.9678224)) } @Test fun equalCircles() { diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt index 6d4493124..2ae89038c 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.geometry.LineSegment import space.kscience.kmath.geometry.equalsLine import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFailsWith import kotlin.test.assertTrue class TangentTest { @@ -60,18 +61,4 @@ class TangentTest { val c2 = Circle2D(vector(0.0, 0.0), 1.0) assertEquals(emptyMap(), c1.tangentsToCircle(c2)) } -// -// @Test -// fun nonExistingTangents() { -// assertFailsWith { -// val c1 = Circle2D(vector(0.0, 0.0), 1.0) -// val c2 = Circle2D(vector(2.0, 0.0), 1.0) -// c1.tangentsToCircle(c2) -// } -// assertFailsWith { -// val c1 = Circle2D(vector(0.0, 0.0), 1.0) -// val c2 = Circle2D(vector(0.5, 0.0), 1.0) -// c1.tangentsToCircle(c2) -// } -// } } \ No newline at end of file From 24c39c97cd4b9186a8445dedffff4c7fcc3e5ca1 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Fri, 24 Mar 2023 10:30:13 +0300 Subject: [PATCH 42/58] search for shortest path algorithm --- .../kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt index 896803fba..ee0b58a15 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt @@ -255,7 +255,6 @@ private fun constructTangentCircles(point: DoubleVector2D, val center1 = point + normalVectors(direction, r).first val center2 = point + normalVectors(direction, r).second val p1 = center1 - point - val p2 = center2 - point return if (atan2(p1.y, p1.x) - atan2(direction.y, direction.x) in listOf(PI/2, -3*PI/2)) { mapOf(DubinsPath.SimpleType.L to Circle2D(center1, r), DubinsPath.SimpleType.R to Circle2D(center2, r)) From 11dd4088d977f5c2ecacfe264e77bf432a44a8e3 Mon Sep 17 00:00:00 2001 From: Artyom Degtyarev Date: Fri, 24 Mar 2023 10:39:51 +0300 Subject: [PATCH 43/58] search for shortest path algorithm --- .../kotlin/space/kscience/kmath/trajectory/DubinsTest.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt index fdc3bd3c7..07e9861c7 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt @@ -9,6 +9,7 @@ import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace.vector import space.kscience.kmath.geometry.equalsFloat import kotlin.test.Test +import kotlin.test.assertEquals import kotlin.test.assertTrue class DubinsTest { @@ -33,7 +34,7 @@ class DubinsTest { finalRadius, obstacles) val length = pathLength(shortestPath(outputTangents)) - assertTrue(length.equalsFloat(27.2113183)) + assertEquals(length, 27.2113183, 1e-6) } @Test @@ -67,7 +68,7 @@ class DubinsTest { finalRadius, obstacles) val length = pathLength(shortestPath(paths)) - assertTrue(length.equalsFloat(28.9678224)) + assertEquals(length,28.9678224, 1e-6) } @Test fun equalCircles() { From f809e40791f73ab33bb05d3a23947fe8af310f98 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Apr 2023 11:42:58 +0300 Subject: [PATCH 44/58] Disentangle obstacle code phase 1 --- .../kmath/trajectory/DubinsObstacle.kt | 519 --------------- .../kscience/kmath/trajectory/DubinsPath.kt | 241 ++----- .../kscience/kmath/trajectory/Obstacle.kt | 619 ++++++++++++++++++ .../kscience/kmath/trajectory/Trajectory2D.kt | 34 +- .../kscience/kmath/trajectory/tangent.kt | 114 ---- .../trajectory/{dubins => }/DubinsTests.kt | 7 +- .../{DubinsTest.kt => ObstacleTest.kt} | 65 +- .../kmath/trajectory/segments/ArcTests.kt | 3 +- 8 files changed, 748 insertions(+), 854 deletions(-) delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt rename kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/{dubins => }/DubinsTests.kt (93%) rename kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/{DubinsTest.kt => ObstacleTest.kt} (55%) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt deleted file mode 100644 index ee0b58a15..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsObstacle.kt +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.trajectory - -import space.kscience.kmath.geometry.* -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Euclidean2DSpace.minus -import space.kscience.kmath.geometry.Euclidean2DSpace.plus -import space.kscience.kmath.geometry.Euclidean2DSpace.times -import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import space.kscience.kmath.geometry.Euclidean2DSpace.norm -import space.kscience.kmath.operations.DoubleField.pow -import kotlin.math.* - -public fun LineSegment2D.length(): Double { - return ((end.y - begin.y).pow(2.0) + (end.x - begin.x).pow(2.0)).pow(0.5) -} -public class DubinsObstacle( - public val circles: List -) { - public val tangents: List = boundaryTangents().first - public val boundaryRoute: DubinsPath.Type = boundaryTangents().second - public val center: Vector2D = - vector(this.circles.sumOf{it.center.x} / this.circles.size, - this.circles.sumOf{it.center.y} / this.circles.size) - private fun boundaryTangents(): Pair, DubinsPath.Type> { - // outer tangents for a polygon circles can be either lsl or rsr - - fun Circle2D.dubinsTangentsToCircles( - other: Circle2D, - ): Map = with(Euclidean2DSpace) { - val line = LineSegment(center, other.center) - val d = line.begin.distanceTo(line.end) - val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) - var r: Double - var angle2: Double - val routes = mapOf( - DubinsPath.Type.RSR to Pair(radius, other.radius), - DubinsPath.Type.LSL to Pair(-radius, -other.radius) - ) - return buildMap { - for ((route, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - if (d * d >= r * r) { - val l = (d * d - r * r).pow(0.5) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, l) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, l) - } - val w = vector(-cos(angle2), sin(angle2)) - put(route, DubinsTangent(Circle2D(center, radius), - other, - this@DubinsObstacle, - this@DubinsObstacle, - LineSegment2D( - center + w * r1, - other.center + w * r2 - ), - DubinsPath.toSimpleTypes(route)) - ) - } else { - throw Exception("Circles should not intersect") - } - } - } - } - - val firstCircles = this.circles - val secondCircles = this.circles.slice(1..this.circles.lastIndex) + - this.circles[0] - val lslTangents = firstCircles.zip(secondCircles) - {a, b -> a.dubinsTangentsToCircles(b)[DubinsPath.Type.LSL]!!} - val rsrTangents = firstCircles.zip(secondCircles) - {a, b -> a.dubinsTangentsToCircles(b)[DubinsPath.Type.RSR]!!} - val center = vector( - this.circles.sumOf { it.center.x } / this.circles.size, - this.circles.sumOf { it.center.y } / this.circles.size - ) - val lslToCenter = lslTangents.sumOf { it.lineSegment.begin.distanceTo(center) } + - lslTangents.sumOf { it.lineSegment.end.distanceTo(center) } - val rsrToCenter = rsrTangents.sumOf { it.lineSegment.begin.distanceTo(center) } + - rsrTangents.sumOf { it.lineSegment.end.distanceTo(center) } - return if (rsrToCenter >= lslToCenter) { - Pair(rsrTangents, DubinsPath.Type.RSR) - } else { - Pair(lslTangents, DubinsPath.Type.LSL) - } - } - - public fun nextTangent(circle: Circle2D, route: DubinsPath.Type): DubinsTangent { - if (route == this.boundaryRoute) { - for (i in this.circles.indices) { - if (this.circles[i] == circle) { - return this.tangents[i] - } - } - } - else { - for (i in this.circles.indices) { - if (this.circles[i] == circle) { - if (i > 0) { - return DubinsTangent(this.circles[i], - this.circles[i-1], - this, - this, - LineSegment2D(this.tangents[i-1].lineSegment.end, - this.tangents[i-1].lineSegment.begin), - DubinsPath.toSimpleTypes(route)) - } - else { - return DubinsTangent(this.circles[0], - this.circles.last(), - this, - this, - LineSegment2D(this.tangents.last().lineSegment.end, - this.tangents.last().lineSegment.begin), - DubinsPath.toSimpleTypes(route)) - } - } - } - } - - error("next tangent not found") - } - - override fun equals(other: Any?): Boolean { - if (other == null || other !is DubinsObstacle) return false - return this.circles == other.circles - } -} - -public data class DubinsTangent(val startCircle: Circle2D, - val endCircle: Circle2D, - val startObstacle: DubinsObstacle, - val endObstacle: DubinsObstacle, - val lineSegment: LineSegment2D, - val route: PathTypes) - -private fun LineSegment2D.intersectSegment(other: LineSegment2D): Boolean { - fun crossProduct(v1: DoubleVector2D, v2: DoubleVector2D): Double { - return v1.x * v2.y - v1.y * v2.x - } - if (crossProduct(other.begin - this.begin, other.end - this.begin).sign == - crossProduct(other.begin - this.end, other.end - this.end).sign) { - return false - } - if (crossProduct(this.begin - other.begin, this.end - other.begin).sign == - crossProduct(this.begin - other.end, this.end - other.end).sign) { - return false - } - return true -} - -private fun LineSegment2D.intersectCircle(circle: Circle2D): Boolean { - val a = (this.begin.x - this.end.x).pow(2.0) + (this.begin.y - this.end.y).pow(2.0) - val b = 2 * ((this.begin.x - this.end.x) * (this.end.x - circle.center.x) + - (this.begin.y - this.end.y) * (this.end.y - circle.center.y)) - val c = (this.end.x - circle.center.x).pow(2.0) + (this.end.y - circle.center.y).pow(2.0) - - circle.radius.pow(2.0) - val d = b.pow(2.0) - 4 * a * c - if (d < 1e-6) { - return false - } - else { - val t1 = (-b - d.pow(0.5)) * 0.5 / a - val t2 = (-b + d.pow(0.5)) * 0.5 / a - if (((0 < t1) and (t1 < 1)) or ((0 < t2) and (t2 < 1))) { - return true - } - } - return false -} - -private fun DubinsTangent.intersectObstacle(obstacle: DubinsObstacle): Boolean { - for (tangent in obstacle.tangents) { - if (this.lineSegment.intersectSegment(tangent.lineSegment)) { - return true - } - } - for (circle in obstacle.circles) { - if (this.lineSegment.intersectCircle(circle)) { - return true - } - } - return false -} - -private fun outerTangents(first: DubinsObstacle, second: DubinsObstacle): MutableMap { - return buildMap { - for (circle1 in first.circles) { - for (circle2 in second.circles) { - for (tangent in dubinsTangentsToCircles(circle1, circle2, first, second)) { - if (!(tangent.value.intersectObstacle(first)) - and !(tangent.value.intersectObstacle(second))) { - put( - tangent.key, - tangent.value - ) - } - } - } - } - }.toMutableMap() -} - -private fun arcLength(circle: Circle2D, - point1: DoubleVector2D, - point2: DoubleVector2D, - route: DubinsPath.SimpleType): Double { - val phi1 = atan2(point1.y - circle.center.y, point1.x - circle.center.x) - val phi2 = atan2(point2.y - circle.center.y, point2.x - circle.center.x) - var angle = 0.0 - when (route) { - DubinsPath.SimpleType.L -> { - angle = if (phi2 >= phi1) { - phi2 - phi1 - } else { - 2 * PI + phi2 - phi1 - } - } - DubinsPath.SimpleType.R -> { - angle = if (phi2 >= phi1) { - 2 * PI - (phi2 - phi1) - } else { - -(phi2 - phi1) - } - } - DubinsPath.SimpleType.S -> { - error("L or R route is expected") - } - } - return circle.radius * angle -} - -private fun normalVectors(v: DoubleVector2D, r: Double): Pair { - return Pair( - r * vector(v.y / norm(v), -v.x / norm(v)), - r * vector(-v.y / norm(v), v.x / norm(v)) - ) -} - -private fun constructTangentCircles(point: DoubleVector2D, - direction: DoubleVector2D, - r: Double): Map { - val center1 = point + normalVectors(direction, r).first - val center2 = point + normalVectors(direction, r).second - val p1 = center1 - point - return if (atan2(p1.y, p1.x) - atan2(direction.y, direction.x) in listOf(PI/2, -3*PI/2)) { - mapOf(DubinsPath.SimpleType.L to Circle2D(center1, r), - DubinsPath.SimpleType.R to Circle2D(center2, r)) - } - else { - mapOf(DubinsPath.SimpleType.L to Circle2D(center2, r), - DubinsPath.SimpleType.R to Circle2D(center1, r)) - } -} - -private fun sortedObstacles(currentObstacle: DubinsObstacle, - obstacles: List): List { - return obstacles.sortedBy {norm(it.center - currentObstacle.center)}//.reversed() -} - -private fun tangentsAlongTheObstacle(initialCircle: Circle2D, - initialRoute: DubinsPath.Type, - finalCircle: Circle2D, - obstacle: DubinsObstacle): MutableList { - val dubinsTangents = mutableListOf() - var tangent = obstacle.nextTangent(initialCircle, initialRoute) - dubinsTangents.add(tangent) - while (tangent.endCircle != finalCircle) { - tangent = obstacle.nextTangent(tangent.endCircle, initialRoute) - dubinsTangents.add(tangent) - } - return dubinsTangents -} - -private fun allFinished(paths: List>, - finalObstacle: DubinsObstacle): Boolean { - for (path in paths) { - if (path.last().endObstacle != finalObstacle) { - return false - } - } - return true -} - -public fun pathLength(path: List): Double { - val tangentsLength = path.sumOf{norm(it.lineSegment.end - it.lineSegment.begin)} - val arcsLength = buildList{ - for (i in 1..path.lastIndex) { - add(arcLength(path[i].startCircle, - path[i-1].lineSegment.end, - path[i].lineSegment.begin, - path[i].route[0])) - } - }.sum() - return tangentsLength + arcsLength -} - -public fun shortestPath(path: List>): List { - return path.sortedBy { pathLength(it) }[0] -} - -public typealias Path = List -public fun findAllPaths( - startingPoint: DoubleVector2D, - startingDirection: DoubleVector2D, - startingRadius: Double, - finalPoint: DoubleVector2D, - finalDirection: DoubleVector2D, - finalRadius: Double, - obstacles: List -): List> { - val initialCircles = constructTangentCircles( - startingPoint, - startingDirection, - startingRadius) - val finalCircles = constructTangentCircles( - finalPoint, - finalDirection, - finalRadius) - var path = mutableMapOf>>() - for (i in listOf(DubinsPath.SimpleType.L, DubinsPath.SimpleType.R)) { - for (j in listOf(DubinsPath.SimpleType.L, DubinsPath.SimpleType.R)) { - val finalCircle = finalCircles[j]!! - val finalObstacle = DubinsObstacle(listOf(finalCircle)) - path[listOf(i, - DubinsPath.SimpleType.S, - j)] = mutableListOf( - mutableListOf(DubinsTangent( - initialCircles[i]!!, - initialCircles[i]!!, - DubinsObstacle(listOf(initialCircles[i]!!)), - DubinsObstacle(listOf(initialCircles[i]!!)), - LineSegment2D(startingPoint, startingPoint), - listOf(i, DubinsPath.SimpleType.S, i) - ))) - //var currentObstacle = DubinsObstacle(listOf(initialCircles[i]!!)) - while (!allFinished(path[listOf(i, - DubinsPath.SimpleType.S, - j)]!!, finalObstacle)) { - var newPaths = mutableListOf>() - for (line in path[listOf(i, - DubinsPath.SimpleType.S, - j)]!!) { - var currentCircle = line.last().endCircle - var currentDirection = line.last().route.last() - var currentObstacle = line.last().endObstacle - var nextObstacle: DubinsObstacle? = null - if (currentObstacle != finalObstacle) { - var tangentToFinal = outerTangents(currentObstacle, finalObstacle)[DubinsPath.toType(listOf( - currentDirection, - DubinsPath.SimpleType.S, - j) - )] - for (obstacle in sortedObstacles(currentObstacle, obstacles)) { - if (tangentToFinal!!.intersectObstacle(obstacle)) { - nextObstacle = obstacle - break - } - } - if (nextObstacle == null) { - nextObstacle = finalObstacle - } - var nextTangents = outerTangents(currentObstacle, nextObstacle) - - for (pathType in DubinsPath.Type.values()) { - for (obstacle in obstacles) { - // in Python code here try/except was used, but seems unneeded - if (nextTangents.containsKey(pathType)) { - if (nextTangents[pathType]!!.intersectObstacle(obstacle)) { - nextTangents.remove(pathType) - } - } - } - } - nextTangents = if (nextObstacle == finalObstacle) { - nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection) and - (DubinsPath.toSimpleTypes(it.key)[2] == j)} - as MutableMap - } else { - nextTangents.filter {(DubinsPath.toSimpleTypes(it.key)[0] == currentDirection)} - as MutableMap - } - var tangentsAlong = mutableListOf() - for (tangent in nextTangents.values) { - if (tangent.startCircle == line.last().endCircle) { - val lengthMaxPossible = arcLength( - tangent.startCircle, - line.last().lineSegment.end, - tangent.startObstacle.nextTangent( - tangent.startCircle, - DubinsPath.toType(listOf(currentDirection, DubinsPath.SimpleType.S, currentDirection)), - ).lineSegment.begin, - currentDirection - ) - val lengthCalculated = arcLength( - tangent.startCircle, - line.last().lineSegment.end, - tangent.lineSegment.begin, - currentDirection) - if (lengthCalculated > lengthMaxPossible) { - tangentsAlong = tangentsAlongTheObstacle( - currentCircle, - DubinsPath.toType(listOf( - currentDirection, - DubinsPath.SimpleType.S, - currentDirection)), - tangent.startCircle, - currentObstacle - ) - } - else { - tangentsAlong = mutableListOf() - } - } - else { - tangentsAlong = tangentsAlongTheObstacle( - currentCircle, - DubinsPath.toType(listOf( - currentDirection, - DubinsPath.SimpleType.S, - currentDirection)), - tangent.startCircle, - currentObstacle - ) - } - newPaths.add((line + tangentsAlong + listOf(tangent)).toMutableList()) - } - path[listOf( - i, - DubinsPath.SimpleType.S, - j - )] = newPaths - } - else { - // minor changes from Python code - newPaths.add(line) - path[listOf( - i, - DubinsPath.SimpleType.S, - j - )] = newPaths - } - } - path[listOf( - i, - DubinsPath.SimpleType.S, - j - )] = newPaths - } - for (lineId in path[listOf( - i, - DubinsPath.SimpleType.S, - j - )]!!.indices) { - val lastDirection = path[listOf( - i, - DubinsPath.SimpleType.S, - j - )]!![lineId].last().route[2] - path[listOf( - i, - DubinsPath.SimpleType.S, - j - )]!![lineId].add(DubinsTangent( - finalCircles[j]!!, - finalCircles[j]!!, - DubinsObstacle( - listOf(finalCircles[j]!!) - ), - DubinsObstacle( - listOf(finalCircles[j]!!) - ), - LineSegment2D(finalPoint, finalPoint), - listOf( - lastDirection, - DubinsPath.SimpleType.S, - j - ) - )) - } - } - } - return path[listOf( - DubinsPath.SimpleType.L, - DubinsPath.SimpleType.S, - DubinsPath.SimpleType.L - )]!! + path[listOf( - DubinsPath.SimpleType.L, - DubinsPath.SimpleType.S, - DubinsPath.SimpleType.R - )]!! + path[listOf( - DubinsPath.SimpleType.R, - DubinsPath.SimpleType.S, - DubinsPath.SimpleType.L - )]!! + path[listOf( - DubinsPath.SimpleType.R, - DubinsPath.SimpleType.S, - DubinsPath.SimpleType.R)]!! -} - - - - - - - - diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index 5654d10ae..272cf9e5b 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -7,6 +7,8 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.* import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.trajectory.Trajectory2D.Type +import space.kscience.kmath.trajectory.Trajectory2D.Type.* import kotlin.math.acos internal fun DubinsPose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first @@ -19,27 +21,21 @@ internal fun DubinsPose2D.getTangentCircles(radius: Double): Pair vector( - a.center.x - a.radius * cos(centers.bearing), - a.center.y + a.radius * sin(centers.bearing) + val centers = StraightTrajectory2D(from.center, to.center) + val p1 = when (direction) { + L -> vector( + from.center.x - from.radius * cos(centers.bearing), + from.center.y + from.radius * sin(centers.bearing) ) - CircleTrajectory2D.Direction.RIGHT -> vector( - a.center.x + a.radius * cos(centers.bearing), - a.center.y - a.radius * sin(centers.bearing) + R -> vector( + from.center.x + from.radius * cos(centers.bearing), + from.center.y - from.radius * sin(centers.bearing) ) + + else -> error("S trajectory type not allowed") } return StraightTrajectory2D( p1, @@ -47,29 +43,25 @@ private fun outerTangent(a: Circle2D, b: Circle2D, side: CircleTrajectory2D.Dire ) } -internal fun leftInnerTangent(base: Circle2D, direction: Circle2D): StraightTrajectory2D? = - innerTangent(base, direction, CircleTrajectory2D.Direction.LEFT) - -internal fun rightInnerTangent(base: Circle2D, direction: Circle2D): StraightTrajectory2D? = - innerTangent(base, direction, CircleTrajectory2D.Direction.RIGHT) private fun innerTangent( - base: Circle2D, - direction: Circle2D, - side: CircleTrajectory2D.Direction, + from: Circle2D, + to: Circle2D, + direction: Type, ): StraightTrajectory2D? = with(Euclidean2DSpace) { - val centers = StraightTrajectory2D(base.center, direction.center) - if (centers.length < base.radius * 2) return null - val angle = when (side) { - CircleTrajectory2D.Direction.LEFT -> centers.bearing + acos(base.radius * 2 / centers.length).radians - CircleTrajectory2D.Direction.RIGHT -> centers.bearing - acos(base.radius * 2 / centers.length).radians + val centers = StraightTrajectory2D(from.center, to.center) + if (centers.length < from.radius * 2) return null + val angle = when (direction) { + L -> centers.bearing + acos(from.radius * 2 / centers.length).radians + R -> centers.bearing - acos(from.radius * 2 / centers.length).radians + else -> error("S trajectory type not allowed") }.normalized() - val dX = base.radius * sin(angle) - val dY = base.radius * cos(angle) - val p1 = vector(base.center.x + dX, base.center.y + dY) - val p2 = vector(direction.center.x - dX, direction.center.y - dY) + val dX = from.radius * sin(angle) + val dY = from.radius * cos(angle) + val p1 = vector(from.center.x + dX, from.center.y + dY) + val p2 = vector(to.center.x - dX, to.center.y - dY) return StraightTrajectory2D(p1, p2) } @@ -77,118 +69,25 @@ private fun innerTangent( @Suppress("DuplicatedCode") public object DubinsPath { -// public class ArcType(private val type: Type){ -// public val first: SimpleType -// get() { -// if (this.type in listOf(Type.RSR, Type.RSL, Type.RLR)) { -// return SimpleType.R -// } -// else if (type in listOf(Type.LSL, Type.LSR, Type.LRL)) { -// return SimpleType.L -// } -// error("Wrong DubinsPath.Type") -// } -// -// public val last: SimpleType -// get() { -// if (type in listOf(Type.RSR, Type.LSR, Type.RLR)) { -// return SimpleType.R -// } -// else if (type in listOf(Type.LSL, Type.RSL, Type.LRL)) { -// return SimpleType.L -// } -// error("Wrong DubinsPath.Type") -// } -// public val intermediate: SimpleType -// get() { -// if (type == Type.RLR) { -// return SimpleType.L -// } -// else if (type == Type.LRL) { -// return SimpleType.R -// } -// error("This DubinsPath.Type doesn't contain intermediate arc") -// } -// } + public data class Type( + public val first: Trajectory2D.Type, + public val second: Trajectory2D.Type, + public val third: Trajectory2D.Type, + ) { + public fun toList(): List = listOf(first, second, third) - public enum class SimpleType { - R, S, L - } + override fun toString(): String = "${first.name}${second.name}${third.name}" - public enum class Type { - RLR, LRL, RSR, LSL, RSL, LSR - } - - public fun toSimpleTypes(type: Type): List { - when (type) { - Type.RLR -> { - return listOf(SimpleType.R, SimpleType.L, SimpleType.R) - } - Type.LRL -> { - return listOf(SimpleType.L, SimpleType.R, SimpleType.L) - } - Type.RSR -> { - return listOf(SimpleType.R, SimpleType.S, SimpleType.R) - } - Type.LSL -> { - return listOf(SimpleType.L, SimpleType.S, SimpleType.L) - } - Type.RSL -> { - return listOf(SimpleType.R, SimpleType.S, SimpleType.L) - } - Type.LSR -> { - return listOf(SimpleType.L, SimpleType.S, SimpleType.R) - } - else -> error("This type doesn't exist") + public companion object { + public val RLR: Type = Type(R, L, R) + public val LRL: Type = Type(L, R, L) + public val RSR: Type = Type(R, S, R) + public val LSL: Type = Type(L, S, L) + public val RSL: Type = Type(R, S, L) + public val LSR: Type = Type(L, S, R) } } - public fun toType(types: List): Type { - when (types) { - listOf(SimpleType.R, SimpleType.L, SimpleType.R) -> { - return Type.RLR - } - listOf(SimpleType.L, SimpleType.R, SimpleType.L) -> { - return Type.LRL - } - listOf(SimpleType.R, SimpleType.S, SimpleType.R) -> { - return Type.RSR - } - listOf(SimpleType.L, SimpleType.S, SimpleType.L) -> { - return Type.LSL - } - listOf(SimpleType.R, SimpleType.S, SimpleType.L) -> { - return Type.RSL - } - listOf(SimpleType.L, SimpleType.S, SimpleType.R) -> { - return Type.LSR - } - else -> error("This type doesn't exist") - } - } - -// public class PathTypes(private val inputTypes: List) { -// public val type: Type -// get() { -// when (this.inputTypes) { -// listOf(SimpleType.R, SimpleType.S, SimpleType.R) -> { -// return Type.RSR -// } -// listOf(SimpleType.R, SimpleType.S, SimpleType.L) -> { -// return Type.RSL -// } -// listOf(SimpleType.L, SimpleType.S, SimpleType.R) -> { -// return Type.LSR -// } -// listOf(SimpleType.L, SimpleType.S, SimpleType.L) -> { -// return Type.LSL -// } -// else -> error("Wrong list of SimpleTypes") -// } -// } -// public val chain: List = this.inputTypes -// } - /** * Return Dubins trajectory type or null if trajectory is not a Dubins path */ @@ -197,12 +96,10 @@ public object DubinsPath { val a = trajectory2D.segments.first() as? CircleTrajectory2D ?: return null val b = trajectory2D.segments[1] val c = trajectory2D.segments.last() as? CircleTrajectory2D ?: return null - return Type.valueOf( - arrayOf( - a.direction.name[0], - if (b is CircleTrajectory2D) b.direction.name[0] else 'S', - c.direction.name[0] - ).toCharArray().concatToString() + return Type( + a.direction, + if (b is CircleTrajectory2D) b.direction else Trajectory2D.Type.S, + c.direction ) } @@ -240,9 +137,9 @@ public object DubinsPath { dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, CircleTrajectory2D.Direction.RIGHT) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, CircleTrajectory2D.Direction.LEFT) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, CircleTrajectory2D.Direction.RIGHT) + val a1 = CircleTrajectory2D.of(c1.center, start, p1, Trajectory2D.Type.R) + val a2 = CircleTrajectory2D.of(e.center, p1, p2, Trajectory2D.Type.L) + val a3 = CircleTrajectory2D.of(c2.center, p2, end, Trajectory2D.Type.R) CompositeTrajectory2D(a1, a2, a3) } @@ -257,9 +154,9 @@ public object DubinsPath { dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, CircleTrajectory2D.Direction.RIGHT) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, CircleTrajectory2D.Direction.LEFT) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, CircleTrajectory2D.Direction.RIGHT) + val a1 = CircleTrajectory2D.of(c1.center, start, p1, Trajectory2D.Type.R) + val a2 = CircleTrajectory2D.of(e.center, p1, p2, Trajectory2D.Type.L) + val a3 = CircleTrajectory2D.of(c2.center, p2, end, Trajectory2D.Type.R) CompositeTrajectory2D(a1, a2, a3) } @@ -284,9 +181,9 @@ public object DubinsPath { dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, CircleTrajectory2D.Direction.LEFT) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, CircleTrajectory2D.Direction.RIGHT) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, CircleTrajectory2D.Direction.LEFT) + val a1 = CircleTrajectory2D.of(c1.center, start, p1, Trajectory2D.Type.L) + val a2 = CircleTrajectory2D.of(e.center, p1, p2, Trajectory2D.Type.R) + val a3 = CircleTrajectory2D.of(c2.center, p2, end, Trajectory2D.Type.L) CompositeTrajectory2D(a1, a2, a3) } @@ -301,9 +198,9 @@ public object DubinsPath { dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, CircleTrajectory2D.Direction.LEFT) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, CircleTrajectory2D.Direction.RIGHT) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, CircleTrajectory2D.Direction.LEFT) + val a1 = CircleTrajectory2D.of(c1.center, start, p1, Trajectory2D.Type.L) + val a2 = CircleTrajectory2D.of(e.center, p1, p2, Trajectory2D.Type.R) + val a3 = CircleTrajectory2D.of(c2.center, p2, end, Trajectory2D.Type.L) CompositeTrajectory2D(a1, a2, a3) } @@ -313,45 +210,45 @@ public object DubinsPath { public fun rsr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D { val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) - val s = leftOuterTangent(c1, c2) - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.RIGHT) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.RIGHT) + val s = outerTangent(c1, c2, L) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, Trajectory2D.Type.R) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, Trajectory2D.Type.R) return CompositeTrajectory2D(a1, s, a3) } public fun lsl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D { val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) - val s = rightOuterTangent(c1, c2) - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.LEFT) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.LEFT) + val s = outerTangent(c1, c2, R) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, Trajectory2D.Type.L) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, Trajectory2D.Type.L) return CompositeTrajectory2D(a1, s, a3) } public fun rsl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? { val c1 = start.getRightCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) - val s = rightInnerTangent(c1, c2) + val s = innerTangent(c1, c2, R) if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.RIGHT) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.LEFT) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, Trajectory2D.Type.R) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, Trajectory2D.Type.L) return CompositeTrajectory2D(a1, s, a3) } public fun lsr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? { val c1 = start.getLeftCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) - val s = leftInnerTangent(c1, c2) + val s = innerTangent(c1, c2, L) if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, CircleTrajectory2D.Direction.LEFT) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, CircleTrajectory2D.Direction.RIGHT) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, Trajectory2D.Type.L) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, Trajectory2D.Type.R) return CompositeTrajectory2D(a1, s, a3) } } -public typealias PathTypes = List +public typealias PathTypes = List public fun interface MaxCurvature { public fun compute(startPoint: PhaseVector2D): Double diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt new file mode 100644 index 000000000..d5d04e1a4 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt @@ -0,0 +1,619 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.trajectory + +import space.kscience.kmath.geometry.* +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.Euclidean2DSpace.minus +import space.kscience.kmath.geometry.Euclidean2DSpace.norm +import space.kscience.kmath.geometry.Euclidean2DSpace.plus +import space.kscience.kmath.geometry.Euclidean2DSpace.times +import space.kscience.kmath.geometry.Euclidean2DSpace.vector +import space.kscience.kmath.operations.DoubleField.pow +import kotlin.math.* + +internal data class Tangent( + val startCircle: Circle2D, + val endCircle: Circle2D, + val startObstacle: Obstacle, + val endObstacle: Obstacle, + val lineSegment: LineSegment2D, + val trajectoryType: List, +) + +private class TangentPath(val tangents: List) { + fun last() = tangents.last() +} + +private fun TangentPath(vararg tangents: Tangent) = TangentPath(listOf(*tangents)) + +/** + * Create inner and outer tangents between two circles. + * This method returns a map of segments using [DubinsPath] connection type notation. + */ +internal fun Circle2D.tangentsToCircle( + other: Circle2D, +): Map = with(Euclidean2DSpace) { + //return empty map for concentric circles + if (center.equalsVector(other.center)) return emptyMap() + + // A line connecting centers + val line = LineSegment(center, other.center) + // Distance between centers + val distance = line.begin.distanceTo(line.end) + val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) + var angle2: Double + val routes = mapOf( + DubinsPath.Type.RSR to Pair(radius, other.radius), + DubinsPath.Type.RSL to Pair(radius, -other.radius), + DubinsPath.Type.LSR to Pair(-radius, other.radius), + DubinsPath.Type.LSL to Pair(-radius, -other.radius) + ) + return buildMap { + for ((route, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + val r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + if (distance * distance >= r * r) { + val l = sqrt(distance * distance - r * r) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) + put( + route, + LineSegment( + center + w * r1, + other.center + w * r2 + ) + ) + } else { + throw Exception("Circles should not intersect") + } + } + } +} + +private fun dubinsTangentsToCircles( + firstCircle: Circle2D, + secondCircle: Circle2D, + firstObstacle: Obstacle, + secondObstacle: Obstacle, +): Map = with(Euclidean2DSpace) { + val line = LineSegment(firstCircle.center, secondCircle.center) + val distance = line.begin.distanceTo(line.end) + val angle1 = atan2( + secondCircle.center.x - firstCircle.center.x, + secondCircle.center.y - firstCircle.center.y + ) + var r: Double + var angle2: Double + val routes = mapOf( + DubinsPath.Type.RSR to Pair(firstCircle.radius, secondCircle.radius), + DubinsPath.Type.RSL to Pair(firstCircle.radius, -secondCircle.radius), + DubinsPath.Type.LSR to Pair(-firstCircle.radius, secondCircle.radius), + DubinsPath.Type.LSL to Pair(-firstCircle.radius, -secondCircle.radius) + ) + return buildMap { + for ((route: DubinsPath.Type, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + if (distance * distance >= r * r) { + val l = sqrt(distance * distance - r * r) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = vector(-cos(angle2), sin(angle2)) + put( + route, + Tangent( + startCircle = Circle2D(firstCircle.center, firstCircle.radius), + endCircle = secondCircle, + startObstacle = firstObstacle, + endObstacle = secondObstacle, + lineSegment = LineSegment2D( + firstCircle.center + w * r1, + secondCircle.center + w * r2 + ), + trajectoryType = route.toList() + ) + ) + } else { + throw Exception("Circles should not intersect") + } + } + } +} + +public class Obstacle( + public val circles: List, +) { + internal val tangents: List = boundaryTangents().first + public val boundaryRoute: DubinsPath.Type = boundaryTangents().second + + public val center: Vector2D = vector( + circles.sumOf { it.center.x } / circles.size, + circles.sumOf { it.center.y } / circles.size + ) + + private fun boundaryTangents(): Pair, DubinsPath.Type> { + // outer tangents for a polygon circles can be either lsl or rsr + + fun Circle2D.dubinsTangentsToCircles( + other: Circle2D, + ): Map = with(Euclidean2DSpace) { + val line = LineSegment(center, other.center) + val d = line.begin.distanceTo(line.end) + val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) + var r: Double + var angle2: Double + val routes = mapOf( + DubinsPath.Type.RSR to Pair(radius, other.radius), + DubinsPath.Type.LSL to Pair(-radius, -other.radius) + ) + return buildMap { + for ((routeType, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + if (d * d >= r * r) { + val l = (d * d - r * r).pow(0.5) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, l) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, l) + } + val w = vector(-cos(angle2), sin(angle2)) + put( + routeType, Tangent( + Circle2D(center, radius), + other, + this@Obstacle, + this@Obstacle, + LineSegment2D( + center + w * r1, + other.center + w * r2 + ), + routeType.toList() + ) + ) + } else { + throw Exception("Circles should not intersect") + } + } + } + } + + val firstCircles = circles + val secondCircles = circles.slice(1..circles.lastIndex) + + circles[0] + val lslTangents = firstCircles.zip(secondCircles) + { a, b -> a.dubinsTangentsToCircles(b)[DubinsPath.Type.LSL]!! } + val rsrTangents = firstCircles.zip(secondCircles) + { a, b -> a.dubinsTangentsToCircles(b)[DubinsPath.Type.RSR]!! } + val center = vector( + circles.sumOf { it.center.x } / circles.size, + circles.sumOf { it.center.y } / circles.size + ) + val lslToCenter = lslTangents.sumOf { it.lineSegment.begin.distanceTo(center) } + + lslTangents.sumOf { it.lineSegment.end.distanceTo(center) } + val rsrToCenter = rsrTangents.sumOf { it.lineSegment.begin.distanceTo(center) } + + rsrTangents.sumOf { it.lineSegment.end.distanceTo(center) } + return if (rsrToCenter >= lslToCenter) { + Pair(rsrTangents, DubinsPath.Type.RSR) + } else { + Pair(lslTangents, DubinsPath.Type.LSL) + } + } + + override fun equals(other: Any?): Boolean { + if (other == null || other !is Obstacle) return false + return circles == other.circles + } + + override fun hashCode(): Int { + return circles.hashCode() + } +} + +private fun Obstacle.nextTangent(circle: Circle2D, routeType: DubinsPath.Type): Tangent { + if (routeType == boundaryRoute) { + for (i in circles.indices) { + if (circles[i] == circle) { + return tangents[i] + } + } + } else { + for (i in circles.indices) { + if (circles[i] == circle) { + if (i > 0) { + return Tangent( + circles[i], + circles[i - 1], + this, + this, + LineSegment2D( + tangents[i - 1].lineSegment.end, + tangents[i - 1].lineSegment.begin + ), + routeType.toList() + ) + } else { + return Tangent( + circles[0], + circles.last(), + this, + this, + LineSegment2D( + tangents.last().lineSegment.end, + tangents.last().lineSegment.begin + ), + routeType.toList() + ) + } + } + } + } + + error("next tangent not found") +} + +public fun Obstacle(vararg circles: Circle2D): Obstacle = Obstacle(listOf(*circles)) + +private fun LineSegment2D.intersectSegment(other: LineSegment2D): Boolean { + fun crossProduct(v1: DoubleVector2D, v2: DoubleVector2D): Double { + return v1.x * v2.y - v1.y * v2.x + } + return if (crossProduct(other.begin - begin, other.end - begin).sign == + crossProduct(other.begin - end, other.end - end).sign + ) { + false + } else { + crossProduct(begin - other.begin, end - other.begin).sign != crossProduct( + begin - other.end, + end - other.end + ).sign + } +} + +private fun LineSegment2D.intersectCircle(circle: Circle2D): Boolean { + val a = (begin.x - end.x).pow(2.0) + (begin.y - end.y).pow(2.0) + val b = 2 * ((begin.x - end.x) * (end.x - circle.center.x) + + (begin.y - end.y) * (end.y - circle.center.y)) + val c = (end.x - circle.center.x).pow(2.0) + (end.y - circle.center.y).pow(2.0) - + circle.radius.pow(2.0) + val d = b.pow(2.0) - 4 * a * c + if (d < 1e-6) { + return false + } else { + val t1 = (-b - d.pow(0.5)) * 0.5 / a + val t2 = (-b + d.pow(0.5)) * 0.5 / a + if (((0 < t1) and (t1 < 1)) or ((0 < t2) and (t2 < 1))) { + return true + } + } + return false +} + +private fun Tangent.intersectObstacle(obstacle: Obstacle): Boolean { + for (tangent in obstacle.tangents) { + if (lineSegment.intersectSegment(tangent.lineSegment)) { + return true + } + } + for (circle in obstacle.circles) { + if (lineSegment.intersectCircle(circle)) { + return true + } + } + return false +} + +private fun outerTangents(first: Obstacle, second: Obstacle): Map = buildMap { + for (circle1 in first.circles) { + for (circle2 in second.circles) { + for (tangent in dubinsTangentsToCircles(circle1, circle2, first, second)) { + if (!(tangent.value.intersectObstacle(first)) + and !(tangent.value.intersectObstacle(second)) + ) { + put( + tangent.key, + tangent.value + ) + } + } + } + } +} + +private fun arcLength( + circle: Circle2D, + point1: DoubleVector2D, + point2: DoubleVector2D, + route: Trajectory2D.Type, +): Double { + val phi1 = atan2(point1.y - circle.center.y, point1.x - circle.center.x) + val phi2 = atan2(point2.y - circle.center.y, point2.x - circle.center.x) + var angle = 0.0 + when (route) { + Trajectory2D.Type.L -> { + angle = if (phi2 >= phi1) { + phi2 - phi1 + } else { + 2 * PI + phi2 - phi1 + } + } + + Trajectory2D.Type.R -> { + angle = if (phi2 >= phi1) { + 2 * PI - (phi2 - phi1) + } else { + -(phi2 - phi1) + } + } + + Trajectory2D.Type.S -> { + error("L or R route is expected") + } + } + return circle.radius * angle +} + +private fun normalVectors(v: DoubleVector2D, r: Double): Pair { + return Pair( + r * vector(v.y / norm(v), -v.x / norm(v)), + r * vector(-v.y / norm(v), v.x / norm(v)) + ) +} + +private fun constructTangentCircles( + point: DoubleVector2D, + direction: DoubleVector2D, + r: Double, +): Map { + val center1 = point + normalVectors(direction, r).first + val center2 = point + normalVectors(direction, r).second + val p1 = center1 - point + return if (atan2(p1.y, p1.x) - atan2(direction.y, direction.x) in listOf(PI / 2, -3 * PI / 2)) { + mapOf( + Trajectory2D.Type.L to Circle2D(center1, r), + Trajectory2D.Type.R to Circle2D(center2, r) + ) + } else { + mapOf( + Trajectory2D.Type.L to Circle2D(center2, r), + Trajectory2D.Type.R to Circle2D(center1, r) + ) + } +} + +private fun sortedObstacles( + currentObstacle: Obstacle, + obstacles: List, +): List { + return obstacles.sortedBy { norm(it.center - currentObstacle.center) }//.reversed() +} + +private fun tangentsAlongTheObstacle( + initialCircle: Circle2D, + initialRoute: DubinsPath.Type, + finalCircle: Circle2D, + obstacle: Obstacle, +): List { + val dubinsTangents = mutableListOf() + var tangent = obstacle.nextTangent(initialCircle, initialRoute) + dubinsTangents.add(tangent) + while (tangent.endCircle != finalCircle) { + tangent = obstacle.nextTangent(tangent.endCircle, initialRoute) + dubinsTangents.add(tangent) + } + return dubinsTangents +} + +private fun allFinished( + paths: List, + finalObstacle: Obstacle, +): Boolean { + for (path in paths) { + if (path.last().endObstacle != finalObstacle) { + return false + } + } + return true +} + +private fun LineSegment2D.toTrajectory() = StraightTrajectory2D(begin, end) + + +private fun TangentPath.toTrajectory(): CompositeTrajectory2D = CompositeTrajectory2D( + buildList { + tangents.zipWithNext().forEach { (left, right) -> + add(left.lineSegment.toTrajectory()) + add( + CircleTrajectory2D.of( + right.startCircle.center, + left.lineSegment.end, + right.lineSegment.begin, + right.trajectoryType.first() + ) + ) + } + + add(tangents.last().lineSegment.toTrajectory()) + } +) + +internal fun findAllPaths( + startingPoint: DoubleVector2D, + startingDirection: DoubleVector2D, + startingRadius: Double, + finalPoint: DoubleVector2D, + finalDirection: DoubleVector2D, + finalRadius: Double, + obstacles: List, +): List { + val initialCircles = constructTangentCircles( + startingPoint, + startingDirection, + startingRadius + ) + val finalCircles = constructTangentCircles( + finalPoint, + finalDirection, + finalRadius + ) + val trajectories = mutableListOf() + for (i in listOf(Trajectory2D.Type.L, Trajectory2D.Type.R)) { + for (j in listOf(Trajectory2D.Type.L, Trajectory2D.Type.R)) { + val finalCircle = finalCircles[j]!! + val finalObstacle = Obstacle(listOf(finalCircle)) + var currentPaths: List = listOf( + TangentPath( + Tangent( + initialCircles[i]!!, + initialCircles[i]!!, + Obstacle(listOf(initialCircles[i]!!)), + Obstacle(listOf(initialCircles[i]!!)), + LineSegment2D(startingPoint, startingPoint), + listOf(i, Trajectory2D.Type.S, i) + ) + ) + ) + while (!allFinished(currentPaths, finalObstacle)) { + val newPaths = mutableListOf() + for (tangentPath: TangentPath in currentPaths) { + val currentCircle = tangentPath.last().endCircle + val currentDirection = tangentPath.last().trajectoryType.last() + val currentObstacle = tangentPath.last().endObstacle + var nextObstacle: Obstacle? = null + if (currentObstacle != finalObstacle) { + val tangentToFinal = outerTangents(currentObstacle, finalObstacle)[DubinsPath.Type( + currentDirection, + Trajectory2D.Type.S, + j + )] + for (obstacle in sortedObstacles(currentObstacle, obstacles)) { + if (tangentToFinal!!.intersectObstacle(obstacle)) { + nextObstacle = obstacle + break + } + } + if (nextObstacle == null) { + nextObstacle = finalObstacle + } + val nextTangents: Map = outerTangents(currentObstacle, nextObstacle) + .filter { (key, tangent) -> + obstacles.none { obstacle -> tangent.intersectObstacle(obstacle) } && + key.first == currentDirection && + (nextObstacle != finalObstacle || key.third == j) + } + + var tangentsAlong: List + for (tangent in nextTangents.values) { + if (tangent.startCircle == tangentPath.last().endCircle) { + val lengthMaxPossible = arcLength( + tangent.startCircle, + tangentPath.last().lineSegment.end, + tangent.startObstacle.nextTangent( + tangent.startCircle, + DubinsPath.Type( + currentDirection, + Trajectory2D.Type.S, + currentDirection + ), + ).lineSegment.begin, + currentDirection + ) + val lengthCalculated = arcLength( + tangent.startCircle, + tangentPath.last().lineSegment.end, + tangent.lineSegment.begin, + currentDirection + ) + tangentsAlong = if (lengthCalculated > lengthMaxPossible) { + tangentsAlongTheObstacle( + currentCircle, + DubinsPath.Type( + currentDirection, + Trajectory2D.Type.S, + currentDirection + ), + tangent.startCircle, + currentObstacle + ) + } else { + emptyList() + } + } else { + tangentsAlong = tangentsAlongTheObstacle( + currentCircle, + DubinsPath.Type( + currentDirection, + Trajectory2D.Type.S, + currentDirection + ), + tangent.startCircle, + currentObstacle + ) + } + newPaths.add(TangentPath(tangentPath.tangents + tangentsAlong + tangent)) + } + } else { + // minor changes from Python code + newPaths.add(tangentPath) + } + } + currentPaths = newPaths + } + + trajectories += currentPaths.map { tangentPath -> + val lastDirection: Trajectory2D.Type = tangentPath.last().trajectoryType[2] + val end = finalCircles[j]!! + TangentPath( + tangentPath.tangents + + Tangent( + end, + end, + Obstacle(end), + Obstacle(end), + LineSegment2D(finalPoint, finalPoint), + listOf( + lastDirection, + Trajectory2D.Type.S, + j + ) + ) + ) + }.map { it.toTrajectory() } + } + } + return trajectories +} + + + + + + + + diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt index e5f60e025..7bf17fc26 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt @@ -16,6 +16,12 @@ import kotlin.math.atan2 @Serializable public sealed interface Trajectory2D { public val length: Double + + public enum class Type { + R, + S, + L + } } /** @@ -27,11 +33,14 @@ public data class StraightTrajectory2D( public val start: DoubleVector2D, public val end: DoubleVector2D, ) : Trajectory2D { + override val length: Double get() = start.distanceTo(end) public val bearing: Angle get() = (atan2(end.x - start.x, end.y - start.y).radians).normalized() } +public fun StraightTrajectory2D.toSegment(): LineSegment> = LineSegment2D(start, end) + /** * An arc segment */ @@ -43,15 +52,11 @@ public data class CircleTrajectory2D( public val end: DubinsPose2D, ) : Trajectory2D { - public enum class Direction { - LEFT, RIGHT - } - /** * Arc length in radians */ val arcLength: Angle - get() = if (direction == Direction.LEFT) { + get() = if (direction == Trajectory2D.Type.L) { start.bearing - end.bearing } else { end.bearing - start.bearing @@ -62,16 +67,16 @@ public data class CircleTrajectory2D( circle.radius * arcLength.radians } - public val direction: Direction by lazy { + public val direction: Trajectory2D.Type by lazy { if (start.y < circle.center.y) { - if (start.bearing > Angle.pi) Direction.RIGHT else Direction.LEFT + if (start.bearing > Angle.pi) Trajectory2D.Type.R else Trajectory2D.Type.L } else if (start.y > circle.center.y) { - if (start.bearing < Angle.pi) Direction.RIGHT else Direction.LEFT + if (start.bearing < Angle.pi) Trajectory2D.Type.R else Trajectory2D.Type.L } else { if (start.bearing == Angle.zero) { - if (start.x < circle.center.x) Direction.RIGHT else Direction.LEFT + if (start.x < circle.center.x) Trajectory2D.Type.R else Trajectory2D.Type.L } else { - if (start.x > circle.center.x) Direction.RIGHT else Direction.LEFT + if (start.x > circle.center.x) Trajectory2D.Type.R else Trajectory2D.Type.L } } } @@ -81,17 +86,18 @@ public data class CircleTrajectory2D( center: DoubleVector2D, start: DoubleVector2D, end: DoubleVector2D, - direction: Direction, + direction: Trajectory2D.Type, ): CircleTrajectory2D { fun calculatePose( vector: DoubleVector2D, theta: Angle, - direction: Direction, + direction: Trajectory2D.Type, ): DubinsPose2D = DubinsPose2D( vector, when (direction) { - Direction.LEFT -> (theta - Angle.piDiv2).normalized() - Direction.RIGHT -> (theta + Angle.piDiv2).normalized() + Trajectory2D.Type.L -> (theta - Angle.piDiv2).normalized() + Trajectory2D.Type.R -> (theta + Angle.piDiv2).normalized() + else -> error("S trajectory type is not allowed in circle constructor") } ) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt deleted file mode 100644 index fb1c3927b..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/tangent.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.trajectory - -import space.kscience.kmath.geometry.* -import kotlin.math.* - -/** - * Create inner and outer tangents between two circles. - * This method returns a map of segments using [DubinsPath] connection type notation. - */ -public fun Circle2D.tangentsToCircle( - other: Circle2D, -): Map> = with(Euclidean2DSpace) { - //return empty map for concentric circles - if(center.equalsVector(other.center)) return@tangentsToCircle emptyMap() - - // A line connecting centers - val line = LineSegment(center, other.center) - // Distance between centers - val distance = line.begin.distanceTo(line.end) - val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) - var angle2: Double - val routes = mapOf( - DubinsPath.Type.RSR to Pair(radius, other.radius), - DubinsPath.Type.RSL to Pair(radius, -other.radius), - DubinsPath.Type.LSR to Pair(-radius, other.radius), - DubinsPath.Type.LSL to Pair(-radius, -other.radius) - ) - return buildMap { - for ((route, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - val r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - if (distance * distance >= r * r) { - val l = sqrt(distance * distance - r * r) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, l) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, l) - } - val w = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) - put( - route, - LineSegment( - center + w * r1, - other.center + w * r2 - ) - ) - } else { - throw Exception("Circles should not intersect") - } - } - } -} - -public fun dubinsTangentsToCircles( - firstCircle: Circle2D, - secondCircle: Circle2D, - firstObstacle: DubinsObstacle, - secondObstacle: DubinsObstacle -): Map = with(Euclidean2DSpace) { - val line = LineSegment(firstCircle.center, secondCircle.center) - val distance = line.begin.distanceTo(line.end) - val angle1 = atan2(secondCircle.center.x - firstCircle.center.x, - secondCircle.center.y - firstCircle.center.y) - var r: Double - var angle2: Double - val routes = mapOf( - DubinsPath.Type.RSR to Pair(firstCircle.radius, secondCircle.radius), - DubinsPath.Type.RSL to Pair(firstCircle.radius, -secondCircle.radius), - DubinsPath.Type.LSR to Pair(-firstCircle.radius, secondCircle.radius), - DubinsPath.Type.LSL to Pair(-firstCircle.radius, -secondCircle.radius) - ) - return buildMap { - for ((route, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - if (distance * distance >= r * r) { - val l = sqrt(distance * distance - r * r) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, l) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, l) - } - val w = vector(-cos(angle2), sin(angle2)) - put(route, DubinsTangent(Circle2D(firstCircle.center, firstCircle.radius), - secondCircle, - firstObstacle, - secondObstacle, - LineSegment2D( - firstCircle.center + w * r1, - secondCircle.center + w * r2 - ), - DubinsPath.toSimpleTypes(route)) - ) - } else { - throw Exception("Circles should not intersect") - } - } - } -} \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt similarity index 93% rename from kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt rename to kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt index 481ea4786..f5bfb884e 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt @@ -1,13 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2023 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.trajectory.dubins +package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.equalsFloat -import space.kscience.kmath.trajectory.* import kotlin.test.Test import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -37,7 +36,7 @@ class DubinsTests { ) expectedLengths.forEach { - val path = dubins.find { p -> DubinsPath.trajectoryTypeOf(p) === it.key } + val path = dubins.find { p -> DubinsPath.trajectoryTypeOf(p) == it.key } assertNotNull(path, "Path ${it.key} not found") println("${it.key}: ${path.length}") assertTrue(it.value.equalsFloat(path.length)) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt similarity index 55% rename from kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt rename to kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt index 07e9861c7..446e0a4d3 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt @@ -7,12 +7,10 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import space.kscience.kmath.geometry.equalsFloat import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertTrue -class DubinsTest { +class ObstacleTest { @Test fun firstPath() { val startPoint = vector(-5.0, -1.0) @@ -22,8 +20,13 @@ class DubinsTest { val finalDirection = vector(1.0, -1.0) val finalRadius = 0.5 - val obstacles = listOf(DubinsObstacle(listOf( - Circle2D(vector(7.0, 1.0), 5.0)))) + val obstacles = listOf( + Obstacle( + listOf( + Circle2D(vector(7.0, 1.0), 5.0) + ) + ) + ) val outputTangents = findAllPaths( startPoint, @@ -32,8 +35,9 @@ class DubinsTest { finalPoint, finalDirection, finalRadius, - obstacles) - val length = pathLength(shortestPath(outputTangents)) + obstacles + ) + val length = outputTangents.minOf { it.length } assertEquals(length, 27.2113183, 1e-6) } @@ -47,17 +51,21 @@ class DubinsTest { val finalRadius = 0.5 val obstacles = listOf( - DubinsObstacle(listOf( - Circle2D(vector(1.0, 6.5), 0.5), - Circle2D(vector(2.0, 1.0), 0.5), - Circle2D(vector(6.0, 0.0), 0.5), - Circle2D(vector(5.0, 5.0), 0.5) - )), DubinsObstacle(listOf( - Circle2D(vector(10.0, 1.0), 0.5), - Circle2D(vector(16.0, 0.0), 0.5), - Circle2D(vector(14.0, 6.0), 0.5), - Circle2D(vector(9.0, 4.0), 0.5) - )) + Obstacle( + listOf( + Circle2D(vector(1.0, 6.5), 0.5), + Circle2D(vector(2.0, 1.0), 0.5), + Circle2D(vector(6.0, 0.0), 0.5), + Circle2D(vector(5.0, 5.0), 0.5) + ) + ), Obstacle( + listOf( + Circle2D(vector(10.0, 1.0), 0.5), + Circle2D(vector(16.0, 0.0), 0.5), + Circle2D(vector(14.0, 6.0), 0.5), + Circle2D(vector(9.0, 4.0), 0.5) + ) + ) ) val paths = findAllPaths( startPoint, @@ -66,22 +74,19 @@ class DubinsTest { finalPoint, finalDirection, finalRadius, - obstacles) - val length = pathLength(shortestPath(paths)) - assertEquals(length,28.9678224, 1e-6) - } - @Test - fun equalCircles() { - val circle1 = Circle2D(vector(1.0, 6.5), 0.5) - val circle2 = Circle2D(vector(1.0, 6.5), 0.5) - println(circle1 == circle2) + obstacles + ) + val length = paths.minOf { it.length } + assertEquals(length, 28.9678224, 1e-6) } + @Test fun equalObstacles() { val circle1 = Circle2D(vector(1.0, 6.5), 0.5) val circle2 = Circle2D(vector(1.0, 6.5), 0.5) - val obstacle1 = DubinsObstacle(listOf(circle1)) - val obstacle2 = DubinsObstacle(listOf(circle2)) - println(obstacle1 == obstacle2) + assertEquals(circle1, circle2) + val obstacle1 = Obstacle(listOf(circle1)) + val obstacle2 = Obstacle(listOf(circle2)) + assertEquals(obstacle1, obstacle2) } } \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index 7594aa046..f149004bb 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -10,6 +10,7 @@ import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.circumference import space.kscience.kmath.geometry.degrees import space.kscience.kmath.trajectory.CircleTrajectory2D +import space.kscience.kmath.trajectory.Trajectory2D import kotlin.test.Test import kotlin.test.assertEquals @@ -22,7 +23,7 @@ class ArcTests { circle.center, vector(-2.0, 0.0), vector(0.0, 2.0), - CircleTrajectory2D.Direction.RIGHT + Trajectory2D.Type.R ) assertEquals(circle.circumference / 4, arc.length, 1.0) assertEquals(0.0, arc.start.bearing.degrees) From 109e050f03abc0b585a024dd8abd743aa434e8d1 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Apr 2023 15:16:33 +0300 Subject: [PATCH 45/58] Hieraechy for trajectory types --- .../space/kscience/kmath/misc/Featured.kt | 2 +- .../space/kscience/kmath/misc/collections.kt | 22 +++++++ .../kscience/kmath/trajectory/DubinsPath.kt | 58 +++++++++---------- .../kscience/kmath/trajectory/Trajectory2D.kt | 40 ++++++++----- .../kscience/kmath/trajectory/ObstacleTest.kt | 4 +- .../kmath/trajectory/segments/ArcTests.kt | 2 +- 6 files changed, 78 insertions(+), 50 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt index a752a8339..bdda674dc 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt @@ -9,7 +9,7 @@ import kotlin.jvm.JvmInline import kotlin.reflect.KClass /** - * A entity that contains a set of features defined by their types + * An entity that contains a set of features defined by their types */ public interface Featured { public fun getFeature(type: FeatureKey): T? diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt new file mode 100644 index 000000000..90cc5bbfa --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.misc + +/** + * The same as [zipWithNext], but includes link between last and first element + */ +public inline fun List.zipWithNextCircular(transform: (a: T, b: T) -> R): List { + if (isEmpty()) return emptyList() + return indices.map { i -> + if (i == size - 1) { + transform(last(), first()) + } else { + transform(get(i), get(i + 1)) + } + } +} + +public inline fun List.zipWithNextCircular(): List> = zipWithNextCircular { l, r -> l to r } \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index 272cf9e5b..87ea52a69 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -7,8 +7,7 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.* import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.trajectory.Trajectory2D.Type -import space.kscience.kmath.trajectory.Trajectory2D.Type.* +import space.kscience.kmath.trajectory.Trajectory2D.* import kotlin.math.acos internal fun DubinsPose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first @@ -21,7 +20,7 @@ internal fun DubinsPose2D.getTangentCircles(radius: Double): Pair error("S trajectory type not allowed") } return StraightTrajectory2D( p1, @@ -47,7 +44,7 @@ private fun outerTangent(from: Circle2D, to: Circle2D, direction: Type): Straigh private fun innerTangent( from: Circle2D, to: Circle2D, - direction: Type, + direction: Direction, ): StraightTrajectory2D? = with(Euclidean2DSpace) { val centers = StraightTrajectory2D(from.center, to.center) @@ -55,7 +52,6 @@ private fun innerTangent( val angle = when (direction) { L -> centers.bearing + acos(from.radius * 2 / centers.length).radians R -> centers.bearing - acos(from.radius * 2 / centers.length).radians - else -> error("S trajectory type not allowed") }.normalized() val dX = from.radius * sin(angle) @@ -70,13 +66,13 @@ private fun innerTangent( public object DubinsPath { public data class Type( - public val first: Trajectory2D.Type, + public val first: Direction, public val second: Trajectory2D.Type, - public val third: Trajectory2D.Type, + public val third: Direction, ) { public fun toList(): List = listOf(first, second, third) - override fun toString(): String = "${first.name}${second.name}${third.name}" + override fun toString(): String = "${first}${second}${third}" public companion object { public val RLR: Type = Type(R, L, R) @@ -98,7 +94,7 @@ public object DubinsPath { val c = trajectory2D.segments.last() as? CircleTrajectory2D ?: return null return Type( a.direction, - if (b is CircleTrajectory2D) b.direction else Trajectory2D.Type.S, + if (b is CircleTrajectory2D) b.direction else S, c.direction ) } @@ -137,9 +133,9 @@ public object DubinsPath { dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, Trajectory2D.Type.R) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, Trajectory2D.Type.L) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, Trajectory2D.Type.R) + val a1 = CircleTrajectory2D.of(c1.center, start, p1, R) + val a2 = CircleTrajectory2D.of(e.center, p1, p2, L) + val a3 = CircleTrajectory2D.of(c2.center, p2, end, R) CompositeTrajectory2D(a1, a2, a3) } @@ -154,9 +150,9 @@ public object DubinsPath { dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, Trajectory2D.Type.R) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, Trajectory2D.Type.L) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, Trajectory2D.Type.R) + val a1 = CircleTrajectory2D.of(c1.center, start, p1, R) + val a2 = CircleTrajectory2D.of(e.center, p1, p2, L) + val a3 = CircleTrajectory2D.of(c2.center, p2, end, R) CompositeTrajectory2D(a1, a2, a3) } @@ -181,9 +177,9 @@ public object DubinsPath { dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, Trajectory2D.Type.L) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, Trajectory2D.Type.R) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, Trajectory2D.Type.L) + val a1 = CircleTrajectory2D.of(c1.center, start, p1, L) + val a2 = CircleTrajectory2D.of(e.center, p1, p2, R) + val a3 = CircleTrajectory2D.of(c2.center, p2, end, L) CompositeTrajectory2D(a1, a2, a3) } @@ -198,9 +194,9 @@ public object DubinsPath { dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, Trajectory2D.Type.L) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, Trajectory2D.Type.R) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, Trajectory2D.Type.L) + val a1 = CircleTrajectory2D.of(c1.center, start, p1, L) + val a2 = CircleTrajectory2D.of(e.center, p1, p2, R) + val a3 = CircleTrajectory2D.of(c2.center, p2, end, L) CompositeTrajectory2D(a1, a2, a3) } @@ -211,8 +207,8 @@ public object DubinsPath { val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) val s = outerTangent(c1, c2, L) - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, Trajectory2D.Type.R) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, Trajectory2D.Type.R) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, R) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, R) return CompositeTrajectory2D(a1, s, a3) } @@ -220,8 +216,8 @@ public object DubinsPath { val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) val s = outerTangent(c1, c2, R) - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, Trajectory2D.Type.L) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, Trajectory2D.Type.L) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, L) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, L) return CompositeTrajectory2D(a1, s, a3) } @@ -231,8 +227,8 @@ public object DubinsPath { val s = innerTangent(c1, c2, R) if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, Trajectory2D.Type.R) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, Trajectory2D.Type.L) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, R) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, L) return CompositeTrajectory2D(a1, s, a3) } @@ -242,8 +238,8 @@ public object DubinsPath { val s = innerTangent(c1, c2, L) if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, Trajectory2D.Type.L) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, Trajectory2D.Type.R) + val a1 = CircleTrajectory2D.of(c1.center, start, s.start, L) + val a3 = CircleTrajectory2D.of(c2.center, s.end, end, R) return CompositeTrajectory2D(a1, s, a3) } } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt index 7bf17fc26..d6974b105 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt @@ -17,10 +17,21 @@ import kotlin.math.atan2 public sealed interface Trajectory2D { public val length: Double - public enum class Type { - R, - S, - L + + public sealed interface Type + + public sealed interface Direction: Type + + public object R : Direction { + override fun toString(): String = "R" + } + + public object S : Type { + override fun toString(): String = "L" + } + + public object L : Direction { + override fun toString(): String = "L" } } @@ -56,7 +67,7 @@ public data class CircleTrajectory2D( * Arc length in radians */ val arcLength: Angle - get() = if (direction == Trajectory2D.Type.L) { + get() = if (direction == Trajectory2D.L) { start.bearing - end.bearing } else { end.bearing - start.bearing @@ -67,16 +78,16 @@ public data class CircleTrajectory2D( circle.radius * arcLength.radians } - public val direction: Trajectory2D.Type by lazy { + public val direction: Trajectory2D.Direction by lazy { if (start.y < circle.center.y) { - if (start.bearing > Angle.pi) Trajectory2D.Type.R else Trajectory2D.Type.L + if (start.bearing > Angle.pi) Trajectory2D.R else Trajectory2D.L } else if (start.y > circle.center.y) { - if (start.bearing < Angle.pi) Trajectory2D.Type.R else Trajectory2D.Type.L + if (start.bearing < Angle.pi) Trajectory2D.R else Trajectory2D.L } else { if (start.bearing == Angle.zero) { - if (start.x < circle.center.x) Trajectory2D.Type.R else Trajectory2D.Type.L + if (start.x < circle.center.x) Trajectory2D.R else Trajectory2D.L } else { - if (start.x > circle.center.x) Trajectory2D.Type.R else Trajectory2D.Type.L + if (start.x > circle.center.x) Trajectory2D.R else Trajectory2D.L } } } @@ -86,18 +97,17 @@ public data class CircleTrajectory2D( center: DoubleVector2D, start: DoubleVector2D, end: DoubleVector2D, - direction: Trajectory2D.Type, + direction: Trajectory2D.Direction, ): CircleTrajectory2D { fun calculatePose( vector: DoubleVector2D, theta: Angle, - direction: Trajectory2D.Type, + direction: Trajectory2D.Direction, ): DubinsPose2D = DubinsPose2D( vector, when (direction) { - Trajectory2D.Type.L -> (theta - Angle.piDiv2).normalized() - Trajectory2D.Type.R -> (theta + Angle.piDiv2).normalized() - else -> error("S trajectory type is not allowed in circle constructor") + Trajectory2D.L -> (theta - Angle.piDiv2).normalized() + Trajectory2D.R -> (theta + Angle.piDiv2).normalized() } ) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt index 446e0a4d3..150b370d0 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt @@ -38,7 +38,7 @@ class ObstacleTest { obstacles ) val length = outputTangents.minOf { it.length } - assertEquals(length, 27.2113183, 1e-6) + assertEquals(27.2113183, length, 1e-6) } @Test @@ -77,7 +77,7 @@ class ObstacleTest { obstacles ) val length = paths.minOf { it.length } - assertEquals(length, 28.9678224, 1e-6) + assertEquals(28.9678224, length, 1e-6) } @Test diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index f149004bb..b3825b93b 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -23,7 +23,7 @@ class ArcTests { circle.center, vector(-2.0, 0.0), vector(0.0, 2.0), - Trajectory2D.Type.R + Trajectory2D.R ) assertEquals(circle.circumference / 4, arc.length, 1.0) assertEquals(0.0, arc.start.bearing.degrees) From fd35d7c6143a5f544788bfda005cc399dc3cb245 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Apr 2023 15:28:02 +0300 Subject: [PATCH 46/58] [WIP] refactoring directions --- .../kscience/kmath/trajectory/Obstacle.kt | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt index d5d04e1a4..b4ae04342 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt @@ -350,13 +350,13 @@ private fun arcLength( circle: Circle2D, point1: DoubleVector2D, point2: DoubleVector2D, - route: Trajectory2D.Type, + direction: Trajectory2D.Direction, ): Double { val phi1 = atan2(point1.y - circle.center.y, point1.x - circle.center.x) val phi2 = atan2(point2.y - circle.center.y, point2.x - circle.center.x) var angle = 0.0 - when (route) { - Trajectory2D.Type.L -> { + when (direction) { + Trajectory2D.L -> { angle = if (phi2 >= phi1) { phi2 - phi1 } else { @@ -364,17 +364,13 @@ private fun arcLength( } } - Trajectory2D.Type.R -> { + Trajectory2D.R -> { angle = if (phi2 >= phi1) { 2 * PI - (phi2 - phi1) } else { -(phi2 - phi1) } } - - Trajectory2D.Type.S -> { - error("L or R route is expected") - } } return circle.radius * angle } @@ -396,13 +392,13 @@ private fun constructTangentCircles( val p1 = center1 - point return if (atan2(p1.y, p1.x) - atan2(direction.y, direction.x) in listOf(PI / 2, -3 * PI / 2)) { mapOf( - Trajectory2D.Type.L to Circle2D(center1, r), - Trajectory2D.Type.R to Circle2D(center2, r) + Trajectory2D.L to Circle2D(center1, r), + Trajectory2D.R to Circle2D(center2, r) ) } else { mapOf( - Trajectory2D.Type.L to Circle2D(center2, r), - Trajectory2D.Type.R to Circle2D(center1, r) + Trajectory2D.L to Circle2D(center2, r), + Trajectory2D.R to Circle2D(center1, r) ) } } @@ -483,8 +479,8 @@ internal fun findAllPaths( finalRadius ) val trajectories = mutableListOf() - for (i in listOf(Trajectory2D.Type.L, Trajectory2D.Type.R)) { - for (j in listOf(Trajectory2D.Type.L, Trajectory2D.Type.R)) { + for (i in listOf(Trajectory2D.L, Trajectory2D.R)) { + for (j in listOf(Trajectory2D.L, Trajectory2D.R)) { val finalCircle = finalCircles[j]!! val finalObstacle = Obstacle(listOf(finalCircle)) var currentPaths: List = listOf( @@ -495,7 +491,7 @@ internal fun findAllPaths( Obstacle(listOf(initialCircles[i]!!)), Obstacle(listOf(initialCircles[i]!!)), LineSegment2D(startingPoint, startingPoint), - listOf(i, Trajectory2D.Type.S, i) + listOf(i, Trajectory2D.S, i) ) ) ) @@ -503,13 +499,13 @@ internal fun findAllPaths( val newPaths = mutableListOf() for (tangentPath: TangentPath in currentPaths) { val currentCircle = tangentPath.last().endCircle - val currentDirection = tangentPath.last().trajectoryType.last() + val currentDirection: Trajectory2D.Direction = tangentPath.last().trajectoryType.last() val currentObstacle = tangentPath.last().endObstacle var nextObstacle: Obstacle? = null if (currentObstacle != finalObstacle) { val tangentToFinal = outerTangents(currentObstacle, finalObstacle)[DubinsPath.Type( currentDirection, - Trajectory2D.Type.S, + Trajectory2D.S, j )] for (obstacle in sortedObstacles(currentObstacle, obstacles)) { @@ -538,7 +534,7 @@ internal fun findAllPaths( tangent.startCircle, DubinsPath.Type( currentDirection, - Trajectory2D.Type.S, + Trajectory2D.S, currentDirection ), ).lineSegment.begin, @@ -555,7 +551,7 @@ internal fun findAllPaths( currentCircle, DubinsPath.Type( currentDirection, - Trajectory2D.Type.S, + Trajectory2D.S, currentDirection ), tangent.startCircle, @@ -569,7 +565,7 @@ internal fun findAllPaths( currentCircle, DubinsPath.Type( currentDirection, - Trajectory2D.Type.S, + Trajectory2D.S, currentDirection ), tangent.startCircle, @@ -599,7 +595,7 @@ internal fun findAllPaths( LineSegment2D(finalPoint, finalPoint), listOf( lastDirection, - Trajectory2D.Type.S, + Trajectory2D.S, j ) ) From 1e46ffbd98809c43b14c5b8f4df65f9315d040c7 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Apr 2023 16:50:30 +0300 Subject: [PATCH 47/58] refactoring directions --- .../kscience/kmath/trajectory/Obstacle.kt | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt index b4ae04342..c4ff34295 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt @@ -21,7 +21,8 @@ internal data class Tangent( val startObstacle: Obstacle, val endObstacle: Obstacle, val lineSegment: LineSegment2D, - val trajectoryType: List, + val startDirection: Trajectory2D.Direction, + val endDirection: Trajectory2D.Direction = startDirection ) private class TangentPath(val tangents: List) { @@ -131,7 +132,8 @@ private fun dubinsTangentsToCircles( firstCircle.center + w * r1, secondCircle.center + w * r2 ), - trajectoryType = route.toList() + startDirection = route.first, + endDirection = route.third ) ) } else { @@ -194,7 +196,8 @@ public class Obstacle( center + w * r1, other.center + w * r2 ), - routeType.toList() + startDirection = routeType.first, + endDirection = routeType.third ) ) } else { @@ -256,7 +259,8 @@ private fun Obstacle.nextTangent(circle: Circle2D, routeType: DubinsPath.Type): tangents[i - 1].lineSegment.end, tangents[i - 1].lineSegment.begin ), - routeType.toList() + startDirection = routeType.first, + endDirection = routeType.third ) } else { return Tangent( @@ -268,7 +272,8 @@ private fun Obstacle.nextTangent(circle: Circle2D, routeType: DubinsPath.Type): tangents.last().lineSegment.end, tangents.last().lineSegment.begin ), - routeType.toList() + startDirection = routeType.first, + endDirection = routeType.third ) } } @@ -450,7 +455,7 @@ private fun TangentPath.toTrajectory(): CompositeTrajectory2D = CompositeTraject right.startCircle.center, left.lineSegment.end, right.lineSegment.begin, - right.trajectoryType.first() + right.startDirection ) ) } @@ -491,7 +496,7 @@ internal fun findAllPaths( Obstacle(listOf(initialCircles[i]!!)), Obstacle(listOf(initialCircles[i]!!)), LineSegment2D(startingPoint, startingPoint), - listOf(i, Trajectory2D.S, i) + i ) ) ) @@ -499,7 +504,7 @@ internal fun findAllPaths( val newPaths = mutableListOf() for (tangentPath: TangentPath in currentPaths) { val currentCircle = tangentPath.last().endCircle - val currentDirection: Trajectory2D.Direction = tangentPath.last().trajectoryType.last() + val currentDirection: Trajectory2D.Direction = tangentPath.last().endDirection val currentObstacle = tangentPath.last().endObstacle var nextObstacle: Obstacle? = null if (currentObstacle != finalObstacle) { @@ -583,7 +588,7 @@ internal fun findAllPaths( } trajectories += currentPaths.map { tangentPath -> - val lastDirection: Trajectory2D.Type = tangentPath.last().trajectoryType[2] + val lastDirection: Trajectory2D.Direction = tangentPath.last().endDirection val end = finalCircles[j]!! TangentPath( tangentPath.tangents + @@ -593,11 +598,8 @@ internal fun findAllPaths( Obstacle(end), Obstacle(end), LineSegment2D(finalPoint, finalPoint), - listOf( - lastDirection, - Trajectory2D.S, - j - ) + startDirection = lastDirection, + endDirection = j ) ) }.map { it.toTrajectory() } From f5201b6be0c2cf784e2a192193d2f7130caac857 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Apr 2023 17:42:40 +0300 Subject: [PATCH 48/58] refactoring directions --- .../kotlin/space/kscience/kmath/trajectory/Obstacle.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt index c4ff34295..553ca0388 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt @@ -69,7 +69,7 @@ internal fun Circle2D.tangentsToCircle( } else { angle1 - r2.sign * atan2(r.absoluteValue, l) } - val w = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) + val w = vector(-cos(angle2), sin(angle2)) put( route, LineSegment( @@ -412,7 +412,7 @@ private fun sortedObstacles( currentObstacle: Obstacle, obstacles: List, ): List { - return obstacles.sortedBy { norm(it.center - currentObstacle.center) }//.reversed() + return obstacles.sortedBy { norm(it.center - currentObstacle.center) } } private fun tangentsAlongTheObstacle( @@ -580,7 +580,6 @@ internal fun findAllPaths( newPaths.add(TangentPath(tangentPath.tangents + tangentsAlong + tangent)) } } else { - // minor changes from Python code newPaths.add(tangentPath) } } From 639a255aaf96c3b41a458774036b3f48efd86765 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Apr 2023 18:50:17 +0300 Subject: [PATCH 49/58] refactoring directions --- .../kscience/kmath/trajectory/DubinsPose2D.kt | 18 +++++++++++++-- .../kscience/kmath/trajectory/Obstacle.kt | 22 +++++++++---------- .../kscience/kmath/trajectory/ObstacleTest.kt | 12 ++++------ 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt index 8362d0cb5..078e158ea 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt @@ -3,6 +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. */ @file:UseSerializers(Euclidean2DSpace.VectorSerializer::class) + package space.kscience.kmath.trajectory import kotlinx.serialization.KSerializer @@ -22,6 +23,19 @@ import kotlin.math.atan2 public interface DubinsPose2D : DoubleVector2D { public val coordinates: DoubleVector2D public val bearing: Angle + + public companion object { + public fun bearingToVector(bearing: Angle): Vector2D = + Euclidean2DSpace.vector(cos(bearing), sin(bearing)) + + public fun vectorToBearing(vector2D: DoubleVector2D): Angle { + require(vector2D.x != 0.0 || vector2D.y != 0.0) { "Can't get bearing of zero vector" } + return atan2(vector2D.y, vector2D.x).radians + } + + public fun of(point: DoubleVector2D, direction: DoubleVector2D): DubinsPose2D = + DubinsPose2D(point, vectorToBearing(direction)) + } } @Serializable @@ -37,12 +51,12 @@ public class PhaseVector2D( private class DubinsPose2DImpl( override val coordinates: DoubleVector2D, override val bearing: Angle, -) : DubinsPose2D, DoubleVector2D by coordinates{ +) : DubinsPose2D, DoubleVector2D by coordinates { override fun toString(): String = "DubinsPose2D(x=$x, y=$y, bearing=$bearing)" } -public object DubinsPose2DSerializer: KSerializer{ +public object DubinsPose2DSerializer : KSerializer { private val proxySerializer = DubinsPose2DImpl.serializer() override val descriptor: SerialDescriptor diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt index 553ca0388..a00fe24d4 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt @@ -22,7 +22,7 @@ internal data class Tangent( val endObstacle: Obstacle, val lineSegment: LineSegment2D, val startDirection: Trajectory2D.Direction, - val endDirection: Trajectory2D.Direction = startDirection + val endDirection: Trajectory2D.Direction = startDirection, ) private class TangentPath(val tangents: List) { @@ -465,22 +465,22 @@ private fun TangentPath.toTrajectory(): CompositeTrajectory2D = CompositeTraject ) internal fun findAllPaths( - startingPoint: DoubleVector2D, - startingDirection: DoubleVector2D, + start: DubinsPose2D, startingRadius: Double, - finalPoint: DoubleVector2D, - finalDirection: DoubleVector2D, + finish: DubinsPose2D, finalRadius: Double, obstacles: List, ): List { + fun DubinsPose2D.direction() = vector(cos(bearing),sin(bearing)) + val initialCircles = constructTangentCircles( - startingPoint, - startingDirection, + start, + start.direction(), startingRadius ) val finalCircles = constructTangentCircles( - finalPoint, - finalDirection, + finish, + finish.direction(), finalRadius ) val trajectories = mutableListOf() @@ -495,7 +495,7 @@ internal fun findAllPaths( initialCircles[i]!!, Obstacle(listOf(initialCircles[i]!!)), Obstacle(listOf(initialCircles[i]!!)), - LineSegment2D(startingPoint, startingPoint), + LineSegment2D(start, start), i ) ) @@ -596,7 +596,7 @@ internal fun findAllPaths( end, Obstacle(end), Obstacle(end), - LineSegment2D(finalPoint, finalPoint), + LineSegment2D(finish, finish), startDirection = lastDirection, endDirection = j ) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt index 150b370d0..1a8c3a474 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt @@ -29,11 +29,9 @@ class ObstacleTest { ) val outputTangents = findAllPaths( - startPoint, - startDirection, + DubinsPose2D.of(startPoint, startDirection), startRadius, - finalPoint, - finalDirection, + DubinsPose2D.of(finalPoint, finalDirection), finalRadius, obstacles ) @@ -68,11 +66,9 @@ class ObstacleTest { ) ) val paths = findAllPaths( - startPoint, - startDirection, + DubinsPose2D.of(startPoint, startDirection), startRadius, - finalPoint, - finalDirection, + DubinsPose2D.of(finalPoint, finalDirection), finalRadius, obstacles ) From 025cb5806030665550f0767bc7de8ecec7ad3c7a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Apr 2023 19:02:24 +0300 Subject: [PATCH 50/58] refactoring directions --- .../kscience/kmath/trajectory/Obstacle.kt | 112 ++++++++---------- 1 file changed, 49 insertions(+), 63 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt index a00fe24d4..f2768bbca 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt @@ -229,6 +229,48 @@ public class Obstacle( } } + internal fun nextTangent(circle: Circle2D, direction: Trajectory2D.Direction): Tangent { + if (direction == boundaryRoute.first) { + for (i in circles.indices) { + if (circles[i] == circle) { + return tangents[i] + } + } + } else { + for (i in circles.indices) { + if (circles[i] == circle) { + if (i > 0) { + return Tangent( + circles[i], + circles[i - 1], + this, + this, + LineSegment2D( + tangents[i - 1].lineSegment.end, + tangents[i - 1].lineSegment.begin + ), + direction + ) + } else { + return Tangent( + circles[0], + circles.last(), + this, + this, + LineSegment2D( + tangents.last().lineSegment.end, + tangents.last().lineSegment.begin + ), + direction + ) + } + } + } + } + + error("next tangent not found") + } + override fun equals(other: Any?): Boolean { if (other == null || other !is Obstacle) return false return circles == other.circles @@ -239,50 +281,6 @@ public class Obstacle( } } -private fun Obstacle.nextTangent(circle: Circle2D, routeType: DubinsPath.Type): Tangent { - if (routeType == boundaryRoute) { - for (i in circles.indices) { - if (circles[i] == circle) { - return tangents[i] - } - } - } else { - for (i in circles.indices) { - if (circles[i] == circle) { - if (i > 0) { - return Tangent( - circles[i], - circles[i - 1], - this, - this, - LineSegment2D( - tangents[i - 1].lineSegment.end, - tangents[i - 1].lineSegment.begin - ), - startDirection = routeType.first, - endDirection = routeType.third - ) - } else { - return Tangent( - circles[0], - circles.last(), - this, - this, - LineSegment2D( - tangents.last().lineSegment.end, - tangents.last().lineSegment.begin - ), - startDirection = routeType.first, - endDirection = routeType.third - ) - } - } - } - } - - error("next tangent not found") -} - public fun Obstacle(vararg circles: Circle2D): Obstacle = Obstacle(listOf(*circles)) private fun LineSegment2D.intersectSegment(other: LineSegment2D): Boolean { @@ -417,15 +415,15 @@ private fun sortedObstacles( private fun tangentsAlongTheObstacle( initialCircle: Circle2D, - initialRoute: DubinsPath.Type, + direction: Trajectory2D.Direction, finalCircle: Circle2D, obstacle: Obstacle, ): List { val dubinsTangents = mutableListOf() - var tangent = obstacle.nextTangent(initialCircle, initialRoute) + var tangent = obstacle.nextTangent(initialCircle, direction) dubinsTangents.add(tangent) while (tangent.endCircle != finalCircle) { - tangent = obstacle.nextTangent(tangent.endCircle, initialRoute) + tangent = obstacle.nextTangent(tangent.endCircle, direction) dubinsTangents.add(tangent) } return dubinsTangents @@ -471,7 +469,7 @@ internal fun findAllPaths( finalRadius: Double, obstacles: List, ): List { - fun DubinsPose2D.direction() = vector(cos(bearing),sin(bearing)) + fun DubinsPose2D.direction() = vector(cos(bearing), sin(bearing)) val initialCircles = constructTangentCircles( start, @@ -537,11 +535,7 @@ internal fun findAllPaths( tangentPath.last().lineSegment.end, tangent.startObstacle.nextTangent( tangent.startCircle, - DubinsPath.Type( - currentDirection, - Trajectory2D.S, - currentDirection - ), + currentDirection ).lineSegment.begin, currentDirection ) @@ -554,11 +548,7 @@ internal fun findAllPaths( tangentsAlong = if (lengthCalculated > lengthMaxPossible) { tangentsAlongTheObstacle( currentCircle, - DubinsPath.Type( - currentDirection, - Trajectory2D.S, - currentDirection - ), + currentDirection, tangent.startCircle, currentObstacle ) @@ -568,11 +558,7 @@ internal fun findAllPaths( } else { tangentsAlong = tangentsAlongTheObstacle( currentCircle, - DubinsPath.Type( - currentDirection, - Trajectory2D.S, - currentDirection - ), + currentDirection, tangent.startCircle, currentObstacle ) From a0e2ef1afc08765240f0e00ac39205a25bdc92e8 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Apr 2023 19:33:43 +0300 Subject: [PATCH 51/58] refactor lines and segments --- .../space/kscience/kmath/geometry/Line.kt | 27 ++++++++++++++++--- .../kscience/kmath/geometry/projections.kt | 2 +- .../kscience/kmath/trajectory/Obstacle.kt | 14 +++++----- .../kscience/kmath/trajectory/Trajectory2D.kt | 2 +- 4 files changed, 32 insertions(+), 13 deletions(-) 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 e593150f1..a7f6ae35d 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,15 +5,23 @@ package space.kscience.kmath.geometry +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.kmath.operations.DoubleField.pow /** - * A line formed by [base] vector of start and a [direction] vector. Direction vector is not necessarily normalized, + * A line formed by [start] vector of start and a [direction] vector. Direction vector is not necessarily normalized, * but its length does not affect line properties */ +public interface Line { + public val start: V + public val direction: V +} + @Serializable -public data class Line(val base: V, val direction: V) +@SerialName("Line") +private data class LineImpl(override val start: V, override val direction: V): Line + +public fun Line(base: V, direction: V): Line = LineImpl(base, direction) public typealias Line2D = Line public typealias Line3D = Line @@ -21,8 +29,19 @@ public typealias Line3D = Line /** * A directed line segment between [begin] and [end] */ +public interface LineSegment { + public val begin: V + public val end: V +} + +/** + * Basic implementation for [LineSegment] + */ @Serializable -public data class LineSegment(val begin: V, val end: V) +@SerialName("LineSegment") +private data class LineSegmentImpl(override val begin: V, override val end: V) : LineSegment + +public fun LineSegment(begin: V, end: V): LineSegment = LineSegmentImpl(begin, end) public fun LineSegment.line(algebra: GeometrySpace): Line = with(algebra) { Line(begin, end - begin) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt index 6950abbdc..c5c3487a1 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt @@ -13,7 +13,7 @@ package space.kscience.kmath.geometry * @param line line to which vector should be projected */ public fun GeometrySpace.projectToLine(vector: V, line: Line): V = with(line) { - base + (direction dot (vector - base)) / (direction dot direction) * direction + start + (direction dot (vector - start)) / (direction dot direction) * direction } /** diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt index f2768bbca..3819afb54 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt @@ -23,7 +23,7 @@ internal data class Tangent( val lineSegment: LineSegment2D, val startDirection: Trajectory2D.Direction, val endDirection: Trajectory2D.Direction = startDirection, -) +): LineSegment2D by lineSegment private class TangentPath(val tangents: List) { fun last() = tangents.last() @@ -128,7 +128,7 @@ private fun dubinsTangentsToCircles( endCircle = secondCircle, startObstacle = firstObstacle, endObstacle = secondObstacle, - lineSegment = LineSegment2D( + lineSegment = LineSegment( firstCircle.center + w * r1, secondCircle.center + w * r2 ), @@ -192,7 +192,7 @@ public class Obstacle( other, this@Obstacle, this@Obstacle, - LineSegment2D( + LineSegment( center + w * r1, other.center + w * r2 ), @@ -245,7 +245,7 @@ public class Obstacle( circles[i - 1], this, this, - LineSegment2D( + LineSegment( tangents[i - 1].lineSegment.end, tangents[i - 1].lineSegment.begin ), @@ -257,7 +257,7 @@ public class Obstacle( circles.last(), this, this, - LineSegment2D( + LineSegment( tangents.last().lineSegment.end, tangents.last().lineSegment.begin ), @@ -493,7 +493,7 @@ internal fun findAllPaths( initialCircles[i]!!, Obstacle(listOf(initialCircles[i]!!)), Obstacle(listOf(initialCircles[i]!!)), - LineSegment2D(start, start), + LineSegment(start, start), i ) ) @@ -582,7 +582,7 @@ internal fun findAllPaths( end, Obstacle(end), Obstacle(end), - LineSegment2D(finish, finish), + LineSegment(finish, finish), startDirection = lastDirection, endDirection = j ) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt index d6974b105..8df0de237 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt @@ -50,7 +50,7 @@ public data class StraightTrajectory2D( public val bearing: Angle get() = (atan2(end.x - start.x, end.y - start.y).radians).normalized() } -public fun StraightTrajectory2D.toSegment(): LineSegment> = LineSegment2D(start, end) +public fun StraightTrajectory2D.toSegment(): LineSegment> = LineSegment(start, end) /** * An arc segment From 00ce7d5a48e4736ec6d80a480327a2c550787425 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 5 Apr 2023 13:30:13 +0300 Subject: [PATCH 52/58] Obstacle avoidance finished --- .../space/kscience/kmath/geometry/Polygon.kt | 14 +++++++++++++ .../kmath/geometry/ProjectionOntoLineTest.kt | 4 ++-- .../kscience/kmath/trajectory/DubinsPath.kt | 10 +++++----- .../kscience/kmath/trajectory/Obstacle.kt | 20 +++++++++++++++---- .../kscience/kmath/trajectory/Trajectory2D.kt | 12 +++++------ .../kscience/kmath/trajectory/DubinsTests.kt | 4 ++-- .../space/kscience/kmath/trajectory/math.kt | 4 ++-- 7 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt new file mode 100644 index 000000000..20f4a031e --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.geometry + + +/** + * A closed polygon in 2D space + */ +public interface Polygon { + public val points: List> +} \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt index cdb8ea870..7c6c105cf 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt @@ -63,7 +63,7 @@ internal class ProjectionOntoLineTest { @Test fun projectionOntoLine3d() = with(Euclidean3DSpace) { - val line = Line3D( + val line = Line( base = vector(1.0, 3.5, 0.07), direction = vector(2.0, -0.0037, 11.1111) ) @@ -77,7 +77,7 @@ internal class ProjectionOntoLineTest { val result = projectToLine(v, line) // assert that result is on the line - assertTrue(isCollinear(result - line.base, line.direction)) + assertTrue(isCollinear(result - line.start, line.direction)) // assert that PV vector is orthogonal to direction vector assertTrue(isOrthogonal(v - result, line.direction)) } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index 87ea52a69..a1563b29c 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -36,7 +36,7 @@ private fun outerTangent(from: Circle2D, to: Circle2D, direction: Direction): St } return StraightTrajectory2D( p1, - vector(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) + vector(p1.x + (centers.end.x - centers.begin.x), p1.y + (centers.end.y - centers.begin.y)) ) } @@ -207,7 +207,7 @@ public object DubinsPath { val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) val s = outerTangent(c1, c2, L) - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, R) + val a1 = CircleTrajectory2D.of(c1.center, start, s.begin, R) val a3 = CircleTrajectory2D.of(c2.center, s.end, end, R) return CompositeTrajectory2D(a1, s, a3) } @@ -216,7 +216,7 @@ public object DubinsPath { val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) val s = outerTangent(c1, c2, R) - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, L) + val a1 = CircleTrajectory2D.of(c1.center, start, s.begin, L) val a3 = CircleTrajectory2D.of(c2.center, s.end, end, L) return CompositeTrajectory2D(a1, s, a3) } @@ -227,7 +227,7 @@ public object DubinsPath { val s = innerTangent(c1, c2, R) if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, R) + val a1 = CircleTrajectory2D.of(c1.center, start, s.begin, R) val a3 = CircleTrajectory2D.of(c2.center, s.end, end, L) return CompositeTrajectory2D(a1, s, a3) } @@ -238,7 +238,7 @@ public object DubinsPath { val s = innerTangent(c1, c2, L) if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - val a1 = CircleTrajectory2D.of(c1.center, start, s.start, L) + val a1 = CircleTrajectory2D.of(c1.center, start, s.begin, L) val a3 = CircleTrajectory2D.of(c2.center, s.end, end, R) return CompositeTrajectory2D(a1, s, a3) } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt index 3819afb54..32061efea 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt @@ -23,7 +23,7 @@ internal data class Tangent( val lineSegment: LineSegment2D, val startDirection: Trajectory2D.Direction, val endDirection: Trajectory2D.Direction = startDirection, -): LineSegment2D by lineSegment +) : LineSegment2D by lineSegment private class TangentPath(val tangents: List) { fun last() = tangents.last() @@ -143,7 +143,7 @@ private fun dubinsTangentsToCircles( } } -public class Obstacle( +internal class Obstacle( public val circles: List, ) { internal val tangents: List = boundaryTangents().first @@ -281,7 +281,7 @@ public class Obstacle( } } -public fun Obstacle(vararg circles: Circle2D): Obstacle = Obstacle(listOf(*circles)) +internal fun Obstacle(vararg circles: Circle2D): Obstacle = Obstacle(listOf(*circles)) private fun LineSegment2D.intersectSegment(other: LineSegment2D): Boolean { fun crossProduct(v1: DoubleVector2D, v2: DoubleVector2D): Double { @@ -594,7 +594,19 @@ internal fun findAllPaths( } - +public object Obstacles { + public fun allPathsAvoiding( + start: DubinsPose2D, + finish: DubinsPose2D, + trajectoryRadius: Double, + obstaclePolygons: List>, + ): List { + val obstacles: List = obstaclePolygons.map { polygon -> + Obstacle(polygon.points.map { point -> Circle2D(point, trajectoryRadius) }) + } + return findAllPaths(start, trajectoryRadius, finish, trajectoryRadius, obstacles) + } +} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt index 8df0de237..59a8e613a 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt @@ -41,17 +41,15 @@ public sealed interface Trajectory2D { @Serializable @SerialName("straight") public data class StraightTrajectory2D( - public val start: DoubleVector2D, - public val end: DoubleVector2D, -) : Trajectory2D { + override val begin: DoubleVector2D, + override val end: DoubleVector2D, +) : Trajectory2D, LineSegment2D { - override val length: Double get() = start.distanceTo(end) + override val length: Double get() = begin.distanceTo(end) - public val bearing: Angle get() = (atan2(end.x - start.x, end.y - start.y).radians).normalized() + public val bearing: Angle get() = (atan2(end.x - begin.x, end.y - begin.y).radians).normalized() } -public fun StraightTrajectory2D.toSegment(): LineSegment> = LineSegment(start, end) - /** * An arc segment */ diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt index f5bfb884e..80f7173f1 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt @@ -20,7 +20,7 @@ class DubinsTests { val lineP1 = straight.shift(1, 10.0).inverse() val start = DubinsPose2D(straight.end, straight.bearing) - val end = DubinsPose2D(lineP1.start, lineP1.bearing) + val end = DubinsPose2D(lineP1.begin, lineP1.bearing) val radius = 2.0 val dubins = DubinsPath.all(start, end, radius) @@ -53,7 +53,7 @@ class DubinsTests { assertTrue(a.end.equalsFloat(b.start)) assertTrue(c.start.equalsFloat(b.end)) } else if (b is StraightTrajectory2D) { - assertTrue(a.end.equalsFloat(DubinsPose2D(b.start, b.bearing))) + assertTrue(a.end.equalsFloat(DubinsPose2D(b.begin, b.bearing))) assertTrue(c.start.equalsFloat(DubinsPose2D(b.end, b.bearing))) } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt index 24685f528..8b8ccf95e 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt @@ -14,14 +14,14 @@ import space.kscience.kmath.geometry.sin fun DubinsPose2D.equalsFloat(other: DubinsPose2D) = x.equalsFloat(other.x) && y.equalsFloat(other.y) && bearing.radians.equalsFloat(other.bearing.radians) -fun StraightTrajectory2D.inverse() = StraightTrajectory2D(end, start) +fun StraightTrajectory2D.inverse() = StraightTrajectory2D(end, begin) fun StraightTrajectory2D.shift(shift: Int, width: Double): StraightTrajectory2D = with(Euclidean2DSpace) { val dX = width * sin(inverse().bearing) val dY = width * sin(bearing) return StraightTrajectory2D( - vector(start.x - dX * shift, start.y - dY * shift), + vector(begin.x - dX * shift, begin.y - dY * shift), vector(end.x - dX * shift, end.y - dY * shift) ) } From 7cc6a4be400bb7195dba6df50259a2c48cee849f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 5 Apr 2023 15:26:09 +0300 Subject: [PATCH 53/58] remove trajectory --- CHANGELOG.md | 1 + build.gradle.kts | 2 +- gradle.properties | 2 +- kmath-trajectory/README.md | 34 - kmath-trajectory/build.gradle.kts | 21 - kmath-trajectory/docs/README-TEMPLATE.md | 13 - .../kscience/kmath/trajectory/DubinsPath.kt | 258 -------- .../kscience/kmath/trajectory/DubinsPose2D.kt | 75 --- .../kscience/kmath/trajectory/Obstacle.kt | 614 ------------------ .../kscience/kmath/trajectory/Trajectory2D.kt | 131 ---- .../kscience/kmath/trajectory/DubinsTests.kt | 61 -- .../kscience/kmath/trajectory/ObstacleTest.kt | 88 --- .../kscience/kmath/trajectory/TangentTest.kt | 64 -- .../space/kscience/kmath/trajectory/math.kt | 27 - .../kmath/trajectory/segments/ArcTests.kt | 32 - .../kmath/trajectory/segments/CircleTests.kt | 24 - .../kmath/trajectory/segments/LineTests.kt | 37 -- settings.gradle.kts | 1 - 18 files changed, 3 insertions(+), 1482 deletions(-) delete mode 100644 kmath-trajectory/README.md delete mode 100644 kmath-trajectory/build.gradle.kts delete mode 100644 kmath-trajectory/docs/README-TEMPLATE.md delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt delete mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt delete mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt delete mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt delete mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt delete mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt delete mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt delete mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index c5fa3f372..24b592430 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ ### Deprecated ### Removed +- Trajectory moved to https://github.com/SciProgCentre/maps-kt - Polynomials moved to https://github.com/SciProgCentre/kmath-polynomial ### Fixed diff --git a/build.gradle.kts b/build.gradle.kts index 9b1101a22..cd8dfb4a0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,7 @@ allprojects { } group = "space.kscience" - version = "0.3.1-dev-10" + version = "0.3.1-dev-11" } subprojects { diff --git a/gradle.properties b/gradle.properties index 262bcabfb..e33106c0c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin.native.ignoreDisabledTargets=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.14.5-kotlin-1.8.20-RC +toolsVersion=0.14.6-kotlin-1.8.20 org.gradle.parallel=true diff --git a/kmath-trajectory/README.md b/kmath-trajectory/README.md deleted file mode 100644 index ac2930b04..000000000 --- a/kmath-trajectory/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# kmath-trajectory - - - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-trajectory:0.3.1-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-trajectory:0.3.1-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-trajectory:0.3.1-dev-1") -} -``` - -## Contributors -Erik Schouten (github: @ESchouten, email: erik-schouten@hotmail.nl) diff --git a/kmath-trajectory/build.gradle.kts b/kmath-trajectory/build.gradle.kts deleted file mode 100644 index 32b87bb06..000000000 --- a/kmath-trajectory/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -plugins { - id("space.kscience.gradle.mpp") -} - -kscience{ - jvm() - js() - native() - - useContextReceivers() - useSerialization() - dependencies { - api(projects.kmath.kmathGeometry) - } -} - -readme { - description = "Path and trajectory optimization (to be moved to a separate project)" - maturity = space.kscience.gradle.Maturity.DEPRECATED - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) -} diff --git a/kmath-trajectory/docs/README-TEMPLATE.md b/kmath-trajectory/docs/README-TEMPLATE.md deleted file mode 100644 index eb8e4a0c0..000000000 --- a/kmath-trajectory/docs/README-TEMPLATE.md +++ /dev/null @@ -1,13 +0,0 @@ -# kmath-trajectory - - -${features} - -${artifact} - -## Author -Erik Schouten - -Github: ESchouten - -Email: erik-schouten@hotmail.nl diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt deleted file mode 100644 index a1563b29c..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2018-2022 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.trajectory - -import space.kscience.kmath.geometry.* -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.trajectory.Trajectory2D.* -import kotlin.math.acos - -internal fun DubinsPose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first - -internal fun DubinsPose2D.getRightCircle(radius: Double): Circle2D = getTangentCircles(radius).second - -internal fun DubinsPose2D.getTangentCircles(radius: Double): Pair = with(Euclidean2DSpace) { - val dX = radius * cos(bearing) - val dY = radius * sin(bearing) - return Circle2D(vector(x - dX, y + dY), radius) to Circle2D(vector(x + dX, y - dY), radius) -} - -private fun outerTangent(from: Circle2D, to: Circle2D, direction: Direction): StraightTrajectory2D = - with(Euclidean2DSpace) { - val centers = StraightTrajectory2D(from.center, to.center) - val p1 = when (direction) { - L -> vector( - from.center.x - from.radius * cos(centers.bearing), - from.center.y + from.radius * sin(centers.bearing) - ) - - R -> vector( - from.center.x + from.radius * cos(centers.bearing), - from.center.y - from.radius * sin(centers.bearing) - ) - } - return StraightTrajectory2D( - p1, - vector(p1.x + (centers.end.x - centers.begin.x), p1.y + (centers.end.y - centers.begin.y)) - ) - } - - -private fun innerTangent( - from: Circle2D, - to: Circle2D, - direction: Direction, -): StraightTrajectory2D? = - with(Euclidean2DSpace) { - val centers = StraightTrajectory2D(from.center, to.center) - if (centers.length < from.radius * 2) return null - val angle = when (direction) { - L -> centers.bearing + acos(from.radius * 2 / centers.length).radians - R -> centers.bearing - acos(from.radius * 2 / centers.length).radians - }.normalized() - - val dX = from.radius * sin(angle) - val dY = from.radius * cos(angle) - val p1 = vector(from.center.x + dX, from.center.y + dY) - val p2 = vector(to.center.x - dX, to.center.y - dY) - return StraightTrajectory2D(p1, p2) - } - - -@Suppress("DuplicatedCode") -public object DubinsPath { - - public data class Type( - public val first: Direction, - public val second: Trajectory2D.Type, - public val third: Direction, - ) { - public fun toList(): List = listOf(first, second, third) - - override fun toString(): String = "${first}${second}${third}" - - public companion object { - public val RLR: Type = Type(R, L, R) - public val LRL: Type = Type(L, R, L) - public val RSR: Type = Type(R, S, R) - public val LSL: Type = Type(L, S, L) - public val RSL: Type = Type(R, S, L) - public val LSR: Type = Type(L, S, R) - } - } - - /** - * Return Dubins trajectory type or null if trajectory is not a Dubins path - */ - public fun trajectoryTypeOf(trajectory2D: CompositeTrajectory2D): Type? { - if (trajectory2D.segments.size != 3) return null - val a = trajectory2D.segments.first() as? CircleTrajectory2D ?: return null - val b = trajectory2D.segments[1] - val c = trajectory2D.segments.last() as? CircleTrajectory2D ?: return null - return Type( - a.direction, - if (b is CircleTrajectory2D) b.direction else S, - c.direction - ) - } - - public fun all( - start: DubinsPose2D, - end: DubinsPose2D, - turningRadius: Double, - ): List = listOfNotNull( - rlr(start, end, turningRadius), - lrl(start, end, turningRadius), - rsr(start, end, turningRadius), - lsl(start, end, turningRadius), - rsl(start, end, turningRadius), - lsr(start, end, turningRadius) - ) - - public fun shortest(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D = - all(start, end, turningRadius).minBy { it.length } - - public fun rlr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? = - with(Euclidean2DSpace) { - val c1 = start.getRightCircle(turningRadius) - val c2 = end.getRightCircle(turningRadius) - val centers = StraightTrajectory2D(c1.center, c2.center) - if (centers.length > turningRadius * 4) return null - - val firstVariant = run { - var theta = (centers.bearing - acos(centers.length / (turningRadius * 4)).radians).normalized() - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle2D(p, turningRadius) - val p1 = vector(c1.center.x + dX, c1.center.y + dY) - theta = (centers.bearing + acos(centers.length / (turningRadius * 4)).radians).normalized() - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, R) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, L) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, R) - CompositeTrajectory2D(a1, a2, a3) - } - - val secondVariant = run { - var theta = (centers.bearing + acos(centers.length / (turningRadius * 4)).radians).normalized() - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle2D(p, turningRadius) - val p1 = vector(c1.center.x + dX, c1.center.y + dY) - theta = (centers.bearing - acos(centers.length / (turningRadius * 4)).radians).normalized() - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, R) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, L) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, R) - CompositeTrajectory2D(a1, a2, a3) - } - - return if (firstVariant.length < secondVariant.length) firstVariant else secondVariant - } - - public fun lrl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? = - with(Euclidean2DSpace) { - val c1 = start.getLeftCircle(turningRadius) - val c2 = end.getLeftCircle(turningRadius) - val centers = StraightTrajectory2D(c1.center, c2.center) - if (centers.length > turningRadius * 4) return null - - val firstVariant = run { - var theta = (centers.bearing + acos(centers.length / (turningRadius * 4)).radians).normalized() - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle2D(p, turningRadius) - val p1 = vector(c1.center.x + dX, c1.center.y + dY) - theta = (centers.bearing - acos(centers.length / (turningRadius * 4)).radians).normalized() - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, L) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, R) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, L) - CompositeTrajectory2D(a1, a2, a3) - } - - val secondVariant = run { - var theta = (centers.bearing - acos(centers.length / (turningRadius * 4)).radians).normalized() - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle2D(p, turningRadius) - val p1 = vector(c1.center.x + dX, c1.center.y + dY) - theta = (centers.bearing + acos(centers.length / (turningRadius * 4)).radians).normalized() - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = vector(e.center.x + dX, e.center.y + dY) - val a1 = CircleTrajectory2D.of(c1.center, start, p1, L) - val a2 = CircleTrajectory2D.of(e.center, p1, p2, R) - val a3 = CircleTrajectory2D.of(c2.center, p2, end, L) - CompositeTrajectory2D(a1, a2, a3) - } - - return if (firstVariant.length < secondVariant.length) firstVariant else secondVariant - } - - public fun rsr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D { - val c1 = start.getRightCircle(turningRadius) - val c2 = end.getRightCircle(turningRadius) - val s = outerTangent(c1, c2, L) - val a1 = CircleTrajectory2D.of(c1.center, start, s.begin, R) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, R) - return CompositeTrajectory2D(a1, s, a3) - } - - public fun lsl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D { - val c1 = start.getLeftCircle(turningRadius) - val c2 = end.getLeftCircle(turningRadius) - val s = outerTangent(c1, c2, R) - val a1 = CircleTrajectory2D.of(c1.center, start, s.begin, L) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, L) - return CompositeTrajectory2D(a1, s, a3) - } - - public fun rsl(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? { - val c1 = start.getRightCircle(turningRadius) - val c2 = end.getLeftCircle(turningRadius) - val s = innerTangent(c1, c2, R) - if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - - val a1 = CircleTrajectory2D.of(c1.center, start, s.begin, R) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, L) - return CompositeTrajectory2D(a1, s, a3) - } - - public fun lsr(start: DubinsPose2D, end: DubinsPose2D, turningRadius: Double): CompositeTrajectory2D? { - val c1 = start.getLeftCircle(turningRadius) - val c2 = end.getRightCircle(turningRadius) - val s = innerTangent(c1, c2, L) - if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null - - val a1 = CircleTrajectory2D.of(c1.center, start, s.begin, L) - val a3 = CircleTrajectory2D.of(c2.center, s.end, end, R) - return CompositeTrajectory2D(a1, s, a3) - } -} - -public typealias PathTypes = List - -public fun interface MaxCurvature { - public fun compute(startPoint: PhaseVector2D): Double -} - -public fun DubinsPath.shortest( - start: PhaseVector2D, - end: PhaseVector2D, - maxCurvature: MaxCurvature, -): CompositeTrajectory2D = shortest(start, end, maxCurvature.compute(start)) - diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt deleted file mode 100644 index 078e158ea..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPose2D.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2018-2022 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. - */ -@file:UseSerializers(Euclidean2DSpace.VectorSerializer::class) - -package space.kscience.kmath.trajectory - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import space.kscience.kmath.geometry.* -import kotlin.math.atan2 - -/** - * Combination of [Vector] and its view angle (clockwise from positive y-axis direction) - */ -@Serializable(DubinsPose2DSerializer::class) -public interface DubinsPose2D : DoubleVector2D { - public val coordinates: DoubleVector2D - public val bearing: Angle - - public companion object { - public fun bearingToVector(bearing: Angle): Vector2D = - Euclidean2DSpace.vector(cos(bearing), sin(bearing)) - - public fun vectorToBearing(vector2D: DoubleVector2D): Angle { - require(vector2D.x != 0.0 || vector2D.y != 0.0) { "Can't get bearing of zero vector" } - return atan2(vector2D.y, vector2D.x).radians - } - - public fun of(point: DoubleVector2D, direction: DoubleVector2D): DubinsPose2D = - DubinsPose2D(point, vectorToBearing(direction)) - } -} - -@Serializable -public class PhaseVector2D( - override val coordinates: DoubleVector2D, - public val velocity: DoubleVector2D, -) : DubinsPose2D, DoubleVector2D by coordinates { - override val bearing: Angle get() = atan2(velocity.x, velocity.y).radians -} - -@Serializable -@SerialName("DubinsPose2D") -private class DubinsPose2DImpl( - override val coordinates: DoubleVector2D, - override val bearing: Angle, -) : DubinsPose2D, DoubleVector2D by coordinates { - - override fun toString(): String = "DubinsPose2D(x=$x, y=$y, bearing=$bearing)" -} - -public object DubinsPose2DSerializer : KSerializer { - private val proxySerializer = DubinsPose2DImpl.serializer() - - override val descriptor: SerialDescriptor - get() = proxySerializer.descriptor - - override fun deserialize(decoder: Decoder): DubinsPose2D { - return decoder.decodeSerializableValue(proxySerializer) - } - - override fun serialize(encoder: Encoder, value: DubinsPose2D) { - val pose = value as? DubinsPose2DImpl ?: DubinsPose2DImpl(value.coordinates, value.bearing) - encoder.encodeSerializableValue(proxySerializer, pose) - } -} - -public fun DubinsPose2D(coordinate: DoubleVector2D, theta: Angle): DubinsPose2D = DubinsPose2DImpl(coordinate, theta) \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt deleted file mode 100644 index 32061efea..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Obstacle.kt +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.trajectory - -import space.kscience.kmath.geometry.* -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Euclidean2DSpace.minus -import space.kscience.kmath.geometry.Euclidean2DSpace.norm -import space.kscience.kmath.geometry.Euclidean2DSpace.plus -import space.kscience.kmath.geometry.Euclidean2DSpace.times -import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import space.kscience.kmath.operations.DoubleField.pow -import kotlin.math.* - -internal data class Tangent( - val startCircle: Circle2D, - val endCircle: Circle2D, - val startObstacle: Obstacle, - val endObstacle: Obstacle, - val lineSegment: LineSegment2D, - val startDirection: Trajectory2D.Direction, - val endDirection: Trajectory2D.Direction = startDirection, -) : LineSegment2D by lineSegment - -private class TangentPath(val tangents: List) { - fun last() = tangents.last() -} - -private fun TangentPath(vararg tangents: Tangent) = TangentPath(listOf(*tangents)) - -/** - * Create inner and outer tangents between two circles. - * This method returns a map of segments using [DubinsPath] connection type notation. - */ -internal fun Circle2D.tangentsToCircle( - other: Circle2D, -): Map = with(Euclidean2DSpace) { - //return empty map for concentric circles - if (center.equalsVector(other.center)) return emptyMap() - - // A line connecting centers - val line = LineSegment(center, other.center) - // Distance between centers - val distance = line.begin.distanceTo(line.end) - val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) - var angle2: Double - val routes = mapOf( - DubinsPath.Type.RSR to Pair(radius, other.radius), - DubinsPath.Type.RSL to Pair(radius, -other.radius), - DubinsPath.Type.LSR to Pair(-radius, other.radius), - DubinsPath.Type.LSL to Pair(-radius, -other.radius) - ) - return buildMap { - for ((route, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - val r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - if (distance * distance >= r * r) { - val l = sqrt(distance * distance - r * r) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, l) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, l) - } - val w = vector(-cos(angle2), sin(angle2)) - put( - route, - LineSegment( - center + w * r1, - other.center + w * r2 - ) - ) - } else { - throw Exception("Circles should not intersect") - } - } - } -} - -private fun dubinsTangentsToCircles( - firstCircle: Circle2D, - secondCircle: Circle2D, - firstObstacle: Obstacle, - secondObstacle: Obstacle, -): Map = with(Euclidean2DSpace) { - val line = LineSegment(firstCircle.center, secondCircle.center) - val distance = line.begin.distanceTo(line.end) - val angle1 = atan2( - secondCircle.center.x - firstCircle.center.x, - secondCircle.center.y - firstCircle.center.y - ) - var r: Double - var angle2: Double - val routes = mapOf( - DubinsPath.Type.RSR to Pair(firstCircle.radius, secondCircle.radius), - DubinsPath.Type.RSL to Pair(firstCircle.radius, -secondCircle.radius), - DubinsPath.Type.LSR to Pair(-firstCircle.radius, secondCircle.radius), - DubinsPath.Type.LSL to Pair(-firstCircle.radius, -secondCircle.radius) - ) - return buildMap { - for ((route: DubinsPath.Type, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - if (distance * distance >= r * r) { - val l = sqrt(distance * distance - r * r) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, l) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, l) - } - val w = vector(-cos(angle2), sin(angle2)) - put( - route, - Tangent( - startCircle = Circle2D(firstCircle.center, firstCircle.radius), - endCircle = secondCircle, - startObstacle = firstObstacle, - endObstacle = secondObstacle, - lineSegment = LineSegment( - firstCircle.center + w * r1, - secondCircle.center + w * r2 - ), - startDirection = route.first, - endDirection = route.third - ) - ) - } else { - throw Exception("Circles should not intersect") - } - } - } -} - -internal class Obstacle( - public val circles: List, -) { - internal val tangents: List = boundaryTangents().first - public val boundaryRoute: DubinsPath.Type = boundaryTangents().second - - public val center: Vector2D = vector( - circles.sumOf { it.center.x } / circles.size, - circles.sumOf { it.center.y } / circles.size - ) - - private fun boundaryTangents(): Pair, DubinsPath.Type> { - // outer tangents for a polygon circles can be either lsl or rsr - - fun Circle2D.dubinsTangentsToCircles( - other: Circle2D, - ): Map = with(Euclidean2DSpace) { - val line = LineSegment(center, other.center) - val d = line.begin.distanceTo(line.end) - val angle1 = atan2(other.center.x - center.x, other.center.y - center.y) - var r: Double - var angle2: Double - val routes = mapOf( - DubinsPath.Type.RSR to Pair(radius, other.radius), - DubinsPath.Type.LSL to Pair(-radius, -other.radius) - ) - return buildMap { - for ((routeType, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - if (d * d >= r * r) { - val l = (d * d - r * r).pow(0.5) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, l) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, l) - } - val w = vector(-cos(angle2), sin(angle2)) - put( - routeType, Tangent( - Circle2D(center, radius), - other, - this@Obstacle, - this@Obstacle, - LineSegment( - center + w * r1, - other.center + w * r2 - ), - startDirection = routeType.first, - endDirection = routeType.third - ) - ) - } else { - throw Exception("Circles should not intersect") - } - } - } - } - - val firstCircles = circles - val secondCircles = circles.slice(1..circles.lastIndex) + - circles[0] - val lslTangents = firstCircles.zip(secondCircles) - { a, b -> a.dubinsTangentsToCircles(b)[DubinsPath.Type.LSL]!! } - val rsrTangents = firstCircles.zip(secondCircles) - { a, b -> a.dubinsTangentsToCircles(b)[DubinsPath.Type.RSR]!! } - val center = vector( - circles.sumOf { it.center.x } / circles.size, - circles.sumOf { it.center.y } / circles.size - ) - val lslToCenter = lslTangents.sumOf { it.lineSegment.begin.distanceTo(center) } + - lslTangents.sumOf { it.lineSegment.end.distanceTo(center) } - val rsrToCenter = rsrTangents.sumOf { it.lineSegment.begin.distanceTo(center) } + - rsrTangents.sumOf { it.lineSegment.end.distanceTo(center) } - return if (rsrToCenter >= lslToCenter) { - Pair(rsrTangents, DubinsPath.Type.RSR) - } else { - Pair(lslTangents, DubinsPath.Type.LSL) - } - } - - internal fun nextTangent(circle: Circle2D, direction: Trajectory2D.Direction): Tangent { - if (direction == boundaryRoute.first) { - for (i in circles.indices) { - if (circles[i] == circle) { - return tangents[i] - } - } - } else { - for (i in circles.indices) { - if (circles[i] == circle) { - if (i > 0) { - return Tangent( - circles[i], - circles[i - 1], - this, - this, - LineSegment( - tangents[i - 1].lineSegment.end, - tangents[i - 1].lineSegment.begin - ), - direction - ) - } else { - return Tangent( - circles[0], - circles.last(), - this, - this, - LineSegment( - tangents.last().lineSegment.end, - tangents.last().lineSegment.begin - ), - direction - ) - } - } - } - } - - error("next tangent not found") - } - - override fun equals(other: Any?): Boolean { - if (other == null || other !is Obstacle) return false - return circles == other.circles - } - - override fun hashCode(): Int { - return circles.hashCode() - } -} - -internal fun Obstacle(vararg circles: Circle2D): Obstacle = Obstacle(listOf(*circles)) - -private fun LineSegment2D.intersectSegment(other: LineSegment2D): Boolean { - fun crossProduct(v1: DoubleVector2D, v2: DoubleVector2D): Double { - return v1.x * v2.y - v1.y * v2.x - } - return if (crossProduct(other.begin - begin, other.end - begin).sign == - crossProduct(other.begin - end, other.end - end).sign - ) { - false - } else { - crossProduct(begin - other.begin, end - other.begin).sign != crossProduct( - begin - other.end, - end - other.end - ).sign - } -} - -private fun LineSegment2D.intersectCircle(circle: Circle2D): Boolean { - val a = (begin.x - end.x).pow(2.0) + (begin.y - end.y).pow(2.0) - val b = 2 * ((begin.x - end.x) * (end.x - circle.center.x) + - (begin.y - end.y) * (end.y - circle.center.y)) - val c = (end.x - circle.center.x).pow(2.0) + (end.y - circle.center.y).pow(2.0) - - circle.radius.pow(2.0) - val d = b.pow(2.0) - 4 * a * c - if (d < 1e-6) { - return false - } else { - val t1 = (-b - d.pow(0.5)) * 0.5 / a - val t2 = (-b + d.pow(0.5)) * 0.5 / a - if (((0 < t1) and (t1 < 1)) or ((0 < t2) and (t2 < 1))) { - return true - } - } - return false -} - -private fun Tangent.intersectObstacle(obstacle: Obstacle): Boolean { - for (tangent in obstacle.tangents) { - if (lineSegment.intersectSegment(tangent.lineSegment)) { - return true - } - } - for (circle in obstacle.circles) { - if (lineSegment.intersectCircle(circle)) { - return true - } - } - return false -} - -private fun outerTangents(first: Obstacle, second: Obstacle): Map = buildMap { - for (circle1 in first.circles) { - for (circle2 in second.circles) { - for (tangent in dubinsTangentsToCircles(circle1, circle2, first, second)) { - if (!(tangent.value.intersectObstacle(first)) - and !(tangent.value.intersectObstacle(second)) - ) { - put( - tangent.key, - tangent.value - ) - } - } - } - } -} - -private fun arcLength( - circle: Circle2D, - point1: DoubleVector2D, - point2: DoubleVector2D, - direction: Trajectory2D.Direction, -): Double { - val phi1 = atan2(point1.y - circle.center.y, point1.x - circle.center.x) - val phi2 = atan2(point2.y - circle.center.y, point2.x - circle.center.x) - var angle = 0.0 - when (direction) { - Trajectory2D.L -> { - angle = if (phi2 >= phi1) { - phi2 - phi1 - } else { - 2 * PI + phi2 - phi1 - } - } - - Trajectory2D.R -> { - angle = if (phi2 >= phi1) { - 2 * PI - (phi2 - phi1) - } else { - -(phi2 - phi1) - } - } - } - return circle.radius * angle -} - -private fun normalVectors(v: DoubleVector2D, r: Double): Pair { - return Pair( - r * vector(v.y / norm(v), -v.x / norm(v)), - r * vector(-v.y / norm(v), v.x / norm(v)) - ) -} - -private fun constructTangentCircles( - point: DoubleVector2D, - direction: DoubleVector2D, - r: Double, -): Map { - val center1 = point + normalVectors(direction, r).first - val center2 = point + normalVectors(direction, r).second - val p1 = center1 - point - return if (atan2(p1.y, p1.x) - atan2(direction.y, direction.x) in listOf(PI / 2, -3 * PI / 2)) { - mapOf( - Trajectory2D.L to Circle2D(center1, r), - Trajectory2D.R to Circle2D(center2, r) - ) - } else { - mapOf( - Trajectory2D.L to Circle2D(center2, r), - Trajectory2D.R to Circle2D(center1, r) - ) - } -} - -private fun sortedObstacles( - currentObstacle: Obstacle, - obstacles: List, -): List { - return obstacles.sortedBy { norm(it.center - currentObstacle.center) } -} - -private fun tangentsAlongTheObstacle( - initialCircle: Circle2D, - direction: Trajectory2D.Direction, - finalCircle: Circle2D, - obstacle: Obstacle, -): List { - val dubinsTangents = mutableListOf() - var tangent = obstacle.nextTangent(initialCircle, direction) - dubinsTangents.add(tangent) - while (tangent.endCircle != finalCircle) { - tangent = obstacle.nextTangent(tangent.endCircle, direction) - dubinsTangents.add(tangent) - } - return dubinsTangents -} - -private fun allFinished( - paths: List, - finalObstacle: Obstacle, -): Boolean { - for (path in paths) { - if (path.last().endObstacle != finalObstacle) { - return false - } - } - return true -} - -private fun LineSegment2D.toTrajectory() = StraightTrajectory2D(begin, end) - - -private fun TangentPath.toTrajectory(): CompositeTrajectory2D = CompositeTrajectory2D( - buildList { - tangents.zipWithNext().forEach { (left, right) -> - add(left.lineSegment.toTrajectory()) - add( - CircleTrajectory2D.of( - right.startCircle.center, - left.lineSegment.end, - right.lineSegment.begin, - right.startDirection - ) - ) - } - - add(tangents.last().lineSegment.toTrajectory()) - } -) - -internal fun findAllPaths( - start: DubinsPose2D, - startingRadius: Double, - finish: DubinsPose2D, - finalRadius: Double, - obstacles: List, -): List { - fun DubinsPose2D.direction() = vector(cos(bearing), sin(bearing)) - - val initialCircles = constructTangentCircles( - start, - start.direction(), - startingRadius - ) - val finalCircles = constructTangentCircles( - finish, - finish.direction(), - finalRadius - ) - val trajectories = mutableListOf() - for (i in listOf(Trajectory2D.L, Trajectory2D.R)) { - for (j in listOf(Trajectory2D.L, Trajectory2D.R)) { - val finalCircle = finalCircles[j]!! - val finalObstacle = Obstacle(listOf(finalCircle)) - var currentPaths: List = listOf( - TangentPath( - Tangent( - initialCircles[i]!!, - initialCircles[i]!!, - Obstacle(listOf(initialCircles[i]!!)), - Obstacle(listOf(initialCircles[i]!!)), - LineSegment(start, start), - i - ) - ) - ) - while (!allFinished(currentPaths, finalObstacle)) { - val newPaths = mutableListOf() - for (tangentPath: TangentPath in currentPaths) { - val currentCircle = tangentPath.last().endCircle - val currentDirection: Trajectory2D.Direction = tangentPath.last().endDirection - val currentObstacle = tangentPath.last().endObstacle - var nextObstacle: Obstacle? = null - if (currentObstacle != finalObstacle) { - val tangentToFinal = outerTangents(currentObstacle, finalObstacle)[DubinsPath.Type( - currentDirection, - Trajectory2D.S, - j - )] - for (obstacle in sortedObstacles(currentObstacle, obstacles)) { - if (tangentToFinal!!.intersectObstacle(obstacle)) { - nextObstacle = obstacle - break - } - } - if (nextObstacle == null) { - nextObstacle = finalObstacle - } - val nextTangents: Map = outerTangents(currentObstacle, nextObstacle) - .filter { (key, tangent) -> - obstacles.none { obstacle -> tangent.intersectObstacle(obstacle) } && - key.first == currentDirection && - (nextObstacle != finalObstacle || key.third == j) - } - - var tangentsAlong: List - for (tangent in nextTangents.values) { - if (tangent.startCircle == tangentPath.last().endCircle) { - val lengthMaxPossible = arcLength( - tangent.startCircle, - tangentPath.last().lineSegment.end, - tangent.startObstacle.nextTangent( - tangent.startCircle, - currentDirection - ).lineSegment.begin, - currentDirection - ) - val lengthCalculated = arcLength( - tangent.startCircle, - tangentPath.last().lineSegment.end, - tangent.lineSegment.begin, - currentDirection - ) - tangentsAlong = if (lengthCalculated > lengthMaxPossible) { - tangentsAlongTheObstacle( - currentCircle, - currentDirection, - tangent.startCircle, - currentObstacle - ) - } else { - emptyList() - } - } else { - tangentsAlong = tangentsAlongTheObstacle( - currentCircle, - currentDirection, - tangent.startCircle, - currentObstacle - ) - } - newPaths.add(TangentPath(tangentPath.tangents + tangentsAlong + tangent)) - } - } else { - newPaths.add(tangentPath) - } - } - currentPaths = newPaths - } - - trajectories += currentPaths.map { tangentPath -> - val lastDirection: Trajectory2D.Direction = tangentPath.last().endDirection - val end = finalCircles[j]!! - TangentPath( - tangentPath.tangents + - Tangent( - end, - end, - Obstacle(end), - Obstacle(end), - LineSegment(finish, finish), - startDirection = lastDirection, - endDirection = j - ) - ) - }.map { it.toTrajectory() } - } - } - return trajectories -} - - -public object Obstacles { - public fun allPathsAvoiding( - start: DubinsPose2D, - finish: DubinsPose2D, - trajectoryRadius: Double, - obstaclePolygons: List>, - ): List { - val obstacles: List = obstaclePolygons.map { polygon -> - Obstacle(polygon.points.map { point -> Circle2D(point, trajectoryRadius) }) - } - return findAllPaths(start, trajectoryRadius, finish, trajectoryRadius, obstacles) - } -} - - - - - diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt deleted file mode 100644 index 59a8e613a..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory2D.kt +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2018-2022 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. - */ -@file:UseSerializers(Euclidean2DSpace.VectorSerializer::class) - -package space.kscience.kmath.trajectory - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import space.kscience.kmath.geometry.* -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import kotlin.math.atan2 - -@Serializable -public sealed interface Trajectory2D { - public val length: Double - - - public sealed interface Type - - public sealed interface Direction: Type - - public object R : Direction { - override fun toString(): String = "R" - } - - public object S : Type { - override fun toString(): String = "L" - } - - public object L : Direction { - override fun toString(): String = "L" - } -} - -/** - * Straight path segment. The order of start and end defines the direction - */ -@Serializable -@SerialName("straight") -public data class StraightTrajectory2D( - override val begin: DoubleVector2D, - override val end: DoubleVector2D, -) : Trajectory2D, LineSegment2D { - - override val length: Double get() = begin.distanceTo(end) - - public val bearing: Angle get() = (atan2(end.x - begin.x, end.y - begin.y).radians).normalized() -} - -/** - * An arc segment - */ -@Serializable -@SerialName("arc") -public data class CircleTrajectory2D( - public val circle: Circle2D, - public val start: DubinsPose2D, - public val end: DubinsPose2D, -) : Trajectory2D { - - /** - * Arc length in radians - */ - val arcLength: Angle - get() = if (direction == Trajectory2D.L) { - start.bearing - end.bearing - } else { - end.bearing - start.bearing - }.normalized() - - - override val length: Double by lazy { - circle.radius * arcLength.radians - } - - public val direction: Trajectory2D.Direction by lazy { - if (start.y < circle.center.y) { - if (start.bearing > Angle.pi) Trajectory2D.R else Trajectory2D.L - } else if (start.y > circle.center.y) { - if (start.bearing < Angle.pi) Trajectory2D.R else Trajectory2D.L - } else { - if (start.bearing == Angle.zero) { - if (start.x < circle.center.x) Trajectory2D.R else Trajectory2D.L - } else { - if (start.x > circle.center.x) Trajectory2D.R else Trajectory2D.L - } - } - } - - public companion object { - public fun of( - center: DoubleVector2D, - start: DoubleVector2D, - end: DoubleVector2D, - direction: Trajectory2D.Direction, - ): CircleTrajectory2D { - fun calculatePose( - vector: DoubleVector2D, - theta: Angle, - direction: Trajectory2D.Direction, - ): DubinsPose2D = DubinsPose2D( - vector, - when (direction) { - Trajectory2D.L -> (theta - Angle.piDiv2).normalized() - Trajectory2D.R -> (theta + Angle.piDiv2).normalized() - } - ) - - val s1 = StraightTrajectory2D(center, start) - val s2 = StraightTrajectory2D(center, end) - val pose1 = calculatePose(start, s1.bearing, direction) - val pose2 = calculatePose(end, s2.bearing, direction) - val trajectory = CircleTrajectory2D(Circle2D(center, s1.length), pose1, pose2) - if (trajectory.direction != direction) error("Trajectory direction mismatch") - return trajectory - } - } -} - -@Serializable -@SerialName("composite") -public class CompositeTrajectory2D(public val segments: List) : Trajectory2D { - override val length: Double get() = segments.sumOf { it.length } -} - -public fun CompositeTrajectory2D(vararg segments: Trajectory2D): CompositeTrajectory2D = - CompositeTrajectory2D(segments.toList()) - diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt deleted file mode 100644 index 80f7173f1..000000000 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/DubinsTests.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.trajectory - -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.equalsFloat -import kotlin.test.Test -import kotlin.test.assertNotNull -import kotlin.test.assertTrue - - -class DubinsTests { - - @Test - fun dubinsTest() = with(Euclidean2DSpace){ - val straight = StraightTrajectory2D(vector(0.0, 0.0), vector(100.0, 100.0)) - val lineP1 = straight.shift(1, 10.0).inverse() - - val start = DubinsPose2D(straight.end, straight.bearing) - val end = DubinsPose2D(lineP1.begin, lineP1.bearing) - val radius = 2.0 - val dubins = DubinsPath.all(start, end, radius) - - val absoluteDistance = start.distanceTo(end) - println("Absolute distance: $absoluteDistance") - - val expectedLengths = mapOf( - DubinsPath.Type.RLR to 13.067681939031397, - DubinsPath.Type.RSR to 12.28318530717957, - DubinsPath.Type.LSL to 32.84955592153878, - DubinsPath.Type.RSL to 23.37758938854081, - DubinsPath.Type.LSR to 23.37758938854081 - ) - - expectedLengths.forEach { - val path = dubins.find { p -> DubinsPath.trajectoryTypeOf(p) == it.key } - assertNotNull(path, "Path ${it.key} not found") - println("${it.key}: ${path.length}") - assertTrue(it.value.equalsFloat(path.length)) - - val a = path.segments[0] as CircleTrajectory2D - val b = path.segments[1] - val c = path.segments[2] as CircleTrajectory2D - - assertTrue(start.equalsFloat(a.start)) - assertTrue(end.equalsFloat(c.end)) - - // Not working, theta double precision inaccuracy - if (b is CircleTrajectory2D) { - assertTrue(a.end.equalsFloat(b.start)) - assertTrue(c.start.equalsFloat(b.end)) - } else if (b is StraightTrajectory2D) { - assertTrue(a.end.equalsFloat(DubinsPose2D(b.begin, b.bearing))) - assertTrue(c.start.equalsFloat(DubinsPose2D(b.end, b.bearing))) - } - } - } -} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt deleted file mode 100644 index 1a8c3a474..000000000 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/ObstacleTest.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.trajectory - -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import kotlin.test.Test -import kotlin.test.assertEquals - -class ObstacleTest { - @Test - fun firstPath() { - val startPoint = vector(-5.0, -1.0) - val startDirection = vector(1.0, 1.0) - val startRadius = 0.5 - val finalPoint = vector(20.0, 4.0) - val finalDirection = vector(1.0, -1.0) - val finalRadius = 0.5 - - val obstacles = listOf( - Obstacle( - listOf( - Circle2D(vector(7.0, 1.0), 5.0) - ) - ) - ) - - val outputTangents = findAllPaths( - DubinsPose2D.of(startPoint, startDirection), - startRadius, - DubinsPose2D.of(finalPoint, finalDirection), - finalRadius, - obstacles - ) - val length = outputTangents.minOf { it.length } - assertEquals(27.2113183, length, 1e-6) - } - - @Test - fun secondPath() { - val startPoint = vector(-5.0, -1.0) - val startDirection = vector(1.0, 1.0) - val startRadius = 0.5 - val finalPoint = vector(20.0, 4.0) - val finalDirection = vector(1.0, -1.0) - val finalRadius = 0.5 - - val obstacles = listOf( - Obstacle( - listOf( - Circle2D(vector(1.0, 6.5), 0.5), - Circle2D(vector(2.0, 1.0), 0.5), - Circle2D(vector(6.0, 0.0), 0.5), - Circle2D(vector(5.0, 5.0), 0.5) - ) - ), Obstacle( - listOf( - Circle2D(vector(10.0, 1.0), 0.5), - Circle2D(vector(16.0, 0.0), 0.5), - Circle2D(vector(14.0, 6.0), 0.5), - Circle2D(vector(9.0, 4.0), 0.5) - ) - ) - ) - val paths = findAllPaths( - DubinsPose2D.of(startPoint, startDirection), - startRadius, - DubinsPose2D.of(finalPoint, finalDirection), - finalRadius, - obstacles - ) - val length = paths.minOf { it.length } - assertEquals(28.9678224, length, 1e-6) - } - - @Test - fun equalObstacles() { - val circle1 = Circle2D(vector(1.0, 6.5), 0.5) - val circle2 = Circle2D(vector(1.0, 6.5), 0.5) - assertEquals(circle1, circle2) - val obstacle1 = Obstacle(listOf(circle1)) - val obstacle2 = Obstacle(listOf(circle2)) - assertEquals(obstacle1, obstacle2) - } -} \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt deleted file mode 100644 index 2ae89038c..000000000 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/TangentTest.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.trajectory - -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import space.kscience.kmath.geometry.LineSegment -import space.kscience.kmath.geometry.equalsLine -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -import kotlin.test.assertTrue - -class TangentTest { - @Test - fun tangents() { - val c1 = Circle2D(vector(0.0, 0.0), 1.0) - val c2 = Circle2D(vector(4.0, 0.0), 1.0) - val routes = listOf( - DubinsPath.Type.RSR, - DubinsPath.Type.RSL, - DubinsPath.Type.LSR, - DubinsPath.Type.LSL - ) - val segments = listOf( - LineSegment( - begin = vector(0.0, 1.0), - end = vector(4.0, 1.0) - ), - LineSegment( - begin = vector(0.5, 0.8660254), - end = vector(3.5, -0.8660254) - ), - LineSegment( - begin = vector(0.5, -0.8660254), - end = vector(3.5, 0.8660254) - ), - LineSegment( - begin = vector(0.0, -1.0), - end = vector(4.0, -1.0) - ) - ) - - val tangentMap = c1.tangentsToCircle(c2) - val tangentMapKeys = tangentMap.keys.toList() - val tangentMapValues = tangentMap.values.toList() - - assertEquals(routes, tangentMapKeys) - for (i in segments.indices) { - assertTrue(segments[i].equalsLine(Euclidean2DSpace, tangentMapValues[i])) - } - } - - @Test - fun concentric(){ - val c1 = Circle2D(vector(0.0, 0.0), 10.0) - val c2 = Circle2D(vector(0.0, 0.0), 1.0) - assertEquals(emptyMap(), c1.tangentsToCircle(c2)) - } -} \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt deleted file mode 100644 index 8b8ccf95e..000000000 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/math.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018-2022 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.trajectory - -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.equalsFloat -import space.kscience.kmath.geometry.radians -import space.kscience.kmath.geometry.sin - - -fun DubinsPose2D.equalsFloat(other: DubinsPose2D) = - x.equalsFloat(other.x) && y.equalsFloat(other.y) && bearing.radians.equalsFloat(other.bearing.radians) - -fun StraightTrajectory2D.inverse() = StraightTrajectory2D(end, begin) - -fun StraightTrajectory2D.shift(shift: Int, width: Double): StraightTrajectory2D = with(Euclidean2DSpace) { - val dX = width * sin(inverse().bearing) - val dY = width * sin(bearing) - - return StraightTrajectory2D( - vector(begin.x - dX * shift, begin.y - dY * shift), - vector(end.x - dX * shift, end.y - dY * shift) - ) -} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt deleted file mode 100644 index b3825b93b..000000000 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2018-2022 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.trajectory.segments - -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.circumference -import space.kscience.kmath.geometry.degrees -import space.kscience.kmath.trajectory.CircleTrajectory2D -import space.kscience.kmath.trajectory.Trajectory2D -import kotlin.test.Test -import kotlin.test.assertEquals - -class ArcTests { - - @Test - fun arcTest() = with(Euclidean2DSpace){ - val circle = Circle2D(vector(0.0, 0.0), 2.0) - val arc = CircleTrajectory2D.of( - circle.center, - vector(-2.0, 0.0), - vector(0.0, 2.0), - Trajectory2D.R - ) - assertEquals(circle.circumference / 4, arc.length, 1.0) - assertEquals(0.0, arc.start.bearing.degrees) - assertEquals(90.0, arc.end.bearing.degrees) - } -} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt deleted file mode 100644 index c3fca06ec..000000000 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2018-2022 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.trajectory.segments - -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.circumference -import kotlin.test.Test -import kotlin.test.assertEquals - -class CircleTests { - - @Test - fun arcTest() { - val center = Euclidean2DSpace.vector(0.0, 0.0) - val radius = 2.0 - val expectedCircumference = 12.56637 - val circle = Circle2D(center, radius) - assertEquals(expectedCircumference, circle.circumference, 1e-4) - } -} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt deleted file mode 100644 index 54deb2193..000000000 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2018-2022 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.trajectory.segments - -import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.degrees -import space.kscience.kmath.trajectory.StraightTrajectory2D -import kotlin.math.pow -import kotlin.math.sqrt -import kotlin.test.Test -import kotlin.test.assertEquals - -class LineTests { - - @Test - fun lineTest() = with(Euclidean2DSpace){ - val straight = StraightTrajectory2D(vector(0.0, 0.0), vector(100.0, 100.0)) - assertEquals(sqrt(100.0.pow(2) + 100.0.pow(2)), straight.length) - assertEquals(45.0, straight.bearing.degrees) - } - - @Test - fun lineAngleTest() = with(Euclidean2DSpace){ - //val zero = Vector2D(0.0, 0.0) - val north = StraightTrajectory2D(zero, vector(0.0, 2.0)) - assertEquals(0.0, north.bearing.degrees) - val east = StraightTrajectory2D(zero, vector(2.0, 0.0)) - assertEquals(90.0, east.bearing.degrees) - val south = StraightTrajectory2D(zero, vector(0.0, -2.0)) - assertEquals(180.0, south.bearing.degrees) - val west = StraightTrajectory2D(zero, vector(-2.0, 0.0)) - assertEquals(270.0, west.bearing.degrees) - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 7d92dc36e..f158f3444 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -44,7 +44,6 @@ include( ":kmath-jupyter", ":kmath-symja", ":kmath-jafama", - ":kmath-trajectory", ":examples", ":benchmarks", ) From ce388fed44205fa813028facb29eee0ef3cc59c6 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 7 Apr 2023 19:55:34 +0300 Subject: [PATCH 54/58] Move annotations to base package. Fix series --- CHANGELOG.md | 1 + README.md | 29 +------- .../ExpressionsInterpretersBenchmark.kt | 3 +- .../kmath/benchmarks/BigIntBenchmark.kt | 2 +- .../kmath/benchmarks/NDFieldBenchmark.kt | 2 +- build.gradle.kts | 2 +- .../kmath/ejml/codegen/ejmlCodegen.kt | 2 +- .../kmath/{stat => series}/DateTimeSeries.kt | 4 +- .../space/kscience/kmath/series/analyzeDif.kt | 55 +++++++++------- .../kmath/structures/StreamDoubleFieldND.kt | 2 +- .../structures/StructureReadBenchmark.kt | 2 +- kmath-ast/README.md | 6 +- .../space/kscience/kmath/ast/TypedMst.kt | 2 +- .../kscience/kmath/ast/evaluateConstants.kt | 2 +- .../ast/rendering/LatexSyntaxRenderer.kt | 2 +- .../ast/rendering/MathMLSyntaxRenderer.kt | 2 +- .../kmath/ast/rendering/MathRenderer.kt | 2 +- .../kmath/ast/rendering/MathSyntax.kt | 2 +- .../kmath/ast/rendering/SyntaxRenderer.kt | 2 +- .../kscience/kmath/ast/rendering/features.kt | 2 +- .../kscience/kmath/ast/rendering/phases.kt | 2 +- .../space/kscience/kmath/estree/estree.kt | 2 +- .../kmath/wasm/internal/WasmBuilder.kt | 2 +- .../kotlin/space/kscience/kmath/wasm/wasm.kt | 2 +- .../kotlin/space/kscience/kmath/asm/asm.kt | 2 +- .../kmath/asm/internal/PrimitiveAsmBuilder.kt | 2 +- kmath-commons/README.md | 6 +- .../commons/expressions/CmDsExpression.kt | 2 +- .../kmath/commons/integration/CMIntegrator.kt | 2 +- .../kscience/kmath/commons/linear/CMMatrix.kt | 2 +- .../kmath/commons/optimization/CMOptimizer.kt | 2 +- .../commons/integration/IntegrationTest.kt | 2 +- .../commons/optimization/OptimizeTest.kt | 2 +- kmath-complex/README.md | 6 +- .../space/kscience/kmath/complex/Complex.kt | 2 +- .../kscience/kmath/complex/ComplexFieldND.kt | 4 +- .../kscience/kmath/complex/Quaternion.kt | 2 +- kmath-core/README.md | 6 +- kmath-core/build.gradle.kts | 1 + .../space/kscience/kmath/data/ColumnarData.kt | 4 +- .../kscience/kmath/data/XYColumnarData.kt | 4 +- .../kmath/data/XYErrorColumnarData.kt | 2 +- .../kscience/kmath/data/XYZColumnarData.kt | 2 +- .../space/kscience/kmath/domains/Domain1D.kt | 2 +- .../kscience/kmath/domains/DoubleDomain.kt | 2 +- .../kmath/domains/HyperSquareDomain.kt | 2 +- .../kmath/domains/UnconstrainedDomain.kt | 2 +- .../kscience/kmath/expressions/DSAlgebra.kt | 2 +- .../kscience/kmath/expressions/Expression.kt | 2 +- .../kscience/kmath/expressions/MstAlgebra.kt | 2 +- .../kscience/kmath/expressions/NamedMatrix.kt | 4 +- .../kmath/expressions/SimpleAutoDiff.kt | 2 +- .../kmath/expressions/SymbolIndexer.kt | 2 +- .../kmath/linear/BufferedLinearSpace.kt | 2 +- .../kmath/linear/DoubleLinearSpace.kt | 2 +- .../kscience/kmath/linear/LinearSpace.kt | 2 +- .../kscience/kmath/linear/LupDecomposition.kt | 2 +- .../kscience/kmath/linear/MatrixBuilder.kt | 2 +- .../kscience/kmath/linear/MatrixWrapper.kt | 2 +- .../space/kscience/kmath/misc/collections.kt | 2 +- .../space/kscience/kmath/misc/sorting.kt | 1 + .../space/kscience/kmath/nd/AlgebraND.kt | 4 +- .../kscience/kmath/nd/BufferAlgebraND.kt | 4 +- .../space/kscience/kmath/nd/BufferND.kt | 2 +- .../space/kscience/kmath/nd/DoubleFieldND.kt | 4 +- .../space/kscience/kmath/nd/IntRingND.kt | 2 +- .../kscience/kmath/nd/PermutedStructureND.kt | 2 +- .../kotlin/space/kscience/kmath/nd/ShapeND.kt | 2 +- .../space/kscience/kmath/nd/ShortRingND.kt | 2 +- .../space/kscience/kmath/nd/Structure1D.kt | 2 +- .../space/kscience/kmath/nd/Structure2D.kt | 2 +- .../space/kscience/kmath/nd/StructureND.kt | 2 +- .../kscience/kmath/nd/VirtualStructureND.kt | 4 +- .../space/kscience/kmath/nd/operationsND.kt | 2 +- .../kscience/kmath/nd/primitiveStructureND.kt | 2 +- .../kscience/kmath/operations/Algebra.kt | 2 +- .../space/kscience/kmath/operations/BigInt.kt | 2 +- .../kmath/operations/DoubleBufferOps.kt | 5 +- .../kscience/kmath/operations/LogicAlgebra.kt | 2 +- .../kmath/operations/NumericAlgebra.kt | 2 +- .../kmath/operations/algebraExtensions.kt | 2 +- .../kscience/kmath/structures/BufferView.kt | 2 +- .../kscience/kmath/structures/MemoryBuffer.kt | 4 +- .../kmath/structures/bufferExtensions.kt | 2 +- .../kmath/structures/bufferPrimitiveAccess.kt | 2 +- .../kscience/kmath/expressions/DSTest.kt | 2 +- .../kmath/expressions/InterpretTest.kt | 2 +- .../kmath/linear/DoubleLUSolverTest.kt | 4 +- .../space/kscience/kmath/linear/MatrixTest.kt | 4 +- .../kmath/operations/BigIntAlgebraTest.kt | 2 +- .../kmath/structures/NumberNDFieldTest.kt | 9 ++- .../space/kscience/kmath/misc/numbers.kt | 12 ++++ .../kscience/kmath/operations/isInteger.kt | 12 ++++ kmath-coroutines/README.md | 6 +- .../space/kscience/kmath/chains/Chain.kt | 2 +- .../kmath/structures/LazyStructureND.kt | 2 +- kmath-dimensions/README.md | 6 +- kmath-ejml/README.md | 6 +- .../kscience/kmath/ejml/EjmlLinearSpace.kt | 2 +- .../space/kscience/kmath/ejml/_generated.kt | 2 +- .../kscience/kmath/ejml/EjmlMatrixTest.kt | 4 +- kmath-for-real/README.md | 6 +- .../space/kscience/kmath/real/DoubleVector.kt | 2 +- .../space/kscience/kmath/real/RealMatrix.kt | 4 +- .../kotlin/space/kscience/kmath/real/grids.kt | 2 +- .../kscience/kmath/real/DoubleMatrixTest.kt | 4 +- .../space/kscience/kmath/real/GridTest.kt | 6 +- kmath-functions/README.md | 6 +- .../kscience/kmath/functions/Piecewise.kt | 2 +- .../kmath/functions/polynomialUtil.kt | 2 +- .../kmath/integration/GaussIntegrator.kt | 2 +- .../kmath/integration/SimpsonIntegrator.kt | 2 +- .../kmath/integration/SplineIntegrator.kt | 4 +- .../kmath/integration/UnivariateIntegrand.kt | 2 +- .../kmath/interpolation/Interpolator.kt | 2 +- .../kmath/interpolation/LinearInterpolator.kt | 2 +- .../kmath/interpolation/SplineInterpolator.kt | 2 +- .../kmath/functions/PolynomialUtilTest.kt | 2 +- .../kmath/functions/testUtils/Rational.kt | 2 +- .../kmath/integration/GaussIntegralTest.kt | 2 +- .../kmath/integration/SimpsonIntegralTest.kt | 2 +- .../kmath/integration/SplineIntegralTest.kt | 2 +- kmath-geometry/README.md | 6 +- .../kscience/kmath/geometry/rotations3D.kt | 7 +- kmath-histograms/README.md | 6 +- .../kscience/kmath/histogram/Histogram1D.kt | 2 +- .../kscience/kmath/histogram/HistogramND.kt | 2 +- .../kmath/histogram/UniformHistogram1D.kt | 2 +- .../histogram/UniformHistogramGroupND.kt | 4 +- .../histogram/MultivariateHistogramTest.kt | 4 +- .../kmath/histogram/UniformHistogram1DTest.kt | 2 +- .../kmath/histogram/TreeHistogramGroup.kt | 2 +- .../kmath/histogram/TreeHistogramTest.kt | 2 +- kmath-jafama/README.md | 6 +- kmath-jupyter/README.md | 6 +- .../kscience/kmath/jupyter/KMathJupyter.kt | 2 +- kmath-kotlingrad/README.md | 6 +- kmath-memory/README.md | 6 +- kmath-memory/build.gradle.kts | 1 + .../space/kscience/kmath}/annotations.kt | 4 +- .../space/kscience/kmath/memory/Memory.kt | 15 ++--- .../kscience/kmath/memory/DataViewMemory.kt | 4 +- .../kscience/kmath/memory/ByteBufferMemory.kt | 4 +- .../kscience/kmath/memory/NativeMemory.kt | 4 +- .../space/kscience/kmath/memory/WasmMemory.kt | 66 +++++++++++++++++++ kmath-multik/README.md | 6 +- .../kmath/multik/MultikDoubleAlgebra.kt | 2 +- .../kscience/kmath/multik/MultikTensor.kt | 2 +- .../kmath/multik/MultikTensorAlgebra.kt | 7 +- .../kscience/kmath/multik/MultikNDTest.kt | 2 +- kmath-nd4j/README.md | 6 +- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 6 +- .../kscience/kmath/nd4j/Nd4jArrayStructure.kt | 2 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 4 +- .../kmath/nd4j/Nd4jArrayAlgebraTest.kt | 2 +- .../kmath/nd4j/Nd4jArrayStructureTest.kt | 2 +- kmath-optimization/README.md | 6 +- .../kmath/optimization/QowOptimizer.kt | 2 +- .../kscience/kmath/optimization/XYFit.kt | 2 +- .../kmath/optimization/logLikelihood.kt | 2 +- kmath-stat/README.md | 6 +- kmath-stat/build.gradle.kts | 2 +- .../space/kscience/kmath/samplers/Sampler.kt | 2 +- .../kmath/series/MonotonicSeriesAlgebra.kt | 8 +-- .../kscience/kmath/series/SeriesAlgebra.kt | 39 +++++++---- .../space/kscience/kmath/series/resampling.kt | 22 +++++++ .../kscience/kmath/stat/StatisticalAlgebra.kt | 4 +- .../space/kscience/kmath/series/TestSeries.kt | 28 ++++++++ kmath-symja/README.md | 6 +- kmath-tensorflow/README.md | 6 +- .../tensorflow/DoubleTensorFlowAlgebra.kt | 4 +- .../kmath/tensorflow/TensorFlowAlgebra.kt | 6 +- .../kmath/tensorflow/DoubleTensorFlowOps.kt | 2 +- kmath-tensors/README.md | 6 +- .../core/BroadcastDoubleTensorAlgebra.kt | 2 +- .../kmath/tensors/core/BufferedTensor.kt | 2 +- .../kmath/tensors/core/DoubleTensor.kt | 7 +- .../kmath/tensors/core/DoubleTensor1D.kt | 2 +- .../kmath/tensors/core/DoubleTensor2D.kt | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 11 ++-- .../kscience/kmath/tensors/core/IntTensor.kt | 2 +- .../kmath/tensors/core/IntTensorAlgebra.kt | 2 +- .../tensors/core/internal/broadcastUtils.kt | 2 +- .../kmath/tensors/core/internal/utils.kt | 2 +- .../tensors/core/tensorAlgebraExtensions.kt | 2 +- .../kmath/tensors/core/TestDoubleTensor.kt | 3 +- kmath-viktor/README.md | 6 +- .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 6 +- .../kmath/viktor/ViktorStructureND.kt | 2 +- test-utils/build.gradle.kts | 1 + 190 files changed, 485 insertions(+), 350 deletions(-) rename examples/src/main/kotlin/space/kscience/kmath/{stat => series}/DateTimeSeries.kt (79%) create mode 100644 kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt create mode 100644 kmath-core/src/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt rename {kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc => kmath-memory/src/commonMain/kotlin/space/kscience/kmath}/annotations.kt (95%) create mode 100644 kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmMemory.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt create mode 100644 kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b592430..0d4e6123b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ ### Changed +- Annotations moved to `space.kscience.kmath` - Exponential operations merged with hyperbolic functions - Space is replaced by Group. Space is reserved for vector spaces. - VectorSpace is now a vector space diff --git a/README.md b/README.md index 03e803180..dbd670264 100644 --- a/README.md +++ b/README.md @@ -214,28 +214,6 @@ One can still use generic algebras though. > > **Maturity**: EXPERIMENTAL -### [kmath-polynomial](kmath-polynomial) -> -> -> **Maturity**: PROTOTYPE -> -> **Features:** -> - [polynomial abstraction](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Abstraction for polynomial spaces. -> - [rational function abstraction](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt) : Abstraction for rational functions spaces. -> - ["list" polynomials](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt) : List implementation of univariate polynomials. -> - ["list" rational functions](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt) : List implementation of univariate rational functions. -> - ["list" polynomials and rational functions constructors](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt) : Constructors for list polynomials and rational functions. -> - ["list" polynomials and rational functions utilities](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt) : Utilities for list polynomials and rational functions. -> - ["numbered" polynomials](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt) : Numbered implementation of multivariate polynomials. -> - ["numbered" rational functions](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt) : Numbered implementation of multivariate rational functions. -> - ["numbered" polynomials and rational functions constructors](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt) : Constructors for numbered polynomials and rational functions. -> - ["numbered" polynomials and rational functions utilities](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt) : Utilities for numbered polynomials and rational functions. -> - ["labeled" polynomials](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt) : Labeled implementation of multivariate polynomials. -> - ["labeled" rational functions](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt) : Labeled implementation of multivariate rational functions. -> - ["labeled" polynomials and rational functions constructors](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt) : Constructors for labeled polynomials and rational functions. -> - ["labeled" polynomials and rational functions utilities](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt) : Utilities for labeled polynomials and rational functions. - - ### [kmath-stat](kmath-stat) > > @@ -262,11 +240,6 @@ One can still use generic algebras though. > - [linear algebra operations](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. -### [kmath-trajectory](kmath-trajectory) -> Path and trajectory optimization -> -> **Maturity**: PROTOTYPE - ### [kmath-viktor](kmath-viktor) > > @@ -325,4 +298,4 @@ Gradle `6.0+` is required for multiplatform artifacts. 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/SciProgCentre/kmath/labels/waiting%20for%20a%20hero) label. \ No newline at end of file +[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. \ No newline at end of file diff --git a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index fd1b4307a..cb07e489a 100644 --- a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -9,8 +9,8 @@ import kotlinx.benchmark.Benchmark import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke @@ -94,6 +94,7 @@ class ExpressionsInterpretersBenchmark { } private val mst = node.toExpression(DoubleField) + @OptIn(UnstableKMathAPI::class) private val wasm = node.wasmCompileToExpression(DoubleField) private val estree = node.estreeCompileToExpression(DoubleField) diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt index 19795b9eb..d07b7b4df 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt @@ -10,7 +10,7 @@ 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.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.BigIntField import space.kscience.kmath.operations.JBigIntegerField import space.kscience.kmath.operations.invoke diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt index 3d39e89a5..fb8d845e8 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ones import org.jetbrains.kotlinx.multik.ndarray.data.DN import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.misc.UnsafeKMathAPI +import space.kscience.kmath.UnsafeKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.nd4j.nd4j import space.kscience.kmath.operations.DoubleField diff --git a/build.gradle.kts b/build.gradle.kts index cd8dfb4a0..2eea9c47b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,7 @@ allprojects { } group = "space.kscience" - version = "0.3.1-dev-11" + version = "0.4.0-dev-1" } subprojects { 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 183510232..d973ebae4 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 @@ -385,7 +385,7 @@ import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC import space.kscience.kmath.linear.* import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.FloatField diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DateTimeSeries.kt b/examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt similarity index 79% rename from examples/src/main/kotlin/space/kscience/kmath/stat/DateTimeSeries.kt rename to examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt index 9836db6ea..ca10fc290 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DateTimeSeries.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt @@ -3,13 +3,11 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.stat +package space.kscience.kmath.series import kotlinx.datetime.Instant import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.bufferAlgebra -import space.kscience.kmath.series.MonotonicSeriesAlgebra -import space.kscience.kmath.series.SeriesAlgebra import kotlin.time.Duration fun SeriesAlgebra.Companion.time(zero: Instant, step: Duration) = MonotonicSeriesAlgebra( diff --git a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt b/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt index c94cb0e71..0e10f1a9a 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt @@ -1,9 +1,8 @@ package space.kscience.kmath.series -import kotlinx.html.FlowContent import kotlinx.html.h1 -import space.kscience.kmath.operations.DoubleBufferOps +import kotlinx.html.p import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.bufferAlgebra import space.kscience.kmath.operations.toList @@ -15,35 +14,43 @@ import space.kscience.plotly.* import kotlin.math.PI fun main() = with(Double.algebra.bufferAlgebra.seriesAlgebra()) { - fun FlowContent.plotSeries(buffer: Buffer) { - val ls = buffer.labels - plot { - scatter { - x.numbers = ls - y.numbers = buffer.toList() - } + + + fun Plot.plotSeries(name: String, buffer: Buffer) { + scatter { + this.name = name + x.numbers = buffer.labels + y.numbers = buffer.toList() + } + } + + + val s1 = series(100) { sin(2 * PI * it / 100) + 1.0 } + + val s2 = s1.slice(20..50).moveTo(40) + + val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 + val s4 = s3.map { ln(it) } + + val kmTest: KMComparisonResult = ksComparisonStatistic(s1, s2) + + Plotly.page { + h1 { +"This is my plot" } + p{ + +"Kolmogorov-smirnov test for s1 and s2: ${kmTest.value}" + } + plot{ + plotSeries("s1", s1) + plotSeries("s2", s2) + plotSeries("s3", s3) + plotSeries("s4", s4) layout { xaxis { range(0.0..100.0) } } } - } - - val s1 = series(100) { sin(2 * PI * it / 100) + 1.0 } - val s2 = s1.slice(20..50).moveTo(40) - - val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 - val s4 = DoubleBufferOps.ln(s3) - - @Suppress("UNUSED_VARIABLE") val kmTest: KMComparisonResult = ksComparisonStatistic(s1, s2) - - Plotly.page { - h1 { +"This is my plot" } - plotSeries(s1) - plotSeries(s2) - plotSeries(s4) }.makeFile() } \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt index 67c9b421f..2ce2c21a6 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.structures -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt index e3e7daaae..e6ff0ee28 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.structures -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.BufferND import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.nd.ShapeND diff --git a/kmath-ast/README.md b/kmath-ast/README.md index c6da64982..d85a18e1c 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.1-dev-1' + implementation 'space.kscience:kmath-ast:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.1-dev-1") + implementation("space.kscience:kmath-ast:0.4.0-dev-1") } ``` diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt index 6458dc123..e211259af 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt @@ -5,9 +5,9 @@ package space.kscience.kmath.ast +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.NumericAlgebra diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt index e411cd251..fb0c9b872 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt @@ -5,9 +5,9 @@ package space.kscience.kmath.ast +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.NumericAlgebra import space.kscience.kmath.operations.bindSymbolOrNull 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 13806703c..50162a4f5 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI /** * [SyntaxRenderer] implementation for LaTeX. 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 bd941745b..bb49c5df4 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI /** * [SyntaxRenderer] implementation for MathML. 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 dd8ed3457..afa25febe 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.ast.rendering +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.MST -import space.kscience.kmath.misc.UnstableKMathAPI /** * Renders [MST] to [MathSyntax]. 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 14df5ad8d..887469164 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI /** * Syntax node for mathematical typography. 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 e19a9722e..7669be664 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI /** * Abstraction of writing [MathSyntax] as a string of an actual markup language. Typical implementation should 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 c1a895015..8bb7e3585 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 @@ -5,10 +5,10 @@ package space.kscience.kmath.ast.rendering +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.rendering.FeaturedMathRenderer.RenderFeature import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.reflect.KClass 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 f42237ba6..2399e8f68 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.ast.rendering +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess.PostProcessPhase -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.FieldOps import space.kscience.kmath.operations.GroupOps import space.kscience.kmath.operations.PowerOperations diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt index 853f5f983..87c2df2d2 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.estree +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.ast.evaluateConstants import space.kscience.kmath.estree.internal.ESTreeBuilder @@ -13,7 +14,6 @@ import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.invoke import space.kscience.kmath.internal.estree.BaseExpression -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Algebra /** 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 d29fbde55..1908f0659 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 @@ -5,11 +5,11 @@ package space.kscience.kmath.wasm.internal +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.expressions.* import space.kscience.kmath.internal.binaryen.* import space.kscience.kmath.internal.webassembly.Instance -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.internal.binaryen.Module as BinaryenModule import space.kscience.kmath.internal.webassembly.Module as WasmModule diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt index 6a20da799..acb26f918 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt @@ -7,10 +7,10 @@ package space.kscience.kmath.wasm +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.ast.evaluateConstants import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing import space.kscience.kmath.wasm.internal.DoubleWasmBuilder diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt index 59a26af7d..7094d0442 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt @@ -7,11 +7,11 @@ package space.kscience.kmath.asm +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.asm.internal.* import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.ast.evaluateConstants import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt index d50318cd1..a3e5b7522 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt @@ -11,9 +11,9 @@ import org.objectweb.asm.Opcodes.* import org.objectweb.asm.Type import org.objectweb.asm.Type.* import org.objectweb.asm.commons.InstructionAdapter +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType diff --git a/kmath-commons/README.md b/kmath-commons/README.md index 89f1f6c9f..47b61c409 100644 --- a/kmath-commons/README.md +++ b/kmath-commons/README.md @@ -6,7 +6,7 @@ Commons math binding for kmath ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-commons:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-commons:0.3.1-dev-1' + implementation 'space.kscience:kmath-commons:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-commons:0.3.1-dev-1") + implementation("space.kscience:kmath-commons:0.4.0-dev-1") } ``` diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt index cb7fb543f..38eaf8868 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt @@ -8,8 +8,8 @@ package space.kscience.kmath.commons.expressions import org.apache.commons.math3.analysis.differentiation.DerivativeStructure +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.NumbersAddOps diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt index 4839518e6..c3e581d31 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt @@ -7,8 +7,8 @@ package space.kscience.kmath.commons.integration import org.apache.commons.math3.analysis.integration.IterativeLegendreGaussIntegrator import org.apache.commons.math3.analysis.integration.SimpsonIntegrator +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.integration.* -import space.kscience.kmath.misc.UnstableKMathAPI /** * Integration wrapper for Common-maths UnivariateIntegrator 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 e95c9115d..d19bd1be0 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 @@ -6,8 +6,8 @@ package space.kscience.kmath.commons.linear import org.apache.commons.math3.linear.* +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.Buffer diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt index 46baa7d50..c4dafb6a6 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt @@ -13,11 +13,11 @@ import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.SymbolIndexer import space.kscience.kmath.expressions.derivative import space.kscience.kmath.expressions.withSymbols -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.log import space.kscience.kmath.optimization.* import kotlin.collections.set diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt index 308f504af..6541736ce 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt @@ -6,9 +6,9 @@ package space.kscience.kmath.commons.integration import org.junit.jupiter.api.Test +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField.sin import kotlin.math.PI import kotlin.math.abs 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 03b1426f5..d2e86bb40 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 @@ -6,13 +6,13 @@ package space.kscience.kmath.commons.optimization import kotlinx.coroutines.runBlocking +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.expressions.DSFieldExpression import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.Symbol.Companion.y import space.kscience.kmath.expressions.autodiff import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleBufferOps.Companion.map import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.optimization.* diff --git a/kmath-complex/README.md b/kmath-complex/README.md index f00952065..4e800b7ac 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.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.1-dev-1' + implementation 'space.kscience:kmath-complex:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.1-dev-1") + implementation("space.kscience:kmath-complex:0.4.0-dev-1") } ``` 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 bb580989b..b5f1aabe7 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 @@ -5,10 +5,10 @@ package space.kscience.kmath.complex +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.memory.MemoryReader import space.kscience.kmath.memory.MemorySpec import space.kscience.kmath.memory.MemoryWriter -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.* import kotlin.math.* 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 06f6cad85..90a6b3253 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.complex -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer 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 e9b42118f..d4259c4dc 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 @@ -5,10 +5,10 @@ package space.kscience.kmath.complex +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.memory.MemoryReader import space.kscience.kmath.memory.MemorySpec import space.kscience.kmath.memory.MemoryWriter -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MemoryBuffer diff --git a/kmath-core/README.md b/kmath-core/README.md index e84ca38d7..b58105d2f 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.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.1-dev-1' + implementation 'space.kscience:kmath-core:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.1-dev-1") + implementation("space.kscience:kmath-core:0.4.0-dev-1") } ``` diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 0e4646bed..b6a955b12 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -6,6 +6,7 @@ kscience{ jvm() js() native() +// wasm() dependencies { api(projects.kmathMemory) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt index d09228e96..49e2ee8d0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt @@ -5,9 +5,9 @@ package space.kscience.kmath.data +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.structures.Buffer 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 a3c3a2eda..de7e6f79b 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 @@ -5,9 +5,9 @@ package space.kscience.kmath.data +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.structures.Buffer import kotlin.math.max diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt index dd0e35bc8..797a25443 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.data +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer 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 3dc1bb99b..846bbad62 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.data +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt index 10755e633..d619883b4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.domains +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI @UnstableKMathAPI public abstract class Domain1D>(public val range: ClosedRange) : Domain { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt index b0803f3e1..e56173624 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt @@ -4,7 +4,7 @@ */ package space.kscience.kmath.domains -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI /** * n-dimensional volume 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 7d5843a97..1049a251a 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 @@ -4,8 +4,8 @@ */ package space.kscience.kmath.domains +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.indices 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 e8b867fac..5351a295d 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 @@ -4,8 +4,8 @@ */ package space.kscience.kmath.domains +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI @UnstableKMathAPI public class UnconstrainedDomain(override val dimension: Int) : DoubleDomain { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt index 9e91ff26b..8c7cb0cf1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.expressions -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer 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 cf59efe71..f350303bc 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.expressions -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.Algebra import kotlin.jvm.JvmName import kotlin.properties.ReadOnlyProperty 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 a75940cca..c894cf00a 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.expressions -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt index 24bdfce7e..5d047d5b7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt @@ -7,9 +7,9 @@ package space.kscience.kmath.expressions +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.getOrNull public class NamedMatrix(public val values: Matrix, public val indexer: SymbolIndexer) : Matrix by values { 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 f00e6d3f3..2bb5043b7 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.expressions +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.asBuffer import kotlin.contracts.InvocationKind 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 e5f92efc9..7112e921a 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.expressions +import space.kscience.kmath.UnstableKMathAPI 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 space.kscience.kmath.structures.DoubleBuffer 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 5976b67b1..4bba47a91 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.linear -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt index 4e7ab55ef..940af4a86 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.linear -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleBufferOps import space.kscience.kmath.operations.DoubleField 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 757752115..a82bafe57 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.linear -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.nd.StructureFeature 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 0ee7c8828..650e7be5c 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.linear -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.BufferAccessor2D import space.kscience.kmath.structures.DoubleBuffer diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt index d0105e4cd..4d2f01e68 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.linear -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.structures.BufferAccessor2D import space.kscience.kmath.structures.MutableBuffer 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 feea26b40..46454a584 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.linear +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.operations.Ring import kotlin.reflect.KClass diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt index 90cc5bbfa..afa76d2a9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt @@ -19,4 +19,4 @@ public inline fun List.zipWithNextCircular(transform: (a: T, b: T) -> } } -public inline fun List.zipWithNextCircular(): List> = zipWithNextCircular { l, r -> l to r } \ No newline at end of file +public fun List.zipWithNextCircular(): List> = zipWithNextCircular { l, r -> l to r } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt index daf5e1eff..31b8c0037 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.misc +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.VirtualBuffer 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 d53f5488a..91e26cc1b 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.reflect.KClass 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 781d2e367..74c63e6e2 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 @@ -7,8 +7,8 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* public interface BufferAlgebraND> : AlgebraND { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt index a6bab8be1..9217f6fdc 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.MutableBuffer 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 b5ed64108..265d1eec8 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.DoubleBuffer import kotlin.contracts.InvocationKind diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt index f46defeee..1491950d6 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.IntRing import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.bufferAlgebra diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt index e4ba72cec..6c35e2f44 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall public class PermutedStructureND( diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt index 63728e94f..d43ebaf1c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.UnsafeKMathAPI +import space.kscience.kmath.UnsafeKMathAPI import kotlin.jvm.JvmInline /** 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 34d748b3f..1b4647146 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.ShortRing import space.kscience.kmath.operations.bufferAlgebra 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 ba48e25ce..984b5ad0f 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer 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 a9c6c2748..e006d09eb 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableListBuffer 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 c96843651..e643186ba 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,10 +5,10 @@ package space.kscience.kmath.nd +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.misc.Feature import space.kscience.kmath.misc.Featured -import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt index 4932dca41..606b9a631 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI public open class VirtualStructureND( override val shape: ShapeND, diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt index 424081738..40db5187f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall @OptIn(PerformancePitfall::class) public fun StructureND.roll(axis: Int, step: Int = 1): StructureND { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt index f50233ecc..28e32363f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall public interface StructureNDOfDouble : StructureND { /** 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 a7a5bc5fd..0960ab023 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.operations +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring.Companion.optimizedPower import space.kscience.kmath.structures.MutableBufferFactory 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 8730ff163..34a6d4a80 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.operations -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.BufferedRingOpsND import space.kscience.kmath.operations.BigInt.Companion.BASE import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt index 7ba1a7066..74b41be9d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt @@ -5,10 +5,11 @@ package space.kscience.kmath.operations +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.* -import kotlin.math.* +import kotlin.math.pow +import kotlin.math.sqrt /** * [ExtendedFieldOps] over [DoubleBuffer]. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt index 5cf98c7d5..7aa5aed80 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt @@ -5,9 +5,9 @@ package space.kscience.kmath.operations +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.misc.UnstableKMathAPI /** * An algebra for generic boolean logic 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 5c2747686..9bcfb00a2 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.operations -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import kotlin.math.E import kotlin.math.PI diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt index 84fb2ea41..ddf599240 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.operations -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.structures.Buffer /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt index 697939bdf..02fd2600d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.structures -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI /** * A buffer that wraps an original buffer 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 80d5033c4..cbfd6b9cd 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 @@ -17,9 +17,7 @@ import space.kscience.kmath.memory.* public open class MemoryBuffer(protected val memory: Memory, protected val spec: MemorySpec) : Buffer { override val size: Int get() = memory.size / spec.objectSize - private val reader: MemoryReader = memory.reader() - - override operator fun get(index: Int): T = reader.read(spec, spec.objectSize * index) + override operator fun get(index: Int): T = memory.read { read(spec, spec.objectSize * index) } override operator fun iterator(): Iterator = (0 until size).asSequence().map { get(it) }.iterator() override fun toString(): String = Buffer.toString(this) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt index 0a475187f..6a7b6d836 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.operations -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.structures.* /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt index 2f2cc80b3..791d7d16f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.structures -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI /** * Non-boxing access to primitive [Double] diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt index 0bfcb04a7..871119f48 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.expressions -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import kotlin.contracts.InvocationKind import kotlin.contracts.contract diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt index 6f207eab3..83f00ce6c 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.expressions +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.BooleanAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt index 25e29f3d6..4d05f9043 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.linear -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.algebra import kotlin.test.Test diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt index fe5ea3642..531aee259 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.linear -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as2D import space.kscience.kmath.operations.algebra diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt index f4f7b1a51..06a9ab439 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.operations -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.testutils.RingVerifier import kotlin.math.pow import kotlin.test.Test diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt index 147488273..1572db816 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt @@ -5,13 +5,18 @@ package space.kscience.kmath.structures +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.get +import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.nd.structureND import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.invoke +import kotlin.collections.component1 +import kotlin.collections.component2 import kotlin.math.abs import kotlin.math.pow import kotlin.test.Test diff --git a/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt new file mode 100644 index 000000000..e320f350e --- /dev/null +++ b/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.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/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt new file mode 100644 index 000000000..11c82bf9e --- /dev/null +++ b/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.operations + +/** + * Check if number is an integer from platform point of view + */ +public actual fun Number.isInteger(): Boolean = + (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0) \ No newline at end of file diff --git a/kmath-coroutines/README.md b/kmath-coroutines/README.md index 337d8e037..21831e514 100644 --- a/kmath-coroutines/README.md +++ b/kmath-coroutines/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-coroutines:0.3.1-dev-1' + implementation 'space.kscience:kmath-coroutines:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-coroutines:0.3.1-dev-1") + implementation("space.kscience:kmath-coroutines:0.4.0-dev-1") } ``` 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 ed0283630..977346e68 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 @@ -10,7 +10,7 @@ import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.flow import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI /** * A not-necessary-Markov chain of some type 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 1f717658e..22c2ac3ff 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 @@ -6,8 +6,8 @@ package space.kscience.kmath.structures import kotlinx.coroutines.* +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.coroutines.Math -import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.StructureND diff --git a/kmath-dimensions/README.md b/kmath-dimensions/README.md index 12aa2a7fa..2e7250b51 100644 --- a/kmath-dimensions/README.md +++ b/kmath-dimensions/README.md @@ -6,7 +6,7 @@ A proof of concept module for adding type-safe dimensions to structures ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-dimensions:0.3.1-dev-1' + implementation 'space.kscience:kmath-dimensions:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-dimensions:0.3.1-dev-1") + implementation("space.kscience:kmath-dimensions:0.4.0-dev-1") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index 2d6c661e4..ad80ba183 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.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.1-dev-1' + implementation 'space.kscience:kmath-ejml:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.1-dev-1") + implementation("space.kscience:kmath-ejml:0.4.0-dev-1") } ``` diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt index beb79fc0e..8925fb045 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt @@ -5,11 +5,11 @@ package space.kscience.kmath.ejml +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.InverseMatrixFeature import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.operations.Ring 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 aac327a84..c56583fa8 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 @@ -19,9 +19,9 @@ import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.* import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.FloatField diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt index d1ae80ef9..e89810e0d 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt @@ -11,9 +11,9 @@ import org.ejml.data.DMatrixRMaj import org.ejml.dense.row.CommonOps_DDRM import org.ejml.dense.row.RandomMatrices_DDRM import org.ejml.dense.row.factory.DecompositionFactory_DDRM +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.toArray import space.kscience.kmath.operations.algebra diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 5a8376976..638b15bfa 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.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.1-dev-1' + implementation 'space.kscience:kmath-for-real:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.1-dev-1") + implementation("space.kscience:kmath-for-real:0.4.0-dev-1") } ``` diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt index e607786fb..411a35188 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.real +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleL2Norm import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer.Companion.double 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 cfa59bf32..40e4a91f1 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 @@ -8,9 +8,9 @@ package space.kscience.kmath.real +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.asIterable 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 6403cf509..adb62b173 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.real -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import kotlin.math.floor diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt index 0d016116d..c00cd84d1 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt @@ -5,10 +5,10 @@ package space.kscience.kmath.real +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.matrix -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.algebra import space.kscience.kmath.testutils.contentEquals diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt index 31be9a452..35c53f9d6 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt @@ -5,11 +5,7 @@ package space.kscience.kmath.real -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.real.DoubleVector -import space.kscience.kmath.real.minus -import space.kscience.kmath.real.norm -import space.kscience.kmath.real.step +import space.kscience.kmath.UnstableKMathAPI import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 1292424b5..929fd9172 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.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.1-dev-1' + implementation 'space.kscience:kmath-functions:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.1-dev-1") + implementation("space.kscience:kmath-functions:0.4.0-dev-1") } ``` 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 a9f51f7b0..a9e75e456 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.operations.Ring /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 5effe566a..0d4b93f03 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.contracts.InvocationKind import kotlin.contracts.contract 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 603f0503a..f2ac0a296 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 @@ -4,7 +4,7 @@ */ package space.kscience.kmath.integration -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer 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 7e4ff0f8b..73a3cc25b 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.integration -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.invoke 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 c66674fbb..993812b29 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 @@ -5,13 +5,13 @@ package space.kscience.kmath.integration +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.integrate import space.kscience.kmath.interpolation.PolynomialInterpolator import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer 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 af8c858fa..f18e86b80 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 @@ -5,8 +5,8 @@ package space.kscience.kmath.integration +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer 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 52e8991b1..191e7dfd9 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 @@ -7,11 +7,11 @@ package space.kscience.kmath.interpolation +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.asFunction import space.kscience.kmath.functions.value -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer 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 49d7fd1ca..5c56e406a 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 @@ -5,10 +5,10 @@ package space.kscience.kmath.interpolation +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.invoke 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 a63142be4..a3cc17954 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 @@ -5,10 +5,10 @@ package space.kscience.kmath.interpolation +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.invoke diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt index c1b1008ae..48e641335 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -5,9 +5,9 @@ package space.kscience.kmath.functions +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField -import space.kscience.kmath.misc.UnstableKMathAPI import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt index 0a3d00e96..ff05805da 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.functions.testUtils -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt index 32fc08ae4..7424f3566 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.integration -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import kotlin.math.PI import kotlin.math.sin diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt index 188f8d15f..7b699ebbc 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.integration -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import kotlin.math.PI import kotlin.math.sin diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt index 4a15e96c3..b17d21abf 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -5,9 +5,9 @@ package space.kscience.kmath.integration +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.integrate -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import kotlin.math.PI import kotlin.math.sin diff --git a/kmath-geometry/README.md b/kmath-geometry/README.md index 72d275697..480945c4f 100644 --- a/kmath-geometry/README.md +++ b/kmath-geometry/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-geometry:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-geometry:0.3.1-dev-1' + implementation 'space.kscience:kmath-geometry:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-geometry:0.3.1-dev-1") + implementation("space.kscience:kmath-geometry:0.4.0-dev-1") } ``` diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt index 487af7e50..1f3850c7c 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt @@ -5,12 +5,15 @@ package space.kscience.kmath.geometry +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.complex.Quaternion import space.kscience.kmath.complex.QuaternionField import space.kscience.kmath.complex.normalized import space.kscience.kmath.complex.reciprocal -import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.linear.linearSpace +import space.kscience.kmath.linear.matrix import space.kscience.kmath.operations.DoubleField import kotlin.math.pow import kotlin.math.sqrt diff --git a/kmath-histograms/README.md b/kmath-histograms/README.md index 5fd91ee0c..bc7f0fa5b 100644 --- a/kmath-histograms/README.md +++ b/kmath-histograms/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-histograms:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-histograms:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-histograms:0.3.1-dev-1' + implementation 'space.kscience:kmath-histograms:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-histograms:0.3.1-dev-1") + implementation("space.kscience:kmath-histograms:0.4.0-dev-1") } ``` diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt index f9ca6a486..f50610a17 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt @@ -5,10 +5,10 @@ package space.kscience.kmath.histogram +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.domains.Domain1D import space.kscience.kmath.domains.center import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt index 623452422..5fdc2ffb0 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt @@ -5,9 +5,9 @@ package space.kscience.kmath.histogram +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.domains.Domain import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.nd.FieldOpsND import space.kscience.kmath.nd.ShapeND diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt index 3c687d2df..154d35350 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.histogram +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.domains.DoubleDomain1D -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Group import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt index b62780ed5..61ce450a7 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt @@ -7,10 +7,10 @@ package space.kscience.kmath.histogram +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.domains.HyperSquareDomain import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.* import space.kscience.kmath.structures.* diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt index 64cc4f203..54806c9fa 100644 --- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt +++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt @@ -7,8 +7,8 @@ package space.kscience.kmath.histogram -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.operations.invoke import space.kscience.kmath.real.DoubleVector diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt index c4554b575..fa129fad6 100644 --- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt +++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt @@ -7,8 +7,8 @@ package space.kscience.kmath.histogram import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.stat.nextBuffer diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt index a7d34ff71..772db7df3 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt @@ -7,9 +7,9 @@ package space.kscience.kmath.histogram +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.domains.DoubleDomain1D import space.kscience.kmath.domains.center -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.sorted import space.kscience.kmath.operations.Group import space.kscience.kmath.operations.Ring 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 index 77dc189ee..b7c1f34ba 100644 --- a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt +++ b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.histogram import org.junit.jupiter.api.Test -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.real.step import kotlin.random.Random diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index c008c76ca..47142f174 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.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.1-dev-1' + implementation 'space.kscience:kmath-jafama:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.1-dev-1") + implementation("space.kscience:kmath-jafama:0.4.0-dev-1") } ``` diff --git a/kmath-jupyter/README.md b/kmath-jupyter/README.md index 3c9832625..2b26878dc 100644 --- a/kmath-jupyter/README.md +++ b/kmath-jupyter/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jupyter:0.3.1-dev-1' + implementation 'space.kscience:kmath-jupyter:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jupyter:0.3.1-dev-1") + implementation("space.kscience:kmath-jupyter:0.4.0-dev-1") } ``` diff --git a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt index 1fe9fe92f..2d32dd609 100644 --- a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt +++ b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt @@ -12,6 +12,7 @@ import kotlinx.html.unsafe import org.jetbrains.kotlinx.jupyter.api.DisplayResult import org.jetbrains.kotlinx.jupyter.api.HTML import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer import space.kscience.kmath.ast.rendering.renderWithStringBuilder @@ -19,7 +20,6 @@ import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.Quaternion import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.MstRing -import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.operations.asSequence import space.kscience.kmath.operations.invoke diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 457652aaf..f1a918b4b 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.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.1-dev-1' + implementation 'space.kscience:kmath-kotlingrad:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.1-dev-1") + implementation("space.kscience:kmath-kotlingrad:0.4.0-dev-1") } ``` diff --git a/kmath-memory/README.md b/kmath-memory/README.md index 536d7f145..594588ecf 100644 --- a/kmath-memory/README.md +++ b/kmath-memory/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-memory:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-memory:0.3.1-dev-1' + implementation 'space.kscience:kmath-memory:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-memory:0.3.1-dev-1") + implementation("space.kscience:kmath-memory:0.4.0-dev-1") } ``` diff --git a/kmath-memory/build.gradle.kts b/kmath-memory/build.gradle.kts index 4f0f996b9..d8af1e3a2 100644 --- a/kmath-memory/build.gradle.kts +++ b/kmath-memory/build.gradle.kts @@ -6,6 +6,7 @@ kscience { jvm() js() native() +// wasm() } readme { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/annotations.kt similarity index 95% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt rename to kmath-memory/src/commonMain/kotlin/space/kscience/kmath/annotations.kt index 7da333a45..a95b166cf 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/annotations.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2023 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.misc +package space.kscience.kmath /** * Marks declarations that are still experimental in the KMath APIs, which means that the design of the corresponding 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 006d57c5f..a63753015 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 @@ -43,7 +43,7 @@ public interface Memory { /** * The interface to read primitive types in this memory. */ -public interface MemoryReader { +public interface MemoryReader: AutoCloseable { /** * The underlying memory. */ @@ -82,7 +82,7 @@ public interface MemoryReader { /** * Disposes this reader if needed. */ - public fun release() + override fun close() } /** @@ -90,16 +90,13 @@ public interface MemoryReader { */ public inline fun Memory.read(block: MemoryReader.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - val reader = reader() - val result = reader.block() - reader.release() - return result + return reader().use(block) } /** * The interface to write primitive types into this memory. */ -public interface MemoryWriter { +public interface MemoryWriter: AutoCloseable { /** * The underlying memory. */ @@ -138,7 +135,7 @@ public interface MemoryWriter { /** * Disposes this writer if needed. */ - public fun release() + override fun close() } /** @@ -146,7 +143,7 @@ public interface MemoryWriter { */ public inline fun Memory.write(block: MemoryWriter.() -> Unit) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - writer().apply(block).release() + writer().use(block) } /** 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 40ba84c10..f8bcef010 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 @@ -41,7 +41,7 @@ private class DataViewMemory(val view: DataView) : Memory { override fun readLong(offset: Int): Long = view.getInt32(offset, false).toLong() shl 32 or view.getInt32(offset + 4, false).toLong() - override fun release() { + override fun close() { // does nothing on JS } } @@ -76,7 +76,7 @@ private class DataViewMemory(val view: DataView) : Memory { view.setInt32(offset + 4, (value and 0xffffffffL).toInt(), littleEndian = false) } - override fun release() { + override fun close() { // does nothing on JS } } 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 84f7ea412..19910a396 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 @@ -53,7 +53,7 @@ internal class ByteBufferMemory( override fun readLong(offset: Int) = buffer.getLong(position(offset)) - override fun release() { + override fun close() { // does nothing on JVM } } @@ -87,7 +87,7 @@ internal class ByteBufferMemory( buffer.putLong(position(offset), value) } - override fun release() { + override fun close() { // does nothing on JVM } } 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 b224383e4..32bc8d6a5 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 @@ -41,7 +41,7 @@ internal class NativeMemory( override fun readLong(offset: Int) = array.getLongAt(position(offset)) - override fun release() { + override fun close() { // does nothing on JVM } } @@ -75,7 +75,7 @@ internal class NativeMemory( array.setLongAt(position(offset), value) } - override fun release() { + override fun close() { // does nothing on JVM } } diff --git a/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmMemory.kt b/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmMemory.kt new file mode 100644 index 000000000..7c2be19cc --- /dev/null +++ b/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmMemory.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.memory + +import kotlin.wasm.unsafe.Pointer +import kotlin.wasm.unsafe.UnsafeWasmMemoryApi + +@OptIn(UnsafeWasmMemoryApi::class) +public class WasmMemory private constructor( + public val pointer: Pointer, + override val size: Int, +) : Memory { + + override fun view(offset: Int, length: Int): Memory { + TODO("Not yet implemented") + } + + override fun copy(): Memory { + TODO("Not yet implemented") + } + + override fun reader(): MemoryReader = object : MemoryReader { + override val memory: Memory + get() = this@WasmMemory + + override fun readDouble(offset: Int): Double { + return Double.fromBits(pointer.plus(offset).loadLong()) + } + + override fun readFloat(offset: Int): Float { + return Float.fromBits(pointer.plus(offset).loadInt()) + } + + override fun readByte(offset: Int): Byte { + return pointer.plus(offset).loadByte() + } + + override fun readShort(offset: Int): Short { + return pointer.plus(offset).loadShort() + } + + override fun readInt(offset: Int): Int { + return pointer.plus(offset).loadInt() + } + + override fun readLong(offset: Int): Long { + return pointer.plus(offset).loadLong() + } + + override fun close() { + TODO() + } + + } + + override fun writer(): MemoryWriter = TODO() +} + +public actual fun Memory.Companion.allocate(length: Int): Memory { + TODO() +} + +public actual fun Memory.Companion.wrap(array: ByteArray): Memory = TODO() \ No newline at end of file diff --git a/kmath-multik/README.md b/kmath-multik/README.md index 0f5b65b4c..127b12a49 100644 --- a/kmath-multik/README.md +++ b/kmath-multik/README.md @@ -6,7 +6,7 @@ JetBrains Multik connector ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-multik:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-multik:0.3.1-dev-1' + implementation 'space.kscience:kmath-multik:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-multik:0.3.1-dev-1") + implementation("space.kscience:kmath-multik:0.4.0-dev-1") } ``` diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt index 989ebcd5d..beab5c18b 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlinx.multik.api.Engine import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ndarrayOf import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExponentialOperations diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt index ae526873d..59a9a1bf3 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.multik import org.jetbrains.kotlinx.multik.ndarray.data.* -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.tensors.api.Tensor import kotlin.jvm.JvmInline diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index 1736b48e3..c3a82b167 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -13,10 +13,11 @@ import org.jetbrains.kotlinx.multik.api.math.Math import org.jetbrains.kotlinx.multik.api.stat.Statistics import org.jetbrains.kotlinx.multik.ndarray.data.* import org.jetbrains.kotlinx.multik.ndarray.operations.* -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnsafeKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnsafeKMathAPI import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.Ring import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra diff --git a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt index d52420fc6..1a130aa92 100644 --- a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt +++ b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.multik import org.jetbrains.kotlinx.multik.default.DefaultEngine -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.one diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index bb065a300..b299c1b37 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.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.1-dev-1' + implementation 'space.kscience:kmath-nd4j:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.1-dev-1") + implementation("space.kscience:kmath-nd4j:0.4.0-dev-1") } ``` 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 6f01233d7..0eb147b6f 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 @@ -10,9 +10,9 @@ import org.nd4j.linalg.api.ops.impl.transforms.strict.ACosh import org.nd4j.linalg.api.ops.impl.transforms.strict.ASinh import org.nd4j.linalg.factory.Nd4j import org.nd4j.linalg.ops.transforms.Transforms -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnsafeKMathAPI -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnsafeKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.* 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 a1405ccfb..93fbc8f85 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 @@ -6,7 +6,7 @@ package space.kscience.kmath.nd4j import org.nd4j.linalg.api.ndarray.INDArray -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* /** 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 ef7b7f257..5905739f8 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 @@ -12,8 +12,8 @@ import org.nd4j.linalg.api.ops.impl.transforms.strict.ASinh import org.nd4j.linalg.factory.Nd4j import org.nd4j.linalg.factory.ops.NDBase import org.nd4j.linalg.ops.transforms.Transforms -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnsafeKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnsafeKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Field diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt index 9f1022fd9..708778e77 100644 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt +++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.nd4j import org.nd4j.linalg.factory.Nd4j -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.one import space.kscience.kmath.nd.structureND diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt index 25c3fe23f..d57eb2e2d 100644 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt +++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.nd4j import org.nd4j.linalg.factory.Nd4j -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.asList import space.kscience.kmath.nd.get import kotlin.test.Test diff --git a/kmath-optimization/README.md b/kmath-optimization/README.md index d7441ebd1..79a4f5d24 100644 --- a/kmath-optimization/README.md +++ b/kmath-optimization/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-optimization:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-optimization:0.3.1-dev-1' + implementation 'space.kscience:kmath-optimization:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-optimization:0.3.1-dev-1") + implementation("space.kscience:kmath-optimization:0.4.0-dev-1") } ``` diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt index bbebec6af..b698584aa 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt @@ -5,9 +5,9 @@ package space.kscience.kmath.optimization +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.* import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.log import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleL2Norm diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt index 5c28826ee..9e5396491 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -6,12 +6,12 @@ package space.kscience.kmath.optimization +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.data.indices import space.kscience.kmath.expressions.* import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.Loggable -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.bindSymbol import kotlin.math.pow diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt index e0eeb339c..8ab9de48d 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt @@ -5,13 +5,13 @@ package space.kscience.kmath.optimization +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.data.indices import space.kscience.kmath.expressions.DifferentiableExpression import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.derivative -import space.kscience.kmath.misc.UnstableKMathAPI import kotlin.math.PI import kotlin.math.ln import kotlin.math.pow diff --git a/kmath-stat/README.md b/kmath-stat/README.md index 7ed20fcf4..e7e0a4d92 100644 --- a/kmath-stat/README.md +++ b/kmath-stat/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-stat:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-stat:0.3.1-dev-1' + implementation 'space.kscience:kmath-stat:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-stat:0.3.1-dev-1") + implementation("space.kscience:kmath-stat:0.4.0-dev-1") } ``` diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index 267bfd0f3..1426e913a 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -12,7 +12,7 @@ kotlin.sourceSets { commonMain { dependencies { api(project(":kmath-coroutines")) - implementation(spclibs.atomicfu) + //implementation(spclibs.atomicfu) } } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt index 52e400bf1..b87a429df 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt @@ -6,9 +6,9 @@ package space.kscience.kmath.stat import kotlinx.coroutines.flow.first +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.combine -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt index 2bc363934..ed6f4e07b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt @@ -37,11 +37,5 @@ public class MonotonicSeriesAlgebra, out BA : BufferAlgebra.getByLabelOrNull(label: L): T? = getByOffsetOrNull(floorOffset(label)) - - /** - * Get value by label (rounded down) or throw [IndexOutOfBoundsException] if the value is outside series boundaries. - */ - public fun Buffer.getByLabel(label: L): T = getByLabelOrNull(label) - ?: throw IndexOutOfBoundsException("Label $label is not in $labelRange") + override fun Buffer.getByLabelOrNull(label: L): T? = getByOffsetOrNull(floorOffset(label)) } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt index 1847e33b6..3ccbca5a1 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt @@ -112,14 +112,21 @@ public open class SeriesAlgebra, out BA : BufferAlgebra public val Buffer.startLabel: L get() = offsetToLabel(startOffset) /** - * Build a new series positioned at [startOffset]. + * Build a new series by offset positioned at [startOffset]. */ - public fun series(size: Int, startOffset: Int = 0, block: A.(label: L) -> T): Series { - return elementAlgebra.bufferFactory(size) { - val index = it + startOffset - elementAlgebra.block(offsetToLabel(index)) - }.moveTo(startOffset) - } + public inline fun seriesByOffset( + size: Int, + startOffset: Int = 0, + crossinline block: A.(offset: Int) -> T, + ): Series = elementAlgebra.bufferFactory(size) { + elementAlgebra.block(it + startOffset) + }.moveTo(startOffset) + + /** + * Build a new series by label positioned at [startOffset]. + */ + public inline fun series(size: Int, startOffset: Int = 0, crossinline block: A.(label: L) -> T): Series = + seriesByOffset(size, startOffset) { offset -> block(offsetToLabel(offset)) } /** * Get a label buffer for given buffer. @@ -129,18 +136,24 @@ public open class SeriesAlgebra, out BA : BufferAlgebra /** * Try to resolve element by label and return null if element with a given label is not found */ - public operator fun Buffer.get(label: L): T? { + public open fun Buffer.getByLabelOrNull(label: L): T? { val index = labels.indexOf(label) if (index == -1) return null return getByOffset(index + startOffset) } + /** + * Get value by label (rounded down) or throw [IndexOutOfBoundsException] if the value is outside series boundaries. + */ + public open fun Buffer.getByLabel(label: L): T = getByLabelOrNull(label) + ?: throw IndexOutOfBoundsException("Label $label is not in ${labels.first()}..${labels.last()}") + /** * Map a series to another series of the same size */ public inline fun Buffer.map(crossinline transform: A.(T) -> T): Series { val buf = elementAlgebra.bufferFactory(size) { - elementAlgebra.transform(getByOffset(it)) + elementAlgebra.transform(get(it)) } return buf.moveTo(offsetIndices.first) } @@ -178,12 +191,12 @@ public open class SeriesAlgebra, out BA : BufferAlgebra crossinline operation: A.(left: T, right: T) -> T, ): Series { val newRange = offsetIndices.intersect(other.offsetIndices) - return elementAlgebra.bufferFactory(newRange.size) { + return seriesByOffset(startOffset = newRange.first, size = newRange.last - newRange.first) { offset -> elementAlgebra.operation( - getByOffset(it), - other.getByOffset(it) + getByOffset(offset), + other.getByOffset(offset) ) - }.moveTo(newRange.first) + } } override fun Buffer.unaryMinus(): Buffer = map { -it } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt new file mode 100644 index 000000000..dc21fe6d9 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.series + +import space.kscience.kmath.operations.BufferAlgebra +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.sumWithGroupOf + +public fun , BA : BufferAlgebra, L : Comparable> MonotonicSeriesAlgebra.import( + data: List>, +): Series { + val groupedData: Map>> = data.groupBy { floorOffset(it.first) } + val minIndex = groupedData.minOf { it.key } + val maxIndex = groupedData.maxOf { it.key } + return elementAlgebra.bufferFactory(maxIndex - minIndex) { relativeIndex -> + val index = relativeIndex + minIndex + groupedData[index]?.sumWithGroupOf(elementAlgebra) { it.second } ?: elementAlgebra.zero + }.moveTo(minIndex) +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt index f36826c28..cce61519b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.stat -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.misc.sorted import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer @@ -33,7 +33,7 @@ public data class KMComparisonResult>(val n: Int, val m: Int, public fun , A, BA : BufferAlgebra> StatisticalAlgebra.ksComparisonStatistic( x: Buffer, y: Buffer, -): KMComparisonResult where A : Group, A : NumericAlgebra = elementAlgebra.invoke { +): KMComparisonResult where A : Group, A : NumericAlgebra = with(elementAlgebra) { // Copy and sort the sample arrays val sx = x.sorted() val sy = y.sorted() diff --git a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt new file mode 100644 index 000000000..d83abb3f4 --- /dev/null +++ b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.series + +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.bufferAlgebra +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.slice +import kotlin.math.PI +import kotlin.test.Test +import kotlin.test.assertEquals + +class TestSeries { + + @Test + fun zip() = with(Double.algebra.bufferAlgebra.seriesAlgebra()){ + val s1 = series(100) { sin(2 * PI * it / 100) + 1.0 } + + val s2 = s1.slice(20..50).moveTo(40) + + val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 + + assertEquals(s3.getByOffset(40),s1.getByOffset(40) + s1.getByOffset(20)) + } +} \ No newline at end of file diff --git a/kmath-symja/README.md b/kmath-symja/README.md index a96b0e835..8672c6a71 100644 --- a/kmath-symja/README.md +++ b/kmath-symja/README.md @@ -6,7 +6,7 @@ Symja integration module ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-symja:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-symja:0.3.1-dev-1' + implementation 'space.kscience:kmath-symja:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-symja:0.3.1-dev-1") + implementation("space.kscience:kmath-symja:0.4.0-dev-1") } ``` diff --git a/kmath-tensorflow/README.md b/kmath-tensorflow/README.md index 83f2eb315..a5b48de4d 100644 --- a/kmath-tensorflow/README.md +++ b/kmath-tensorflow/README.md @@ -6,7 +6,7 @@ Google tensorflow connector ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensorflow:0.3.1-dev-1' + implementation 'space.kscience:kmath-tensorflow:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensorflow:0.3.1-dev-1") + implementation("space.kscience:kmath-tensorflow:0.4.0-dev-1") } ``` diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt index 27a20aafe..41c7c0b68 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -10,9 +10,9 @@ import org.tensorflow.Output import org.tensorflow.ndarray.NdArray import org.tensorflow.op.core.Constant import org.tensorflow.types.TFloat64 +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.StructureND diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index bc5fb9616..73b36cd67 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -17,9 +17,9 @@ import org.tensorflow.op.core.* import org.tensorflow.types.TInt32 import org.tensorflow.types.family.TNumber import org.tensorflow.types.family.TType -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnsafeKMathAPI -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnsafeKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.asArray diff --git a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt index af754f841..730feede6 100644 --- a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt +++ b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.tensorflow import org.junit.jupiter.api.Test -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.get import space.kscience.kmath.nd.structureND diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 4208cd83d..80f751ffe 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.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.1-dev-1' + implementation 'space.kscience:kmath-tensors:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.1-dev-1") + implementation("space.kscience:kmath-tensors:0.4.0-dev-1") } ``` diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index f337a2175..7db91722f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.tensors.api.Tensor 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 a7283e4c8..eaec43e2c 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.RowStrides import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.Strides 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 4eed7a2a8..d2c2e9d5d 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 @@ -5,9 +5,10 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.* +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.nd.MutableStructureNDOfDouble +import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.core.internal.toPrettyString diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt index e74f73800..d2066e404 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.MutableStructure1D import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.structures.MutableBuffer diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt index 7c84b91e1..fa142afa0 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.linearSize 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 997c0a316..70a3ef7e2 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 @@ -8,8 +8,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleBufferOps import space.kscience.kmath.operations.DoubleField @@ -18,7 +17,10 @@ import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.internal.* -import kotlin.math.* +import kotlin.math.abs +import kotlin.math.ceil +import kotlin.math.floor +import kotlin.math.sqrt /** * Implementation of basic operations over double tensors and basic algebra operations on them. @@ -349,7 +351,6 @@ public open class DoubleTensorAlgebra : * @param other tensor to be multiplied. * @return a mathematical product of two tensors. */ - @UnstableKMathAPI public infix fun StructureND.matmul(other: StructureND): DoubleTensor { if (shape.size == 1 && other.shape.size == 1) { return DoubleTensor(ShapeND(1), DoubleBuffer(times(other).sum())) @@ -411,7 +412,7 @@ public open class DoubleTensorAlgebra : } override fun StructureND.dot(other: StructureND): DoubleTensor { - return if (dimension in 0..2 && other.dimension in 0..2) matmul(other) + return if (dimension in 0..2 && other.dimension in 0..2) this.matmul(other) else error("Only vectors and matrices are allowed in non-broadcasting dot operation") } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt index a77c4de4c..f028e2cbb 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.structures.* diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt index 429b3ffa9..d1cdc68d4 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.IntRing import space.kscience.kmath.structures.* diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt index 0b0325a85..1e87e6620 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.core.internal -import space.kscience.kmath.misc.UnsafeKMathAPI +import space.kscience.kmath.UnsafeKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.tensors.core.DoubleTensor 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 91fcc90ee..2709ac474 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 @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.core.internal -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.asList import space.kscience.kmath.nd.last import space.kscience.kmath.operations.DoubleBufferOps.Companion.map diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt index 1733c1a7e..e2b7c23e6 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.ShapeND import kotlin.jvm.JvmName diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index d01ae124b..811fc1117 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.DoubleBuffer @@ -16,6 +16,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue +@OptIn(PerformancePitfall::class) internal class TestDoubleTensor { @Test diff --git a/kmath-viktor/README.md b/kmath-viktor/README.md index abff20427..8a781af4c 100644 --- a/kmath-viktor/README.md +++ b/kmath-viktor/README.md @@ -6,7 +6,7 @@ Binding for https://github.com/JetBrains-Research/viktor ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-viktor:0.3.1-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-viktor:0.4.0-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-viktor:0.3.1-dev-1' + implementation 'space.kscience:kmath-viktor:0.4.0-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-viktor:0.3.1-dev-1") + implementation("space.kscience:kmath-viktor:0.4.0-dev-1") } ``` diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt index 8533c9d32..8c7d6d199 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt @@ -8,9 +8,9 @@ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnsafeKMathAPI -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnsafeKMathAPI +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedFieldOps 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 085790355..7c0c02086 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 @@ -6,7 +6,7 @@ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.nd.MutableStructureND import space.kscience.kmath.nd.ShapeND diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts index b860a62ec..31c57aca7 100644 --- a/test-utils/build.gradle.kts +++ b/test-utils/build.gradle.kts @@ -6,6 +6,7 @@ kscience{ jvm() js() native() +// wasm() } kotlin.sourceSets { From b2746e5c0ef6c31d89640f6cfe7f41e3c2c74930 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 9 Apr 2023 10:55:58 +0300 Subject: [PATCH 55/58] Wasm support --- CHANGELOG.md | 1 + build.gradle.kts | 14 +-- .../space/kscience/kmath/ast/TypedMst.kt | 5 - .../kscience/kmath/ast/evaluateConstants.kt | 2 - .../ast/rendering/LatexSyntaxRenderer.kt | 3 - .../ast/rendering/MathMLSyntaxRenderer.kt | 3 - .../kmath/ast/rendering/MathRenderer.kt | 4 - .../kmath/ast/rendering/MathSyntax.kt | 25 ----- .../kmath/ast/rendering/SyntaxRenderer.kt | 4 - .../kscience/kmath/ast/rendering/features.kt | 22 ---- .../kscience/kmath/ast/rendering/phases.kt | 5 - kmath-complex/build.gradle.kts | 22 ++++ kmath-core/build.gradle.kts | 22 +++- .../space/kscience/kmath/misc/PermSortTest.kt | 2 + .../kmath/structures/NumberNDFieldTest.kt | 1 + kmath-coroutines/build.gradle.kts | 1 + kmath-functions/build.gradle.kts | 30 +++-- kmath-geometry/build.gradle.kts | 5 + .../kscience/kmath/jupyter/KMathJupyter.kt | 2 + kmath-memory/build.gradle.kts | 18 ++- .../space/kscience/kmath/memory/MemoryTest.kt | 37 +++++++ .../kscience/kmath/memory/ByteBufferMemory.kt | 5 +- .../kmath/memory/WasmDataViewMemory.kt | 103 ++++++++++++++++++ .../space/kscience/kmath/memory/WasmMemory.kt | 66 ----------- .../kmath/optimization/OptimizationBuilder.kt | 3 + kmath-stat/build.gradle.kts | 2 +- test-utils/build.gradle.kts | 2 +- 27 files changed, 242 insertions(+), 167 deletions(-) create mode 100644 kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt create mode 100644 kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt delete mode 100644 kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmMemory.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d4e6123b..08b72f0d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [Unreleased] ### Added +- Wasm support for `memory`, `core`, `complex` and `functions` modules. - Generic builders for `BufferND` and `MutableBufferND` - `NamedMatrix` - matrix with symbol-based indexing - `Expression` with default arguments diff --git a/build.gradle.kts b/build.gradle.kts index 2eea9c47b..ec67eaa54 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,7 @@ allprojects { } group = "space.kscience" - version = "0.4.0-dev-1" + version = "0.3.1-dev-RC" } subprojects { @@ -55,18 +55,6 @@ subprojects { } } } - - plugins.withId("org.jetbrains.kotlin.multiplatform") { - configure { - sourceSets { - val commonTest by getting { - dependencies { - implementation(projects.testUtils) - } - } - } - } - } } readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt index e211259af..e82f7a3ab 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt @@ -5,7 +5,6 @@ package space.kscience.kmath.ast -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.Algebra @@ -16,7 +15,6 @@ import space.kscience.kmath.operations.NumericAlgebra * * @param T the type. */ -@UnstableKMathAPI public sealed interface TypedMst { /** * A node containing a unary operation. @@ -133,7 +131,6 @@ public sealed interface TypedMst { /** * Interprets the [TypedMst] node with this [Algebra] and [arguments]. */ -@UnstableKMathAPI public fun TypedMst.interpret(algebra: Algebra, arguments: Map): T = when (this) { is TypedMst.Unary -> algebra.unaryOperation(operation, interpret(algebra, arguments)) @@ -158,7 +155,6 @@ public fun TypedMst.interpret(algebra: Algebra, arguments: Map TypedMst.interpret(algebra: Algebra, vararg arguments: Pair): T = interpret( algebra, when (arguments.size) { @@ -171,7 +167,6 @@ public fun TypedMst.interpret(algebra: Algebra, vararg arguments: Pair /** * Interpret this [TypedMst] node as expression. */ -@UnstableKMathAPI public fun TypedMst.toExpression(algebra: Algebra): Expression = Expression { arguments -> interpret(algebra, arguments) } diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt index fb0c9b872..8fc5a6aaf 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt @@ -5,7 +5,6 @@ package space.kscience.kmath.ast -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.Algebra @@ -15,7 +14,6 @@ import space.kscience.kmath.operations.bindSymbolOrNull /** * Evaluates constants in given [MST] for given [algebra] at the same time with converting to [TypedMst]. */ -@UnstableKMathAPI public fun MST.evaluateConstants(algebra: Algebra): TypedMst = when (this) { is MST.Numeric -> TypedMst.Constant( (algebra as? NumericAlgebra)?.number(value) ?: error("Numeric nodes are not supported by $algebra"), 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 50162a4f5..5a338afed 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 @@ -5,8 +5,6 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.UnstableKMathAPI - /** * [SyntaxRenderer] implementation for LaTeX. * @@ -25,7 +23,6 @@ import space.kscience.kmath.UnstableKMathAPI * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public object LatexSyntaxRenderer : SyntaxRenderer { override fun render(node: MathSyntax, output: Appendable): Unit = output.run { fun render(syntax: MathSyntax) = render(syntax, output) 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 bb49c5df4..bfd9aeef9 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 @@ -5,8 +5,6 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.UnstableKMathAPI - /** * [SyntaxRenderer] implementation for MathML. * @@ -14,7 +12,6 @@ import space.kscience.kmath.UnstableKMathAPI * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public object MathMLSyntaxRenderer : SyntaxRenderer { override fun render(node: MathSyntax, output: Appendable) { 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 afa25febe..f88a5b319 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 @@ -5,7 +5,6 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.MST /** @@ -13,7 +12,6 @@ import space.kscience.kmath.expressions.MST * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public fun interface MathRenderer { /** * Renders [MST] to [MathSyntax]. @@ -27,7 +25,6 @@ public fun interface MathRenderer { * @property features The applied features. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public open class FeaturedMathRenderer(public val features: List) : MathRenderer { override fun render(mst: MST): MathSyntax { for (feature in features) feature.render(this, mst)?.let { return it } @@ -51,7 +48,6 @@ public open class FeaturedMathRenderer(public val features: List) * @property stages The applied stages. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public open class FeaturedMathRendererWithPostProcess( features: List, public val stages: List, 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 887469164..0196be3b6 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 @@ -5,14 +5,11 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.UnstableKMathAPI - /** * Syntax node for mathematical typography. * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public sealed class MathSyntax { /** * The parent node of this syntax node. @@ -25,7 +22,6 @@ public sealed class MathSyntax { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public sealed class TerminalSyntax : MathSyntax() /** @@ -33,7 +29,6 @@ public sealed class TerminalSyntax : MathSyntax() * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public sealed class OperationSyntax : MathSyntax() { /** * The operation token. @@ -46,7 +41,6 @@ public sealed class OperationSyntax : MathSyntax() { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public sealed class UnarySyntax : OperationSyntax() { /** * The operand of this node. @@ -59,7 +53,6 @@ public sealed class UnarySyntax : OperationSyntax() { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public sealed class BinarySyntax : OperationSyntax() { /** * The left-hand side operand. @@ -78,7 +71,6 @@ public sealed class BinarySyntax : OperationSyntax() { * @property string The digits of number. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class NumberSyntax(public var string: String) : TerminalSyntax() /** @@ -87,7 +79,6 @@ public data class NumberSyntax(public var string: String) : TerminalSyntax() * @property string The symbol. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class SymbolSyntax(public var string: String) : TerminalSyntax() /** @@ -98,7 +89,6 @@ public data class SymbolSyntax(public var string: String) : TerminalSyntax() * @see UnaryOperatorSyntax * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class OperatorNameSyntax(public var name: String) : TerminalSyntax() /** @@ -107,7 +97,6 @@ public data class OperatorNameSyntax(public var name: String) : TerminalSyntax() * @property kind The kind of symbol. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class SpecialSymbolSyntax(public var kind: Kind) : TerminalSyntax() { /** * The kind of symbol. @@ -132,7 +121,6 @@ public data class SpecialSymbolSyntax(public var kind: Kind) : TerminalSyntax() * @property parentheses Whether the operand should be wrapped with parentheses. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class OperandSyntax( public val operand: MathSyntax, public var parentheses: Boolean, @@ -148,7 +136,6 @@ public data class OperandSyntax( * @property prefix The prefix. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class UnaryOperatorSyntax( override val operation: String, public var prefix: MathSyntax, @@ -164,7 +151,6 @@ public data class UnaryOperatorSyntax( * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class UnaryPlusSyntax( override val operation: String, override val operand: OperandSyntax, @@ -179,7 +165,6 @@ public data class UnaryPlusSyntax( * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class UnaryMinusSyntax( override val operation: String, override val operand: OperandSyntax, @@ -195,7 +180,6 @@ public data class UnaryMinusSyntax( * @property operand The radicand. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class RadicalSyntax( override val operation: String, override val operand: MathSyntax, @@ -213,7 +197,6 @@ public data class RadicalSyntax( * (*ex*). * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class ExponentSyntax( override val operation: String, override val operand: OperandSyntax, @@ -231,7 +214,6 @@ public data class ExponentSyntax( * @property right The superscript. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class SuperscriptSyntax( override val operation: String, override val left: MathSyntax, @@ -250,7 +232,6 @@ public data class SuperscriptSyntax( * @property right The subscript. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class SubscriptSyntax( override val operation: String, override val left: MathSyntax, @@ -268,7 +249,6 @@ public data class SubscriptSyntax( * @property prefix The prefix. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class BinaryOperatorSyntax( override val operation: String, public var prefix: MathSyntax, @@ -288,7 +268,6 @@ public data class BinaryOperatorSyntax( * @param right The addend. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class BinaryPlusSyntax( override val operation: String, override val left: OperandSyntax, @@ -307,7 +286,6 @@ public data class BinaryPlusSyntax( * @param right The subtrahend. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class BinaryMinusSyntax( override val operation: String, override val left: OperandSyntax, @@ -327,7 +305,6 @@ public data class BinaryMinusSyntax( * @property infix Whether infix (*1 / 2*) or normal (*½*) fraction should be made. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class FractionSyntax( override val operation: String, override val left: OperandSyntax, @@ -347,7 +324,6 @@ public data class FractionSyntax( * @property right The radicand. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class RadicalWithIndexSyntax( override val operation: String, override val left: MathSyntax, @@ -367,7 +343,6 @@ public data class RadicalWithIndexSyntax( * @property times Whether the times (×) symbol should be used. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public data class MultiplicationSyntax( override val operation: String, override val left: OperandSyntax, 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 7669be664..16957bdd2 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 @@ -5,15 +5,12 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.UnstableKMathAPI - /** * Abstraction of writing [MathSyntax] as a string of an actual markup language. Typical implementation should * involve traversal of MathSyntax with handling each subtype. * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public fun interface SyntaxRenderer { /** * Renders the [MathSyntax] to [output]. @@ -26,7 +23,6 @@ public fun interface SyntaxRenderer { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public fun SyntaxRenderer.renderWithStringBuilder(node: MathSyntax): String { val sb = StringBuilder() render(node, sb) 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 8bb7e3585..4deffc83c 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 @@ -5,7 +5,6 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.rendering.FeaturedMathRenderer.RenderFeature import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol @@ -17,7 +16,6 @@ import kotlin.reflect.KClass * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public val PrintSymbol: RenderFeature = RenderFeature { _, node -> if (node !is Symbol) null else SymbolSyntax(string = node.identity) @@ -28,7 +26,6 @@ public val PrintSymbol: RenderFeature = RenderFeature { _, node -> * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public val PrintNumeric: RenderFeature = RenderFeature { _, node -> if (node !is MST.Numeric) null @@ -36,7 +33,6 @@ public val PrintNumeric: RenderFeature = RenderFeature { _, node -> NumberSyntax(string = node.value.toString()) } -@UnstableKMathAPI private fun printSignedNumberString(s: String): MathSyntax = if (s.startsWith('-')) UnaryMinusSyntax( operation = GroupOps.MINUS_OPERATION, @@ -55,7 +51,6 @@ else * @property types The suitable types. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class PrettyPrintFloats(public val types: Set>) : RenderFeature { override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { if (node !is MST.Numeric || node.value::class !in types) return null @@ -115,7 +110,6 @@ public class PrettyPrintFloats(public val types: Set>) : Rend * @property types The suitable types. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class PrettyPrintIntegers(public val types: Set>) : RenderFeature { override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = if (node !is MST.Numeric || node.value::class !in types) @@ -138,7 +132,6 @@ public class PrettyPrintIntegers(public val types: Set>) : Re * @property symbols The allowed symbols. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class PrettyPrintPi(public val symbols: Set) : RenderFeature { override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = if (node !is Symbol || node.identity !in symbols) @@ -161,7 +154,6 @@ public class PrettyPrintPi(public val symbols: Set) : RenderFeature { * @param operations the allowed operations. If `null`, any operation is accepted. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public abstract class Unary(public val operations: Collection?) : RenderFeature { /** * The actual render function specialized for [MST.Unary]. @@ -182,7 +174,6 @@ public abstract class Unary(public val operations: Collection?) : Render * @property operations the allowed operations. If `null`, any operation is accepted. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public abstract class Binary(public val operations: Collection?) : RenderFeature { /** * The actual render function specialized for [MST.Binary]. @@ -200,7 +191,6 @@ public abstract class Binary(public val operations: Collection?) : Rende * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class BinaryPlus(operations: Collection?) : Binary(operations) { override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryPlusSyntax( @@ -222,7 +212,6 @@ public class BinaryPlus(operations: Collection?) : Binary(operations) { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class BinaryMinus(operations: Collection?) : Binary(operations) { override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryMinusSyntax( @@ -244,7 +233,6 @@ public class BinaryMinus(operations: Collection?) : Binary(operations) { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class UnaryPlus(operations: Collection?) : Unary(operations) { override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryPlusSyntax( operation = node.operation, @@ -264,7 +252,6 @@ public class UnaryPlus(operations: Collection?) : Unary(operations) { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class UnaryMinus(operations: Collection?) : Unary(operations) { override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryMinusSyntax( operation = node.operation, @@ -284,7 +271,6 @@ public class UnaryMinus(operations: Collection?) : Unary(operations) { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class Fraction(operations: Collection?) : Binary(operations) { override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = FractionSyntax( operation = node.operation, @@ -306,7 +292,6 @@ public class Fraction(operations: Collection?) : Binary(operations) { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class BinaryOperator(operations: Collection?) : Binary(operations) { override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryOperatorSyntax( @@ -329,7 +314,6 @@ public class BinaryOperator(operations: Collection?) : Binary(operations * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class UnaryOperator(operations: Collection?) : Unary(operations) { override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( @@ -351,7 +335,6 @@ public class UnaryOperator(operations: Collection?) : Unary(operations) * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class Power(operations: Collection?) : Binary(operations) { override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = SuperscriptSyntax( @@ -371,7 +354,6 @@ public class Power(operations: Collection?) : Binary(operations) { /** * Handles binary nodes by producing [RadicalSyntax] with no index. */ -@UnstableKMathAPI public class SquareRoot(operations: Collection?) : Unary(operations) { override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = RadicalSyntax(operation = node.operation, operand = parent.render(node.value)) @@ -389,7 +371,6 @@ public class SquareRoot(operations: Collection?) : Unary(operations) { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class Exponent(operations: Collection?) : Unary(operations) { override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = ExponentSyntax( operation = node.operation, @@ -410,7 +391,6 @@ public class Exponent(operations: Collection?) : Unary(operations) { * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class Multiplication(operations: Collection?) : Binary(operations) { override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = MultiplicationSyntax( @@ -433,7 +413,6 @@ public class Multiplication(operations: Collection?) : Binary(operations * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class InverseTrigonometricOperations(operations: Collection?) : Unary(operations) { override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( @@ -460,7 +439,6 @@ public class InverseTrigonometricOperations(operations: Collection?) : U * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class InverseHyperbolicOperations(operations: Collection?) : Unary(operations) { override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( 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 2399e8f68..0d26621d3 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 @@ -5,7 +5,6 @@ package space.kscience.kmath.ast.rendering -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess.PostProcessPhase import space.kscience.kmath.operations.FieldOps import space.kscience.kmath.operations.GroupOps @@ -17,7 +16,6 @@ import space.kscience.kmath.operations.RingOps * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public val BetterMultiplication: PostProcessPhase = PostProcessPhase { node -> fun perform(node: MathSyntax): Unit = when (node) { is NumberSyntax -> Unit @@ -91,7 +89,6 @@ public val BetterMultiplication: PostProcessPhase = PostProcessPhase { node -> * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public val BetterFraction: PostProcessPhase = PostProcessPhase { node -> fun perform(node: MathSyntax, infix: Boolean = false): Unit = when (node) { is NumberSyntax -> Unit @@ -162,7 +159,6 @@ public val BetterFraction: PostProcessPhase = PostProcessPhase { node -> * * @author Iaroslav Postovalov */ -@UnstableKMathAPI public val BetterExponent: PostProcessPhase = PostProcessPhase { node -> fun perform(node: MathSyntax): Boolean { return when (node) { @@ -202,7 +198,6 @@ public val BetterExponent: PostProcessPhase = PostProcessPhase { node -> * @property precedenceFunction Returns the precedence number for syntax node. Higher number is lower priority. * @author Iaroslav Postovalov */ -@UnstableKMathAPI public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) : PostProcessPhase { override fun perform(node: MathSyntax): Unit = when (node) { diff --git a/kmath-complex/build.gradle.kts b/kmath-complex/build.gradle.kts index 76d5a4c9a..0611e9aae 100644 --- a/kmath-complex/build.gradle.kts +++ b/kmath-complex/build.gradle.kts @@ -7,9 +7,31 @@ kscience { js() native() + wasm{ + browser { + testTask { + useKarma { + this.webpackConfig.experiments.add("topLevelAwait") + useChromeHeadless() + useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm")) + } + } + } + } + + wasmTest{ + dependencies { + implementation(kotlin("test")) + } + } + dependencies { api(projects.kmathCore) } + + testDependencies { + implementation(projects.testUtils) + } } readme { diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index b6a955b12..08411be59 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -6,11 +6,31 @@ kscience{ jvm() js() native() -// wasm() + wasm{ + browser { + testTask { + useKarma { + this.webpackConfig.experiments.add("topLevelAwait") + useChromeHeadless() + useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm")) + } + } + } + } + + wasmTest{ + dependencies { + implementation(kotlin("test")) + } + } dependencies { api(projects.kmathMemory) } + + testDependencies { + implementation(projects.testUtils) + } } kotlin.sourceSets { diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt index 4f3469ea2..dd97df1e8 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.misc +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.misc.PermSortTest.Platform.* import space.kscience.kmath.structures.IntBuffer import space.kscience.kmath.structures.asBuffer @@ -14,6 +15,7 @@ import kotlin.test.assertContentEquals import kotlin.test.assertEquals import kotlin.test.assertTrue +@OptIn(UnstableKMathAPI::class) class PermSortTest { private enum class Platform { diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt index 1572db816..993fb089f 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt @@ -22,6 +22,7 @@ import kotlin.math.pow import kotlin.test.Test import kotlin.test.assertEquals +@OptIn(PerformancePitfall::class) @Suppress("UNUSED_VARIABLE") class NumberNDFieldTest { val algebra = DoubleField.ndAlgebra diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts index 9d5cfabe4..1e901ca98 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -6,6 +6,7 @@ kscience { jvm() js() native() + dependencies { api(project(":kmath-core")) api(project(":kmath-complex")) diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 08e76aef0..acabd1eb9 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -6,18 +6,32 @@ kscience{ jvm() js() native() + + wasm{ + browser { + testTask { + useKarma { + this.webpackConfig.experiments.add("topLevelAwait") + useChromeHeadless() + useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm")) + } + } + } + } + + wasmTest{ + dependencies { + implementation(kotlin("test")) + } + } + + dependencies { + api(projects.kmathCore) + } } description = "Functions, integration and interpolation" -kotlin.sourceSets { - commonMain { - dependencies { - api(project(":kmath-core")) - } - } -} - dependencies { dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${spclibs.versions.dokka.get()}") } diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index f248a1717..32926db7e 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -12,6 +12,11 @@ kscience{ dependencies{ api(projects.kmath.kmathComplex) } + + testDependencies { + implementation(projects.testUtils) + } + } readme { diff --git a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt index 2d32dd609..944666c9e 100644 --- a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt +++ b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlinx.jupyter.api.DisplayResult import org.jetbrains.kotlinx.jupyter.api.HTML import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer import space.kscience.kmath.ast.rendering.renderWithStringBuilder @@ -30,6 +31,7 @@ import space.kscience.kmath.structures.Buffer */ public fun Number.toMst(): MST.Numeric = MST.Numeric(this) +@OptIn(UnstableKMathAPI::class) internal class KMathJupyter : JupyterIntegration() { private val mathRender = FeaturedMathRendererWithPostProcess.Default private val syntaxRender = MathMLSyntaxRenderer diff --git a/kmath-memory/build.gradle.kts b/kmath-memory/build.gradle.kts index d8af1e3a2..4e5370c0f 100644 --- a/kmath-memory/build.gradle.kts +++ b/kmath-memory/build.gradle.kts @@ -6,7 +6,23 @@ kscience { jvm() js() native() -// wasm() + wasm{ + browser { + testTask { + useKarma { + this.webpackConfig.experiments.add("topLevelAwait") + useChromeHeadless() + useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm")) + } + } + } + } + + wasmTest{ + dependencies { + implementation(kotlin("test")) + } + } } readme { diff --git a/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt b/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt new file mode 100644 index 000000000..3726ddbb7 --- /dev/null +++ b/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.memory + +import kotlin.test.Test +import kotlin.test.assertEquals + +class MemoryTest { + @Test + fun memoryWriteRead() { + val memorySize = 60 + val data = buildList { + for (i in 0 until (memorySize / 4)) { + add(i) + } + } + val memory = Memory.allocate(memorySize) + memory.write { + for (i in 0 until (memory.size / 4)) { + writeInt(i*4, data[i]) + } + } + + val result = memory.read { + buildList { + for (i in 0 until (memory.size / 4)) { + add(readInt(i*4)) + } + } + } + + assertEquals(data,result) + } +} \ No newline at end of file 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 19910a396..d022cab23 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 @@ -20,8 +20,7 @@ internal class ByteBufferMemory( val startOffset: Int = 0, override val size: Int = buffer.limit(), ) : Memory { - @Suppress("NOTHING_TO_INLINE") - private inline fun position(o: Int): Int = startOffset + o + private fun position(offset: Int): Int = startOffset + offset override fun view(offset: Int, length: Int): Memory { require(offset >= 0) { "offset shouldn't be negative: $offset" } @@ -120,7 +119,7 @@ public fun ByteBuffer.asMemory(startOffset: Int = 0, size: Int = limit()): Memor ByteBufferMemory(this, startOffset, size) /** - * Uses direct memory-mapped buffer from file to read something and close it afterwards. + * Uses direct memory-mapped buffer from file to read something and close it afterward. */ @Throws(IOException::class) public inline fun Path.readAsMemory(position: Long = 0, size: Long = Files.size(this), block: Memory.() -> R): R { diff --git a/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt b/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt new file mode 100644 index 000000000..0cff551fa --- /dev/null +++ b/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt @@ -0,0 +1,103 @@ +/* + * Copyright 2018-2022 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.memory + +import org.khronos.webgl.ArrayBuffer +import org.khronos.webgl.DataView +import org.khronos.webgl.Int8Array + +private class WasmDataViewMemory(val view: DataView) : Memory { + override val size: Int get() = view.byteLength + + override fun view(offset: Int, length: Int): Memory { + require(offset >= 0) { "offset shouldn't be negative: $offset" } + require(length >= 0) { "length shouldn't be negative: $length" } + require(offset + length <= size) { "Can't view memory outside the parent region." } + + if (offset + length > size) + throw IndexOutOfBoundsException("offset + length > size: $offset + $length > $size") + + return WasmDataViewMemory(DataView(view.buffer, view.byteOffset + offset, length)) + } + + override fun copy(): Memory = WasmDataViewMemory(DataView(view.buffer.slice(0))) + + private val reader: MemoryReader = object : MemoryReader { + override val memory: Memory get() = this@WasmDataViewMemory + + override fun readDouble(offset: Int): Double = view.getFloat64(offset, false) + + override fun readFloat(offset: Int): Float = view.getFloat32(offset, false) + + override fun readByte(offset: Int): Byte = view.getInt8(offset) + + override fun readShort(offset: Int): Short = view.getInt16(offset, false) + + override fun readInt(offset: Int): Int = view.getInt32(offset, false) + + override fun readLong(offset: Int): Long = + view.getInt32(offset, false).toLong() shl 32 or view.getInt32(offset + 4, false).toLong() + + override fun close() { + // does nothing on JS + } + } + + override fun reader(): MemoryReader = reader + + private val writer: MemoryWriter = object : MemoryWriter { + override val memory: Memory get() = this@WasmDataViewMemory + + override fun writeDouble(offset: Int, value: Double) { + view.setFloat64(offset, value, false) + } + + override fun writeFloat(offset: Int, value: Float) { + view.setFloat32(offset, value, false) + } + + override fun writeByte(offset: Int, value: Byte) { + view.setInt8(offset, value) + } + + override fun writeShort(offset: Int, value: Short) { + view.setUint16(offset, value, false) + } + + override fun writeInt(offset: Int, value: Int) { + view.setInt32(offset, value, false) + } + + override fun writeLong(offset: Int, value: Long) { + view.setInt32(offset, (value shr 32).toInt(), littleEndian = false) + view.setInt32(offset + 4, (value and 0xffffffffL).toInt(), littleEndian = false) + } + + override fun close() { + // does nothing on JS + } + } + + override fun writer(): MemoryWriter = writer + +} + +/** + * Allocates memory based on a [DataView]. + */ +public actual fun Memory.Companion.allocate(length: Int): Memory { + val buffer = ArrayBuffer(length) + return WasmDataViewMemory(DataView(buffer, 0, length)) +} + +/** + * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied + * 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 + return WasmDataViewMemory(DataView(int8Array.buffer, int8Array.byteOffset, int8Array.length)) +} diff --git a/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmMemory.kt b/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmMemory.kt deleted file mode 100644 index 7c2be19cc..000000000 --- a/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmMemory.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.memory - -import kotlin.wasm.unsafe.Pointer -import kotlin.wasm.unsafe.UnsafeWasmMemoryApi - -@OptIn(UnsafeWasmMemoryApi::class) -public class WasmMemory private constructor( - public val pointer: Pointer, - override val size: Int, -) : Memory { - - override fun view(offset: Int, length: Int): Memory { - TODO("Not yet implemented") - } - - override fun copy(): Memory { - TODO("Not yet implemented") - } - - override fun reader(): MemoryReader = object : MemoryReader { - override val memory: Memory - get() = this@WasmMemory - - override fun readDouble(offset: Int): Double { - return Double.fromBits(pointer.plus(offset).loadLong()) - } - - override fun readFloat(offset: Int): Float { - return Float.fromBits(pointer.plus(offset).loadInt()) - } - - override fun readByte(offset: Int): Byte { - return pointer.plus(offset).loadByte() - } - - override fun readShort(offset: Int): Short { - return pointer.plus(offset).loadShort() - } - - override fun readInt(offset: Int): Int { - return pointer.plus(offset).loadInt() - } - - override fun readLong(offset: Int): Long { - return pointer.plus(offset).loadLong() - } - - override fun close() { - TODO() - } - - } - - override fun writer(): MemoryWriter = TODO() -} - -public actual fun Memory.Companion.allocate(length: Int): Memory { - TODO() -} - -public actual fun Memory.Companion.wrap(array: ByteArray): Memory = TODO() \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt index d1ceccf1a..0459d46ee 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.optimization +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.expressions.DifferentiableExpression import space.kscience.kmath.expressions.Symbol @@ -69,6 +70,7 @@ public suspend fun DifferentiableExpression.optimizeWith( } +@OptIn(UnstableKMathAPI::class) public class XYOptimizationBuilder( public val data: XYColumnarData, public val model: DifferentiableExpression, @@ -86,6 +88,7 @@ public class XYOptimizationBuilder( ) } +@OptIn(UnstableKMathAPI::class) public fun XYOptimization( data: XYColumnarData, model: DifferentiableExpression, diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index 1426e913a..000280def 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -11,7 +11,7 @@ kscience{ kotlin.sourceSets { commonMain { dependencies { - api(project(":kmath-coroutines")) + api(projects.kmathCoroutines) //implementation(spclibs.atomicfu) } } diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts index 31c57aca7..b03059eaf 100644 --- a/test-utils/build.gradle.kts +++ b/test-utils/build.gradle.kts @@ -6,7 +6,7 @@ kscience{ jvm() js() native() -// wasm() + wasm() } kotlin.sourceSets { From 8ac7567afdd5c94526bf12b153d5fdf11b2a6b60 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 9 Apr 2023 11:08:39 +0300 Subject: [PATCH 56/58] Patch changelog --- CHANGELOG.md | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08b72f0d0..e42fe61f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,27 @@ # KMath -## [Unreleased] +## Unreleased + +### Added + +### Changed + +### Deprecated + +### Removed + +### Fixed + +### Security + +## 0.3.1-dev-RC - 2023-04-09 + ### Added - Wasm support for `memory`, `core`, `complex` and `functions` modules. - Generic builders for `BufferND` and `MutableBufferND` - `NamedMatrix` - matrix with symbol-based indexing - `Expression` with default arguments - Type-aliases for numbers like `Float64` -- 2D optimal trajectory computation in a separate module `kmath-trajectory` - Autodiff for generic algebra elements in core! - Algebra now has an obligatory `bufferFactory` (#477). @@ -17,22 +31,17 @@ - Row-wise and column-wise ND shapes in the core - Shape is read-only - Major refactor of tensors (only minor API changes) -- Kotlin 1.7.20 +- Kotlin 1.8.20 - `LazyStructure` `deffered` -> `async` to comply with coroutines code style - Default `dot` operation in tensor algebra no longer support broadcasting. Instead `matmul` operation is added to `DoubleTensorAlgebra`. - Multik went MPP -### Deprecated - ### Removed - Trajectory moved to https://github.com/SciProgCentre/maps-kt - Polynomials moved to https://github.com/SciProgCentre/kmath-polynomial -### Fixed +## 0.3.0 -### Security - -## [0.3.0] ### Added - `ScaleOperations` interface - `Field` extends `ScaleOperations` @@ -57,9 +66,8 @@ - `contentEquals` with tolerance: #364 - Compilation to TeX for MST: #254 - ### Changed -- Annotations moved to `space.kscience.kmath` +- Annotations moved to `space.kscience.kmath` - Exponential operations merged with hyperbolic functions - Space is replaced by Group. Space is reserved for vector spaces. - VectorSpace is now a vector space @@ -91,11 +99,9 @@ - Rework of histograms. - `UnivariateFunction` -> `Function1D`, `MultivariateFunction` -> `FunctionND` - ### Deprecated - Specialized `DoubleBufferAlgebra` - ### Removed - Nearest in Domain. To be implemented in geometry package. - Number multiplication and division in main Algebra chain @@ -106,15 +112,12 @@ - Second generic from DifferentiableExpression - Algebra elements are completely removed. Use algebra contexts instead. - ### Fixed - Ring inherits RingOperations, not GroupOperations - Univariate histogram filling +## 0.2.0 -### Security - -## [0.2.0] ### Added - `fun` annotation for SAM interfaces in library - Explicit `public` visibility for all public APIs @@ -134,7 +137,6 @@ - New `MatrixFeature` interfaces for matrix decompositions - Basic Quaternion vector support in `kmath-complex`. - ### Changed - Package changed from `scientifik` to `space.kscience` - Gradle version: 6.6 -> 6.8.2 @@ -159,7 +161,6 @@ - `symbol` method in `Algebra` renamed to `bindSymbol` to avoid ambiguity - Add `out` projection to `Buffer` generic - ### Removed - `kmath-koma` module because it doesn't support Kotlin 1.4. - Support of `legacy` JS backend (we will support only IR) @@ -168,11 +169,11 @@ - `Real` class - StructureND identity and equals - ### Fixed - `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140) -## [0.1.4] +## 0.1.4 + ### Added - Functional Expressions API - Mathematical Syntax Tree, its interpreter and API @@ -190,7 +191,6 @@ - Full hyperbolic functions support and default implementations within `ExtendedField` - Norm support for `Complex` - ### Changed - `readAsMemory` now has `throws IOException` in JVM signature. - Several functions taking functional types were made `inline`. @@ -202,10 +202,9 @@ - Gradle version: 6.3 -> 6.6 - Moved probability distributions to commons-rng and to `kmath-prob` - ### Fixed - Missing copy method in Memory implementation on JS (https://github.com/mipt-npm/kmath/pull/106) - D3.dim value in `kmath-dimensions` - Multiplication in integer rings in `kmath-core` (https://github.com/mipt-npm/kmath/pull/101) - Commons RNG compatibility (https://github.com/mipt-npm/kmath/issues/93) -- Multiplication of BigInt by scalar \ No newline at end of file +- Multiplication of BigInt by scalar From e1d5409c0d1148b2ba9e8221d09cb514c22e7fb9 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 9 Apr 2023 11:12:04 +0300 Subject: [PATCH 57/58] Patch changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e42fe61f3..998e6daae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ - Algebra now has an obligatory `bufferFactory` (#477). ### Changed -- Trajectory use type-safe angles +- Geometry uses type-safe angles - Tensor operations switched to prefix notation - Row-wise and column-wise ND shapes in the core - Shape is read-only From 85395ff82ed76f480a67b36827397ecdd66c4728 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 14 Apr 2023 21:17:44 +0300 Subject: [PATCH 58/58] Add autodiff example --- .../kscience/kmath/expressions/autodiff.kt | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt b/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt new file mode 100644 index 000000000..b1e14591a --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.expressions + +import space.kscience.kmath.UnstableKMathAPI +// Only kmath-core is needed. + +// Let's declare some variables +val x by symbol +val y by symbol +val z by symbol + +@OptIn(UnstableKMathAPI::class) +fun main() { + // Let's define some random expression. + val someExpression = Double.autodiff.differentiate { + // We bind variables `x` and `y` to the builder scope, + val x = bindSymbol(x) + val y = bindSymbol(y) + + // Then we use the bindings to define expression `xy + x + y - 1` + x * y + x + y - 1 + } + + // Then we can evaluate it at any point ((-1, -1) in the case): + println(someExpression(mapOf(x to -1.0, y to -1.0))) + // >>> -2.0 + + // We can also construct its partial derivatives: + val dxExpression = someExpression.derivative(x) // ∂/∂x. Must be `y+1` + val dyExpression = someExpression.derivative(y) // ∂/∂y. Must be `x+1` + val dxdxExpression = someExpression.derivative(x, x) // ∂^2/∂x^2. Must be `0` + + // We can evaluate them as well + println(dxExpression(mapOf(x to 57.0, y to 6.0))) + // >>> 7.0 + println(dyExpression(mapOf(x to -1.0, y to 179.0))) + // >>> 0.0 + println(dxdxExpression(mapOf(x to 239.0, y to 30.0))) + // >>> 0.0 + + // You can also provide extra arguments that obviously won't affect the result: + println(dxExpression(mapOf(x to 57.0, y to 6.0, z to 42.0))) + // >>> 7.0 + println(dyExpression(mapOf(x to -1.0, y to 179.0, z to 0.0))) + // >>> 0.0 + println(dxdxExpression(mapOf(x to 239.0, y to 30.0, z to 100_000.0))) + // >>> 0.0 + + // But in case you forgot to specify bound symbol's value, exception is thrown: + println( runCatching { someExpression(mapOf(z to 4.0)) } ) + // >>> Failure(java.lang.IllegalStateException: Symbol 'x' is not supported in ...) + + // The reason is that the expression is evaluated lazily, + // and each `bindSymbol` operation actually substitutes the provided symbol with the corresponding value. + + // For example, let there be an expression + val simpleExpression = Double.autodiff.differentiate { + val x = bindSymbol(x) + x pow 2 + } + // When you evaluate it via + simpleExpression(mapOf(x to 1.0, y to 57.0, z to 179.0)) + // lambda above has the context of map `{x: 1.0, y: 57.0, z: 179.0}`. + // When x is bound, you can think of it as substitution `x -> 1.0`. + // Other values are unused which does not make any problem to us. + // But in the case the corresponding value is not provided, + // we cannot bind the variable. Thus, exception is thrown. + + // There is also a function `bindSymbolOrNull` that fixes the problem: + val fixedExpression = Double.autodiff.differentiate { + val x = bindSymbolOrNull(x) ?: const(8.0) + x pow -2 + } + println(fixedExpression()) + // >>> 0.015625 + // It works! + + // The expression provides a bunch of operations: + // 1. Constant bindings (via `const` and `number`). + // 2. Variable bindings (via `bindVariable`, `bindVariableOrNull`). + // 3. Arithmetic operations (via `+`, `-`, `*`, and `-`). + // 4. Exponentiation (via `pow` or `power`). + // 5. `exp` and `ln`. + // 6. Trigonometrical functions (`sin`, `cos`, `tan`, `cot`). + // 7. Inverse trigonometrical functions (`asin`, `acos`, `atan`, `acot`). + // 8. Hyperbolic functions and inverse hyperbolic functions. +}