From 257337f4fb2a7681ff769b202dd4f16ebb8e0725 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 25 Apr 2021 22:34:59 +0300 Subject: [PATCH 001/102] [WIP] Refactor optimization --- .../kscience/kmath/functions/integrate.kt | 4 +- .../kmath/functions/matrixIntegration.kt | 4 +- .../kmath/commons/integration/CMIntegrator.kt | 13 +- .../integration/GaussRuleIntegrator.kt | 4 +- .../commons/optimization/CMOptimization.kt | 145 ++-- .../kmath/commons/optimization/cmFit.kt | 20 +- .../commons/optimization/OptimizeTest.kt | 4 +- .../kmath/data/XYErrorColumnarData.kt | 33 + .../kscience/kmath/data/XYZColumnarData.kt | 2 +- .../expressions/DifferentiableExpression.kt | 2 +- .../kmath/expressions/SymbolIndexer.kt | 10 + .../space/kscience/kmath/linear/symmetric.kt | 34 + .../space/kscience/kmath/misc/Featured.kt | 37 + .../kmath/structures/BufferAccessor2D.kt | 2 +- .../kmath/structures/DoubleBufferField.kt | 10 +- .../space/kscience/kmath/real/RealVector.kt | 11 +- .../kmath/integration/GaussIntegrator.kt | 12 +- .../kscience/kmath/integration/Integrand.kt | 7 +- .../kscience/kmath/integration/Integrator.kt | 2 +- .../integration/MultivariateIntegrand.kt | 18 +- .../kmath/integration/UnivariateIntegrand.kt | 24 +- .../kmath/integration/GaussIntegralTest.kt | 4 +- .../optimization/FunctionOptimization.kt | 163 ++-- .../NoDerivFunctionOptimization.kt | 74 -- .../kmath/optimization/Optimization.kt | 49 -- .../kmath/optimization/OptimizationProblem.kt | 46 ++ .../kscience/kmath/optimization/XYFit.kt | 2 +- .../minuit/AnalyticalGradientCalculator.kt | 61 ++ .../optimization/minuit/CombinedMinimizer.kt | 32 + .../minuit/CombinedMinimumBuilder.kt | 57 ++ .../optimization/minuit/ContoursError.kt | 150 ++++ .../minuit/DavidonErrorUpdator.kt | 45 ++ .../optimization/minuit/FunctionGradient.kt | 72 ++ .../optimization/minuit/FunctionMinimum.kt | 259 ++++++ .../optimization/minuit/GradientCalculator.kt | 41 + .../minuit/HessianGradientCalculator.kt | 137 ++++ .../minuit/InitialGradientCalculator.kt | 116 +++ .../kmath/optimization/minuit/MINOSResult.kt | 70 ++ .../kmath/optimization/minuit/MINUITFitter.kt | 205 +++++ .../kmath/optimization/minuit/MINUITPlugin.kt | 86 ++ .../kmath/optimization/minuit/MINUITUtils.kt | 121 +++ .../optimization/minuit/MinimumBuilder.kt | 43 + .../kmath/optimization/minuit/MinimumError.kt | 155 ++++ .../minuit/MinimumErrorUpdator.kt | 33 + .../optimization/minuit/MinimumParameters.kt | 70 ++ .../kmath/optimization/minuit/MinimumSeed.kt | 64 ++ .../minuit/MinimumSeedGenerator.kt | 37 + .../kmath/optimization/minuit/MinimumState.kt | 104 +++ .../kmath/optimization/minuit/MinosError.kt | 219 +++++ .../optimization/minuit/MinuitParameter.kt | 314 ++++++++ .../minuit/MnAlgebraicSymMatrix.kt | 458 +++++++++++ .../optimization/minuit/MnApplication.kt | 554 +++++++++++++ .../kmath/optimization/minuit/MnContours.kt | 283 +++++++ .../minuit/MnCovarianceSqueeze.kt | 113 +++ .../kmath/optimization/minuit/MnCross.kt | 99 +++ .../kmath/optimization/minuit/MnEigen.kt | 50 ++ .../kmath/optimization/minuit/MnFcn.kt | 50 ++ .../optimization/minuit/MnFunctionCross.kt | 369 +++++++++ .../minuit/MnGlobalCorrelationCoeff.kt | 79 ++ .../kmath/optimization/minuit/MnHesse.kt | 371 +++++++++ .../kmath/optimization/minuit/MnLineSearch.kt | 204 +++++ .../optimization/minuit/MnMachinePrecision.kt | 71 ++ .../kmath/optimization/minuit/MnMigrad.kt | 136 ++++ .../kmath/optimization/minuit/MnMinimize.kt | 133 +++ .../kmath/optimization/minuit/MnMinos.kt | 379 +++++++++ .../kmath/optimization/minuit/MnParabola.kt | 55 ++ .../optimization/minuit/MnParabolaFactory.kt | 58 ++ .../optimization/minuit/MnParabolaPoint.kt | 30 + .../optimization/minuit/MnParameterScan.kt | 113 +++ .../kmath/optimization/minuit/MnPlot.kt | 438 ++++++++++ .../kmath/optimization/minuit/MnPosDef.kt | 89 +++ .../kmath/optimization/minuit/MnPrint.kt | 387 +++++++++ .../kmath/optimization/minuit/MnScan.kt | 181 +++++ .../optimization/minuit/MnSeedGenerator.kt | 107 +++ .../kmath/optimization/minuit/MnSimplex.kt | 138 ++++ .../kmath/optimization/minuit/MnStrategy.kt | 310 +++++++ .../optimization/minuit/MnUserCovariance.kt | 147 ++++ .../kmath/optimization/minuit/MnUserFcn.kt | 30 + .../minuit/MnUserParameterState.kt | 756 ++++++++++++++++++ .../optimization/minuit/MnUserParameters.kt | 402 ++++++++++ .../minuit/MnUserTransformation.kt | 390 +++++++++ .../kmath/optimization/minuit/MnUtils.kt | 147 ++++ .../minuit/ModularFunctionMinimizer.kt | 72 ++ .../minuit/NegativeG2LineSearch.kt | 80 ++ .../minuit/Numerical2PGradientCalculator.kt | 122 +++ .../kmath/optimization/minuit/Range.kt | 32 + .../kmath/optimization/minuit/ScanBuilder.kt | 58 ++ .../optimization/minuit/ScanMinimizer.kt | 36 + .../optimization/minuit/SimplexBuilder.kt | 179 +++++ .../optimization/minuit/SimplexMinimizer.kt | 43 + .../optimization/minuit/SimplexParameters.kt | 85 ++ .../minuit/SimplexSeedGenerator.kt | 52 ++ .../minuit/SinParameterTransformation.kt | 48 ++ .../minuit/SqrtLowParameterTransformation.kt | 43 + .../minuit/SqrtUpParameterTransformation.kt | 43 + .../minuit/VariableMetricBuilder.kt | 137 ++++ .../minuit/VariableMetricEDMEstimator.kt | 31 + .../minuit/VariableMetricMinimizer.kt | 43 + .../kmath/optimization/minuit/package-info.kt | 17 + .../kscience/kmath/optimization/qow/QowFit.kt | 380 +++++++++ 100 files changed, 11509 insertions(+), 346 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/symmetric.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt delete mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt delete mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/AnalyticalGradientCalculator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimizer.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimumBuilder.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ContoursError.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/DavidonErrorUpdator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionGradient.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionMinimum.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/GradientCalculator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/HessianGradientCalculator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/InitialGradientCalculator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINOSResult.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITFitter.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITPlugin.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITUtils.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumBuilder.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumError.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumErrorUpdator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumParameters.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeed.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeedGenerator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumState.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinosError.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinuitParameter.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnAlgebraicSymMatrix.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnApplication.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnContours.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCovarianceSqueeze.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCross.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnEigen.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFcn.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFunctionCross.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnGlobalCorrelationCoeff.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnHesse.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnLineSearch.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMachinePrecision.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMigrad.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinimize.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinos.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabola.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaFactory.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaPoint.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParameterScan.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPlot.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPosDef.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPrint.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnScan.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSeedGenerator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSimplex.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnStrategy.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserCovariance.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserFcn.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameterState.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameters.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserTransformation.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUtils.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ModularFunctionMinimizer.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/NegativeG2LineSearch.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Numerical2PGradientCalculator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Range.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanBuilder.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanMinimizer.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexBuilder.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexMinimizer.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexParameters.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexSeedGenerator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SinParameterTransformation.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtLowParameterTransformation.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtUpParameterTransformation.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricBuilder.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricEDMEstimator.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricMinimizer.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/package-info.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt 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 6990e8c8f..7cdf7bef6 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.functions -import space.kscience.kmath.integration.integrate +import space.kscience.kmath.integration.process import space.kscience.kmath.integration.value import space.kscience.kmath.operations.DoubleField import kotlin.math.pow @@ -15,7 +15,7 @@ fun main() { val function: UnivariateFunction = { x -> 3 * x.pow(2) + 2 * x + 1 } //get the result of the integration - val result = DoubleField.integrate(0.0..10.0, function = function) + val result = DoubleField.process(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/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt index 8020df8f6..206ba3054 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.functions -import space.kscience.kmath.integration.integrate +import space.kscience.kmath.integration.process import space.kscience.kmath.integration.value import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.nd @@ -24,7 +24,7 @@ fun main(): Unit = DoubleField { val function: (Double) -> StructureND = { x: Double -> 3 * number(x).pow(2) + 2 * diagonal(x) + 1 } //get the result of the integration - val result = integrate(0.0..10.0, function = function) + val result = process(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/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 92bf86128..9da35a7c0 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 @@ -24,7 +24,7 @@ public class CMIntegrator( public class MinIterations(public val value: Int) : IntegrandFeature public class MaxIterations(public val value: Int) : IntegrandFeature - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { val integrator = integratorBuilder(integrand) val maxCalls = integrand.getFeature()?.maxCalls ?: defaultMaxCalls val remainingCalls = maxCalls - integrand.calls @@ -32,11 +32,12 @@ public class CMIntegrator( ?: error("Integration range is not provided") val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive) - return integrand + - IntegrandValue(res) + - IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy) + - IntegrandRelativeAccuracy(integrator.relativeAccuracy) + - IntegrandCallsPerformed(integrator.evaluations + integrand.calls) + return integrand.with( + IntegrandValue(res), + IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy), + IntegrandRelativeAccuracy(integrator.relativeAccuracy), + IntegrandCallsPerformed(integrator.evaluations + integrand.calls) + ) } diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/GaussRuleIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/GaussRuleIntegrator.kt index 1c9915563..1361b1079 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/GaussRuleIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/GaussRuleIntegrator.kt @@ -16,7 +16,7 @@ public class GaussRuleIntegrator( private var type: GaussRule = GaussRule.LEGANDRE, ) : UnivariateIntegrator { - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { val range = integrand.getFeature()?.range ?: error("Integration range is not provided") val integrator: GaussIntegrator = getIntegrator(range) @@ -76,7 +76,7 @@ public class GaussRuleIntegrator( numPoints: Int = 100, type: GaussRule = GaussRule.LEGANDRE, function: (Double) -> Double, - ): Double = GaussRuleIntegrator(numPoints, type).integrate( + ): Double = GaussRuleIntegrator(numPoints, type).process( UnivariateIntegrand(function, IntegrationRange(range)) ).value!! } diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt index cfb8c39be..db9ba6f21 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt @@ -14,10 +14,7 @@ import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjuga import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.SymbolIndexer -import space.kscience.kmath.expressions.derivative +import space.kscience.kmath.expressions.* import space.kscience.kmath.misc.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.optimization.* @@ -26,94 +23,98 @@ import kotlin.reflect.KClass public operator fun PointValuePair.component1(): DoubleArray = point public operator fun PointValuePair.component2(): Double = value +public class CMOptimizerFactory(public val optimizerBuilder: () -> MultivariateOptimizer) : OptimizationFeature +//public class CMOptimizerData(public val ) + @OptIn(UnstableKMathAPI::class) -public class CMOptimization( - override val symbols: List, -) : FunctionOptimization, NoDerivFunctionOptimization, SymbolIndexer, OptimizationFeature { +public class CMOptimization : Optimizer> { - private val optimizationData: HashMap, OptimizationData> = HashMap() - private var optimizerBuilder: (() -> MultivariateOptimizer)? = null - public var convergenceChecker: ConvergenceChecker = SimpleValueChecker( - DEFAULT_RELATIVE_TOLERANCE, - DEFAULT_ABSOLUTE_TOLERANCE, - DEFAULT_MAX_ITER - ) + override suspend fun process( + problem: FunctionOptimization + ): FunctionOptimization = withSymbols(problem.parameters){ + val cmOptimizer: MultivariateOptimizer = + problem.getFeature()?.optimizerBuilder?.invoke() ?: SimplexOptimizer() - override var maximize: Boolean - get() = optimizationData[GoalType::class] == GoalType.MAXIMIZE - set(value) { - optimizationData[GoalType::class] = if (value) GoalType.MAXIMIZE else GoalType.MINIMIZE + val convergenceChecker: ConvergenceChecker = SimpleValueChecker( + DEFAULT_RELATIVE_TOLERANCE, + DEFAULT_ABSOLUTE_TOLERANCE, + DEFAULT_MAX_ITER + ) + + val optimizationData: HashMap, OptimizationData> = HashMap() + + fun addOptimizationData(data: OptimizationData) { + optimizationData[data::class] = data } - - public fun addOptimizationData(data: OptimizationData) { - optimizationData[data::class] = data - } - - init { addOptimizationData(MaxEval.unlimited()) - } + addOptimizationData(InitialGuess(problem.initialGuess.toDoubleArray())) - public fun exportOptimizationData(): List = optimizationData.values.toList() + fun exportOptimizationData(): List = optimizationData.values.toList() - public override fun initialGuess(map: Map): Unit { - addOptimizationData(InitialGuess(map.toDoubleArray())) - } - public override fun function(expression: Expression): Unit { - val objectiveFunction = ObjectiveFunction { - val args = it.toMap() - expression(args) + /** + * Register no-deriv function instead of differentiable function + */ + /** + * Register no-deriv function instead of differentiable function + */ + fun noDerivFunction(expression: Expression): Unit { + val objectiveFunction = ObjectiveFunction { + val args = problem.initialGuess + it.toMap() + expression(args) + } + addOptimizationData(objectiveFunction) } - addOptimizationData(objectiveFunction) - } - public override fun diffFunction(expression: DifferentiableExpression>) { - function(expression) - val gradientFunction = ObjectiveFunctionGradient { - val args = it.toMap() - DoubleArray(symbols.size) { index -> - expression.derivative(symbols[index])(args) + public override fun function(expression: DifferentiableExpression>) { + noDerivFunction(expression) + val gradientFunction = ObjectiveFunctionGradient { + val args = startingPoint + it.toMap() + DoubleArray(symbols.size) { index -> + expression.derivative(symbols[index])(args) + } + } + addOptimizationData(gradientFunction) + if (optimizerBuilder == null) { + optimizerBuilder = { + NonLinearConjugateGradientOptimizer( + NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, + convergenceChecker + ) + } } } - addOptimizationData(gradientFunction) - if (optimizerBuilder == null) { - optimizerBuilder = { - NonLinearConjugateGradientOptimizer( - NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, - convergenceChecker - ) + + public fun simplex(simplex: AbstractSimplex) { + addOptimizationData(simplex) + //Set optimization builder to simplex if it is not present + if (optimizerBuilder == null) { + optimizerBuilder = { SimplexOptimizer(convergenceChecker) } } } - } - public fun simplex(simplex: AbstractSimplex) { - addOptimizationData(simplex) - //Set optimization builder to simplex if it is not present - if (optimizerBuilder == null) { - optimizerBuilder = { SimplexOptimizer(convergenceChecker) } + public fun simplexSteps(steps: Map) { + simplex(NelderMeadSimplex(steps.toDoubleArray())) } - } - public fun simplexSteps(steps: Map) { - simplex(NelderMeadSimplex(steps.toDoubleArray())) - } + public fun goal(goalType: GoalType) { + addOptimizationData(goalType) + } - public fun goal(goalType: GoalType) { - addOptimizationData(goalType) - } + public fun optimizer(block: () -> MultivariateOptimizer) { + optimizerBuilder = block + } - public fun optimizer(block: () -> MultivariateOptimizer) { - optimizerBuilder = block - } + override fun update(result: OptimizationResult) { + initialGuess(result.point) + } - override fun update(result: OptimizationResult) { - initialGuess(result.point) - } - - override fun optimize(): OptimizationResult { - val optimizer = optimizerBuilder?.invoke() ?: error("Optimizer not defined") - val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray()) - return OptimizationResult(point.toMap(), value, setOf(this)) + override suspend fun optimize(): OptimizationResult { + val optimizer = optimizerBuilder?.invoke() ?: error("Optimizer not defined") + val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray()) + return OptimizationResult(point.toMap(), value) + } + return@withSymbols TODO() } public companion object : OptimizationProblemFactory { diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt index 13b5c73f4..12d924063 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt @@ -10,10 +10,7 @@ import space.kscience.kmath.commons.expressions.DerivativeStructureField import space.kscience.kmath.expressions.DifferentiableExpression import space.kscience.kmath.expressions.Expression import space.kscience.kmath.misc.Symbol -import space.kscience.kmath.optimization.FunctionOptimization -import space.kscience.kmath.optimization.OptimizationResult -import space.kscience.kmath.optimization.noDerivOptimizeWith -import space.kscience.kmath.optimization.optimizeWith +import space.kscience.kmath.optimization.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer @@ -46,20 +43,25 @@ public fun FunctionOptimization.Companion.chiSquared( /** * Optimize expression without derivatives */ -public fun Expression.optimize( +public suspend fun Expression.optimize( vararg symbols: Symbol, configuration: CMOptimization.() -> Unit, -): OptimizationResult = noDerivOptimizeWith(CMOptimization, symbols = symbols, configuration) +): OptimizationResult { + require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } + val problem = CMOptimization(symbols.toList(), configuration) + problem.noDerivFunction(this) + return problem.optimize() +} /** * Optimize differentiable expression */ -public fun DifferentiableExpression>.optimize( +public suspend fun DifferentiableExpression>.optimize( vararg symbols: Symbol, configuration: CMOptimization.() -> Unit, ): OptimizationResult = optimizeWith(CMOptimization, symbols = symbols, configuration) -public fun DifferentiableExpression>.minimize( +public suspend fun DifferentiableExpression>.minimize( vararg startPoint: Pair, configuration: CMOptimization.() -> Unit = {}, ): OptimizationResult { @@ -67,7 +69,7 @@ public fun DifferentiableExpression>.minimize( return optimize(*symbols){ maximize = false initialGuess(startPoint.toMap()) - diffFunction(this@minimize) + function(this@minimize) configuration() } } \ No newline at end of file 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 716cd1b0f..9b92eaac5 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 @@ -24,7 +24,7 @@ internal class OptimizeTest { } @Test - fun testGradientOptimization() { + fun testGradientOptimization() = runBlocking{ val result = normal.optimize(x, y) { initialGuess(x to 1.0, y to 1.0) //no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function @@ -34,7 +34,7 @@ internal class OptimizeTest { } @Test - fun testSimplexOptimization() { + fun testSimplexOptimization() = runBlocking{ val result = normal.optimize(x, y) { initialGuess(x to 1.0, y to 1.0) simplexSteps(x to 2.0, y to 0.5) 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 new file mode 100644 index 000000000..ea98e88b1 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.data + +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.Symbol.Companion.z +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.misc.symbol +import space.kscience.kmath.structures.Buffer + + +/** + * A [ColumnarData] with additional [Companion.yErr] column for an [Symbol.y] error + * Inherits [XYColumnarData]. + */ +@UnstableKMathAPI +public interface XYErrorColumnarData : XYColumnarData { + public val yErr: Buffer + + override fun get(symbol: Symbol): Buffer = when (symbol) { + Symbol.x -> x + Symbol.y -> y + Companion.yErr -> yErr + else -> error("A column for symbol $symbol not found") + } + + public companion object{ + public val yErr: Symbol by symbol + } +} \ No newline at end of file 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 d76a44e9e..2ae7233ec 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 @@ -10,7 +10,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer /** - * A [XYColumnarData] with guaranteed [x], [y] and [z] columns designated by corresponding symbols. + * A [ColumnarData] with guaranteed [x], [y] and [z] columns designated by corresponding symbols. * Inherits [XYColumnarData]. */ @UnstableKMathAPI diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt index dbc1431b3..f2346f483 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt @@ -51,6 +51,6 @@ public abstract class FirstDerivativeExpression> : Differen /** * A factory that converts an expression in autodiff variables to a [DifferentiableExpression] */ -public fun interface AutoDiffProcessor, out R : Expression> { +public fun interface AutoDiffProcessor, out R : Expression> { public fun process(function: A.() -> I): DifferentiableExpression } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt index 738156975..ea72c5b9e 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 @@ -10,6 +10,7 @@ import space.kscience.kmath.misc.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.structures.BufferFactory +import space.kscience.kmath.structures.DoubleBuffer import kotlin.jvm.JvmInline /** @@ -46,6 +47,11 @@ public interface SymbolIndexer { return symbols.indices.associate { symbols[it] to get(it) } } + public fun Point.toMap(): Map { + require(size == symbols.size) { "The input array size for indexer should be ${symbols.size} but $size found" } + return symbols.indices.associate { symbols[it] to get(it) } + } + public operator fun Structure2D.get(rowSymbol: Symbol, columnSymbol: Symbol): T = get(indexOf(rowSymbol), indexOf(columnSymbol)) @@ -55,6 +61,10 @@ public interface SymbolIndexer { public fun Map.toPoint(bufferFactory: BufferFactory): Point = bufferFactory(symbols.size) { getValue(symbols[it]) } + public fun Map.toPoint(): DoubleBuffer = + DoubleBuffer(symbols.size) { getValue(symbols[it]) } + + public fun Map.toDoubleArray(): DoubleArray = DoubleArray(symbols.size) { getValue(symbols[it]) } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/symmetric.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/symmetric.kt new file mode 100644 index 000000000..04d9a9897 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/symmetric.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.linear + +import space.kscience.kmath.structures.BufferAccessor2D +import space.kscience.kmath.structures.MutableBuffer + +public object SymmetricMatrixFeature : MatrixFeature + +/** + * Naive implementation of a symmetric matrix builder, that adds a [SymmetricMatrixFeature] tag. The resulting matrix contains + * full `size^2` number of elements, but caches elements during calls to save [builder] calls. [builder] is always called in the + * upper triangle region meaning that `i <= j` + */ +public fun > LS.buildSymmetricMatrix( + size: Int, + builder: (i: Int, j: Int) -> T, +): Matrix = BufferAccessor2D(size, size, MutableBuffer.Companion::boxing).run { + val cache = factory(size * size) { null } + buildMatrix(size, size) { i, j -> + val cached = cache[i, j] + if (cached == null) { + val value = if (i <= j) builder(i, j) else builder(j, i) + cache[i, j] = value + cache[j, i] = value + value + } else { + cached + } + } + SymmetricMatrixFeature +} \ No newline at end of file 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 new file mode 100644 index 000000000..157ff980b --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.misc + +import kotlin.reflect.KClass + +/** + * A entity that contains a set of features defined by their types + */ +public interface Featured { + public fun getFeature(type: KClass): T? +} + +/** + * A container for a set of features + */ +public class FeatureSet private constructor(public val features: Map, Any>) : Featured { + @Suppress("UNCHECKED_CAST") + override fun getFeature(type: KClass): T? = features[type] as? T + + public inline fun getFeature(): T? = getFeature(T::class) + + public fun with(feature: T, type: KClass = feature::class): FeatureSet = + FeatureSet(features + (type to feature)) + + public fun with(other: FeatureSet): FeatureSet = FeatureSet(features + other.features) + + public fun with(vararg otherFeatures: F): FeatureSet = + FeatureSet(features + otherFeatures.associateBy { it::class }) + + public companion object { + public fun of(vararg features: F): FeatureSet = FeatureSet(features.associateBy { it::class }) + } +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt index 352c75956..d29c54d46 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt @@ -13,7 +13,7 @@ import space.kscience.kmath.nd.as2D /** * A context that allows to operate on a [MutableBuffer] as on 2d array */ -internal class BufferAccessor2D( +internal class BufferAccessor2D( public val rowNum: Int, public val colNum: Int, val factory: MutableBufferFactory, diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt index 34b5e373b..e438995dd 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt @@ -5,8 +5,10 @@ package space.kscience.kmath.structures +import space.kscience.kmath.linear.Point import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.ExtendedFieldOperations +import space.kscience.kmath.operations.Norm import kotlin.math.* /** @@ -161,12 +163,16 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, Double> { + override fun norm(arg: Point): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) +} + /** * [ExtendedField] over [DoubleBuffer]. * * @property size the size of buffers to operate on. */ -public class DoubleBufferField(public val size: Int) : ExtendedField> { +public class DoubleBufferField(public val size: Int) : ExtendedField>, Norm, Double> { public override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } public override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } @@ -274,4 +280,6 @@ public class DoubleBufferField(public val size: Int) : ExtendedField): Double = DoubleL2Norm.norm(arg) } diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt index d3867ea89..dbf81b133 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt @@ -8,11 +8,8 @@ package space.kscience.kmath.real import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Norm -import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.* import space.kscience.kmath.structures.MutableBuffer.Companion.double -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.fold -import space.kscience.kmath.structures.indices import kotlin.math.pow import kotlin.math.sqrt @@ -105,8 +102,4 @@ public fun DoubleVector.sum(): Double { return res } -public object VectorL2Norm : Norm { - override fun norm(arg: DoubleVector): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) -} - -public val DoubleVector.norm: Double get() = VectorL2Norm.norm(this) \ No newline at end of file +public val DoubleVector.norm: Double get() = DoubleL2Norm.norm(this) \ No newline at end of file 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 ae82a40be..e3a9e5a4a 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 @@ -50,7 +50,7 @@ public class GaussIntegrator( } } - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand = with(algebra) { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = with(algebra) { val f = integrand.function val (points, weights) = buildRule(integrand) var res = zero @@ -63,7 +63,7 @@ public class GaussIntegrator( c = t - res - y res = t } - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + points.size) + return integrand.with(IntegrandValue(res),IntegrandCallsPerformed(integrand.calls + points.size)) } public companion object { @@ -80,17 +80,17 @@ public class GaussIntegrator( * * [UnivariateIntegrandRanges] - Set of ranges and number of points per range. Defaults to given [IntegrationRange] and [IntegrandMaxCalls] */ @UnstableKMathAPI -public fun Field.integrate( +public fun Field.process( vararg features: IntegrandFeature, function: (Double) -> T, -): UnivariateIntegrand = GaussIntegrator(this).integrate(UnivariateIntegrand(function, *features)) +): UnivariateIntegrand = GaussIntegrator(this).process(UnivariateIntegrand(function, *features)) /** * Use [GaussIntegrator.Companion.integrate] to integrate the function in the current algebra with given [range] and [numPoints] */ @UnstableKMathAPI -public fun Field.integrate( +public fun Field.process( range: ClosedRange, order: Int = 10, intervals: Int = 10, @@ -104,7 +104,7 @@ public fun Field.integrate( val ranges = UnivariateIntegrandRanges( (0 until intervals).map { i -> (rangeSize * i)..(rangeSize * (i + 1)) to order } ) - return GaussIntegrator(this).integrate( + return GaussIntegrator(this).process( UnivariateIntegrand( function, IntegrationRange(range), diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt index 1ff8e422e..1f45e825b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt @@ -5,12 +5,15 @@ package space.kscience.kmath.integration +import space.kscience.kmath.misc.FeatureSet +import space.kscience.kmath.misc.Featured import kotlin.reflect.KClass public interface IntegrandFeature -public interface Integrand { - public fun getFeature(type: KClass): T? +public interface Integrand: Featured{ + public val features: FeatureSet + override fun getFeature(type: KClass): T? = features.getFeature(type) } public inline fun Integrand.getFeature(): T? = getFeature(T::class) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt index abe6ea5ff..1cf15b42f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt @@ -12,5 +12,5 @@ public interface Integrator { /** * Runs one integration pass and return a new [Integrand] with a new set of features. */ - public fun integrate(integrand: I): I + public fun process(integrand: I): I } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt index 12d0ef0a6..b9c1589c0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt @@ -6,27 +6,21 @@ package space.kscience.kmath.integration import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.FeatureSet import kotlin.reflect.KClass public class MultivariateIntegrand internal constructor( - private val features: Map, IntegrandFeature>, + override val features: FeatureSet, public val function: (Point) -> T, -) : Integrand { +) : Integrand - @Suppress("UNCHECKED_CAST") - override fun getFeature(type: KClass): T? = features[type] as? T - - public operator fun plus(pair: Pair, F>): MultivariateIntegrand = - MultivariateIntegrand(features + pair, function) - - public operator fun plus(feature: F): MultivariateIntegrand = - plus(feature::class to feature) -} +public fun MultivariateIntegrand.with(vararg newFeatures: IntegrandFeature): MultivariateIntegrand = + MultivariateIntegrand(features.with(*newFeatures), function) @Suppress("FunctionName") public fun MultivariateIntegrand( vararg features: IntegrandFeature, function: (Point) -> T, -): MultivariateIntegrand = MultivariateIntegrand(features.associateBy { it::class }, function) +): MultivariateIntegrand = MultivariateIntegrand(FeatureSet.of(*features), function) public val MultivariateIntegrand.value: T? get() = getFeature>()?.value diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt index bcd5005c4..3fc5b4599 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,30 +5,24 @@ package space.kscience.kmath.integration +import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.UnstableKMathAPI import kotlin.jvm.JvmInline -import kotlin.reflect.KClass + public class UnivariateIntegrand internal constructor( - private val features: Map, IntegrandFeature>, + override val features: FeatureSet, public val function: (Double) -> T, -) : Integrand { +) : Integrand - @Suppress("UNCHECKED_CAST") - override fun getFeature(type: KClass): T? = features[type] as? T - - public operator fun plus(pair: Pair, F>): UnivariateIntegrand = - UnivariateIntegrand(features + pair, function) - - public operator fun plus(feature: F): UnivariateIntegrand = - plus(feature::class to feature) -} +public fun UnivariateIntegrand.with(vararg newFeatures: IntegrandFeature): UnivariateIntegrand = + UnivariateIntegrand(features.with(*newFeatures), function) @Suppress("FunctionName") public fun UnivariateIntegrand( function: (Double) -> T, vararg features: IntegrandFeature, -): UnivariateIntegrand = UnivariateIntegrand(features.associateBy { it::class }, function) +): UnivariateIntegrand = UnivariateIntegrand(FeatureSet.of(*features), function) public typealias UnivariateIntegrator = Integrator> @@ -46,7 +40,7 @@ public fun UnivariateIntegrator.integrate( range: ClosedRange, vararg features: IntegrandFeature, function: (Double) -> Double, -): Double = integrate( +): Double = process( UnivariateIntegrand(function, IntegrationRange(range), *features) ).value ?: error("Unexpected: no value after integration.") @@ -65,7 +59,7 @@ public fun UnivariateIntegrator.integrate( featureBuilder() add(IntegrationRange(range)) } - return integrate( + return process( UnivariateIntegrand(function, *features.toTypedArray()) ).value ?: error("Unexpected: no value after integration.") } 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 195711452..d1e452454 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 @@ -16,7 +16,7 @@ import kotlin.test.assertEquals class GaussIntegralTest { @Test fun gaussSin() { - val res = DoubleField.integrate(0.0..2 * PI) { x -> + val res = DoubleField.process(0.0..2 * PI) { x -> sin(x) } assertEquals(0.0, res.value!!, 1e-2) @@ -24,7 +24,7 @@ class GaussIntegralTest { @Test fun gaussUniform() { - val res = DoubleField.integrate(0.0..100.0) { x -> + val res = DoubleField.process(0.0..100.0) { x -> if(x in 30.0..50.0){ 1.0 } else { diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index 38f3038c2..12ccea1d8 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -9,86 +9,97 @@ import space.kscience.kmath.expressions.AutoDiffProcessor import space.kscience.kmath.expressions.DifferentiableExpression import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.ExpressionAlgebra +import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.Symbol import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.indices -/** - * A likelihood function optimization problem with provided derivatives - */ -public interface FunctionOptimization : Optimization { - /** - * The optimization direction. If true search for function maximum, if false, search for the minimum - */ - public var maximize: Boolean - /** - * Define the initial guess for the optimization problem - */ - public fun initialGuess(map: Map) +public class FunctionOptimization( + override val features: FeatureSet, + public val expression: DifferentiableExpression>, + public val initialGuess: Map, + public val parameters: Collection, + public val maximize: Boolean, +) : OptimizationProblem - /** - * Set a differentiable expression as objective function as function and gradient provider - */ - public fun diffFunction(expression: DifferentiableExpression>) - - public companion object { - /** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation - */ - public fun chiSquared( - autoDiff: AutoDiffProcessor>, - x: Buffer, - y: Buffer, - yErr: Buffer, - model: A.(I) -> I, - ): DifferentiableExpression> where A : ExtendedField, A : ExpressionAlgebra { - require(x.size == y.size) { "X and y buffers should be of the same size" } - require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } - - return autoDiff.process { - var sum = zero - - x.indices.forEach { - val xValue = const(x[it]) - val yValue = const(y[it]) - val yErrValue = const(yErr[it]) - val modelValue = model(xValue) - sum += ((yValue - modelValue) / yErrValue).pow(2) - } - - sum - } - } - } -} - -/** - * Define a chi-squared-based objective function - */ -public fun FunctionOptimization.chiSquared( - autoDiff: AutoDiffProcessor>, - x: Buffer, - y: Buffer, - yErr: Buffer, - model: A.(I) -> I, -) where A : ExtendedField, A : ExpressionAlgebra { - val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) - diffFunction(chiSquared) - maximize = false -} - -/** - * Optimize differentiable expression using specific [OptimizationProblemFactory] - */ -public fun > DifferentiableExpression>.optimizeWith( - factory: OptimizationProblemFactory, - vararg symbols: Symbol, - configuration: F.() -> Unit, -): OptimizationResult { - require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } - val problem = factory(symbols.toList(), configuration) - problem.diffFunction(this) - return problem.optimize() -} +// +///** +// * A likelihood function optimization problem with provided derivatives +// */ +//public interface FunctionOptimizationBuilder { +// /** +// * The optimization direction. If true search for function maximum, if false, search for the minimum +// */ +// public var maximize: Boolean +// +// /** +// * Define the initial guess for the optimization problem +// */ +// public fun initialGuess(map: Map) +// +// /** +// * Set a differentiable expression as objective function as function and gradient provider +// */ +// public fun function(expression: DifferentiableExpression>) +// +// public companion object { +// /** +// * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation +// */ +// public fun chiSquared( +// autoDiff: AutoDiffProcessor>, +// x: Buffer, +// y: Buffer, +// yErr: Buffer, +// model: A.(I) -> I, +// ): DifferentiableExpression> where A : ExtendedField, A : ExpressionAlgebra { +// require(x.size == y.size) { "X and y buffers should be of the same size" } +// require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } +// +// return autoDiff.process { +// var sum = zero +// +// x.indices.forEach { +// val xValue = const(x[it]) +// val yValue = const(y[it]) +// val yErrValue = const(yErr[it]) +// val modelValue = model(xValue) +// sum += ((yValue - modelValue) / yErrValue).pow(2) +// } +// +// sum +// } +// } +// } +//} +// +///** +// * Define a chi-squared-based objective function +// */ +//public fun FunctionOptimization.chiSquared( +// autoDiff: AutoDiffProcessor>, +// x: Buffer, +// y: Buffer, +// yErr: Buffer, +// model: A.(I) -> I, +//) where A : ExtendedField, A : ExpressionAlgebra { +// val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) +// function(chiSquared) +// maximize = false +//} +// +///** +// * Optimize differentiable expression using specific [OptimizationProblemFactory] +// */ +//public suspend fun > DifferentiableExpression>.optimizeWith( +// factory: OptimizationProblemFactory, +// vararg symbols: Symbol, +// configuration: F.() -> Unit, +//): OptimizationResult { +// require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } +// val problem = factory(symbols.toList(), configuration) +// problem.function(this) +// return problem.optimize() +//} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt deleted file mode 100644 index 67a21bf2a..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.misc.Symbol -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices -import kotlin.math.pow - -/** - * A likelihood function optimization problem - */ -public interface NoDerivFunctionOptimization : Optimization { - /** - * The optimization direction. If true search for function maximum, if false, search for the minimum - */ - public var maximize: Boolean - - /** - * Define the initial guess for the optimization problem - */ - public fun initialGuess(map: Map) - - /** - * Set an objective function expression - */ - public fun function(expression: Expression) - - public companion object { - /** - * Generate a chi squared expression from given x-y-sigma model represented by an expression. Does not provide derivatives - */ - public fun chiSquared( - x: Buffer, - y: Buffer, - yErr: Buffer, - model: Expression, - xSymbol: Symbol = Symbol.x, - ): Expression { - require(x.size == y.size) { "X and y buffers should be of the same size" } - require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } - - return Expression { arguments -> - x.indices.sumOf { - val xValue = x[it] - val yValue = y[it] - val yErrValue = yErr[it] - val modifiedArgs = arguments + (xSymbol to xValue) - val modelValue = model(modifiedArgs) - ((yValue - modelValue) / yErrValue).pow(2) - } - } - } - } -} - - -/** - * Optimize expression without derivatives using specific [OptimizationProblemFactory] - */ -public fun > Expression.noDerivOptimizeWith( - factory: OptimizationProblemFactory, - vararg symbols: Symbol, - configuration: F.() -> Unit, -): OptimizationResult { - require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } - val problem = factory(symbols.toList(), configuration) - problem.function(this) - return problem.optimize() -} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt deleted file mode 100644 index 3b9868815..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.misc.Symbol - -public interface OptimizationFeature - -public class OptimizationResult( - public val point: Map, - public val value: T, - public val features: Set = emptySet(), -) { - override fun toString(): String { - return "OptimizationResult(point=$point, value=$value)" - } -} - -public operator fun OptimizationResult.plus( - feature: OptimizationFeature, -): OptimizationResult = OptimizationResult(point, value, features + feature) - -/** - * An optimization problem builder over [T] variables - */ -public interface Optimization { - - /** - * Update the problem from previous optimization run - */ - public fun update(result: OptimizationResult) - - /** - * Make an optimization run - */ - public fun optimize(): OptimizationResult -} - -public fun interface OptimizationProblemFactory> { - public fun build(symbols: List): P -} - -public operator fun > OptimizationProblemFactory.invoke( - symbols: List, - block: P.() -> Unit, -): P = build(symbols).apply(block) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt new file mode 100644 index 000000000..9a5420be6 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.misc.FeatureSet +import space.kscience.kmath.misc.Featured +import kotlin.reflect.KClass + +public interface OptimizationFeature + +public interface OptimizationProblem : Featured { + public val features: FeatureSet + override fun getFeature(type: KClass): T? = features.getFeature(type) +} + +public inline fun OptimizationProblem.getFeature(): T? = getFeature(T::class) + +//public class OptimizationResult( +// public val point: Map, +// public val value: T, +// public val features: Set = emptySet(), +//) { +// override fun toString(): String { +// return "OptimizationResult(point=$point, value=$value)" +// } +//} +// +//public operator fun OptimizationResult.plus( +// feature: OptimizationFeature, +//): OptimizationResult = OptimizationResult(point, value, features + feature) +//public fun interface OptimizationProblemFactory> { +// public fun build(symbols: List): P +//} +// +//public operator fun > OptimizationProblemFactory.invoke( +// symbols: List, +// block: P.() -> Unit, +//): P = build(symbols).apply(block) + +public interface Optimizer

{ + public suspend fun process(problem: P): P +} + diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt index f5cfa05e6..e4998c665 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -16,7 +16,7 @@ import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.Field @UnstableKMathAPI -public interface XYFit : Optimization { +public interface XYFit : OptimizationProblem { public val algebra: Field diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/AnalyticalGradientCalculator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/AnalyticalGradientCalculator.kt new file mode 100644 index 000000000..912fa22eb --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/AnalyticalGradientCalculator.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction + +/** + * + * @version $Id$ + */ +internal class AnalyticalGradientCalculator(fcn: MultiFunction?, state: MnUserTransformation, checkGradient: Boolean) : + GradientCalculator { + private val function: MultiFunction? + private val theCheckGradient: Boolean + private val theTransformation: MnUserTransformation + fun checkGradient(): Boolean { + return theCheckGradient + } + + /** {@inheritDoc} */ + fun gradient(par: MinimumParameters): FunctionGradient { +// double[] grad = theGradCalc.gradientValue(theTransformation.andThen(par.vec()).data()); + val point: DoubleArray = theTransformation.transform(par.vec()).toArray() + require(!(function.getDimension() !== theTransformation.parameters().size())) { "Invalid parameter size" } + val v: RealVector = ArrayRealVector(par.vec().getDimension()) + for (i in 0 until par.vec().getDimension()) { + val ext: Int = theTransformation.extOfInt(i) + if (theTransformation.parameter(ext).hasLimits()) { + val dd: Double = theTransformation.dInt2Ext(i, par.vec().getEntry(i)) + v.setEntry(i, dd * function.derivValue(ext, point)) + } else { + v.setEntry(i, function.derivValue(ext, point)) + } + } + return FunctionGradient(v) + } + + /** {@inheritDoc} */ + fun gradient(par: MinimumParameters, grad: FunctionGradient?): FunctionGradient { + return gradient(par) + } + + init { + function = fcn + theTransformation = state + theCheckGradient = checkGradient + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimizer.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimizer.kt new file mode 100644 index 000000000..9363492ad --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimizer.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal class CombinedMinimizer : ModularFunctionMinimizer() { + private val theMinBuilder: CombinedMinimumBuilder = CombinedMinimumBuilder() + private val theMinSeedGen: MnSeedGenerator = MnSeedGenerator() + override fun builder(): MinimumBuilder { + return theMinBuilder + } + + override fun seedGenerator(): MinimumSeedGenerator { + return theMinSeedGen + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimumBuilder.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimumBuilder.kt new file mode 100644 index 000000000..a2f0a644a --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimumBuilder.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import space.kscience.kmath.optimization.minuit.MINUITPlugin + +/** + * + * @version $Id$ + */ +internal class CombinedMinimumBuilder : MinimumBuilder { + private val theSimplexMinimizer: SimplexMinimizer = SimplexMinimizer() + private val theVMMinimizer: VariableMetricMinimizer = VariableMetricMinimizer() + + /** {@inheritDoc} */ + override fun minimum( + fcn: MnFcn?, + gc: GradientCalculator?, + seed: MinimumSeed?, + strategy: MnStrategy?, + maxfcn: Int, + toler: Double + ): FunctionMinimum { + val min: FunctionMinimum = theVMMinimizer.minimize(fcn!!, gc, seed, strategy, maxfcn, toler) + if (!min.isValid()) { + MINUITPlugin.logStatic("CombinedMinimumBuilder: migrad method fails, will try with simplex method first.") + val str = MnStrategy(2) + val min1: FunctionMinimum = theSimplexMinimizer.minimize(fcn, gc, seed, str, maxfcn, toler) + if (!min1.isValid()) { + MINUITPlugin.logStatic("CombinedMinimumBuilder: both migrad and simplex method fail.") + return min1 + } + val seed1: MinimumSeed = theVMMinimizer.seedGenerator().generate(fcn, gc, min1.userState(), str) + val min2: FunctionMinimum = theVMMinimizer.minimize(fcn, gc, seed1, str, maxfcn, toler) + if (!min2.isValid()) { + MINUITPlugin.logStatic("CombinedMinimumBuilder: both migrad and method fails also at 2nd attempt.") + MINUITPlugin.logStatic("CombinedMinimumBuilder: return simplex minimum.") + return min1 + } + return min2 + } + return min + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ContoursError.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ContoursError.kt new file mode 100644 index 000000000..214d94c80 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ContoursError.kt @@ -0,0 +1,150 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * ContoursError class. + * + * @author Darksnake + * @version $Id$ + */ +class ContoursError internal constructor( + private val theParX: Int, + private val theParY: Int, + points: List, + xmnos: MinosError, + ymnos: MinosError, + nfcn: Int +) { + private val theNFcn: Int + private val thePoints: List = points + private val theXMinos: MinosError + private val theYMinos: MinosError + + /** + * + * nfcn. + * + * @return a int. + */ + fun nfcn(): Int { + return theNFcn + } + + /** + * + * points. + * + * @return a [List] object. + */ + fun points(): List { + return thePoints + } + + /** + * {@inheritDoc} + */ + override fun toString(): String { + return MnPrint.toString(this) + } + + /** + * + * xMinosError. + * + * @return a [hep.dataforge.MINUIT.MinosError] object. + */ + fun xMinosError(): MinosError { + return theXMinos + } + + /** + * + * xRange. + * + * @return + */ + fun xRange(): Range { + return theXMinos.range() + } + + /** + * + * xmin. + * + * @return a double. + */ + fun xmin(): Double { + return theXMinos.min() + } + + /** + * + * xpar. + * + * @return a int. + */ + fun xpar(): Int { + return theParX + } + + /** + * + * yMinosError. + * + * @return a [hep.dataforge.MINUIT.MinosError] object. + */ + fun yMinosError(): MinosError { + return theYMinos + } + + /** + * + * yRange. + * + * @return + */ + fun yRange(): Range { + return theYMinos.range() + } + + /** + * + * ymin. + * + * @return a double. + */ + fun ymin(): Double { + return theYMinos.min() + } + + /** + * + * ypar. + * + * @return a int. + */ + fun ypar(): Int { + return theParY + } + + init { + theXMinos = xmnos + theYMinos = ymnos + theNFcn = nfcn + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/DavidonErrorUpdator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/DavidonErrorUpdator.kt new file mode 100644 index 000000000..9eb2443e4 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/DavidonErrorUpdator.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.RealVector +import ru.inr.mass.minuit.* + +/** + * + * @version $Id$ + */ +internal class DavidonErrorUpdator : MinimumErrorUpdator { + /** {@inheritDoc} */ + fun update(s0: MinimumState, p1: MinimumParameters, g1: FunctionGradient): MinimumError { + val V0: MnAlgebraicSymMatrix = s0.error().invHessian() + val dx: RealVector = MnUtils.sub(p1.vec(), s0.vec()) + val dg: RealVector = MnUtils.sub(g1.getGradient(), s0.gradient().getGradient()) + val delgam: Double = MnUtils.innerProduct(dx, dg) + val gvg: Double = MnUtils.similarity(dg, V0) + val vg: RealVector = MnUtils.mul(V0, dg) + var Vupd: MnAlgebraicSymMatrix = + MnUtils.sub(MnUtils.div(MnUtils.outerProduct(dx), delgam), MnUtils.div(MnUtils.outerProduct(vg), gvg)) + if (delgam > gvg) { + Vupd = MnUtils.add(Vupd, + MnUtils.mul(MnUtils.outerProduct(MnUtils.sub(MnUtils.div(dx, delgam), MnUtils.div(vg, gvg))), gvg)) + } + val sum_upd: Double = MnUtils.absoluteSumOfElements(Vupd) + Vupd = MnUtils.add(Vupd, V0) + val dcov: Double = 0.5 * (s0.error().dcovar() + sum_upd / MnUtils.absoluteSumOfElements(Vupd)) + return MinimumError(Vupd, dcov) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionGradient.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionGradient.kt new file mode 100644 index 000000000..a0866d916 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionGradient.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector + +/** + * + * @version $Id$ + */ +class FunctionGradient { + private var theAnalytical = false + private var theG2ndDerivative: RealVector + private var theGStepSize: RealVector + private var theGradient: RealVector + private var theValid = false + + constructor(n: Int) { + theGradient = ArrayRealVector(n) + theG2ndDerivative = ArrayRealVector(n) + theGStepSize = ArrayRealVector(n) + } + + constructor(grd: RealVector) { + theGradient = grd + theG2ndDerivative = ArrayRealVector(grd.getDimension()) + theGStepSize = ArrayRealVector(grd.getDimension()) + theValid = true + theAnalytical = true + } + + constructor(grd: RealVector, g2: RealVector, gstep: RealVector) { + theGradient = grd + theG2ndDerivative = g2 + theGStepSize = gstep + theValid = true + theAnalytical = false + } + + fun getGradient(): RealVector { + return theGradient + } + + fun getGradientDerivative(): RealVector { + return theG2ndDerivative + } + + fun getStep(): RealVector { + return theGStepSize + } + + fun isAnalytical(): Boolean { + return theAnalytical + } + + fun isValid(): Boolean { + return theValid + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionMinimum.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionMinimum.kt new file mode 100644 index 000000000..56908f00d --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionMinimum.kt @@ -0,0 +1,259 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.minuit.* + +/** + * Result of the minimization. + * + * + * The FunctionMinimum is the output of the minimizers and contains the + * minimization result. The methods + * + * * userState(), + * * userParameters() and + * * userCovariance() + * + * are provided. These can be used as new input to a new minimization after some + * manipulation. The parameters and/or the FunctionMinimum can be printed using + * the toString() method or the MnPrint class. + * + * @author Darksnake + */ +class FunctionMinimum { + private var theAboveMaxEdm = false + private var theErrorDef: Double + private var theReachedCallLimit = false + private var theSeed: MinimumSeed + private var theStates: MutableList + private var theUserState: MnUserParameterState + + internal constructor(seed: MinimumSeed, up: Double) { + theSeed = seed + theStates = ArrayList() + theStates.add(MinimumState(seed.parameters(), + seed.error(), + seed.gradient(), + seed.parameters().fval(), + seed.nfcn())) + theErrorDef = up + theUserState = MnUserParameterState() + } + + internal constructor(seed: MinimumSeed, states: MutableList, up: Double) { + theSeed = seed + theStates = states + theErrorDef = up + theUserState = MnUserParameterState() + } + + internal constructor(seed: MinimumSeed, states: MutableList, up: Double, x: MnReachedCallLimit?) { + theSeed = seed + theStates = states + theErrorDef = up + theReachedCallLimit = true + theUserState = MnUserParameterState() + } + + internal constructor(seed: MinimumSeed, states: MutableList, up: Double, x: MnAboveMaxEdm?) { + theSeed = seed + theStates = states + theErrorDef = up + theAboveMaxEdm = true + theReachedCallLimit = false + theUserState = MnUserParameterState() + } + + // why not + fun add(state: MinimumState) { + theStates.add(state) + } + + /** + * returns the expected vertical distance to the minimum (EDM) + * + * @return a double. + */ + fun edm(): Double { + return lastState().edm() + } + + fun error(): MinimumError { + return lastState().error() + } + + /** + * + * + * errorDef. + * + * @return a double. + */ + fun errorDef(): Double { + return theErrorDef + } + + /** + * Returns the function value at the minimum. + * + * @return a double. + */ + fun fval(): Double { + return lastState().fval() + } + + fun grad(): FunctionGradient { + return lastState().gradient() + } + + fun hasAccurateCovar(): Boolean { + return state().error().isAccurate() + } + + fun hasCovariance(): Boolean { + return state().error().isAvailable() + } + + fun hasMadePosDefCovar(): Boolean { + return state().error().isMadePosDef() + } + + fun hasPosDefCovar(): Boolean { + return state().error().isPosDef() + } + + fun hasReachedCallLimit(): Boolean { + return theReachedCallLimit + } + + fun hasValidCovariance(): Boolean { + return state().error().isValid() + } + + fun hasValidParameters(): Boolean { + return state().parameters().isValid() + } + + fun hesseFailed(): Boolean { + return state().error().hesseFailed() + } + + fun isAboveMaxEdm(): Boolean { + return theAboveMaxEdm + } + + /** + * In general, if this returns true, the minimizer did find a + * minimum without running into troubles. However, in some cases a minimum + * cannot be found, then the return value will be false. + * Reasons for the minimization to fail are + * + * * the number of allowed function calls has been exhausted + * * the minimizer could not improve the values of the parameters (and + * knowing that it has not converged yet) + * * a problem with the calculation of the covariance matrix + * + * Additional methods for the analysis of the state at the minimum are + * provided. + * + * @return a boolean. + */ + fun isValid(): Boolean { + return state().isValid() && !isAboveMaxEdm() && !hasReachedCallLimit() + } + + private fun lastState(): MinimumState { + return theStates[theStates.size - 1] + } + // forward interface of last state + /** + * returns the total number of function calls during the minimization. + * + * @return a int. + */ + fun nfcn(): Int { + return lastState().nfcn() + } + + fun parameters(): MinimumParameters { + return lastState().parameters() + } + + fun seed(): MinimumSeed { + return theSeed + } + + fun state(): MinimumState { + return lastState() + } + + fun states(): List { + return theStates + } + + /** + * {@inheritDoc} + * + * @return + */ + override fun toString(): String { + return MnPrint.toString(this) + } + + /** + * + * + * userCovariance. + * + * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. + */ + fun userCovariance(): MnUserCovariance { + if (!theUserState.isValid()) { + theUserState = MnUserParameterState(state(), errorDef(), seed().trafo()) + } + return theUserState.covariance() + } + + /** + * + * + * userParameters. + * + * @return a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + fun userParameters(): MnUserParameters { + if (!theUserState.isValid()) { + theUserState = MnUserParameterState(state(), errorDef(), seed().trafo()) + } + return theUserState.parameters() + } + + /** + * user representation of state at minimum + * + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun userState(): MnUserParameterState { + if (!theUserState.isValid()) { + theUserState = MnUserParameterState(state(), errorDef(), seed().trafo()) + } + return theUserState + } + + internal class MnAboveMaxEdm + internal class MnReachedCallLimit +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/GradientCalculator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/GradientCalculator.kt new file mode 100644 index 000000000..379de1b6d --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/GradientCalculator.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +interface GradientCalculator { + /** + * + * gradient. + * + * @param par a [hep.dataforge.MINUIT.MinimumParameters] object. + * @return a [hep.dataforge.MINUIT.FunctionGradient] object. + */ + fun gradient(par: MinimumParameters?): FunctionGradient + + /** + * + * gradient. + * + * @param par a [hep.dataforge.MINUIT.MinimumParameters] object. + * @param grad a [hep.dataforge.MINUIT.FunctionGradient] object. + * @return a [hep.dataforge.MINUIT.FunctionGradient] object. + */ + fun gradient(par: MinimumParameters?, grad: FunctionGradient?): FunctionGradient +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/HessianGradientCalculator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/HessianGradientCalculator.kt new file mode 100644 index 000000000..150d192f9 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/HessianGradientCalculator.kt @@ -0,0 +1,137 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector +import ru.inr.mass.minuit.* + +/** + * + * @version $Id$ + */ +internal class HessianGradientCalculator(fcn: MnFcn, par: MnUserTransformation, stra: MnStrategy) : GradientCalculator { + private val theFcn: MnFcn = fcn + private val theStrategy: MnStrategy + private val theTransformation: MnUserTransformation + fun deltaGradient(par: MinimumParameters, gradient: FunctionGradient): Pair { + require(par.isValid()) { "parameters are invalid" } + val x: RealVector = par.vec().copy() + val grd: RealVector = gradient.getGradient().copy() + val g2: RealVector = gradient.getGradientDerivative() + val gstep: RealVector = gradient.getStep() + val fcnmin: Double = par.fval() + // std::cout<<"fval: "< optstp) { + d = optstp + } + if (d < dmin) { + d = dmin + } + var chgold = 10000.0 + var dgmin = 0.0 + var grdold = 0.0 + var grdnew = 0.0 + for (j in 0 until ncycle()) { + x.setEntry(i, xtf + d) + val fs1: Double = theFcn.value(x) + x.setEntry(i, xtf - d) + val fs2: Double = theFcn.value(x) + x.setEntry(i, xtf) + // double sag = 0.5*(fs1+fs2-2.*fcnmin); + grdold = grd.getEntry(i) + grdnew = (fs1 - fs2) / (2.0 * d) + dgmin = precision().eps() * (abs(fs1) + abs(fs2)) / d + if (abs(grdnew) < precision().eps()) { + break + } + val change: Double = abs((grdold - grdnew) / grdnew) + if (change > chgold && j > 1) { + break + } + chgold = change + grd.setEntry(i, grdnew) + if (change < 0.05) { + break + } + if (abs(grdold - grdnew) < dgmin) { + break + } + if (d < dmin) { + break + } + d *= 0.2 + } + dgrd.setEntry(i, max(dgmin, abs(grdold - grdnew))) + } + return Pair(FunctionGradient(grd, g2, gstep), dgrd) + } + + fun fcn(): MnFcn { + return theFcn + } + + fun gradTolerance(): Double { + return strategy().gradientTolerance() + } + + /** {@inheritDoc} */ + fun gradient(par: MinimumParameters): FunctionGradient { + val gc = InitialGradientCalculator(theFcn, theTransformation, theStrategy) + val gra: FunctionGradient = gc.gradient(par) + return gradient(par, gra) + } + + /** {@inheritDoc} */ + fun gradient(par: MinimumParameters, gradient: FunctionGradient): FunctionGradient { + return deltaGradient(par, gradient).getFirst() + } + + fun ncycle(): Int { + return strategy().hessianGradientNCycles() + } + + fun precision(): MnMachinePrecision { + return theTransformation.precision() + } + + fun stepTolerance(): Double { + return strategy().gradientStepTolerance() + } + + fun strategy(): MnStrategy { + return theStrategy + } + + fun trafo(): MnUserTransformation { + return theTransformation + } + + init { + theTransformation = par + theStrategy = stra + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/InitialGradientCalculator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/InitialGradientCalculator.kt new file mode 100644 index 000000000..794556414 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/InitialGradientCalculator.kt @@ -0,0 +1,116 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector +import ru.inr.mass.minuit.* + +/** + * Calculating derivatives via finite differences + * @version $Id$ + */ +internal class InitialGradientCalculator(fcn: MnFcn, par: MnUserTransformation, stra: MnStrategy) { + private val theFcn: MnFcn = fcn + private val theStrategy: MnStrategy + private val theTransformation: MnUserTransformation + fun fcn(): MnFcn { + return theFcn + } + + fun gradTolerance(): Double { + return strategy().gradientTolerance() + } + + fun gradient(par: MinimumParameters): FunctionGradient { + require(par.isValid()) { "Parameters are invalid" } + val n: Int = trafo().variableParameters() + require(n == par.vec().getDimension()) { "Parameters have invalid size" } + val gr: RealVector = ArrayRealVector(n) + val gr2: RealVector = ArrayRealVector(n) + val gst: RealVector = ArrayRealVector(n) + + // initial starting values + for (i in 0 until n) { + val exOfIn: Int = trafo().extOfInt(i) + val `var`: Double = par.vec().getEntry(i) //parameter value + val werr: Double = trafo().parameter(exOfIn).error() //parameter error + val sav: Double = trafo().int2ext(i, `var`) //value after transformation + var sav2 = sav + werr //value after transfomation + error + if (trafo().parameter(exOfIn).hasLimits()) { + if (trafo().parameter(exOfIn).hasUpperLimit() + && sav2 > trafo().parameter(exOfIn).upperLimit() + ) { + sav2 = trafo().parameter(exOfIn).upperLimit() + } + } + var var2: Double = trafo().ext2int(exOfIn, sav2) + val vplu = var2 - `var` + sav2 = sav - werr + if (trafo().parameter(exOfIn).hasLimits()) { + if (trafo().parameter(exOfIn).hasLowerLimit() + && sav2 < trafo().parameter(exOfIn).lowerLimit() + ) { + sav2 = trafo().parameter(exOfIn).lowerLimit() + } + } + var2 = trafo().ext2int(exOfIn, sav2) + val vmin = var2 - `var` + val dirin: Double = 0.5 * (abs(vplu) + abs(vmin)) + val g2: Double = 2.0 * theFcn.errorDef() / (dirin * dirin) + val gsmin: Double = 8.0 * precision().eps2() * (abs(`var`) + precision().eps2()) + var gstep: Double = max(gsmin, 0.1 * dirin) + val grd = g2 * dirin + if (trafo().parameter(exOfIn).hasLimits()) { + if (gstep > 0.5) { + gstep = 0.5 + } + } + gr.setEntry(i, grd) + gr2.setEntry(i, g2) + gst.setEntry(i, gstep) + } + return FunctionGradient(gr, gr2, gst) + } + + fun gradient(par: MinimumParameters, gra: FunctionGradient?): FunctionGradient { + return gradient(par) + } + + fun ncycle(): Int { + return strategy().gradientNCycles() + } + + fun precision(): MnMachinePrecision { + return theTransformation.precision() + } + + fun stepTolerance(): Double { + return strategy().gradientStepTolerance() + } + + fun strategy(): MnStrategy { + return theStrategy + } + + fun trafo(): MnUserTransformation { + return theTransformation + } + + init { + theTransformation = par + theStrategy = stra + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINOSResult.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINOSResult.kt new file mode 100644 index 000000000..c33994648 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINOSResult.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package space.kscience.kmath.optimization.minuit + + +/** + * Контейнер для несимметричных оценок и доверительных интервалов + * + * @author Darksnake + * @version $Id: $Id + */ +class MINOSResult +/** + * + * Constructor for MINOSResult. + * + * @param list an array of [String] objects. + */(private val names: Array, private val errl: DoubleArray?, private val errp: DoubleArray?) : + IntervalEstimate { + fun getNames(): NameList { + return NameList(names) + } + + fun getInterval(parName: String?): Pair { + val index: Int = getNames().getNumberByName(parName) + return Pair(ValueFactory.of(errl!![index]), ValueFactory.of(errp!![index])) + } + + val cL: Double + get() = 0.68 + + /** {@inheritDoc} */ + fun print(out: PrintWriter) { + if (errl != null || errp != null) { + out.println() + out.println("Assymetrical errors:") + out.println() + out.println("Name\tLower\tUpper") + for (i in 0 until getNames().size()) { + out.print(getNames().get(i)) + out.print("\t") + if (errl != null) { + out.print(errl[i]) + } else { + out.print("---") + } + out.print("\t") + if (errp != null) { + out.print(errp[i]) + } else { + out.print("---") + } + out.println() + } + } + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITFitter.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITFitter.kt new file mode 100644 index 000000000..a26321249 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITFitter.kt @@ -0,0 +1,205 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package space.kscience.kmath.optimization.minuit + +import ru.inr.mass.minuit.* + +/** + * + * + * MINUITFitter class. + * + * @author Darksnake + * @version $Id: $Id + */ +class MINUITFitter : Fitter { + fun run(state: FitState, parentLog: History?, meta: Meta): FitResult { + val log = Chronicle("MINUIT", parentLog) + val action: String = meta.getString("action", TASK_RUN) + log.report("MINUIT fit engine started action '{}'", action) + return when (action) { + TASK_COVARIANCE -> runHesse(state, log, meta) + TASK_SINGLE, TASK_RUN -> runFit(state, log, meta) + else -> throw IllegalArgumentException("Unknown task") + } + } + + @NotNull + fun getName(): String { + return MINUIT_ENGINE_NAME + } + + /** + * + * + * runHesse. + * + * @param state a [hep.dataforge.stat.fit.FitState] object. + * @param log + * @return a [FitResult] object. + */ + fun runHesse(state: FitState, log: History, meta: Meta?): FitResult { + val strategy: Int + strategy = Global.INSTANCE.getInt("MINUIT_STRATEGY", 2) + log.report("Generating errors using MnHesse 2-nd order gradient calculator.") + val fcn: MultiFunction + val fitPars: Array = Fitter.Companion.getFitPars(state, meta) + val pars: ParamSet = state.getParameters() + fcn = MINUITUtils.getFcn(state, pars, fitPars) + val hesse = MnHesse(strategy) + val mnState: MnUserParameterState = hesse.calculate(fcn, MINUITUtils.getFitParameters(pars, fitPars)) + val allPars: ParamSet = pars.copy() + for (fitPar in fitPars) { + allPars.setParValue(fitPar, mnState.value(fitPar)) + allPars.setParError(fitPar, mnState.error(fitPar)) + } + val newState: FitState.Builder = state.edit() + newState.setPars(allPars) + if (mnState.hasCovariance()) { + val mnCov: MnUserCovariance = mnState.covariance() + var j: Int + val cov = Array(mnState.variableParameters()) { DoubleArray(mnState.variableParameters()) } + for (i in 0 until mnState.variableParameters()) { + j = 0 + while (j < mnState.variableParameters()) { + cov[i][j] = mnCov.get(i, j) + j++ + } + } + newState.setCovariance(NamedMatrix(fitPars, cov), true) + } + return FitResult.build(newState.build(), fitPars) + } + + fun runFit(state: FitState, log: History, meta: Meta): FitResult { + val minuit: MnApplication + log.report("Starting fit using Minuit.") + val strategy: Int + strategy = Global.INSTANCE.getInt("MINUIT_STRATEGY", 2) + var force: Boolean + force = Global.INSTANCE.getBoolean("FORCE_DERIVS", false) + val fitPars: Array = Fitter.Companion.getFitPars(state, meta) + for (fitPar in fitPars) { + if (!state.modelProvidesDerivs(fitPar)) { + force = true + log.reportError("Model does not provide derivatives for parameter '{}'", fitPar) + } + } + if (force) { + log.report("Using MINUIT gradient calculator.") + } + val fcn: MultiFunction + val pars: ParamSet = state.getParameters().copy() + fcn = MINUITUtils.getFcn(state, pars, fitPars) + val method: String = meta.getString("method", MINUIT_MIGRAD) + when (method) { + MINUIT_MINOS, MINUIT_MINIMIZE -> minuit = + MnMinimize(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy) + MINUIT_SIMPLEX -> minuit = MnSimplex(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy) + else -> minuit = MnMigrad(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy) + } + if (force) { + minuit.setUseAnalyticalDerivatives(false) + log.report("Forced to use MINUIT internal derivative calculator!") + } + +// minuit.setUseAnalyticalDerivatives(true); + val minimum: FunctionMinimum + val maxSteps: Int = meta.getInt("iterations", -1) + val tolerance: Double = meta.getDouble("tolerance", -1) + minimum = if (maxSteps > 0) { + if (tolerance > 0) { + minuit.minimize(maxSteps, tolerance) + } else { + minuit.minimize(maxSteps) + } + } else { + minuit.minimize() + } + if (!minimum.isValid()) { + log.report("Minimization failed!") + } + log.report("MINUIT run completed in {} function calls.", minimum.nfcn()) + + /* + * Генерация результата + */ + val allPars: ParamSet = pars.copy() + for (fitPar in fitPars) { + allPars.setParValue(fitPar, minimum.userParameters().value(fitPar)) + allPars.setParError(fitPar, minimum.userParameters().error(fitPar)) + } + val newState: FitState.Builder = state.edit() + newState.setPars(allPars) + var valid: Boolean = minimum.isValid() + if (minimum.userCovariance().nrow() > 0) { + var j: Int + val cov = Array(minuit.variableParameters()) { DoubleArray(minuit.variableParameters()) } + if (cov[0].length == 1) { + cov[0][0] = minimum.userParameters().error(0) * minimum.userParameters().error(0) + } else { + for (i in 0 until minuit.variableParameters()) { + j = 0 + while (j < minuit.variableParameters()) { + cov[i][j] = minimum.userCovariance().get(i, j) + j++ + } + } + } + newState.setCovariance(NamedMatrix(fitPars, cov), true) + } + if (method == MINUIT_MINOS) { + log.report("Starting MINOS procedure for precise error estimation.") + val minos = MnMinos(fcn, minimum, strategy) + var mnError: MinosError + val errl = DoubleArray(fitPars.size) + val errp = DoubleArray(fitPars.size) + for (i in fitPars.indices) { + mnError = minos.minos(i) + if (mnError.isValid()) { + errl[i] = mnError.lower() + errp[i] = mnError.upper() + } else { + valid = false + } + } + val minosErrors = MINOSResult(fitPars, errl, errp) + newState.setInterval(minosErrors) + } + return FitResult.build(newState.build(), valid, fitPars) + } + + companion object { + /** + * Constant `MINUIT_MIGRAD="MIGRAD"` + */ + const val MINUIT_MIGRAD = "MIGRAD" + + /** + * Constant `MINUIT_MINIMIZE="MINIMIZE"` + */ + const val MINUIT_MINIMIZE = "MINIMIZE" + + /** + * Constant `MINUIT_SIMPLEX="SIMPLEX"` + */ + const val MINUIT_SIMPLEX = "SIMPLEX" + + /** + * Constant `MINUIT_MINOS="MINOS"` + */ + const val MINUIT_MINOS = "MINOS" //MINOS errors + + /** + * Constant `MINUIT_HESSE="HESSE"` + */ + const val MINUIT_HESSE = "HESSE" //HESSE errors + + /** + * Constant `MINUIT_ENGINE_NAME="MINUIT"` + */ + const val MINUIT_ENGINE_NAME = "MINUIT" + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITPlugin.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITPlugin.kt new file mode 100644 index 000000000..7eaefd9d2 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITPlugin.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package space.kscience.kmath.optimization.minuit + +import hep.dataforge.context.* + +/** + * Мэнеджер для MINUITа. Пока не играет никакой активной роли кроме ведения + * внутреннего лога. + * + * @author Darksnake + * @version $Id: $Id + */ +@PluginDef(group = "hep.dataforge", + name = "MINUIT", + dependsOn = ["hep.dataforge:fitting"], + info = "The MINUIT fitter engine for DataForge fitting") +class MINUITPlugin : BasicPlugin() { + fun attach(@NotNull context: Context?) { + super.attach(context) + clearStaticLog() + } + + @Provides(Fitter.FITTER_TARGET) + fun getFitter(fitterName: String): Fitter? { + return if (fitterName == "MINUIT") { + MINUITFitter() + } else { + null + } + } + + @ProvidesNames(Fitter.FITTER_TARGET) + fun listFitters(): List { + return listOf("MINUIT") + } + + fun detach() { + clearStaticLog() + super.detach() + } + + class Factory : PluginFactory() { + fun build(meta: Meta?): Plugin { + return MINUITPlugin() + } + + fun getType(): java.lang.Class { + return MINUITPlugin::class.java + } + } + + companion object { + /** + * Constant `staticLog` + */ + private val staticLog: Chronicle? = Chronicle("MINUIT-STATIC", Global.INSTANCE.getHistory()) + + /** + * + * + * clearStaticLog. + */ + fun clearStaticLog() { + staticLog.clear() + } + + /** + * + * + * logStatic. + * + * @param str a [String] object. + * @param pars a [Object] object. + */ + fun logStatic(str: String?, vararg pars: Any?) { + checkNotNull(staticLog) { "MINUIT log is not initialized." } + staticLog.report(str, pars) + LoggerFactory.getLogger("MINUIT").info(String.format(str, *pars)) + // Out.out.printf(str,pars); +// Out.out.println(); + } + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITUtils.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITUtils.kt new file mode 100644 index 000000000..44c70cb42 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITUtils.kt @@ -0,0 +1,121 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package space.kscience.kmath.optimization.minuit + +import hep.dataforge.MINUIT.FunctionMinimum + +internal object MINUITUtils { + fun getFcn(source: FitState, allPar: ParamSet, fitPars: Array): MultiFunction { + return MnFunc(source, allPar, fitPars) + } + + fun getFitParameters(set: ParamSet, fitPars: Array): MnUserParameters { + val pars = MnUserParameters() + var i: Int + var par: Param + i = 0 + while (i < fitPars.size) { + par = set.getByName(fitPars[i]) + pars.add(fitPars[i], par.getValue(), par.getErr()) + if (par.getLowerBound() > Double.NEGATIVE_INFINITY && par.getUpperBound() < Double.POSITIVE_INFINITY) { + pars.setLimits(i, par.getLowerBound(), par.getUpperBound()) + } else if (par.getLowerBound() > Double.NEGATIVE_INFINITY) { + pars.setLowerLimit(i, par.getLowerBound()) + } else if (par.getUpperBound() < Double.POSITIVE_INFINITY) { + pars.setUpperLimit(i, par.getUpperBound()) + } + i++ + } + return pars + } + + fun getValueSet(allPar: ParamSet, names: Array, values: DoubleArray): ParamSet { + assert(values.size == names.size) + assert(allPar.getNames().contains(names)) + val vector: ParamSet = allPar.copy() + for (i in values.indices) { + vector.setParValue(names[i], values[i]) + } + return vector + } + + fun isValidArray(ar: DoubleArray): Boolean { + for (i in ar.indices) { + if (java.lang.Double.isNaN(ar[i])) { + return false + } + } + return true + } + + /** + * + * + * printMINUITResult. + * + * @param out a [PrintWriter] object. + * @param minimum a [hep.dataforge.MINUIT.FunctionMinimum] object. + */ + fun printMINUITResult(out: PrintWriter, minimum: FunctionMinimum?) { + out.println() + out.println("***MINUIT INTERNAL FIT INFORMATION***") + out.println() + MnPrint.print(out, minimum) + out.println() + out.println("***END OF MINUIT INTERNAL FIT INFORMATION***") + out.println() + } + + internal class MnFunc(source: FitState, allPar: ParamSet, fitPars: Array) : MultiFunction { + var source: FitState + var allPar: ParamSet + var fitPars: Array + fun value(doubles: DoubleArray): Double { + assert(isValidArray(doubles)) + assert(doubles.size == fitPars.size) + return -2 * source.getLogProb(getValueSet(allPar, fitPars, doubles)) + // source.getChi2(getValueSet(allPar, fitPars, doubles)); + } + + @Throws(NotDefinedException::class) + fun derivValue(n: Int, doubles: DoubleArray): Double { + assert(isValidArray(doubles)) + assert(doubles.size == getDimension()) + val set: ParamSet = getValueSet(allPar, fitPars, doubles) + +// double res; +// double d, s, deriv; +// +// res = 0; +// for (int i = 0; i < source.getDataNum(); i++) { +// d = source.getDis(i, set); +// s = source.getDispersion(i, set); +// if (source.modelProvidesDerivs(fitPars[n])) { +// deriv = source.getDisDeriv(fitPars[n], i, set); +// } else { +// throw new NotDefinedException(); +// // Такого не должно быть, поскольку мы где-то наверху должы были проверить, что производные все есть. +// } +// res += 2 * d * deriv / s; +// } + return -2 * source.getLogProbDeriv(fitPars[n], set) + } + + fun getDimension(): Int { + return fitPars.size + } + + fun providesDeriv(n: Int): Boolean { + return source.modelProvidesDerivs(fitPars[n]) + } + + init { + this.source = source + this.allPar = allPar + this.fitPars = fitPars + assert(source.getModel().getNames().contains(fitPars)) + } + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumBuilder.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumBuilder.kt new file mode 100644 index 000000000..eadeeb91d --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumBuilder.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +interface MinimumBuilder { + /** + * + * minimum. + * + * @param fcn a [hep.dataforge.MINUIT.MnFcn] object. + * @param gc a [hep.dataforge.MINUIT.GradientCalculator] object. + * @param seed a [hep.dataforge.MINUIT.MinimumSeed] object. + * @param strategy a [hep.dataforge.MINUIT.MnStrategy] object. + * @param maxfcn a int. + * @param toler a double. + * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. + */ + fun minimum( + fcn: MnFcn?, + gc: GradientCalculator?, + seed: MinimumSeed?, + strategy: MnStrategy?, + maxfcn: Int, + toler: Double + ): FunctionMinimum +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumError.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumError.kt new file mode 100644 index 000000000..6993b9e6d --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumError.kt @@ -0,0 +1,155 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import space.kscience.kmath.optimization.minuit.MINUITPlugin + +/** + * MinimumError keeps the inverse 2nd derivative (inverse Hessian) used for + * calculating the parameter step size (-V*g) and for the covariance update + * (ErrorUpdator). The covariance matrix is equal to twice the inverse Hessian. + * + * @version $Id$ + */ +class MinimumError { + private var theAvailable = false + private var theDCovar: Double + private var theHesseFailed = false + private var theInvertFailed = false + private var theMadePosDef = false + private var theMatrix: MnAlgebraicSymMatrix + private var thePosDef = false + private var theValid = false + + constructor(n: Int) { + theMatrix = MnAlgebraicSymMatrix(n) + theDCovar = 1.0 + } + + constructor(mat: MnAlgebraicSymMatrix, dcov: Double) { + theMatrix = mat + theDCovar = dcov + theValid = true + thePosDef = true + theAvailable = true + } + + constructor(mat: MnAlgebraicSymMatrix, x: MnHesseFailed?) { + theMatrix = mat + theDCovar = 1.0 + theValid = false + thePosDef = false + theMadePosDef = false + theHesseFailed = true + theInvertFailed = false + theAvailable = true + } + + constructor(mat: MnAlgebraicSymMatrix, x: MnMadePosDef?) { + theMatrix = mat + theDCovar = 1.0 + theValid = false + thePosDef = false + theMadePosDef = true + theHesseFailed = false + theInvertFailed = false + theAvailable = true + } + + constructor(mat: MnAlgebraicSymMatrix, x: MnInvertFailed?) { + theMatrix = mat + theDCovar = 1.0 + theValid = false + thePosDef = true + theMadePosDef = false + theHesseFailed = false + theInvertFailed = true + theAvailable = true + } + + constructor(mat: MnAlgebraicSymMatrix, x: MnNotPosDef?) { + theMatrix = mat + theDCovar = 1.0 + theValid = false + thePosDef = false + theMadePosDef = false + theHesseFailed = false + theInvertFailed = false + theAvailable = true + } + + fun dcovar(): Double { + return theDCovar + } + + fun hesseFailed(): Boolean { + return theHesseFailed + } + + fun hessian(): MnAlgebraicSymMatrix { + return try { + val tmp: MnAlgebraicSymMatrix = theMatrix.copy() + tmp.invert() + tmp + } catch (x: SingularMatrixException) { + MINUITPlugin.logStatic("BasicMinimumError inversion fails; return diagonal matrix.") + val tmp = MnAlgebraicSymMatrix(theMatrix.nrow()) + var i = 0 + while (i < theMatrix.nrow()) { + tmp[i, i] = 1.0 / theMatrix[i, i] + i++ + } + tmp + } + } + + fun invHessian(): MnAlgebraicSymMatrix { + return theMatrix + } + + fun invertFailed(): Boolean { + return theInvertFailed + } + + fun isAccurate(): Boolean { + return theDCovar < 0.1 + } + + fun isAvailable(): Boolean { + return theAvailable + } + + fun isMadePosDef(): Boolean { + return theMadePosDef + } + + fun isPosDef(): Boolean { + return thePosDef + } + + fun isValid(): Boolean { + return theValid + } + + fun matrix(): MnAlgebraicSymMatrix { + return MnUtils.mul(theMatrix, 2) + } + + internal class MnHesseFailed + internal class MnInvertFailed + internal class MnMadePosDef + internal class MnNotPosDef +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumErrorUpdator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumErrorUpdator.kt new file mode 100644 index 000000000..6022aa5b7 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumErrorUpdator.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal interface MinimumErrorUpdator { + /** + * + * update. + * + * @param state a [hep.dataforge.MINUIT.MinimumState] object. + * @param par a [hep.dataforge.MINUIT.MinimumParameters] object. + * @param grad a [hep.dataforge.MINUIT.FunctionGradient] object. + * @return a [hep.dataforge.MINUIT.MinimumError] object. + */ + fun update(state: MinimumState?, par: MinimumParameters?, grad: FunctionGradient?): MinimumError? +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumParameters.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumParameters.kt new file mode 100644 index 000000000..bed13ea0b --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumParameters.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector + +/** + * + * @version $Id$ + */ +class MinimumParameters { + private var theFVal = 0.0 + private var theHasStep = false + private var theParameters: RealVector + private var theStepSize: RealVector + private var theValid = false + + constructor(n: Int) { + theParameters = ArrayRealVector(n) + theStepSize = ArrayRealVector(n) + } + + constructor(avec: RealVector, fval: Double) { + theParameters = avec + theStepSize = ArrayRealVector(avec.getDimension()) + theFVal = fval + theValid = true + } + + constructor(avec: RealVector, dirin: RealVector, fval: Double) { + theParameters = avec + theStepSize = dirin + theFVal = fval + theValid = true + theHasStep = true + } + + fun dirin(): RealVector { + return theStepSize + } + + fun fval(): Double { + return theFVal + } + + fun hasStepSize(): Boolean { + return theHasStep + } + + fun isValid(): Boolean { + return theValid + } + + fun vec(): RealVector { + return theParameters + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeed.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeed.kt new file mode 100644 index 000000000..aef672bb7 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeed.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +class MinimumSeed(state: MinimumState, trafo: MnUserTransformation) { + private val theState: MinimumState = state + private val theTrafo: MnUserTransformation = trafo + private val theValid: Boolean = true + val edm: Double get() = state().edm() + + fun error(): MinimumError { + return state().error() + } + + fun fval(): Double { + return state().fval() + } + + fun gradient(): FunctionGradient { + return state().gradient() + } + + fun isValid(): Boolean { + return theValid + } + + fun nfcn(): Int { + return state().nfcn() + } + + fun parameters(): MinimumParameters { + return state().parameters() + } + + fun precision(): MnMachinePrecision { + return theTrafo.precision() + } + + fun state(): MinimumState { + return theState + } + + fun trafo(): MnUserTransformation { + return theTrafo + } + +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeedGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeedGenerator.kt new file mode 100644 index 000000000..bd04c1a45 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeedGenerator.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * base class for seed generators (starting values); the seed generator prepares + * initial starting values from the input (MnUserParameterState) for the + * minimization; + * + * @version $Id$ + */ +interface MinimumSeedGenerator { + /** + * + * generate. + * + * @param fcn a [hep.dataforge.MINUIT.MnFcn] object. + * @param calc a [hep.dataforge.MINUIT.GradientCalculator] object. + * @param user a [hep.dataforge.MINUIT.MnUserParameterState] object. + * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. + * @return a [hep.dataforge.MINUIT.MinimumSeed] object. + */ + fun generate(fcn: MnFcn?, calc: GradientCalculator?, user: MnUserParameterState?, stra: MnStrategy?): MinimumSeed +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumState.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumState.kt new file mode 100644 index 000000000..9f63e0e1f --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumState.kt @@ -0,0 +1,104 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.RealVector + +/** + * MinimumState keeps the information (position, gradient, 2nd deriv, etc) after + * one minimization step (usually in MinimumBuilder). + * + * @version $Id$ + */ +class MinimumState { + private var theEDM = 0.0 + private var theError: MinimumError + private var theGradient: FunctionGradient + private var theNFcn = 0 + private var theParameters: MinimumParameters + + constructor(n: Int) { + theParameters = MinimumParameters(n) + theError = MinimumError(n) + theGradient = FunctionGradient(n) + } + + constructor(states: MinimumParameters, err: MinimumError, grad: FunctionGradient, edm: Double, nfcn: Int) { + theParameters = states + theError = err + theGradient = grad + theEDM = edm + theNFcn = nfcn + } + + constructor(states: MinimumParameters, edm: Double, nfcn: Int) { + theParameters = states + theError = MinimumError(states.vec().getDimension()) + theGradient = FunctionGradient(states.vec().getDimension()) + theEDM = edm + theNFcn = nfcn + } + + fun edm(): Double { + return theEDM + } + + fun error(): MinimumError { + return theError + } + + fun fval(): Double { + return theParameters.fval() + } + + fun gradient(): FunctionGradient { + return theGradient + } + + fun hasCovariance(): Boolean { + return theError.isAvailable() + } + + fun hasParameters(): Boolean { + return theParameters.isValid() + } + + fun isValid(): Boolean { + return if (hasParameters() && hasCovariance()) { + parameters().isValid() && error().isValid() + } else if (hasParameters()) { + parameters().isValid() + } else { + false + } + } + + fun nfcn(): Int { + return theNFcn + } + + fun parameters(): MinimumParameters { + return theParameters + } + + fun size(): Int { + return theParameters.vec().getDimension() + } + + fun vec(): RealVector { + return theParameters.vec() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinosError.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinosError.kt new file mode 100644 index 000000000..c7cf10523 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinosError.kt @@ -0,0 +1,219 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * MinosError class. + * + * @author Darksnake + * @version $Id$ + */ +class MinosError { + private var theLower: MnCross + private var theMinValue = 0.0 + private var theParameter = 0 + private var theUpper: MnCross + + internal constructor() { + theUpper = MnCross() + theLower = MnCross() + } + + internal constructor(par: Int, min: Double, low: MnCross, up: MnCross) { + theParameter = par + theMinValue = min + theUpper = up + theLower = low + } + + /** + * + * atLowerLimit. + * + * @return a boolean. + */ + fun atLowerLimit(): Boolean { + return theLower.atLimit() + } + + /** + * + * atLowerMaxFcn. + * + * @return a boolean. + */ + fun atLowerMaxFcn(): Boolean { + return theLower.atMaxFcn() + } + + /** + * + * atUpperLimit. + * + * @return a boolean. + */ + fun atUpperLimit(): Boolean { + return theUpper.atLimit() + } + + /** + * + * atUpperMaxFcn. + * + * @return a boolean. + */ + fun atUpperMaxFcn(): Boolean { + return theUpper.atMaxFcn() + } + + /** + * + * isValid. + * + * @return a boolean. + */ + fun isValid(): Boolean { + return theLower.isValid() && theUpper.isValid() + } + + /** + * + * lower. + * + * @return a double. + */ + fun lower(): Double { + return -1.0 * lowerState().error(parameter()) * (1.0 + theLower.value()) + } + + /** + * + * lowerNewMin. + * + * @return a boolean. + */ + fun lowerNewMin(): Boolean { + return theLower.newMinimum() + } + + /** + * + * lowerState. + * + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun lowerState(): MnUserParameterState { + return theLower.state() + } + + /** + * + * lowerValid. + * + * @return a boolean. + */ + fun lowerValid(): Boolean { + return theLower.isValid() + } + + /** + * + * min. + * + * @return a double. + */ + fun min(): Double { + return theMinValue + } + + /** + * + * nfcn. + * + * @return a int. + */ + fun nfcn(): Int { + return theUpper.nfcn() + theLower.nfcn() + } + + /** + * + * parameter. + * + * @return a int. + */ + fun parameter(): Int { + return theParameter + } + + /** + * + * range. + * + * @return + */ + fun range(): Range { + return Range(lower(), upper()) + } + + /** + * {@inheritDoc} + */ + override fun toString(): String { + return MnPrint.toString(this) + } + + /** + * + * upper. + * + * @return a double. + */ + fun upper(): Double { + return upperState().error(parameter()) * (1.0 + theUpper.value()) + } + + /** + * + * upperNewMin. + * + * @return a boolean. + */ + fun upperNewMin(): Boolean { + return theUpper.newMinimum() + } + + /** + * + * upperState. + * + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun upperState(): MnUserParameterState { + return theUpper.state() + } + + /** + * + * upperValid. + * + * @return a boolean. + */ + fun upperValid(): Boolean { + return theUpper.isValid() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinuitParameter.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinuitParameter.kt new file mode 100644 index 000000000..ff6834df4 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinuitParameter.kt @@ -0,0 +1,314 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +class MinuitParameter { + private var theConst = false + private var theError = 0.0 + private var theFix = false + private var theLoLimValid = false + private var theLoLimit = 0.0 + private var theName: String + private var theNum: Int + private var theUpLimValid = false + private var theUpLimit = 0.0 + private var theValue: Double + + /** + * constructor for constant parameter + * + * @param num a int. + * @param name a [String] object. + * @param val a double. + */ + constructor(num: Int, name: String, `val`: Double) { + theNum = num + theValue = `val` + theConst = true + theName = name + } + + /** + * constructor for standard parameter + * + * @param num a int. + * @param name a [String] object. + * @param val a double. + * @param err a double. + */ + constructor(num: Int, name: String, `val`: Double, err: Double) { + theNum = num + theValue = `val` + theError = err + theName = name + } + + /** + * constructor for limited parameter + * + * @param num a int. + * @param name a [String] object. + * @param val a double. + * @param err a double. + * @param min a double. + * @param max a double. + */ + constructor(num: Int, name: String, `val`: Double, err: Double, min: Double, max: Double) { + theNum = num + theValue = `val` + theError = err + theLoLimit = min + theUpLimit = max + theLoLimValid = true + theUpLimValid = true + require(min != max) { "min == max" } + if (min > max) { + theLoLimit = max + theUpLimit = min + } + theName = name + } + + private constructor(other: MinuitParameter) { + theNum = other.theNum + theName = other.theName + theValue = other.theValue + theError = other.theError + theConst = other.theConst + theFix = other.theFix + theLoLimit = other.theLoLimit + theUpLimit = other.theUpLimit + theLoLimValid = other.theLoLimValid + theUpLimValid = other.theUpLimValid + } + + /** + * + * copy. + * + * @return a [hep.dataforge.MINUIT.MinuitParameter] object. + */ + fun copy(): MinuitParameter { + return MinuitParameter(this) + } + + /** + * + * error. + * + * @return a double. + */ + fun error(): Double { + return theError + } + + /** + * + * fix. + */ + fun fix() { + theFix = true + } + + /** + * + * hasLimits. + * + * @return a boolean. + */ + fun hasLimits(): Boolean { + return theLoLimValid || theUpLimValid + } + + /** + * + * hasLowerLimit. + * + * @return a boolean. + */ + fun hasLowerLimit(): Boolean { + return theLoLimValid + } + + /** + * + * hasUpperLimit. + * + * @return a boolean. + */ + fun hasUpperLimit(): Boolean { + return theUpLimValid + } + //state of parameter (fixed/const/limited) + /** + * + * isConst. + * + * @return a boolean. + */ + fun isConst(): Boolean { + return theConst + } + + /** + * + * isFixed. + * + * @return a boolean. + */ + fun isFixed(): Boolean { + return theFix + } + + /** + * + * lowerLimit. + * + * @return a double. + */ + fun lowerLimit(): Double { + return theLoLimit + } + + /** + * + * name. + * + * @return a [String] object. + */ + fun name(): String { + return theName + } + //access methods + /** + * + * number. + * + * @return a int. + */ + fun number(): Int { + return theNum + } + + /** + * + * release. + */ + fun release() { + theFix = false + } + + /** + * + * removeLimits. + */ + fun removeLimits() { + theLoLimit = 0.0 + theUpLimit = 0.0 + theLoLimValid = false + theUpLimValid = false + } + + /** + * + * setError. + * + * @param err a double. + */ + fun setError(err: Double) { + theError = err + theConst = false + } + + /** + * + * setLimits. + * + * @param low a double. + * @param up a double. + */ + fun setLimits(low: Double, up: Double) { + require(low != up) { "min == max" } + theLoLimit = low + theUpLimit = up + theLoLimValid = true + theUpLimValid = true + if (low > up) { + theLoLimit = up + theUpLimit = low + } + } + + /** + * + * setLowerLimit. + * + * @param low a double. + */ + fun setLowerLimit(low: Double) { + theLoLimit = low + theUpLimit = 0.0 + theLoLimValid = true + theUpLimValid = false + } + + /** + * + * setUpperLimit. + * + * @param up a double. + */ + fun setUpperLimit(up: Double) { + theLoLimit = 0.0 + theUpLimit = up + theLoLimValid = false + theUpLimValid = true + } + //interaction + /** + * + * setValue. + * + * @param val a double. + */ + fun setValue(`val`: Double) { + theValue = `val` + } + + /** + * + * upperLimit. + * + * @return a double. + */ + fun upperLimit(): Double { + return theUpLimit + } + + /** + * + * value. + * + * @return a double. + */ + fun value(): Double { + return theValue + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnAlgebraicSymMatrix.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnAlgebraicSymMatrix.kt new file mode 100644 index 000000000..4b75858e1 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnAlgebraicSymMatrix.kt @@ -0,0 +1,458 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector + +/** + * + * @version $Id$ + */ +class MnAlgebraicSymMatrix(n: Int) { + private val theData: DoubleArray + private val theNRow: Int + private val theSize: Int + + /** + * + * copy. + * + * @return a [hep.dataforge.MINUIT.MnAlgebraicSymMatrix] object. + */ + fun copy(): MnAlgebraicSymMatrix { + val copy = MnAlgebraicSymMatrix(theNRow) + java.lang.System.arraycopy(theData, 0, copy.theData, 0, theSize) + return copy + } + + fun data(): DoubleArray { + return theData + } + + fun eigenvalues(): ArrayRealVector { + val nrow = theNRow + val tmp = DoubleArray((nrow + 1) * (nrow + 1)) + val work = DoubleArray(1 + 2 * nrow) + for (i in 0 until nrow) { + for (j in 0..i) { + tmp[1 + i + (1 + j) * nrow] = get(i, j) + tmp[(1 + i) * nrow + (1 + j)] = get(i, j) + } + } + val info = mneigen(tmp, nrow, nrow, work.size, work, 1e-6) + if (info != 0) { + throw EigenvaluesException() + } + val result = ArrayRealVector(nrow) + for (i in 0 until nrow) { + result.setEntry(i, work[1 + i]) + } + return result + } + + operator fun get(row: Int, col: Int): Double { + if (row >= theNRow || col >= theNRow) { + throw ArrayIndexOutOfBoundsException() + } + return theData[theIndex(row, col)] + } + + @Throws(SingularMatrixException::class) + fun invert() { + if (theSize == 1) { + val tmp = theData[0] + if (tmp <= 0.0) { + throw SingularMatrixException() + } + theData[0] = 1.0 / tmp + } else { + val nrow = theNRow + val s = DoubleArray(nrow) + val q = DoubleArray(nrow) + val pp = DoubleArray(nrow) + for (i in 0 until nrow) { + val si = theData[theIndex(i, i)] + if (si < 0.0) { + throw SingularMatrixException() + } + s[i] = 1.0 / sqrt(si) + } + for (i in 0 until nrow) { + for (j in i until nrow) { + theData[theIndex(i, j)] *= s[i] * s[j] + } + } + for (i in 0 until nrow) { + var k = i + if (theData[theIndex(k, k)] == 0.0) { + throw SingularMatrixException() + } + q[k] = 1.0 / theData[theIndex(k, k)] + pp[k] = 1.0 + theData[theIndex(k, k)] = 0.0 + val kp1 = k + 1 + if (k != 0) { + for (j in 0 until k) { + val index = theIndex(j, k) + pp[j] = theData[index] + q[j] = theData[index] * q[k] + theData[index] = 0.0 + } + } + if (k != nrow - 1) { + for (j in kp1 until nrow) { + val index = theIndex(k, j) + pp[j] = theData[index] + q[j] = -theData[index] * q[k] + theData[index] = 0.0 + } + } + for (j in 0 until nrow) { + k = j + while (k < nrow) { + theData[theIndex(j, k)] += pp[j] * q[k] + k++ + } + } + } + for (j in 0 until nrow) { + for (k in j until nrow) { + theData[theIndex(j, k)] *= s[j] * s[k] + } + } + } + } + + fun ncol(): Int { + return nrow() + } + + fun nrow(): Int { + return theNRow + } + + operator fun set(row: Int, col: Int, value: Double) { + if (row >= theNRow || col >= theNRow) { + throw ArrayIndexOutOfBoundsException() + } + theData[theIndex(row, col)] = value + } + + fun size(): Int { + return theSize + } + + private fun theIndex(row: Int, col: Int): Int { + return if (row > col) { + col + row * (row + 1) / 2 + } else { + row + col * (col + 1) / 2 + } + } + + /** {@inheritDoc} */ + override fun toString(): String { + return MnPrint.toString(this) + } /* mneig_ */ + + private inner class EigenvaluesException : RuntimeException() + companion object { + private fun mneigen(a: DoubleArray, ndima: Int, n: Int, mits: Int, work: DoubleArray, precis: Double): Int { + + /* System generated locals */ + var i__2: Int + var i__3: Int + + /* Local variables */ + var b: Double + var c__: Double + var f: Double + var h__: Double + var i__: Int + var j: Int + var k: Int + var l: Int + var m = 0 + var r__: Double + var s: Double + var i0: Int + var i1: Int + var j1: Int + var m1: Int + var hh: Double + var gl: Double + var pr: Double + var pt: Double + + /* PRECIS is the machine precision EPSMAC */ + /* Parameter adjustments */ + val a_dim1: Int = ndima + val a_offset: Int = 1 + a_dim1 * 1 + + /* Function Body */ + var ifault = 1 + i__ = n + var i__1: Int = n + i1 = 2 + while (i1 <= i__1) { + l = i__ - 2 + f = a[i__ + (i__ - 1) * a_dim1] + gl = 0.0 + if (l >= 1) { + i__2 = l + k = 1 + while (k <= i__2) { + + /* Computing 2nd power */ + val r__1 = a[i__ + k * a_dim1] + gl += r__1 * r__1 + ++k + } + } + /* Computing 2nd power */h__ = gl + f * f + if (gl <= 1e-35) { + work[i__] = 0.0 + work[n + i__] = f + } else { + ++l + gl = sqrt(h__) + if (f >= 0.0) { + gl = -gl + } + work[n + i__] = gl + h__ -= f * gl + a[i__ + (i__ - 1) * a_dim1] = f - gl + f = 0.0 + i__2 = l + j = 1 + while (j <= i__2) { + a[j + i__ * a_dim1] = a[i__ + j * a_dim1] / h__ + gl = 0.0 + i__3 = j + k = 1 + while (k <= i__3) { + gl += a[j + k * a_dim1] * a[i__ + k * a_dim1] + ++k + } + if (j < l) { + j1 = j + 1 + i__3 = l + k = j1 + while (k <= i__3) { + gl += a[k + j * a_dim1] * a[i__ + k * a_dim1] + ++k + } + } + work[n + j] = gl / h__ + f += gl * a[j + i__ * a_dim1] + ++j + } + hh = f / (h__ + h__) + i__2 = l + j = 1 + while (j <= i__2) { + f = a[i__ + j * a_dim1] + gl = work[n + j] - hh * f + work[n + j] = gl + i__3 = j + k = 1 + while (k <= i__3) { + a[j + k * a_dim1] = a[j + k * a_dim1] - f * work[n + k] - (gl + * a[i__ + k * a_dim1]) + ++k + } + ++j + } + work[i__] = h__ + } + --i__ + ++i1 + } + work[1] = 0.0 + work[n + 1] = 0.0 + i__1 = n + i__ = 1 + while (i__ <= i__1) { + l = i__ - 1 + if (work[i__] != 0.0 && l != 0) { + i__3 = l + j = 1 + while (j <= i__3) { + gl = 0.0 + i__2 = l + k = 1 + while (k <= i__2) { + gl += a[i__ + k * a_dim1] * a[k + j * a_dim1] + ++k + } + i__2 = l + k = 1 + while (k <= i__2) { + a[k + j * a_dim1] -= gl * a[k + i__ * a_dim1] + ++k + } + ++j + } + } + work[i__] = a[i__ + i__ * a_dim1] + a[i__ + i__ * a_dim1] = 1.0 + if (l != 0) { + i__2 = l + j = 1 + while (j <= i__2) { + a[i__ + j * a_dim1] = 0.0 + a[j + i__ * a_dim1] = 0.0 + ++j + } + } + ++i__ + } + val n1: Int = n - 1 + i__1 = n + i__ = 2 + while (i__ <= i__1) { + i0 = n + i__ - 1 + work[i0] = work[i0 + 1] + ++i__ + } + work[n + n] = 0.0 + b = 0.0 + f = 0.0 + i__1 = n + l = 1 + while (l <= i__1) { + j = 0 + h__ = precis * (abs(work[l]) + abs(work[n + l])) + if (b < h__) { + b = h__ + } + i__2 = n + m1 = l + while (m1 <= i__2) { + m = m1 + if (abs(work[n + m]) <= b) { + break + } + ++m1 + } + if (m != l) { + while (true) { + if (j == mits) { + return ifault + } + ++j + pt = (work[l + 1] - work[l]) / (work[n + l] * 2.0) + r__ = sqrt(pt * pt + 1.0) + pr = pt + r__ + if (pt < 0.0) { + pr = pt - r__ + } + h__ = work[l] - work[n + l] / pr + i__2 = n + i__ = l + while (i__ <= i__2) { + work[i__] -= h__ + ++i__ + } + f += h__ + pt = work[m] + c__ = 1.0 + s = 0.0 + m1 = m - 1 + i__ = m + i__2 = m1 + i1 = l + while (i1 <= i__2) { + j = i__ + --i__ + gl = c__ * work[n + i__] + h__ = c__ * pt + if (abs(pt) < abs(work[n + i__])) { + c__ = pt / work[n + i__] + r__ = sqrt(c__ * c__ + 1.0) + work[n + j] = s * work[n + i__] * r__ + s = 1.0 / r__ + c__ /= r__ + } else { + c__ = work[n + i__] / pt + r__ = sqrt(c__ * c__ + 1.0) + work[n + j] = s * pt * r__ + s = c__ / r__ + c__ = 1.0 / r__ + } + pt = c__ * work[i__] - s * gl + work[j] = h__ + s * (c__ * gl + s * work[i__]) + i__3 = n + k = 1 + while (k <= i__3) { + h__ = a[k + j * a_dim1] + a[k + j * a_dim1] = s * a[k + i__ * a_dim1] + c__ * h__ + a[k + i__ * a_dim1] = c__ * a[k + i__ * a_dim1] - s * h__ + ++k + } + ++i1 + } + work[n + l] = s * pt + work[l] = c__ * pt + if (abs(work[n + l]) <= b) { + break + } + } + } + work[l] += f + ++l + } + i__1 = n1 + i__ = 1 + while (i__ <= i__1) { + k = i__ + pt = work[i__] + i1 = i__ + 1 + i__3 = n + j = i1 + while (j <= i__3) { + if (work[j] < pt) { + k = j + pt = work[j] + } + ++j + } + if (k != i__) { + work[k] = work[i__] + work[i__] = pt + i__3 = n + j = 1 + while (j <= i__3) { + pt = a[j + i__ * a_dim1] + a[j + i__ * a_dim1] = a[j + k * a_dim1] + a[j + k * a_dim1] = pt + ++j + } + } + ++i__ + } + ifault = 0 + return ifault + } /* mneig_ */ + } + + init { + require(n >= 0) { "Invalid matrix size: $n" } + theSize = n * (n + 1) / 2 + theNRow = n + theData = DoubleArray(theSize) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnApplication.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnApplication.kt new file mode 100644 index 000000000..025eea4ae --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnApplication.kt @@ -0,0 +1,554 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction +import ru.inr.mass.minuit.* + +/** + * Base class for minimizers. + * + * @version $Id$ + * @author Darksnake + */ +abstract class MnApplication { + /* package protected */ + var checkAnalyticalDerivatives: Boolean + + /* package protected */ /* package protected */ + var theErrorDef = 1.0 /* package protected */ + var theFCN: MultiFunction? + + /* package protected */ /* package protected */ + var theNumCall /* package protected */ = 0 + var theState: MnUserParameterState + + /* package protected */ + var theStrategy: MnStrategy + + /* package protected */ + var useAnalyticalDerivatives: Boolean + + /* package protected */ + internal constructor(fcn: MultiFunction?, state: MnUserParameterState, stra: MnStrategy) { + theFCN = fcn + theState = state + theStrategy = stra + checkAnalyticalDerivatives = true + useAnalyticalDerivatives = true + } + + internal constructor(fcn: MultiFunction?, state: MnUserParameterState, stra: MnStrategy, nfcn: Int) { + theFCN = fcn + theState = state + theStrategy = stra + theNumCall = nfcn + checkAnalyticalDerivatives = true + useAnalyticalDerivatives = true + } + + /** + * + * MultiFunction. + * + * @return a [MultiFunction] object. + */ + fun MultiFunction(): MultiFunction? { + return theFCN + } + + /** + * add free parameter + * + * @param err a double. + * @param val a double. + * @param name a [String] object. + */ + fun add(name: String, `val`: Double, err: Double) { + theState.add(name, `val`, err) + } + + /** + * add limited parameter + * + * @param up a double. + * @param low a double. + * @param name a [String] object. + * @param val a double. + * @param err a double. + */ + fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { + theState.add(name, `val`, err, low, up) + } + + /** + * add const parameter + * + * @param name a [String] object. + * @param val a double. + */ + fun add(name: String, `val`: Double) { + theState.add(name, `val`) + } + + /** + * + * checkAnalyticalDerivatives. + * + * @return a boolean. + */ + fun checkAnalyticalDerivatives(): Boolean { + return checkAnalyticalDerivatives + } + + /** + * + * covariance. + * + * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. + */ + fun covariance(): MnUserCovariance { + return theState.covariance() + } + + /** + * + * error. + * + * @param index a int. + * @return a double. + */ + fun error(index: Int): Double { + return theState.error(index) + } + + /** + * + * error. + * + * @param name a [String] object. + * @return a double. + */ + fun error(name: String?): Double { + return theState.error(name) + } + + /** + * + * errorDef. + * + * @return a double. + */ + fun errorDef(): Double { + return theErrorDef + } + + /** + * + * errors. + * + * @return an array of double. + */ + fun errors(): DoubleArray { + return theState.errors() + } + + fun ext2int(i: Int, value: Double): Double { + return theState.ext2int(i, value) + } + + fun extOfInt(i: Int): Int { + return theState.extOfInt(i) + } + //interaction via external number of parameter + /** + * + * fix. + * + * @param index a int. + */ + fun fix(index: Int) { + theState.fix(index) + } + //interaction via name of parameter + /** + * + * fix. + * + * @param name a [String] object. + */ + fun fix(name: String?) { + theState.fix(name) + } + + /** + * convert name into external number of parameter + * + * @param name a [String] object. + * @return a int. + */ + fun index(name: String?): Int { + return theState.index(name) + } + + // transformation internal <-> external + fun int2ext(i: Int, value: Double): Double { + return theState.int2ext(i, value) + } + + fun intOfExt(i: Int): Int { + return theState.intOfExt(i) + } + + /** + * + * minimize. + * + * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. + */ + fun minimize(): FunctionMinimum { + return minimize(DEFAULT_MAXFCN) + } + + /** + * + * minimize. + * + * @param maxfcn a int. + * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. + */ + fun minimize(maxfcn: Int): FunctionMinimum { + return minimize(maxfcn, DEFAULT_TOLER) + } + + /** + * Causes minimization of the FCN and returns the result in form of a + * FunctionMinimum. + * + * @param maxfcn specifies the (approximate) maximum number of function + * calls after which the calculation will be stopped even if it has not yet + * converged. + * @param toler specifies the required tolerance on the function value at + * the minimum. The default tolerance value is 0.1, and the minimization + * will stop when the estimated vertical distance to the minimum (EDM) is + * less than 0:001*tolerance*errorDef + * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. + */ + fun minimize(maxfcn: Int, toler: Double): FunctionMinimum { + var maxfcn = maxfcn + check(theState.isValid()) { "Invalid state" } + val npar = variableParameters() + if (maxfcn == 0) { + maxfcn = 200 + 100 * npar + 5 * npar * npar + } + val min: FunctionMinimum = minimizer().minimize(theFCN, + theState, + theStrategy, + maxfcn, + toler, + theErrorDef, + useAnalyticalDerivatives, + checkAnalyticalDerivatives) + theNumCall += min.nfcn() + theState = min.userState() + return min + } + + abstract fun minimizer(): ModularFunctionMinimizer + + // facade: forward interface of MnUserParameters and MnUserTransformation + fun minuitParameters(): List { + return theState.minuitParameters() + } + + /** + * convert external number into name of parameter + * + * @param index a int. + * @return a [String] object. + */ + fun name(index: Int): String { + return theState.name(index) + } + + /** + * + * numOfCalls. + * + * @return a int. + */ + fun numOfCalls(): Int { + return theNumCall + } + + /** + * access to single parameter + * @param i + * @return + */ + fun parameter(i: Int): MinuitParameter { + return theState.parameter(i) + } + + /** + * + * parameters. + * + * @return a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + fun parameters(): MnUserParameters { + return theState.parameters() + } + + /** + * access to parameters and errors in column-wise representation + * + * @return an array of double. + */ + fun params(): DoubleArray { + return theState.params() + } + + /** + * + * precision. + * + * @return a [hep.dataforge.MINUIT.MnMachinePrecision] object. + */ + fun precision(): MnMachinePrecision { + return theState.precision() + } + + /** + * + * release. + * + * @param index a int. + */ + fun release(index: Int) { + theState.release(index) + } + + /** + * + * release. + * + * @param name a [String] object. + */ + fun release(name: String?) { + theState.release(name) + } + + /** + * + * removeLimits. + * + * @param index a int. + */ + fun removeLimits(index: Int) { + theState.removeLimits(index) + } + + /** + * + * removeLimits. + * + * @param name a [String] object. + */ + fun removeLimits(name: String?) { + theState.removeLimits(name) + } + + /** + * Minuit does a check of the user gradient at the beginning, if this is not + * wanted the set this to "false". + * + * @param check a boolean. + */ + fun setCheckAnalyticalDerivatives(check: Boolean) { + checkAnalyticalDerivatives = check + } + + /** + * + * setError. + * + * @param index a int. + * @param err a double. + */ + fun setError(index: Int, err: Double) { + theState.setError(index, err) + } + + /** + * + * setError. + * + * @param name a [String] object. + * @param err a double. + */ + fun setError(name: String?, err: Double) { + theState.setError(name, err) + } + + /** + * errorDef() is the error definition of the function. E.g. is 1 if function + * is Chi2 and 0.5 if function is -logLikelihood. If the user wants instead + * the 2-sigma errors, errorDef() = 4, as Chi2(x+n*sigma) = Chi2(x) + n*n. + * + * @param errorDef a double. + */ + fun setErrorDef(errorDef: Double) { + theErrorDef = errorDef + } + + /** + * + * setLimits. + * + * @param index a int. + * @param low a double. + * @param up a double. + */ + fun setLimits(index: Int, low: Double, up: Double) { + theState.setLimits(index, low, up) + } + + /** + * + * setLimits. + * + * @param name a [String] object. + * @param low a double. + * @param up a double. + */ + fun setLimits(name: String?, low: Double, up: Double) { + theState.setLimits(name, low, up) + } + + /** + * + * setPrecision. + * + * @param prec a double. + */ + fun setPrecision(prec: Double) { + theState.setPrecision(prec) + } + + /** + * By default if the function to be minimized implements MultiFunction then + * the analytical gradient provided by the function will be used. Set this + * to + * false to disable this behaviour and force numerical + * calculation of the gradient. + * + * @param use a boolean. + */ + fun setUseAnalyticalDerivatives(use: Boolean) { + useAnalyticalDerivatives = use + } + + /** + * + * setValue. + * + * @param index a int. + * @param val a double. + */ + fun setValue(index: Int, `val`: Double) { + theState.setValue(index, `val`) + } + + /** + * + * setValue. + * + * @param name a [String] object. + * @param val a double. + */ + fun setValue(name: String?, `val`: Double) { + theState.setValue(name, `val`) + } + + /** + * + * state. + * + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun state(): MnUserParameterState { + return theState + } + + /** + * + * strategy. + * + * @return a [hep.dataforge.MINUIT.MnStrategy] object. + */ + fun strategy(): MnStrategy { + return theStrategy + } + + /** + * + * useAnalyticalDerivaties. + * + * @return a boolean. + */ + fun useAnalyticalDerivaties(): Boolean { + return useAnalyticalDerivatives + } + + /** + * + * value. + * + * @param index a int. + * @return a double. + */ + fun value(index: Int): Double { + return theState.value(index) + } + + /** + * + * value. + * + * @param name a [String] object. + * @return a double. + */ + fun value(name: String?): Double { + return theState.value(name) + } + + /** + * + * variableParameters. + * + * @return a int. + */ + fun variableParameters(): Int { + return theState.variableParameters() + } + + companion object { + var DEFAULT_MAXFCN = 0 + var DEFAULT_STRATEGY = 1 + var DEFAULT_TOLER = 0.1 + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnContours.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnContours.kt new file mode 100644 index 000000000..1b700f4e2 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnContours.kt @@ -0,0 +1,283 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction +import ru.inr.mass.minuit.* + +/** + * API class for Contours error analysis (2-dim errors). Minimization has to be + * done before and minimum must be valid. Possibility to ask only for the points + * or the points and associated Minos errors. + * + * @version $Id$ + * @author Darksnake + */ +class MnContours(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) { + private var theFCN: MultiFunction? = null + private var theMinimum: FunctionMinimum? = null + private var theStrategy: MnStrategy? = null + + /** + * construct from FCN + minimum + * + * @param fcn a [MultiFunction] object. + * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. + */ + constructor(fcn: MultiFunction?, min: FunctionMinimum?) : this(fcn, min, MnApplication.DEFAULT_STRATEGY) + + /** + * construct from FCN + minimum + strategy + * + * @param stra a int. + * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, min: FunctionMinimum?, stra: Int) : this(fcn, min, MnStrategy(stra)) + + /** + * + * contour. + * + * @param px a int. + * @param py a int. + * @return a [hep.dataforge.MINUIT.ContoursError] object. + */ + fun contour(px: Int, py: Int): ContoursError { + return contour(px, py, 1.0) + } + + /** + * + * contour. + * + * @param px a int. + * @param py a int. + * @param errDef a double. + * @return a [hep.dataforge.MINUIT.ContoursError] object. + */ + fun contour(px: Int, py: Int, errDef: Double): ContoursError { + return contour(px, py, errDef, 20) + } + + /** + * Causes a CONTOURS error analysis and returns the result in form of + * ContoursError. As a by-product ContoursError keeps the MinosError + * information of parameters parx and pary. The result ContoursError can be + * easily printed using MnPrint or toString(). + * + * @param npoints a int. + * @param px a int. + * @param py a int. + * @param errDef a double. + * @return a [hep.dataforge.MINUIT.ContoursError] object. + */ + fun contour(px: Int, py: Int, errDef: Double, npoints: Int): ContoursError { + var errDef = errDef + errDef *= theMinimum!!.errorDef() + assert(npoints > 3) + val maxcalls: Int = 100 * (npoints + 5) * (theMinimum!!.userState().variableParameters() + 1) + var nfcn = 0 + val result: MutableList = java.util.ArrayList(npoints) + val states: List = java.util.ArrayList() + val toler = 0.05 + + //get first four points + val minos = MnMinos(theFCN, theMinimum, theStrategy) + val valx: Double = theMinimum!!.userState().value(px) + val valy: Double = theMinimum!!.userState().value(py) + val mex: MinosError = minos.minos(px, errDef) + nfcn += mex.nfcn() + if (!mex.isValid()) { + MINUITPlugin.logStatic("MnContours is unable to find first two points.") + return ContoursError(px, py, result, mex, mex, nfcn) + } + val ex: Range = mex.range() + val mey: MinosError = minos.minos(py, errDef) + nfcn += mey.nfcn() + if (!mey.isValid()) { + MINUITPlugin.logStatic("MnContours is unable to find second two points.") + return ContoursError(px, py, result, mex, mey, nfcn) + } + val ey: Range = mey.range() + val migrad = MnMigrad(theFCN, + theMinimum!!.userState().copy(), + MnStrategy(max(0, theStrategy!!.strategy() - 1))) + migrad.fix(px) + migrad.setValue(px, valx + ex.getSecond()) + val exy_up: FunctionMinimum = migrad.minimize() + nfcn += exy_up.nfcn() + if (!exy_up.isValid()) { + MINUITPlugin.logStatic("MnContours is unable to find upper y value for x parameter $px.") + return ContoursError(px, py, result, mex, mey, nfcn) + } + migrad.setValue(px, valx + ex.getFirst()) + val exy_lo: FunctionMinimum = migrad.minimize() + nfcn += exy_lo.nfcn() + if (!exy_lo.isValid()) { + MINUITPlugin.logStatic("MnContours is unable to find lower y value for x parameter $px.") + return ContoursError(px, py, result, mex, mey, nfcn) + } + val migrad1 = MnMigrad(theFCN, + theMinimum!!.userState().copy(), + MnStrategy(max(0, theStrategy!!.strategy() - 1))) + migrad1.fix(py) + migrad1.setValue(py, valy + ey.getSecond()) + val eyx_up: FunctionMinimum = migrad1.minimize() + nfcn += eyx_up.nfcn() + if (!eyx_up.isValid()) { + MINUITPlugin.logStatic("MnContours is unable to find upper x value for y parameter $py.") + return ContoursError(px, py, result, mex, mey, nfcn) + } + migrad1.setValue(py, valy + ey.getFirst()) + val eyx_lo: FunctionMinimum = migrad1.minimize() + nfcn += eyx_lo.nfcn() + if (!eyx_lo.isValid()) { + MINUITPlugin.logStatic("MnContours is unable to find lower x value for y parameter $py.") + return ContoursError(px, py, result, mex, mey, nfcn) + } + val scalx: Double = 1.0 / (ex.getSecond() - ex.getFirst()) + val scaly: Double = 1.0 / (ey.getSecond() - ey.getFirst()) + result.add(Range(valx + ex.getFirst(), exy_lo.userState().value(py))) + result.add(Range(eyx_lo.userState().value(px), valy + ey.getFirst())) + result.add(Range(valx + ex.getSecond(), exy_up.userState().value(py))) + result.add(Range(eyx_up.userState().value(px), valy + ey.getSecond())) + val upar: MnUserParameterState = theMinimum!!.userState().copy() + upar.fix(px) + upar.fix(py) + val par = intArrayOf(px, py) + val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef) + for (i in 4 until npoints) { + var idist1: Range = result[result.size - 1] + var idist2: Range = result[0] + var pos2 = 0 + val distx: Double = idist1.getFirst() - idist2.getFirst() + val disty: Double = idist1.getSecond() - idist2.getSecond() + var bigdis = scalx * scalx * distx * distx + scaly * scaly * disty * disty + for (j in 0 until result.size - 1) { + val ipair: Range = result[j] + val distx2: Double = ipair.getFirst() - result[j + 1].getFirst() + val disty2: Double = ipair.getSecond() - result[j + 1].getSecond() + val dist = scalx * scalx * distx2 * distx2 + scaly * scaly * disty2 * disty2 + if (dist > bigdis) { + bigdis = dist + idist1 = ipair + idist2 = result[j + 1] + pos2 = j + 1 + } + } + val a1 = 0.5 + val a2 = 0.5 + var sca = 1.0 + while (true) { + if (nfcn > maxcalls) { + MINUITPlugin.logStatic("MnContours: maximum number of function calls exhausted.") + return ContoursError(px, py, result, mex, mey, nfcn) + } + val xmidcr: Double = a1 * idist1.getFirst() + a2 * idist2.getFirst() + val ymidcr: Double = a1 * idist1.getSecond() + a2 * idist2.getSecond() + val xdir: Double = idist2.getSecond() - idist1.getSecond() + val ydir: Double = idist1.getFirst() - idist2.getFirst() + val scalfac: Double = + sca * max(abs(xdir * scalx), abs(ydir * scaly)) + val xdircr = xdir / scalfac + val ydircr = ydir / scalfac + val pmid = doubleArrayOf(xmidcr, ymidcr) + val pdir = doubleArrayOf(xdircr, ydircr) + val opt: MnCross = cross.cross(par, pmid, pdir, toler, maxcalls) + nfcn += opt.nfcn() + if (opt.isValid()) { + val aopt: Double = opt.value() + if (pos2 == 0) { + result.add(Range(xmidcr + aopt * xdircr, ymidcr + aopt * ydircr)) + } else { + result.add(pos2, Range(xmidcr + aopt * xdircr, ymidcr + aopt * ydircr)) + } + break + } + if (sca < 0.0) { + MINUITPlugin.logStatic("MnContours is unable to find point " + (i + 1) + " on contour.") + MINUITPlugin.logStatic("MnContours finds only $i points.") + return ContoursError(px, py, result, mex, mey, nfcn) + } + sca = -1.0 + } + } + return ContoursError(px, py, result, mex, mey, nfcn) + } + + /** + * + * points. + * + * @param px a int. + * @param py a int. + * @return a [List] object. + */ + fun points(px: Int, py: Int): List { + return points(px, py, 1.0) + } + + /** + * + * points. + * + * @param px a int. + * @param py a int. + * @param errDef a double. + * @return a [List] object. + */ + fun points(px: Int, py: Int, errDef: Double): List { + return points(px, py, errDef, 20) + } + + /** + * Calculates one function contour of FCN with respect to parameters parx + * and pary. The return value is a list of (x,y) points. FCN minimized + * always with respect to all other n - 2 variable parameters (if any). + * MINUITPlugin will try to find n points on the contour (default 20). To + * calculate more than one contour, the user needs to set the error + * definition in its FCN to the appropriate value for the desired confidence + * level and call this method for each contour. + * + * @param npoints a int. + * @param px a int. + * @param py a int. + * @param errDef a double. + * @return a [List] object. + */ + fun points(px: Int, py: Int, errDef: Double, npoints: Int): List { + val cont: ContoursError = contour(px, py, errDef, npoints) + return cont.points() + } + + fun strategy(): MnStrategy? { + return theStrategy + } + + /** + * construct from FCN + minimum + strategy + * + * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. + * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. + * @param fcn a [MultiFunction] object. + */ + init { + theFCN = fcn + theMinimum = min + theStrategy = stra + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCovarianceSqueeze.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCovarianceSqueeze.kt new file mode 100644 index 000000000..7614a93b0 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCovarianceSqueeze.kt @@ -0,0 +1,113 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import space.kscience.kmath.optimization.minuit.MINUITPlugin + +/** + * + * @version $Id$ + */ +internal object MnCovarianceSqueeze { + fun squeeze(cov: MnUserCovariance, n: Int): MnUserCovariance { + assert(cov.nrow() > 0) + assert(n < cov.nrow()) + val hess = MnAlgebraicSymMatrix(cov.nrow()) + for (i in 0 until cov.nrow()) { + for (j in i until cov.nrow()) { + hess[i, j] = cov[i, j] + } + } + try { + hess.invert() + } catch (x: SingularMatrixException) { + MINUITPlugin.logStatic("MnUserCovariance inversion failed; return diagonal matrix;") + val result = MnUserCovariance(cov.nrow() - 1) + var i = 0 + var j = 0 + while (i < cov.nrow()) { + if (i == n) { + i++ + continue + } + result[j, j] = cov[i, i] + j++ + i++ + } + return result + } + val squeezed: MnAlgebraicSymMatrix = squeeze(hess, n) + try { + squeezed.invert() + } catch (x: SingularMatrixException) { + MINUITPlugin.logStatic("MnUserCovariance back-inversion failed; return diagonal matrix;") + val result = MnUserCovariance(squeezed.nrow()) + var i = 0 + while (i < squeezed.nrow()) { + result[i, i] = 1.0 / squeezed[i, i] + i++ + } + return result + } + return MnUserCovariance(squeezed.data(), squeezed.nrow()) + } + + fun squeeze(err: MinimumError, n: Int): MinimumError { + val hess: MnAlgebraicSymMatrix = err.hessian() + val squeezed: MnAlgebraicSymMatrix = squeeze(hess, n) + try { + squeezed.invert() + } catch (x: SingularMatrixException) { + MINUITPlugin.logStatic("MnCovarianceSqueeze: MinimumError inversion fails; return diagonal matrix.") + val tmp = MnAlgebraicSymMatrix(squeezed.nrow()) + var i = 0 + while (i < squeezed.nrow()) { + tmp[i, i] = 1.0 / squeezed[i, i] + i++ + } + return MinimumError(tmp, MnInvertFailed()) + } + return MinimumError(squeezed, err.dcovar()) + } + + fun squeeze(hess: MnAlgebraicSymMatrix, n: Int): MnAlgebraicSymMatrix { + assert(hess.nrow() > 0) + assert(n < hess.nrow()) + val hs = MnAlgebraicSymMatrix(hess.nrow() - 1) + var i = 0 + var j = 0 + while (i < hess.nrow()) { + if (i == n) { + i++ + continue + } + var k = i + var l = j + while (k < hess.nrow()) { + if (k == n) { + k++ + continue + } + hs[j, l] = hess[i, k] + l++ + k++ + } + j++ + i++ + } + return hs + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCross.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCross.kt new file mode 100644 index 000000000..f1487b106 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCross.kt @@ -0,0 +1,99 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * MnCross class. + * + * @version $Id$ + * @author Darksnake + */ +class MnCross { + private var theLimset = false + private var theMaxFcn = false + private var theNFcn = 0 + private var theNewMin = false + private var theState: MnUserParameterState + private var theValid = false + private var theValue = 0.0 + + internal constructor() { + theState = MnUserParameterState() + } + + internal constructor(nfcn: Int) { + theState = MnUserParameterState() + theNFcn = nfcn + } + + internal constructor(value: Double, state: MnUserParameterState, nfcn: Int) { + theValue = value + theState = state + theNFcn = nfcn + theValid = true + } + + internal constructor(state: MnUserParameterState, nfcn: Int, x: CrossParLimit?) { + theState = state + theNFcn = nfcn + theLimset = true + } + + internal constructor(state: MnUserParameterState, nfcn: Int, x: CrossFcnLimit?) { + theState = state + theNFcn = nfcn + theMaxFcn = true + } + + internal constructor(state: MnUserParameterState, nfcn: Int, x: CrossNewMin?) { + theState = state + theNFcn = nfcn + theNewMin = true + } + + fun atLimit(): Boolean { + return theLimset + } + + fun atMaxFcn(): Boolean { + return theMaxFcn + } + + fun isValid(): Boolean { + return theValid + } + + fun newMinimum(): Boolean { + return theNewMin + } + + fun nfcn(): Int { + return theNFcn + } + + fun state(): MnUserParameterState { + return theState + } + + fun value(): Double { + return theValue + } + + internal class CrossFcnLimit + internal class CrossNewMin + internal class CrossParLimit +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnEigen.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnEigen.kt new file mode 100644 index 000000000..d7aade0c9 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnEigen.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.RealVector + +/** + * Calculates and the eigenvalues of the user covariance matrix + * MnUserCovariance. + * + * @version $Id$ + * @author Darksnake + */ +object MnEigen { + /* Calculate eigenvalues of the covariance matrix. + * Will perform the calculation of the eigenvalues of the covariance matrix + * and return the result in the form of a double array. + * The eigenvalues are ordered from the smallest to the largest eigenvalue. + */ + /** + * + * eigenvalues. + * + * @param covar a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @return an array of double. + */ + fun eigenvalues(covar: MnUserCovariance): DoubleArray { + val cov = MnAlgebraicSymMatrix(covar.nrow()) + for (i in 0 until covar.nrow()) { + for (j in i until covar.nrow()) { + cov[i, j] = covar[i, j] + } + } + val eigen: RealVector = cov.eigenvalues() + return eigen.toArray() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFcn.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFcn.kt new file mode 100644 index 000000000..b11f71035 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFcn.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction + +/** + * Функция, которая помнит количество вызовов себя и ErrorDef + * @version $Id$ + */ +class MnFcn(fcn: MultiFunction?, errorDef: Double) { + private val theErrorDef: Double + private val theFCN: MultiFunction? + protected var theNumCall: Int + fun errorDef(): Double { + return theErrorDef + } + + fun fcn(): MultiFunction? { + return theFCN + } + + fun numOfCalls(): Int { + return theNumCall + } + + fun value(v: RealVector): Double { + theNumCall++ + return theFCN.value(v.toArray()) + } + + init { + theFCN = fcn + theNumCall = 0 + theErrorDef = errorDef + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFunctionCross.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFunctionCross.kt new file mode 100644 index 000000000..a05590e53 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFunctionCross.kt @@ -0,0 +1,369 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction +import ru.inr.mass.minuit.* +import kotlin.math.* + +/** + * + * @version $Id$ + */ +internal class MnFunctionCross( + fcn: MultiFunction?, + state: MnUserParameterState, + fval: Double, + stra: MnStrategy?, + errorDef: Double +) { + private val theErrorDef: Double + private val theFCN: MultiFunction? + private val theFval: Double + private val theState: MnUserParameterState + private val theStrategy: MnStrategy? + fun cross(par: IntArray, pmid: DoubleArray, pdir: DoubleArray, tlr: Double, maxcalls: Int): MnCross { + val npar = par.size + var nfcn = 0 + val prec: MnMachinePrecision = theState.precision() + val tlf = tlr * theErrorDef + var tla = tlr + val maxitr = 15 + var ipt = 0 + val aminsv = theFval + val aim = aminsv + theErrorDef + var aopt = 0.0 + var limset = false + val alsb = DoubleArray(3) + val flsb = DoubleArray(3) + val up = theErrorDef + var aulim = 100.0 + for (i in par.indices) { + val kex = par[i] + if (theState.parameter(kex).hasLimits()) { + val zmid = pmid[i] + val zdir = pdir[i] + if (abs(zdir) < theState.precision().eps()) { + continue + } + if (zdir > 0.0 && theState.parameter(kex).hasUpperLimit()) { + val zlim: Double = theState.parameter(kex).upperLimit() + aulim = min(aulim, (zlim - zmid) / zdir) + } else if (zdir < 0.0 && theState.parameter(kex).hasLowerLimit()) { + val zlim: Double = theState.parameter(kex).lowerLimit() + aulim = min(aulim, (zlim - zmid) / zdir) + } + } + } + if (aulim < aopt + tla) { + limset = true + } + val migrad = MnMigrad(theFCN, theState, MnStrategy(max(0, theStrategy!!.strategy() - 1))) + for (i in 0 until npar) { + migrad.setValue(par[i], pmid[i]) + } + val min0: FunctionMinimum = migrad.minimize(maxcalls, tlr) + nfcn += min0.nfcn() + if (min0.hasReachedCallLimit()) { + return MnCross(min0.userState(), nfcn, MnCross.CrossFcnLimit()) + } + if (!min0.isValid()) { + return MnCross(nfcn) + } + if (limset && min0.fval() < aim) { + return MnCross(min0.userState(), nfcn, MnCross.CrossParLimit()) + } + ipt++ + alsb[0] = 0.0 + flsb[0] = min0.fval() + flsb[0] = max(flsb[0], aminsv + 0.1 * up) + aopt = sqrt(up / (flsb[0] - aminsv)) - 1.0 + if (abs(flsb[0] - aim) < tlf) { + return MnCross(aopt, min0.userState(), nfcn) + } + if (aopt > 1.0) { + aopt = 1.0 + } + if (aopt < -0.5) { + aopt = -0.5 + } + limset = false + if (aopt > aulim) { + aopt = aulim + limset = true + } + for (i in 0 until npar) { + migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) + } + var min1: FunctionMinimum = migrad.minimize(maxcalls, tlr) + nfcn += min1.nfcn() + if (min1.hasReachedCallLimit()) { + return MnCross(min1.userState(), nfcn, MnCross.CrossFcnLimit()) + } + if (!min1.isValid()) { + return MnCross(nfcn) + } + if (limset && min1.fval() < aim) { + return MnCross(min1.userState(), nfcn, MnCross.CrossParLimit()) + } + ipt++ + alsb[1] = aopt + flsb[1] = min1.fval() + var dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]) + var ecarmn = 0.0 + var ecarmx = 0.0 + var ibest = 0 + var iworst = 0 + var noless = 0 + var min2: FunctionMinimum? = null + L300@ while (true) { + if (dfda < 0.0) { + val maxlk = maxitr - ipt + for (it in 0 until maxlk) { + alsb[0] = alsb[1] + flsb[0] = flsb[1] + aopt = alsb[0] + 0.2 * it + limset = false + if (aopt > aulim) { + aopt = aulim + limset = true + } + for (i in 0 until npar) { + migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) + } + min1 = migrad.minimize(maxcalls, tlr) + nfcn += min1.nfcn() + if (min1.hasReachedCallLimit()) { + return MnCross(min1.userState(), nfcn, MnCross.CrossFcnLimit()) + } + if (!min1.isValid()) { + return MnCross(nfcn) + } + if (limset && min1.fval() < aim) { + return MnCross(min1.userState(), nfcn, MnCross.CrossParLimit()) + } + ipt++ + alsb[1] = aopt + flsb[1] = min1.fval() + dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]) + if (dfda > 0.0) { + break + } + } + if (ipt > maxitr) { + return MnCross(nfcn) + } + } + L460@ while (true) { + aopt = alsb[1] + (aim - flsb[1]) / dfda + val fdist: Double = + min(abs(aim - flsb[0]), abs(aim - flsb[1])) + val adist: Double = + min(abs(aopt - alsb[0]), abs(aopt - alsb[1])) + tla = tlr + if (abs(aopt) > 1.0) { + tla = tlr * abs(aopt) + } + if (adist < tla && fdist < tlf) { + return MnCross(aopt, min1.userState(), nfcn) + } + if (ipt > maxitr) { + return MnCross(nfcn) + } + val bmin: Double = min(alsb[0], alsb[1]) - 1.0 + if (aopt < bmin) { + aopt = bmin + } + val bmax: Double = max(alsb[0], alsb[1]) + 1.0 + if (aopt > bmax) { + aopt = bmax + } + limset = false + if (aopt > aulim) { + aopt = aulim + limset = true + } + for (i in 0 until npar) { + migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) + } + min2 = migrad.minimize(maxcalls, tlr) + nfcn += min2.nfcn() + if (min2.hasReachedCallLimit()) { + return MnCross(min2.userState(), nfcn, CrossFcnLimit()) + } + if (!min2.isValid()) { + return MnCross(nfcn) + } + if (limset && min2.fval() < aim) { + return MnCross(min2.userState(), nfcn, MnCross.CrossParLimit()) + } + ipt++ + alsb[2] = aopt + flsb[2] = min2.fval() + ecarmn = abs(flsb[2] - aim) + ecarmx = 0.0 + ibest = 2 + iworst = 0 + noless = 0 + for (i in 0..2) { + val ecart: Double = abs(flsb[i] - aim) + if (ecart > ecarmx) { + ecarmx = ecart + iworst = i + } + if (ecart < ecarmn) { + ecarmn = ecart + ibest = i + } + if (flsb[i] < aim) { + noless++ + } + } + if (noless == 1 || noless == 2) { + break@L300 + } + if (noless == 0 && ibest != 2) { + return MnCross(nfcn) + } + if (noless == 3 && ibest != 2) { + alsb[1] = alsb[2] + flsb[1] = flsb[2] + continue@L300 + } + flsb[iworst] = flsb[2] + alsb[iworst] = alsb[2] + dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]) + } + } + do { + val parbol: MnParabola = MnParabolaFactory.create(MnParabolaPoint(alsb[0], flsb[0]), + MnParabolaPoint(alsb[1], flsb[1]), + MnParabolaPoint( + alsb[2], flsb[2])) + val coeff1: Double = parbol.c() + val coeff2: Double = parbol.b() + val coeff3: Double = parbol.a() + val determ = coeff2 * coeff2 - 4.0 * coeff3 * (coeff1 - aim) + if (determ < prec.eps()) { + return MnCross(nfcn) + } + val rt: Double = sqrt(determ) + val x1 = (-coeff2 + rt) / (2.0 * coeff3) + val x2 = (-coeff2 - rt) / (2.0 * coeff3) + val s1 = coeff2 + 2.0 * x1 * coeff3 + val s2 = coeff2 + 2.0 * x2 * coeff3 + if (s1 * s2 > 0.0) { + MINUITPlugin.logStatic("MnFunctionCross problem 1") + } + aopt = x1 + var slope = s1 + if (s2 > 0.0) { + aopt = x2 + slope = s2 + } + tla = tlr + if (abs(aopt) > 1.0) { + tla = tlr * abs(aopt) + } + if (abs(aopt - alsb[ibest]) < tla && abs(flsb[ibest] - aim) < tlf) { + return MnCross(aopt, min2!!.userState(), nfcn) + } + var ileft = 3 + var iright = 3 + var iout = 3 + ibest = 0 + ecarmx = 0.0 + ecarmn = abs(aim - flsb[0]) + for (i in 0..2) { + val ecart: Double = abs(flsb[i] - aim) + if (ecart < ecarmn) { + ecarmn = ecart + ibest = i + } + if (ecart > ecarmx) { + ecarmx = ecart + } + if (flsb[i] > aim) { + if (iright == 3) { + iright = i + } else if (flsb[i] > flsb[iright]) { + iout = i + } else { + iout = iright + iright = i + } + } else if (ileft == 3) { + ileft = i + } else if (flsb[i] < flsb[ileft]) { + iout = i + } else { + iout = ileft + ileft = i + } + } + if (ecarmx > 10.0 * abs(flsb[iout] - aim)) { + aopt = 0.5 * (aopt + 0.5 * (alsb[iright] + alsb[ileft])) + } + var smalla = 0.1 * tla + if (slope * smalla > tlf) { + smalla = tlf / slope + } + val aleft = alsb[ileft] + smalla + val aright = alsb[iright] - smalla + if (aopt < aleft) { + aopt = aleft + } + if (aopt > aright) { + aopt = aright + } + if (aleft > aright) { + aopt = 0.5 * (aleft + aright) + } + limset = false + if (aopt > aulim) { + aopt = aulim + limset = true + } + for (i in 0 until npar) { + migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) + } + min2 = migrad.minimize(maxcalls, tlr) + nfcn += min2.nfcn() + if (min2.hasReachedCallLimit()) { + return MnCross(min2.userState(), nfcn, CrossFcnLimit()) + } + if (!min2.isValid()) { + return MnCross(nfcn) + } + if (limset && min2.fval() < aim) { + return MnCross(min2.userState(), nfcn, CrossParLimit()) + } + ipt++ + alsb[iout] = aopt + flsb[iout] = min2.fval() + ibest = iout + } while (ipt < maxitr) + return MnCross(nfcn) + } + + init { + theFCN = fcn + theState = state + theFval = fval + theStrategy = stra + theErrorDef = errorDef + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnGlobalCorrelationCoeff.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnGlobalCorrelationCoeff.kt new file mode 100644 index 000000000..939dd7fa0 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnGlobalCorrelationCoeff.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.SingularMatrixException + +/** + * + * MnGlobalCorrelationCoeff class. + * + * @version $Id$ + * @author Darksnake + */ +class MnGlobalCorrelationCoeff { + private var theGlobalCC: DoubleArray + private var theValid = false + + internal constructor() { + theGlobalCC = DoubleArray(0) + } + + internal constructor(cov: MnAlgebraicSymMatrix) { + try { + val inv: MnAlgebraicSymMatrix = cov.copy() + inv.invert() + theGlobalCC = DoubleArray(cov.nrow()) + for (i in 0 until cov.nrow()) { + val denom: Double = inv[i, i] * cov[i, i] + if (denom < 1.0 && denom > 0.0) { + theGlobalCC[i] = 0 + } else { + theGlobalCC[i] = sqrt(1.0 - 1.0 / denom) + } + } + theValid = true + } catch (x: SingularMatrixException) { + theValid = false + theGlobalCC = DoubleArray(0) + } + } + + /** + * + * globalCC. + * + * @return an array of double. + */ + fun globalCC(): DoubleArray { + return theGlobalCC + } + + /** + * + * isValid. + * + * @return a boolean. + */ + fun isValid(): Boolean { + return theValid + } + + /** {@inheritDoc} */ + override fun toString(): String { + return MnPrint.toString(this) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnHesse.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnHesse.kt new file mode 100644 index 000000000..3bb6c4551 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnHesse.kt @@ -0,0 +1,371 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction +import ru.inr.mass.minuit.* + +/** + * With MnHesse the user can instructs MINUITPlugin to calculate, by finite + * differences, the Hessian or error matrix. That is, it calculates the full + * matrix of second derivatives of the function with respect to the currently + * variable parameters, and inverts it. + * + * @version $Id$ + * @author Darksnake + */ +class MnHesse { + private var theStrategy: MnStrategy + + /** + * default constructor with default strategy + */ + constructor() { + theStrategy = MnStrategy(1) + } + + /** + * constructor with user-defined strategy level + * + * @param stra a int. + */ + constructor(stra: Int) { + theStrategy = MnStrategy(stra) + } + + /** + * conctructor with specific strategy + * + * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. + */ + constructor(stra: MnStrategy) { + theStrategy = stra + } + /// + /// low-level API + /// + /** + * + * calculate. + * + * @param fcn a [MultiFunction] object. + * @param par an array of double. + * @param err an array of double. + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun calculate(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray): MnUserParameterState { + return calculate(fcn, par, err, 0) + } + + /** + * FCN + parameters + errors + * + * @param maxcalls a int. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + * @param err an array of double. + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun calculate(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, maxcalls: Int): MnUserParameterState { + return calculate(fcn, MnUserParameterState(par, err), maxcalls) + } + + /** + * + * calculate. + * + * @param fcn a [MultiFunction] object. + * @param par an array of double. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun calculate(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance): MnUserParameterState { + return calculate(fcn, par, cov, 0) + } + + /** + * FCN + parameters + MnUserCovariance + * + * @param maxcalls a int. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun calculate(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, maxcalls: Int): MnUserParameterState { + return calculate(fcn, MnUserParameterState(par, cov), maxcalls) + } + /// + /// high-level API + /// + /** + * + * calculate. + * + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun calculate(fcn: MultiFunction?, par: MnUserParameters): MnUserParameterState { + return calculate(fcn, par, 0) + } + + /** + * FCN + MnUserParameters + * + * @param maxcalls a int. + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun calculate(fcn: MultiFunction?, par: MnUserParameters, maxcalls: Int): MnUserParameterState { + return calculate(fcn, MnUserParameterState(par), maxcalls) + } + + /** + * + * calculate. + * + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun calculate(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance?): MnUserParameterState { + return calculate(fcn, par, 0) + } + + /** + * FCN + MnUserParameters + MnUserCovariance + * + * @param maxcalls a int. + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun calculate( + fcn: MultiFunction?, + par: MnUserParameters, + cov: MnUserCovariance, + maxcalls: Int + ): MnUserParameterState { + return calculate(fcn, MnUserParameterState(par, cov), maxcalls) + } + + /** + * FCN + MnUserParameterState + * + * @param maxcalls a int. + * @param fcn a [MultiFunction] object. + * @param state a [hep.dataforge.MINUIT.MnUserParameterState] object. + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun calculate(fcn: MultiFunction?, state: MnUserParameterState, maxcalls: Int): MnUserParameterState { + val errDef = 1.0 // FixMe! + val n: Int = state.variableParameters() + val mfcn = MnUserFcn(fcn, errDef, state.getTransformation()) + val x: RealVector = ArrayRealVector(n) + for (i in 0 until n) { + x.setEntry(i, state.intParameters()[i]) + } + val amin: Double = mfcn.value(x) + val gc = Numerical2PGradientCalculator(mfcn, state.getTransformation(), theStrategy) + val par = MinimumParameters(x, amin) + val gra: FunctionGradient = gc.gradient(par) + val tmp: MinimumState = calculate(mfcn, + MinimumState(par, MinimumError(MnAlgebraicSymMatrix(n), 1.0), gra, state.edm(), state.nfcn()), + state.getTransformation(), + maxcalls) + return MnUserParameterState(tmp, errDef, state.getTransformation()) + } + + /// + /// internal interface + /// + fun calculate(mfcn: MnFcn, st: MinimumState, trafo: MnUserTransformation, maxcalls: Int): MinimumState { + var maxcalls = maxcalls + val prec: MnMachinePrecision = trafo.precision() + // make sure starting at the right place + val amin: Double = mfcn.value(st.vec()) + val aimsag: Double = sqrt(prec.eps2()) * (abs(amin) + mfcn.errorDef()) + + // diagonal elements first + val n: Int = st.parameters().vec().getDimension() + if (maxcalls == 0) { + maxcalls = 200 + 100 * n + 5 * n * n + } + var vhmat = MnAlgebraicSymMatrix(n) + var g2: RealVector = st.gradient().getGradientDerivative().copy() + var gst: RealVector = st.gradient().getStep().copy() + var grd: RealVector = st.gradient().getGradient().copy() + var dirin: RealVector = st.gradient().getStep().copy() + val yy: RealVector = ArrayRealVector(n) + if (st.gradient().isAnalytical()) { + val igc = InitialGradientCalculator(mfcn, trafo, theStrategy) + val tmp: FunctionGradient = igc.gradient(st.parameters()) + gst = tmp.getStep().copy() + dirin = tmp.getStep().copy() + g2 = tmp.getGradientDerivative().copy() + } + return try { + val x: RealVector = st.parameters().vec().copy() + for (i in 0 until n) { + val xtf: Double = x.getEntry(i) + val dmin: Double = 8.0 * prec.eps2() * (abs(xtf) + prec.eps2()) + var d: Double = abs(gst.getEntry(i)) + if (d < dmin) { + d = dmin + } + for (icyc in 0 until ncycles()) { + var sag = 0.0 + var fs1 = 0.0 + var fs2 = 0.0 + var multpy = 0 + while (multpy < 5) { + x.setEntry(i, xtf + d) + fs1 = mfcn.value(x) + x.setEntry(i, xtf - d) + fs2 = mfcn.value(x) + x.setEntry(i, xtf) + sag = 0.5 * (fs1 + fs2 - 2.0 * amin) + if (sag > prec.eps2()) { + break + } + if (trafo.parameter(i).hasLimits()) { + if (d > 0.5) { + throw MnHesseFailedException("MnHesse: 2nd derivative zero for parameter") + } + d *= 10.0 + if (d > 0.5) { + d = 0.51 + } + multpy++ + continue + } + d *= 10.0 + multpy++ + } + if (multpy >= 5) { + throw MnHesseFailedException("MnHesse: 2nd derivative zero for parameter") + } + val g2bfor: Double = g2.getEntry(i) + g2.setEntry(i, 2.0 * sag / (d * d)) + grd.setEntry(i, (fs1 - fs2) / (2.0 * d)) + gst.setEntry(i, d) + dirin.setEntry(i, d) + yy.setEntry(i, fs1) + val dlast = d + d = sqrt(2.0 * aimsag / abs(g2.getEntry(i))) + if (trafo.parameter(i).hasLimits()) { + d = min(0.5, d) + } + if (d < dmin) { + d = dmin + } + + // see if converged + if (abs((d - dlast) / d) < tolerstp()) { + break + } + if (abs((g2.getEntry(i) - g2bfor) / g2.getEntry(i)) < tolerg2()) { + break + } + d = min(d, 10.0 * dlast) + d = max(d, 0.1 * dlast) + } + vhmat[i, i] = g2.getEntry(i) + if (mfcn.numOfCalls() - st.nfcn() > maxcalls) { + throw MnHesseFailedException("MnHesse: maximum number of allowed function calls exhausted.") + } + } + if (theStrategy.strategy() > 0) { + // refine first derivative + val hgc = HessianGradientCalculator(mfcn, trafo, theStrategy) + val gr: FunctionGradient = hgc.gradient(st.parameters(), FunctionGradient(grd, g2, gst)) + grd = gr.getGradient() + } + + //off-diagonal elements + for (i in 0 until n) { + x.setEntry(i, x.getEntry(i) + dirin.getEntry(i)) + for (j in i + 1 until n) { + x.setEntry(j, x.getEntry(j) + dirin.getEntry(j)) + val fs1: Double = mfcn.value(x) + val elem: Double = + (fs1 + amin - yy.getEntry(i) - yy.getEntry(j)) / (dirin.getEntry(i) * dirin.getEntry(j)) + vhmat[i, j] = elem + x.setEntry(j, x.getEntry(j) - dirin.getEntry(j)) + } + x.setEntry(i, x.getEntry(i) - dirin.getEntry(i)) + } + + //verify if matrix pos-def (still 2nd derivative) + val tmp: MinimumError = MnPosDef.test(MinimumError(vhmat, 1.0), prec) + vhmat = tmp.invHessian() + try { + vhmat.invert() + } catch (xx: SingularMatrixException) { + throw MnHesseFailedException("MnHesse: matrix inversion fails!") + } + val gr = FunctionGradient(grd, g2, gst) + if (tmp.isMadePosDef()) { + MINUITPlugin.logStatic("MnHesse: matrix is invalid!") + MINUITPlugin.logStatic("MnHesse: matrix is not pos. def.!") + MINUITPlugin.logStatic("MnHesse: matrix was forced pos. def.") + return MinimumState(st.parameters(), + MinimumError(vhmat, MnMadePosDef()), + gr, + st.edm(), + mfcn.numOfCalls()) + } + + //calculate edm + val err = MinimumError(vhmat, 0.0) + val edm: Double = VariableMetricEDMEstimator().estimate(gr, err) + MinimumState(st.parameters(), err, gr, edm, mfcn.numOfCalls()) + } catch (x: MnHesseFailedException) { + MINUITPlugin.logStatic(x.message) + MINUITPlugin.logStatic("MnHesse fails and will return diagonal matrix ") + var j = 0 + while (j < n) { + val tmp = if (g2.getEntry(j) < prec.eps2()) 1.0 else 1.0 / g2.getEntry(j) + vhmat[j, j] = if (tmp < prec.eps2()) 1.0 else tmp + j++ + } + MinimumState(st.parameters(), + MinimumError(vhmat, MnHesseFailed()), + st.gradient(), + st.edm(), + st.nfcn() + mfcn.numOfCalls()) + } + } + + /// forward interface of MnStrategy + fun ncycles(): Int { + return theStrategy.hessianNCycles() + } + + fun tolerg2(): Double { + return theStrategy.hessianG2Tolerance() + } + + fun tolerstp(): Double { + return theStrategy.hessianStepTolerance() + } + + private inner class MnHesseFailedException(message: String?) : java.lang.Exception(message) +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnLineSearch.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnLineSearch.kt new file mode 100644 index 000000000..7b1171d3c --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnLineSearch.kt @@ -0,0 +1,204 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.RealVector +import ru.inr.mass.minuit.* + +/** + * + * @version $Id$ + */ +internal object MnLineSearch { + fun search( + fcn: MnFcn, + st: MinimumParameters, + step: RealVector, + gdel: Double, + prec: MnMachinePrecision + ): MnParabolaPoint { + var overal = 1000.0 + var undral = -100.0 + val toler = 0.05 + var slamin = 0.0 + val slambg = 5.0 + val alpha = 2.0 + val maxiter = 12 + var niter = 0 + for (i in 0 until step.getDimension()) { + if (abs(step.getEntry(i)) < prec.eps()) { + continue + } + val ratio: Double = abs(st.vec().getEntry(i) / step.getEntry(i)) + if (abs(slamin) < prec.eps()) { + slamin = ratio + } + if (ratio < slamin) { + slamin = ratio + } + } + if (abs(slamin) < prec.eps()) { + slamin = prec.eps() + } + slamin *= prec.eps2() + val F0: Double = st.fval() + val F1: Double = fcn.value(MnUtils.add(st.vec(), step)) + var fvmin: Double = st.fval() + var xvmin = 0.0 + if (F1 < F0) { + fvmin = F1 + xvmin = 1.0 + } + var toler8 = toler + var slamax = slambg + var flast = F1 + var slam = 1.0 + var iterate = false + var p0 = MnParabolaPoint(0.0, F0) + var p1 = MnParabolaPoint(slam, flast) + var F2 = 0.0 + do { + // cut toler8 as function goes up + iterate = false + val pb: MnParabola = MnParabolaFactory.create(p0, gdel, p1) + var denom = 2.0 * (flast - F0 - gdel * slam) / (slam * slam) + if (abs(denom) < prec.eps()) { + denom = -0.1 * gdel + slam = 1.0 + } + if (abs(denom) > prec.eps()) { + slam = -gdel / denom + } + if (slam < 0.0) { + slam = slamax + } + if (slam > slamax) { + slam = slamax + } + if (slam < toler8) { + slam = toler8 + } + if (slam < slamin) { + return MnParabolaPoint(xvmin, fvmin) + } + if (abs(slam - 1.0) < toler8 && p1.y() < p0.y()) { + return MnParabolaPoint(xvmin, fvmin) + } + if (abs(slam - 1.0) < toler8) { + slam = 1.0 + toler8 + } + F2 = fcn.value(MnUtils.add(st.vec(), MnUtils.mul(step, slam))) + if (F2 < fvmin) { + fvmin = F2 + xvmin = slam + } + if (p0.y() - prec.eps() < fvmin && fvmin < p0.y() + prec.eps()) { + iterate = true + flast = F2 + toler8 = toler * slam + overal = slam - toler8 + slamax = overal + p1 = MnParabolaPoint(slam, flast) + niter++ + } + } while (iterate && niter < maxiter) + if (niter >= maxiter) { + // exhausted max number of iterations + return MnParabolaPoint(xvmin, fvmin) + } + var p2 = MnParabolaPoint(slam, F2) + do { + slamax = max(slamax, alpha * abs(xvmin)) + val pb: MnParabola = MnParabolaFactory.create(p0, p1, p2) + if (pb.a() < prec.eps2()) { + val slopem: Double = 2.0 * pb.a() * xvmin + pb.b() + slam = if (slopem < 0.0) { + xvmin + slamax + } else { + xvmin - slamax + } + } else { + slam = pb.min() + if (slam > xvmin + slamax) { + slam = xvmin + slamax + } + if (slam < xvmin - slamax) { + slam = xvmin - slamax + } + } + if (slam > 0.0) { + if (slam > overal) { + slam = overal + } + } else { + if (slam < undral) { + slam = undral + } + } + var F3 = 0.0 + do { + iterate = false + val toler9: Double = max(toler8, abs(toler8 * slam)) + // min. of parabola at one point + if (abs(p0.x() - slam) < toler9 || abs(p1.x() - slam) < toler9 || abs( + p2.x() - slam) < toler9 + ) { + return MnParabolaPoint(xvmin, fvmin) + } + F3 = fcn.value(MnUtils.add(st.vec(), MnUtils.mul(step, slam))) + // if latest point worse than all three previous, cut step + if (F3 > p0.y() && F3 > p1.y() && F3 > p2.y()) { + if (slam > xvmin) { + overal = min(overal, slam - toler8) + } + if (slam < xvmin) { + undral = max(undral, slam + toler8) + } + slam = 0.5 * (slam + xvmin) + iterate = true + niter++ + } + } while (iterate && niter < maxiter) + if (niter >= maxiter) { + // exhausted max number of iterations + return MnParabolaPoint(xvmin, fvmin) + } + + // find worst previous point out of three and replace + val p3 = MnParabolaPoint(slam, F3) + if (p0.y() > p1.y() && p0.y() > p2.y()) { + p0 = p3 + } else if (p1.y() > p0.y() && p1.y() > p2.y()) { + p1 = p3 + } else { + p2 = p3 + } + if (F3 < fvmin) { + fvmin = F3 + xvmin = slam + } else { + if (slam > xvmin) { + overal = min(overal, slam - toler8) + } + if (slam < xvmin) { + undral = max(undral, slam + toler8) + } + } + niter++ + } while (niter < maxiter) + return MnParabolaPoint(xvmin, fvmin) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMachinePrecision.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMachinePrecision.kt new file mode 100644 index 000000000..161ee0c0a --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMachinePrecision.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * Determines the relative floating point arithmetic precision. The + * setPrecision() method can be used to override Minuit's own determination, + * when the user knows that the {FCN} function value is not calculated to the + * nominal machine accuracy. + * + * @version $Id$ + * @author Darksnake + */ +class MnMachinePrecision internal constructor() { + private var theEpsMa2 = 0.0 + private var theEpsMac = 0.0 + + /** + * eps returns the smallest possible number so that 1.+eps > 1. + * @return + */ + fun eps(): Double { + return theEpsMac + } + + /** + * eps2 returns 2*sqrt(eps) + * @return + */ + fun eps2(): Double { + return theEpsMa2 + } + + /** + * override Minuit's own determination + * + * @param prec a double. + */ + fun setPrecision(prec: Double) { + theEpsMac = prec + theEpsMa2 = 2.0 * sqrt(theEpsMac) + } + + init { + setPrecision(4.0E-7) + var epstry = 0.5 + val one = 1.0 + for (i in 0..99) { + epstry *= 0.5 + val epsp1 = one + epstry + val epsbak = epsp1 - one + if (epsbak < epstry) { + setPrecision(8.0 * epstry) + break + } + } + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMigrad.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMigrad.kt new file mode 100644 index 000000000..22616a1a6 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMigrad.kt @@ -0,0 +1,136 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction + +/** + * MnMigrad provides minimization of the function by the method of MIGRAD, the + * most efficient and complete single method, recommended for general functions, + * and the functionality for parameters interaction. It also retains the result + * from the last minimization in case the user may want to do subsequent + * minimization steps with parameter interactions in between the minimization + * requests. The minimization produces as a by-product the error matrix of the + * parameters, which is usually reliable unless warning messages are produced. + * + * @version $Id$ + * @author Darksnake + */ +class MnMigrad +/** + * construct from MultiFunction + MnUserParameterState + MnStrategy + * + * @param str a [hep.dataforge.MINUIT.MnStrategy] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. + * @param fcn a [MultiFunction] object. + */ + (fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { + private val theMinimizer: VariableMetricMinimizer = VariableMetricMinimizer() + + /** + * construct from MultiFunction + double[] for parameters and errors + * with default strategy + * + * @param err an array of double. + * @param par an array of double. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + double[] for parameters and errors + * + * @param stra a int. + * @param err an array of double. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, + MnUserParameterState(par, err), + MnStrategy(stra)) + + /** + * construct from MultiFunction + double[] for parameters and + * MnUserCovariance with default strategy + * + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param par an array of double. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + double[] for parameters and + * MnUserCovariance + * + * @param stra a int. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, + MnUserParameterState(par, cov), + MnStrategy(stra)) + + /** + * construct from MultiFunction + MnUserParameters with default + * strategy + * + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + MnUserParameters + * + * @param stra a int. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, + MnUserParameterState(par), + MnStrategy(stra)) + + /** + * construct from MultiFunction + MnUserParameters + MnUserCovariance + * with default strategy + * + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, + par, + cov, + DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + MnUserParameters + MnUserCovariance + * + * @param stra a int. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, + MnUserParameterState(par, cov), + MnStrategy(stra)) + + override fun minimizer(): ModularFunctionMinimizer { + return theMinimizer + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinimize.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinimize.kt new file mode 100644 index 000000000..ea14a5453 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinimize.kt @@ -0,0 +1,133 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction + +/** + * Causes minimization of the function by the method of MIGRAD, as does the + * MnMigrad class, but switches to the SIMPLEX method if MIGRAD fails to + * converge. Constructor arguments, methods arguments and names of methods are + * the same as for MnMigrad or MnSimplex. + * + * @version $Id$ + * @author Darksnake + */ +class MnMinimize +/** + * construct from MultiFunction + MnUserParameterState + MnStrategy + * + * @param str a [hep.dataforge.MINUIT.MnStrategy] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. + * @param fcn a [MultiFunction] object. + */ + (fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { + private val theMinimizer: CombinedMinimizer = CombinedMinimizer() + + /** + * construct from MultiFunction + double[] for parameters and errors + * with default strategy + * + * @param err an array of double. + * @param par an array of double. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + double[] for parameters and errors + * + * @param stra a int. + * @param err an array of double. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, + MnUserParameterState(par, err), + MnStrategy(stra)) + + /** + * construct from MultiFunction + double[] for parameters and + * MnUserCovariance with default strategy + * + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param par an array of double. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + double[] for parameters and + * MnUserCovariance + * + * @param stra a int. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, + MnUserParameterState(par, cov), + MnStrategy(stra)) + + /** + * construct from MultiFunction + MnUserParameters with default + * strategy + * + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + MnUserParameters + * + * @param stra a int. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, + MnUserParameterState(par), + MnStrategy(stra)) + + /** + * construct from MultiFunction + MnUserParameters + MnUserCovariance + * with default strategy + * + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, + par, + cov, + DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + MnUserParameters + MnUserCovariance + * + * @param stra a int. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, + MnUserParameterState(par, cov), + MnStrategy(stra)) + + override fun minimizer(): ModularFunctionMinimizer { + return theMinimizer + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinos.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinos.kt new file mode 100644 index 000000000..d49379b3b --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinos.kt @@ -0,0 +1,379 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction +import ru.inr.mass.minuit.* +import kotlin.jvm.JvmOverloads + +/** + * API class for Minos error analysis (asymmetric errors). Minimization has to + * be done before and minimum must be valid; possibility to ask only for one + * side of the Minos error; + * + * @version $Id$ + * @author Darksnake + */ +class MnMinos(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) { + private var theFCN: MultiFunction? = null + private var theMinimum: FunctionMinimum? = null + private var theStrategy: MnStrategy? = null + + /** + * construct from FCN + minimum + * + * @param fcn a [MultiFunction] object. + * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. + */ + constructor(fcn: MultiFunction?, min: FunctionMinimum?) : this(fcn, min, MnApplication.DEFAULT_STRATEGY) + + /** + * construct from FCN + minimum + strategy + * + * @param stra a int. + * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, min: FunctionMinimum?, stra: Int) : this(fcn, min, MnStrategy(stra)) + // public MnMinos(MultiFunction fcn, MnUserParameterState state, double errDef, MnStrategy stra) { + // theFCN = fcn; + // theStrategy = stra; + // + // MinimumState minState = null; + // + // MnUserTransformation transformation = state.getTransformation(); + // + // MinimumSeed seed = new MinimumSeed(minState, transformation); + // + // theMinimum = new FunctionMinimum(seed,errDef); + // } + /** + * + * loval. + * + * @param par a int. + * @return a [hep.dataforge.MINUIT.MnCross] object. + */ + fun loval(par: Int): MnCross { + return loval(par, 1.0) + } + + /** + * + * loval. + * + * @param par a int. + * @param errDef a double. + * @return a [hep.dataforge.MINUIT.MnCross] object. + */ + fun loval(par: Int, errDef: Double): MnCross { + return loval(par, errDef, MnApplication.DEFAULT_MAXFCN) + } + + /** + * + * loval. + * + * @param par a int. + * @param errDef a double. + * @param maxcalls a int. + * @return a [hep.dataforge.MINUIT.MnCross] object. + */ + fun loval(par: Int, errDef: Double, maxcalls: Int): MnCross { + var errDef = errDef + var maxcalls = maxcalls + errDef *= theMinimum!!.errorDef() + assert(theMinimum!!.isValid()) + assert(!theMinimum!!.userState().parameter(par).isFixed()) + assert(!theMinimum!!.userState().parameter(par).isConst()) + if (maxcalls == 0) { + val nvar: Int = theMinimum!!.userState().variableParameters() + maxcalls = 2 * (nvar + 1) * (200 + 100 * nvar + 5 * nvar * nvar) + } + val para = intArrayOf(par) + val upar: MnUserParameterState = theMinimum!!.userState().copy() + val err: Double = upar.error(par) + val `val`: Double = upar.value(par) - err + val xmid = doubleArrayOf(`val`) + val xdir = doubleArrayOf(-err) + val ind: Int = upar.intOfExt(par) + val m: MnAlgebraicSymMatrix = theMinimum!!.error().matrix() + val xunit: Double = sqrt(errDef / err) + for (i in 0 until m.nrow()) { + if (i == ind) { + continue + } + val xdev: Double = xunit * m[ind, i] + val ext: Int = upar.extOfInt(i) + upar.setValue(ext, upar.value(ext) - xdev) + } + upar.fix(par) + upar.setValue(par, `val`) + val toler = 0.1 + val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef) + val aopt: MnCross = cross.cross(para, xmid, xdir, toler, maxcalls) + if (aopt.atLimit()) { + MINUITPlugin.logStatic("MnMinos parameter $par is at lower limit.") + } + if (aopt.atMaxFcn()) { + MINUITPlugin.logStatic("MnMinos maximum number of function calls exceeded for parameter $par") + } + if (aopt.newMinimum()) { + MINUITPlugin.logStatic("MnMinos new minimum found while looking for parameter $par") + } + if (!aopt.isValid()) { + MINUITPlugin.logStatic("MnMinos could not find lower value for parameter $par.") + } + return aopt + } + /** + * calculate one side (negative or positive error) of the parameter + * + * @param maxcalls a int. + * @param par a int. + * @param errDef a double. + * @return a double. + */ + /** + * + * lower. + * + * @param par a int. + * @param errDef a double. + * @return a double. + */ + /** + * + * lower. + * + * @param par a int. + * @return a double. + */ + @JvmOverloads + fun lower(par: Int, errDef: Double = 1.0, maxcalls: Int = MnApplication.DEFAULT_MAXFCN): Double { + val upar: MnUserParameterState = theMinimum!!.userState() + val err: Double = theMinimum!!.userState().error(par) + val aopt: MnCross = loval(par, errDef, maxcalls) + return if (aopt.isValid()) -1.0 * err * (1.0 + aopt.value()) else if (aopt.atLimit()) upar.parameter(par) + .lowerLimit() else upar.value(par) + } + + /** + * + * minos. + * + * @param par a int. + * @return a [hep.dataforge.MINUIT.MinosError] object. + */ + fun minos(par: Int): MinosError { + return minos(par, 1.0) + } + + /** + * + * minos. + * + * @param par a int. + * @param errDef a double. + * @return a [hep.dataforge.MINUIT.MinosError] object. + */ + fun minos(par: Int, errDef: Double): MinosError { + return minos(par, errDef, MnApplication.DEFAULT_MAXFCN) + } + + /** + * Causes a MINOS error analysis to be performed on the parameter whose + * number is specified. MINOS errors may be expensive to calculate, but are + * very reliable since they take account of non-linearities in the problem + * as well as parameter correlations, and are in general asymmetric. + * + * @param maxcalls Specifies the (approximate) maximum number of function + * calls per parameter requested, after which the calculation will be + * stopped for that parameter. + * @param errDef a double. + * @param par a int. + * @return a [hep.dataforge.MINUIT.MinosError] object. + */ + fun minos(par: Int, errDef: Double, maxcalls: Int): MinosError { + assert(theMinimum!!.isValid()) + assert(!theMinimum!!.userState().parameter(par).isFixed()) + assert(!theMinimum!!.userState().parameter(par).isConst()) + val up: MnCross = upval(par, errDef, maxcalls) + val lo: MnCross = loval(par, errDef, maxcalls) + return MinosError(par, theMinimum!!.userState().value(par), lo, up) + } + + /** + * + * range. + * + * @param par a int. + * @return + */ + fun range(par: Int): Range { + return range(par, 1.0) + } + + /** + * + * range. + * + * @param par a int. + * @param errDef a double. + * @return + */ + fun range(par: Int, errDef: Double): Range { + return range(par, errDef, MnApplication.DEFAULT_MAXFCN) + } + + /** + * Causes a MINOS error analysis for external parameter n. + * + * @param maxcalls a int. + * @param errDef a double. + * @return The lower and upper bounds of parameter + * @param par a int. + */ + fun range(par: Int, errDef: Double, maxcalls: Int): Range { + val mnerr: MinosError = minos(par, errDef, maxcalls) + return mnerr.range() + } + /** + * + * upper. + * + * @param par a int. + * @param errDef a double. + * @param maxcalls a int. + * @return a double. + */ + /** + * + * upper. + * + * @param par a int. + * @param errDef a double. + * @return a double. + */ + /** + * + * upper. + * + * @param par a int. + * @return a double. + */ + @JvmOverloads + fun upper(par: Int, errDef: Double = 1.0, maxcalls: Int = MnApplication.DEFAULT_MAXFCN): Double { + val upar: MnUserParameterState = theMinimum!!.userState() + val err: Double = theMinimum!!.userState().error(par) + val aopt: MnCross = upval(par, errDef, maxcalls) + return if (aopt.isValid()) err * (1.0 + aopt.value()) else if (aopt.atLimit()) upar.parameter(par) + .upperLimit() else upar.value(par) + } + + /** + * + * upval. + * + * @param par a int. + * @return a [hep.dataforge.MINUIT.MnCross] object. + */ + fun upval(par: Int): MnCross { + return upval(par, 1.0) + } + + /** + * + * upval. + * + * @param par a int. + * @param errDef a double. + * @return a [hep.dataforge.MINUIT.MnCross] object. + */ + fun upval(par: Int, errDef: Double): MnCross { + return upval(par, errDef, MnApplication.DEFAULT_MAXFCN) + } + + /** + * + * upval. + * + * @param par a int. + * @param errDef a double. + * @param maxcalls a int. + * @return a [hep.dataforge.MINUIT.MnCross] object. + */ + fun upval(par: Int, errDef: Double, maxcalls: Int): MnCross { + var errDef = errDef + var maxcalls = maxcalls + errDef *= theMinimum!!.errorDef() + assert(theMinimum!!.isValid()) + assert(!theMinimum!!.userState().parameter(par).isFixed()) + assert(!theMinimum!!.userState().parameter(par).isConst()) + if (maxcalls == 0) { + val nvar: Int = theMinimum!!.userState().variableParameters() + maxcalls = 2 * (nvar + 1) * (200 + 100 * nvar + 5 * nvar * nvar) + } + val para = intArrayOf(par) + val upar: MnUserParameterState = theMinimum!!.userState().copy() + val err: Double = upar.error(par) + val `val`: Double = upar.value(par) + err + val xmid = doubleArrayOf(`val`) + val xdir = doubleArrayOf(err) + val ind: Int = upar.intOfExt(par) + val m: MnAlgebraicSymMatrix = theMinimum!!.error().matrix() + val xunit: Double = sqrt(errDef / err) + for (i in 0 until m.nrow()) { + if (i == ind) { + continue + } + val xdev: Double = xunit * m[ind, i] + val ext: Int = upar.extOfInt(i) + upar.setValue(ext, upar.value(ext) + xdev) + } + upar.fix(par) + upar.setValue(par, `val`) + val toler = 0.1 + val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef) + val aopt: MnCross = cross.cross(para, xmid, xdir, toler, maxcalls) + if (aopt.atLimit()) { + MINUITPlugin.logStatic("MnMinos parameter $par is at upper limit.") + } + if (aopt.atMaxFcn()) { + MINUITPlugin.logStatic("MnMinos maximum number of function calls exceeded for parameter $par") + } + if (aopt.newMinimum()) { + MINUITPlugin.logStatic("MnMinos new minimum found while looking for parameter $par") + } + if (!aopt.isValid()) { + MINUITPlugin.logStatic("MnMinos could not find upper value for parameter $par.") + } + return aopt + } + + /** + * construct from FCN + minimum + strategy + * + * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. + * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. + * @param fcn a [MultiFunction] object. + */ + init { + theFCN = fcn + theMinimum = min + theStrategy = stra + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabola.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabola.kt new file mode 100644 index 000000000..a0a56dedd --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabola.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * parabola = a*xx + b*x + c + * + * @version $Id$ + */ +internal class MnParabola(private val theA: Double, private val theB: Double, private val theC: Double) { + fun a(): Double { + return theA + } + + fun b(): Double { + return theB + } + + fun c(): Double { + return theC + } + + fun min(): Double { + return -theB / (2.0 * theA) + } + + fun x_neg(y: Double): Double { + return -sqrt(y / theA + min() * min() - theC / theA) + min() + } + + fun x_pos(y: Double): Double { + return sqrt(y / theA + min() * min() - theC / theA) + min() + } + + fun y(x: Double): Double { + return theA * x * x + theB * x + theC + } + + fun ymin(): Double { + return -theB * theB / (4.0 * theA) + theC + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaFactory.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaFactory.kt new file mode 100644 index 000000000..f45d2b9c9 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaFactory.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal object MnParabolaFactory { + fun create(p1: MnParabolaPoint, p2: MnParabolaPoint, p3: MnParabolaPoint): MnParabola { + var x1: Double = p1.x() + var x2: Double = p2.x() + var x3: Double = p3.x() + val dx12 = x1 - x2 + val dx13 = x1 - x3 + val dx23 = x2 - x3 + val xm = (x1 + x2 + x3) / 3.0 + x1 -= xm + x2 -= xm + x3 -= xm + val y1: Double = p1.y() + val y2: Double = p2.y() + val y3: Double = p3.y() + val a = y1 / (dx12 * dx13) - y2 / (dx12 * dx23) + y3 / (dx13 * dx23) + var b = -y1 * (x2 + x3) / (dx12 * dx13) + y2 * (x1 + x3) / (dx12 * dx23) - y3 * (x1 + x2) / (dx13 * dx23) + var c = y1 - a * x1 * x1 - b * x1 + c += xm * (xm * a - b) + b -= 2.0 * xm * a + return MnParabola(a, b, c) + } + + fun create(p1: MnParabolaPoint, dxdy1: Double, p2: MnParabolaPoint): MnParabola { + val x1: Double = p1.x() + val xx1 = x1 * x1 + val x2: Double = p2.x() + val xx2 = x2 * x2 + val y1: Double = p1.y() + val y12: Double = p1.y() - p2.y() + val det = xx1 - xx2 - 2.0 * x1 * (x1 - x2) + val a = -(y12 + (x2 - x1) * dxdy1) / det + val b = -(-2.0 * x1 * y12 + (xx1 - xx2) * dxdy1) / det + val c = y1 - a * xx1 - b * x1 + return MnParabola(a, b, c) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaPoint.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaPoint.kt new file mode 100644 index 000000000..858e010e6 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaPoint.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal class MnParabolaPoint(private val theX: Double, private val theY: Double) { + fun x(): Double { + return theX + } + + fun y(): Double { + return theY + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParameterScan.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParameterScan.kt new file mode 100644 index 000000000..7791c20e8 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParameterScan.kt @@ -0,0 +1,113 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction + +/** + * Scans the values of FCN as a function of one parameter and retains the best + * function and parameter values found + * + * @version $Id$ + */ +internal class MnParameterScan { + private var theAmin: Double + private var theFCN: MultiFunction? + private var theParameters: MnUserParameters + + constructor(fcn: MultiFunction, par: MnUserParameters) { + theFCN = fcn + theParameters = par + theAmin = fcn.value(par.params()) + } + + constructor(fcn: MultiFunction?, par: MnUserParameters, fval: Double) { + theFCN = fcn + theParameters = par + theAmin = fval + } + + fun fval(): Double { + return theAmin + } + + fun parameters(): MnUserParameters { + return theParameters + } + + fun scan(par: Int): List { + return scan(par, 41) + } + + fun scan(par: Int, maxsteps: Int): List { + return scan(par, maxsteps, 0.0, 0.0) + } + + /** + * returns pairs of (x,y) points, x=parameter value, y=function value of FCN + * @param high + * @return + */ + fun scan(par: Int, maxsteps: Int, low: Double, high: Double): List { + var maxsteps = maxsteps + var low = low + var high = high + if (maxsteps > 101) { + maxsteps = 101 + } + val result: MutableList = java.util.ArrayList(maxsteps + 1) + val params: DoubleArray = theParameters.params() + result.add(Range(params[par], theAmin)) + if (low > high) { + return result + } + if (maxsteps < 2) { + return result + } + if (low == 0.0 && high == 0.0) { + low = params[par] - 2.0 * theParameters.error(par) + high = params[par] + 2.0 * theParameters.error(par) + } + if (low == 0.0 && high == 0.0 && theParameters.parameter(par).hasLimits()) { + if (theParameters.parameter(par).hasLowerLimit()) { + low = theParameters.parameter(par).lowerLimit() + } + if (theParameters.parameter(par).hasUpperLimit()) { + high = theParameters.parameter(par).upperLimit() + } + } + if (theParameters.parameter(par).hasLimits()) { + if (theParameters.parameter(par).hasLowerLimit()) { + low = max(low, theParameters.parameter(par).lowerLimit()) + } + if (theParameters.parameter(par).hasUpperLimit()) { + high = min(high, theParameters.parameter(par).upperLimit()) + } + } + val x0 = low + val stp = (high - low) / (maxsteps - 1.0) + for (i in 0 until maxsteps) { + params[par] = x0 + i.toDouble() * stp + val fval: Double = theFCN.value(params) + if (fval < theAmin) { + theParameters.setValue(par, params[par]) + theAmin = fval + } + result.add(Range(params[par], fval)) + } + return result + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPlot.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPlot.kt new file mode 100644 index 000000000..656dd8d35 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPlot.kt @@ -0,0 +1,438 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import java.lang.StringBuffer +import kotlin.jvm.JvmOverloads + +/** + * MnPlot produces a text-screen graphical output of (x,y) points. E.g. from + * Scan or Contours. + * + * @version $Id$ + * @author Darksnake + */ +class MnPlot @JvmOverloads constructor(private val thePageWidth: Int = 80, private val thePageLength: Int = 30) { + private var bh = 0.0 + private var bl = 0.0 + private var bwid = 0.0 + private var nb = 0 + fun length(): Int { + return thePageLength + } + + private fun mnbins(a1: Double, a2: Double, naa: Int) { + + //*-*-*-*-*-*-*-*-*-*-*Compute reasonable histogram intervals*-*-*-*-*-*-*-*-* + //*-* ====================================== + //*-* Function TO DETERMINE REASONABLE HISTOGRAM INTERVALS + //*-* GIVEN ABSOLUTE UPPER AND LOWER BOUNDS A1 AND A2 + //*-* AND DESIRED MAXIMUM NUMBER OF BINS NAA + //*-* PROGRAM MAKES REASONABLE BINNING FROM BL TO BH OF WIDTH BWID + //*-* F. JAMES, AUGUST, 1974 , stolen for Minuit, 1988 + //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* + + /* Local variables */ + var awid: Double + var ah: Double + var sigfig: Double + var sigrnd: Double + var alb: Double + var kwid: Int + var lwid: Int + var na = 0 + var log_: Int + val al: Double = if (a1 < a2) a1 else a2 + ah = if (a1 > a2) a1 else a2 + if (al == ah) { + ah = al + 1 + } + + //*-*- IF NAA .EQ. -1 , PROGRAM USES BWID INPUT FROM CALLING ROUTINE + var skip = naa == -1 && bwid > 0 + if (!skip) { + na = naa - 1 + if (na < 1) { + na = 1 + } + } + while (true) { + if (!skip) { + //*-*- GET NOMINAL BIN WIDTH IN EXPON FORM + awid = (ah - al) / na.toDouble() + log_ = log10(awid) + if (awid <= 1) { + --log_ + } + sigfig = awid * pow(10.0, -log_.toDouble()) + //*-*- ROUND MANTISSA UP TO 2, 2.5, 5, OR 10 + if (sigfig <= 2) { + sigrnd = 2.0 + } else if (sigfig <= 2.5) { + sigrnd = 2.5 + } else if (sigfig <= 5) { + sigrnd = 5.0 + } else { + sigrnd = 1.0 + ++log_ + } + bwid = sigrnd * pow(10.0, log_.toDouble()) + } + alb = al / bwid + lwid = alb.toInt() + if (alb < 0) { + --lwid + } + bl = bwid * lwid.toDouble() + alb = ah / bwid + 1 + kwid = alb.toInt() + if (alb < 0) { + --kwid + } + bh = bwid * kwid.toDouble() + nb = kwid - lwid + if (naa <= 5) { + if (naa == -1) { + return + } + //*-*- REQUEST FOR ONE BIN IS DIFFICULT CASE + if (naa > 1 || nb == 1) { + return + } + bwid *= 2.0 + nb = 1 + return + } + if (nb shl 1 != naa) { + return + } + ++na + skip = false + continue + } + } + + private fun mnplot(xpt: DoubleArray, ypt: DoubleArray, chpt: StringBuffer, nxypt: Int, npagwd: Int, npagln: Int) { + //*-*-*-*Plots points in array xypt onto one page with labelled axes*-*-*-*-* + //*-* =========================================================== + //*-* NXYPT is the number of points to be plotted + //*-* XPT(I) = x-coord. of ith point + //*-* YPT(I) = y-coord. of ith point + //*-* CHPT(I) = character to be plotted at this position + //*-* the input point arrays XPT, YPT, CHPT are destroyed. + //*-* + //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* + + /* Local variables */ + var xmin: Double + var xmax: Double + var ymax: Double + var savx: Double + var savy: Double + var yprt: Double + var xbest: Double + var ybest: Double + val xvalus = DoubleArray(12) + val any: Double + val iten: Int + var j: Int + var k: Int + var maxnx: Int + var maxny: Int + var iquit: Int + var ni: Int + var linodd: Int + var ibk: Int + var isp1: Int + var ks: Int + var ix: Int + var overpr: Boolean + val cline = StringBuffer(npagwd) + for (ii in 0 until npagwd) { + cline.append(' ') + } + var chsav: Char + val chbest: Char + + /* Function Body */ + //*-* Computing MIN + maxnx = if (npagwd - 20 < 100) npagwd - 20 else 100 + if (maxnx < 10) { + maxnx = 10 + } + maxny = npagln + if (maxny < 10) { + maxny = 10 + } + if (nxypt <= 1) { + return + } + xbest = xpt[0] + ybest = ypt[0] + chbest = chpt.get(0) + //*-*- order the points by decreasing y + val km1: Int = nxypt - 1 + var i: Int = 1 + while (i <= km1) { + iquit = 0 + ni = nxypt - i + j = 1 + while (j <= ni) { + if (ypt[j - 1] > ypt[j]) { + ++j + continue + } + savx = xpt[j - 1] + xpt[j - 1] = xpt[j] + xpt[j] = savx + savy = ypt[j - 1] + ypt[j - 1] = ypt[j] + ypt[j] = savy + chsav = chpt.get(j - 1) + chpt.setCharAt(j - 1, chpt.get(j)) + chpt.setCharAt(j, chsav) + iquit = 1 + ++j + } + if (iquit == 0) { + break + } + ++i + } + //*-*- find extreme values + xmax = xpt[0] + xmin = xmax + i = 1 + while (i <= nxypt) { + if (xpt[i - 1] > xmax) { + xmax = xpt[i - 1] + } + if (xpt[i - 1] < xmin) { + xmin = xpt[i - 1] + } + ++i + } + val dxx: Double = (xmax - xmin) * .001 + xmax += dxx + xmin -= dxx + mnbins(xmin, xmax, maxnx) + xmin = bl + xmax = bh + var nx: Int = nb + val bwidx: Double = bwid + ymax = ypt[0] + var ymin: Double = ypt[nxypt - 1] + if (ymax == ymin) { + ymax = ymin + 1 + } + val dyy: Double = (ymax - ymin) * .001 + ymax += dyy + ymin -= dyy + mnbins(ymin, ymax, maxny) + ymin = bl + ymax = bh + var ny: Int = nb + val bwidy: Double = bwid + any = ny.toDouble() + //*-*- if first point is blank, it is an 'origin' + if (chbest != ' ') { + xbest = (xmax + xmin) * .5 + ybest = (ymax + ymin) * .5 + } + //*-*- find scale constants + val ax: Double = 1 / bwidx + val ay: Double = 1 / bwidy + val bx: Double = -ax * xmin + 2 + val by: Double = -ay * ymin - 2 + //*-*- convert points to grid positions + i = 1 + while (i <= nxypt) { + xpt[i - 1] = ax * xpt[i - 1] + bx + ypt[i - 1] = any - ay * ypt[i - 1] - by + ++i + } + val nxbest: Int = (ax * xbest + bx).toInt() + val nybest: Int = (any - ay * ybest - by).toInt() + //*-*- print the points + ny += 2 + nx += 2 + isp1 = 1 + linodd = 1 + overpr = false + i = 1 + while (i <= ny) { + ibk = 1 + while (ibk <= nx) { + cline.setCharAt(ibk - 1, ' ') + ++ibk + } + // cline.setCharAt(nx,'\0'); + // cline.setCharAt(nx+1,'\0'); + cline.setCharAt(0, '.') + cline.setCharAt(nx - 1, '.') + cline.setCharAt(nxbest - 1, '.') + if (i == 1 || i == nybest || i == ny) { + j = 1 + while (j <= nx) { + cline.setCharAt(j - 1, '.') + ++j + } + } + yprt = ymax - (i - 1.0) * bwidy + var isplset = false + if (isp1 <= nxypt) { + //*-*- find the points to be plotted on this line + k = isp1 + while (k <= nxypt) { + ks = ypt[k - 1].toInt() + if (ks > i) { + isp1 = k + isplset = true + break + } + ix = xpt[k - 1].toInt() + if (cline.get(ix - 1) != '.' && cline.get(ix - 1) != ' ') { + if (cline.get(ix - 1) == chpt.get(k - 1)) { + ++k + continue + } + overpr = true + //*-*- OVERPR is true if one or more positions contains more than + //*-*- one point + cline.setCharAt(ix - 1, '&') + ++k + continue + } + cline.setCharAt(ix - 1, chpt.get(k - 1)) + ++k + } + if (!isplset) { + isp1 = nxypt + 1 + } + } + if (linodd != 1 && i != ny) { + linodd = 1 + java.lang.System.out.printf(" %s", cline.substring(0, 60)) + } else { + java.lang.System.out.printf(" %14.7g ..%s", yprt, cline.substring(0, 60)) + linodd = 0 + } + println() + ++i + } + //*-*- print labels on x-axis every ten columns + ibk = 1 + while (ibk <= nx) { + cline.setCharAt(ibk - 1, ' ') + if (ibk % 10 == 1) { + cline.setCharAt(ibk - 1, '/') + } + ++ibk + } + java.lang.System.out.printf(" %s", cline) + java.lang.System.out.printf("\n") + ibk = 1 + while (ibk <= 12) { + xvalus[ibk - 1] = xmin + (ibk - 1.0) * 10 * bwidx + ++ibk + } + java.lang.System.out.printf(" ") + iten = (nx + 9) / 10 + ibk = 1 + while (ibk <= iten) { + java.lang.System.out.printf(" %9.4g", xvalus[ibk - 1]) + ++ibk + } + java.lang.System.out.printf("\n") + if (overpr) { + val chmess = " Overprint character is &" + java.lang.System.out.printf(" ONE COLUMN=%13.7g%s", bwidx, chmess) + } else { + val chmess = " " + java.lang.System.out.printf(" ONE COLUMN=%13.7g%s", bwidx, chmess) + } + println() + } + + /** + * + * plot. + * + * @param points a [List] object. + */ + fun plot(points: List) { + val x = DoubleArray(points.size) + val y = DoubleArray(points.size) + val chpt = StringBuffer(points.size) + for ((i, ipoint) in points.withIndex()) { + x[i] = ipoint.getFirst() + y[i] = ipoint.getSecond() + chpt.append('*') + } + mnplot(x, y, chpt, points.size, width(), length()) + } + + /** + * + * plot. + * + * @param xmin a double. + * @param ymin a double. + * @param points a [List] object. + */ + fun plot(xmin: Double, ymin: Double, points: List) { + val x = DoubleArray(points.size + 2) + x[0] = xmin + x[1] = xmin + val y = DoubleArray(points.size + 2) + y[0] = ymin + y[1] = ymin + val chpt = StringBuffer(points.size + 2) + chpt.append(' ') + chpt.append('X') + var i = 2 + for (ipoint in points) { + x[i] = ipoint.getFirst() + y[i] = ipoint.getSecond() + chpt.append('*') + i++ + } + mnplot(x, y, chpt, points.size + 2, width(), length()) + } + + fun width(): Int { + return thePageWidth + } + /** + * + * Constructor for MnPlot. + * + * @param thePageWidth a int. + * @param thePageLength a int. + */ + /** + * + * Constructor for MnPlot. + */ + init { + if (thePageWidth > 120) { + thePageWidth = 120 + } + if (thePageLength > 56) { + thePageLength = 56 + } + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPosDef.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPosDef.kt new file mode 100644 index 000000000..f94e387d9 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPosDef.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import space.kscience.kmath.optimization.minuit.MINUITPlugin + +/** + * + * @version $Id$ + */ +internal object MnPosDef { + fun test(st: MinimumState, prec: MnMachinePrecision): MinimumState { + val err: MinimumError = test(st.error(), prec) + return MinimumState(st.parameters(), err, st.gradient(), st.edm(), st.nfcn()) + } + + fun test(e: MinimumError, prec: MnMachinePrecision): MinimumError { + val err: MnAlgebraicSymMatrix = e.invHessian().copy() + if (err.size() === 1 && err[0, 0] < prec.eps()) { + err[0, 0] = 1.0 + return MinimumError(err, MnMadePosDef()) + } + if (err.size() === 1 && err[0, 0] > prec.eps()) { + return e + } + // std::cout<<"MnPosDef init matrix= "< 0.0) { + os.printf(" limited || %10g", ipar.value()) + if (abs(ipar.value() - ipar.lowerLimit()) < par.precision().eps2()) { + os.print("* ") + atLoLim = true + } + if (abs(ipar.value() - ipar.upperLimit()) < par.precision().eps2()) { + os.print("**") + atHiLim = true + } + os.printf(" || %10g\n", ipar.error()) + } else { + os.printf(" free || %10g || no\n", ipar.value()) + } + } else { + if (ipar.error() > 0.0) { + os.printf(" free || %10g || %10g\n", ipar.value(), ipar.error()) + } else { + os.printf(" free || %10g || no\n", ipar.value()) + } + } + } + os.println() + if (atLoLim) { + os.print("* parameter is at lower limit") + } + if (atHiLim) { + os.print("** parameter is at upper limit") + } + os.println() + } + + /** + * + * print. + * + * @param os a [PrintWriter] object. + * @param matrix a [hep.dataforge.MINUIT.MnUserCovariance] object. + */ + fun print(os: PrintWriter, matrix: MnUserCovariance) { + os.println() + os.println("MnUserCovariance: ") + run { + os.println() + val n: Int = matrix.nrow() + for (i in 0 until n) { + for (j in 0 until n) { + os.printf("%10g ", matrix[i, j]) + } + os.println() + } + } + os.println() + os.println("MnUserCovariance parameter correlations: ") + run { + os.println() + val n: Int = matrix.nrow() + for (i in 0 until n) { + val di: Double = matrix[i, i] + for (j in 0 until n) { + val dj: Double = matrix[j, j] + os.printf("%g ", matrix[i, j] / sqrt(abs(di * dj))) + } + os.println() + } + } + } + + /** + * + * print. + * + * @param os a [PrintWriter] object. + * @param coeff a [hep.dataforge.MINUIT.MnGlobalCorrelationCoeff] object. + */ + fun print(os: PrintWriter, coeff: MnGlobalCorrelationCoeff) { + os.println() + os.println("MnGlobalCorrelationCoeff: ") + run { + os.println() + for (i in 0 until coeff.globalCC().length) { + os.printf("%g\n", coeff.globalCC()[i]) + } + } + } + + /** + * + * print. + * + * @param os a [PrintWriter] object. + * @param state a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun print(os: PrintWriter, state: MnUserParameterState) { + os.println() + if (!state.isValid()) { + os.println() + os.println("WARNING: MnUserParameterState is not valid.") + os.println() + } + os.println("# of function calls: " + state.nfcn()) + os.println("function value: " + state.fval()) + os.println("expected distance to the minimum (edm): " + state.edm()) + os.println("external parameters: " + state.parameters()) + if (state.hasCovariance()) { + os.println("covariance matrix: " + state.covariance()) + } + if (state.hasGlobalCC()) { + os.println("global correlation coefficients : " + state.globalCC()) + } + if (!state.isValid()) { + os.println("WARNING: MnUserParameterState is not valid.") + } + os.println() + } + + /** + * + * print. + * + * @param os a [PrintWriter] object. + * @param me a [hep.dataforge.MINUIT.MinosError] object. + */ + fun print(os: PrintWriter, me: MinosError) { + os.println() + os.printf("Minos # of function calls: %d\n", me.nfcn()) + if (!me.isValid()) { + os.println("Minos error is not valid.") + } + if (!me.lowerValid()) { + os.println("lower Minos error is not valid.") + } + if (!me.upperValid()) { + os.println("upper Minos error is not valid.") + } + if (me.atLowerLimit()) { + os.println("Minos error is lower limit of parameter " + me.parameter()) + } + if (me.atUpperLimit()) { + os.println("Minos error is upper limit of parameter " + me.parameter()) + } + if (me.atLowerMaxFcn()) { + os.println("Minos number of function calls for lower error exhausted.") + } + if (me.atUpperMaxFcn()) { + os.println("Minos number of function calls for upper error exhausted.") + } + if (me.lowerNewMin()) { + os.println("Minos found a new minimum in negative direction.") + os.println(me.lowerState()) + } + if (me.upperNewMin()) { + os.println("Minos found a new minimum in positive direction.") + os.println(me.upperState()) + } + os.println("# ext. || name || value@min || negative || positive ") + os.printf("%4d||%10s||%10g||%10g||%10g\n", + me.parameter(), + me.lowerState().name(me.parameter()), + me.min(), + me.lower(), + me.upper()) + os.println() + } + + /** + * + * print. + * + * @param os a [PrintWriter] object. + * @param ce a [hep.dataforge.MINUIT.ContoursError] object. + */ + fun print(os: PrintWriter, ce: ContoursError) { + os.println() + os.println("Contours # of function calls: " + ce.nfcn()) + os.println("MinosError in x: ") + os.println(ce.xMinosError()) + os.println("MinosError in y: ") + os.println(ce.yMinosError()) + val plot = MnPlot() + plot.plot(ce.xmin(), ce.ymin(), ce.points()) + for ((i, ipoint) in ce.points().withIndex()) { + os.printf("%d %10g %10g\n", i, ipoint.getFirst(), ipoint.getSecond()) + } + os.println() + } + + fun toString(x: RealVector): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, x) } + return writer.toString() + } + + fun toString(x: MnAlgebraicSymMatrix?): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, x) } + return writer.toString() + } + + fun toString(min: FunctionMinimum?): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, min) } + return writer.toString() + } + + fun toString(x: MinimumState?): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, x) } + return writer.toString() + } + + fun toString(x: MnUserParameters?): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, x) } + return writer.toString() + } + + fun toString(x: MnUserCovariance?): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, x) } + return writer.toString() + } + + fun toString(x: MnGlobalCorrelationCoeff?): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, x) } + return writer.toString() + } + + fun toString(x: MnUserParameterState?): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, x) } + return writer.toString() + } + + fun toString(x: MinosError?): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, x) } + return writer.toString() + } + + fun toString(x: ContoursError?): String { + val writer: java.io.StringWriter = java.io.StringWriter() + PrintWriter(writer).use { pw -> print(pw, x) } + return writer.toString() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnScan.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnScan.kt new file mode 100644 index 000000000..63e565b4f --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnScan.kt @@ -0,0 +1,181 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction +import ru.inr.mass.minuit.* + +/** + * MnScan scans the value of the user function by varying one parameter. It is + * sometimes useful for debugging the user function or finding a reasonable + * starting point. + * construct from MultiFunction + MnUserParameterState + MnStrategy + * + * @param str a [hep.dataforge.MINUIT.MnStrategy] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. + * @param fcn a [MultiFunction] object. + * @version $Id$ + * @author Darksnake + */ +class MnScan(fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { + private val theMinimizer: ScanMinimizer = ScanMinimizer() + + /** + * construct from MultiFunction + double[] for parameters and errors + * with default strategy + * + * @param err an array of double. + * @param par an array of double. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + double[] for parameters and errors + * + * @param stra a int. + * @param err an array of double. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, + MnUserParameterState(par, err), + MnStrategy(stra)) + + /** + * construct from MultiFunction + double[] for parameters and + * MnUserCovariance with default strategy + * + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param par an array of double. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + double[] for parameters and + * MnUserCovariance + * + * @param stra a int. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, + MnUserParameterState(par, cov), + MnStrategy(stra)) + + /** + * construct from MultiFunction + MnUserParameters with default + * strategy + * + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + MnUserParameters + * + * @param stra a int. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, + MnUserParameterState(par), + MnStrategy(stra)) + + /** + * construct from MultiFunction + MnUserParameters + MnUserCovariance + * with default strategy + * + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, + par, + cov, + DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + MnUserParameters + MnUserCovariance + * + * @param stra a int. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, + MnUserParameterState(par, cov), + MnStrategy(stra)) + + override fun minimizer(): ModularFunctionMinimizer { + return theMinimizer + } + + /** + * + * scan. + * + * @param par a int. + * @return a [List] object. + */ + fun scan(par: Int): List { + return scan(par, 41) + } + + /** + * + * scan. + * + * @param par a int. + * @param maxsteps a int. + * @return a [List] object. + */ + fun scan(par: Int, maxsteps: Int): List { + return scan(par, maxsteps, 0.0, 0.0) + } + + /** + * Scans the value of the user function by varying parameter number par, + * leaving all other parameters fixed at the current value. If par is not + * specified, all variable parameters are scanned in sequence. The number of + * points npoints in the scan is 40 by default, and cannot exceed 100. The + * range of the scan is by default 2 standard deviations on each side of the + * current best value, but can be specified as from low to high. After each + * scan, if a new minimum is found, the best parameter values are retained + * as start values for future scans or minimizations. The curve resulting + * from each scan can be plotted on the output terminal using MnPlot in + * order to show the approximate behaviour of the function. + * + * @param high a double. + * @param par a int. + * @param maxsteps a int. + * @param low a double. + * @return a [List] object. + */ + fun scan(par: Int, maxsteps: Int, low: Double, high: Double): List { + val scan = MnParameterScan(theFCN, theState.parameters()) + var amin: Double = scan.fval() + val result: List = scan.scan(par, maxsteps, low, high) + if (scan.fval() < amin) { + theState.setValue(par, scan.parameters().value(par)) + amin = scan.fval() + } + return result + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSeedGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSeedGenerator.kt new file mode 100644 index 000000000..cc3f9547e --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSeedGenerator.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import space.kscience.kmath.optimization.minuit.MINUITPlugin +import ru.inr.mass.minuit.* + +/** + * + * @version $Id$ + */ +internal class MnSeedGenerator : MinimumSeedGenerator { + /** {@inheritDoc} */ + fun generate(fcn: MnFcn, gc: GradientCalculator, st: MnUserParameterState, stra: MnStrategy): MinimumSeed { + val n: Int = st.variableParameters() + val prec: MnMachinePrecision = st.precision() + + // initial starting values + val x: RealVector = ArrayRealVector(n) + for (i in 0 until n) { + x.setEntry(i, st.intParameters()[i]) + } + val fcnmin: Double = fcn.value(x) + val pa = MinimumParameters(x, fcnmin) + val dgrad: FunctionGradient + if (gc is AnalyticalGradientCalculator) { + val igc = InitialGradientCalculator(fcn, st.getTransformation(), stra) + val tmp: FunctionGradient = igc.gradient(pa) + val grd: FunctionGradient = gc.gradient(pa) + dgrad = FunctionGradient(grd.getGradient(), tmp.getGradientDerivative(), tmp.getStep()) + if (gc.checkGradient()) { + val good = true + val hgc = HessianGradientCalculator(fcn, st.getTransformation(), MnStrategy(2)) + val hgrd: Pair = hgc.deltaGradient(pa, dgrad) + for (i in 0 until n) { + val provided: Double = grd.getGradient().getEntry(i) + val calculated: Double = hgrd.getFirst().getGradient().getEntry(i) + val delta: Double = hgrd.getSecond().getEntry(i) + if (abs(calculated - provided) > delta) { + MINUITPlugin.logStatic("" + + "gradient discrepancy of external parameter \"%d\" " + + "(internal parameter \"%d\") too large. Expected: \"%f\", provided: \"%f\"", + st.getTransformation().extOfInt(i), i, provided, calculated) + +// +// MINUITPlugin.logStatic("gradient discrepancy of external parameter " +// + st.getTransformation().extOfInt(i) +// + " (internal parameter " + i + ") too large."); +// good = false; + } + } + if (!good) { + MINUITPlugin.logStatic("Minuit does not accept user specified gradient.") + // assert(good); + } + } + } else { + dgrad = gc.gradient(pa) + } + val mat = MnAlgebraicSymMatrix(n) + var dcovar = 1.0 + if (st.hasCovariance()) { + for (i in 0 until n) { + for (j in i until n) { + mat[i, j] = st.intCovariance()[i, j] + } + } + dcovar = 0.0 + } else { + for (i in 0 until n) { + mat[i, i] = if (abs(dgrad.getGradientDerivative() + .getEntry(i)) > prec.eps2() + ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0 + } + } + val err = MinimumError(mat, dcovar) + val edm: Double = VariableMetricEDMEstimator().estimate(dgrad, err) + var state = MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()) + if (NegativeG2LineSearch.hasNegativeG2(dgrad, prec)) { + state = if (gc is AnalyticalGradientCalculator) { + val ngc = Numerical2PGradientCalculator(fcn, st.getTransformation(), stra) + NegativeG2LineSearch.search(fcn, state, ngc, prec) + } else { + NegativeG2LineSearch.search(fcn, state, gc, prec) + } + } + if (stra.strategy() === 2 && !st.hasCovariance()) { + //calculate full 2nd derivative + val tmp: MinimumState = MnHesse(stra).calculate(fcn, state, st.getTransformation(), 0) + return MinimumSeed(tmp, st.getTransformation()) + } + return MinimumSeed(state, st.getTransformation()) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSimplex.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSimplex.kt new file mode 100644 index 000000000..b00745f26 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSimplex.kt @@ -0,0 +1,138 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction +import ru.inr.mass.minuit.* + +/** + * SIMPLEX is a function minimization method using the simplex method of Nelder + * and Mead. MnSimplex provides minimization of the function by the method of + * SIMPLEX and the functionality for parameters interaction. It also retains the + * result from the last minimization in case the user may want to do subsequent + * minimization steps with parameter interactions in between the minimization + * requests. As SIMPLEX is a stepping method it does not produce a covariance + * matrix. + * + * @version $Id$ + * @author Darksnake + */ +class MnSimplex +/** + * construct from MultiFunction + MnUserParameterState + MnStrategy + * + * @param str a [hep.dataforge.MINUIT.MnStrategy] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. + * @param fcn a [MultiFunction] object. + */ + (fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { + private val theMinimizer: SimplexMinimizer = SimplexMinimizer() + + /** + * construct from MultiFunction + double[] for parameters and errors + * with default strategy + * + * @param err an array of double. + * @param par an array of double. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + double[] for parameters and errors + * + * @param stra a int. + * @param err an array of double. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, + MnUserParameterState(par, err), + MnStrategy(stra)) + + /** + * construct from MultiFunction + double[] for parameters and + * MnUserCovariance with default strategy + * + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param par an array of double. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + double[] for parameters and + * MnUserCovariance + * + * @param stra a int. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param fcn a [MultiFunction] object. + * @param par an array of double. + */ + constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, + MnUserParameterState(par, cov), + MnStrategy(stra)) + + /** + * construct from MultiFunction + MnUserParameters with default + * strategy + * + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + MnUserParameters + * + * @param stra a int. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, + MnUserParameterState(par), + MnStrategy(stra)) + + /** + * construct from MultiFunction + MnUserParameters + MnUserCovariance + * with default strategy + * + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + * @param fcn a [MultiFunction] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, + par, + cov, + DEFAULT_STRATEGY) + + /** + * construct from MultiFunction + MnUserParameters + MnUserCovariance + * + * @param stra a int. + * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. + * @param fcn a [MultiFunction] object. + * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, + MnUserParameterState(par, cov), + MnStrategy(stra)) + + /** {@inheritDoc} */ + override fun minimizer(): ModularFunctionMinimizer { + return theMinimizer + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnStrategy.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnStrategy.kt new file mode 100644 index 000000000..31b894665 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnStrategy.kt @@ -0,0 +1,310 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * API class for defining three levels of strategies: low (0), medium (1), high + * (2). + * + * + * At many places in the analysis of the FCN (the user provided function), + * MINUIT must decide whether to be safe and waste a few function calls + * in order to know where it is, or to be fast and attempt to get the + * requested results with the fewest possible calls at a certain risk of not + * obtaining the precision desired by the user. In order to allow the user to + * infuence these decisions, the MnStrategy class allows the user to control + * different settings. MnStrategy can be instantiated with three different + * minimization quality levels for low (0), medium (1) and high (2) quality. + * Default settings for iteration cycles and tolerances are initialized then. + * + * + * The default setting is set for medium quality. Value 0 (low) indicates to + * MINUIT that it should economize function calls; it is intended for cases + * where there are many variable parameters and/or the function takes a long + * time to calculate and/or the user is not interested in very precise values + * for parameter errors. On the other hand, value 2 (high) indicates that MINUIT + * is allowed to waste function calls in order to be sure that all values are + * precise; it is it is intended for cases where the function is evaluated in a + * relatively short time and/or where the parameter errors must be calculated + * reliably. + * + * In addition all constants set in MnStrategy can be changed individually by + * the user, e.g. the number of iteration cycles in the numerical gradient. + * + * + * + * + * Acts on: Migrad (behavioural), Minos (lowers strategy by 1 for Minos-own + * minimization), Hesse (iterations), Numerical2PDerivative (iterations) + * + * @author Darksnake + * @version $Id$ + */ +class MnStrategy { + private var theGradNCyc = 0 + private var theGradTlr = 0.0 + private var theGradTlrStp = 0.0 + private var theHessGradNCyc = 0 + + //default strategy + private var theHessNCyc = 0 + private var theHessTlrG2 = 0.0 + private var theHessTlrStp = 0.0 + private var theStrategy = 0 + + /** + * Creates a MnStrategy object with the default strategy (medium) + */ + constructor() { + setMediumStrategy() + } + //user defined strategy (0, 1, >=2) + /** + * Creates a MnStrategy object with the user specified strategy. + * + * @param stra The use defined strategy, 0=low, 1 medium, 2=high. + */ + constructor(stra: Int) { + if (stra == 0) { + setLowStrategy() + } else if (stra == 1) { + setMediumStrategy() + } else { + setHighStrategy() + } + } + + /** + * + * gradientNCycles. + * + * @return a int. + */ + fun gradientNCycles(): Int { + return theGradNCyc + } + + /** + * + * gradientStepTolerance. + * + * @return a double. + */ + fun gradientStepTolerance(): Double { + return theGradTlrStp + } + + /** + * + * gradientTolerance. + * + * @return a double. + */ + fun gradientTolerance(): Double { + return theGradTlr + } + + /** + * + * hessianG2Tolerance. + * + * @return a double. + */ + fun hessianG2Tolerance(): Double { + return theHessTlrG2 + } + + /** + * + * hessianGradientNCycles. + * + * @return a int. + */ + fun hessianGradientNCycles(): Int { + return theHessGradNCyc + } + + /** + * + * hessianNCycles. + * + * @return a int. + */ + fun hessianNCycles(): Int { + return theHessNCyc + } + + /** + * + * hessianStepTolerance. + * + * @return a double. + */ + fun hessianStepTolerance(): Double { + return theHessTlrStp + } + + /** + * + * isHigh. + * + * @return a boolean. + */ + fun isHigh(): Boolean { + return theStrategy >= 2 + } + + /** + * + * isLow. + * + * @return a boolean. + */ + fun isLow(): Boolean { + return theStrategy <= 0 + } + + /** + * + * isMedium. + * + * @return a boolean. + */ + fun isMedium(): Boolean { + return theStrategy == 1 + } + + /** + * + * setGradientNCycles. + * + * @param n a int. + */ + fun setGradientNCycles(n: Int) { + theGradNCyc = n + } + + /** + * + * setGradientStepTolerance. + * + * @param stp a double. + */ + fun setGradientStepTolerance(stp: Double) { + theGradTlrStp = stp + } + + /** + * + * setGradientTolerance. + * + * @param toler a double. + */ + fun setGradientTolerance(toler: Double) { + theGradTlr = toler + } + + /** + * + * setHessianG2Tolerance. + * + * @param toler a double. + */ + fun setHessianG2Tolerance(toler: Double) { + theHessTlrG2 = toler + } + + /** + * + * setHessianGradientNCycles. + * + * @param n a int. + */ + fun setHessianGradientNCycles(n: Int) { + theHessGradNCyc = n + } + + /** + * + * setHessianNCycles. + * + * @param n a int. + */ + fun setHessianNCycles(n: Int) { + theHessNCyc = n + } + + /** + * + * setHessianStepTolerance. + * + * @param stp a double. + */ + fun setHessianStepTolerance(stp: Double) { + theHessTlrStp = stp + } + + fun setHighStrategy() { + theStrategy = 2 + setGradientNCycles(5) + setGradientStepTolerance(0.1) + setGradientTolerance(0.02) + setHessianNCycles(7) + setHessianStepTolerance(0.1) + setHessianG2Tolerance(0.02) + setHessianGradientNCycles(6) + } + + /** + * + * setLowStrategy. + */ + fun setLowStrategy() { + theStrategy = 0 + setGradientNCycles(2) + setGradientStepTolerance(0.5) + setGradientTolerance(0.1) + setHessianNCycles(3) + setHessianStepTolerance(0.5) + setHessianG2Tolerance(0.1) + setHessianGradientNCycles(1) + } + + /** + * + * setMediumStrategy. + */ + fun setMediumStrategy() { + theStrategy = 1 + setGradientNCycles(3) + setGradientStepTolerance(0.3) + setGradientTolerance(0.05) + setHessianNCycles(5) + setHessianStepTolerance(0.3) + setHessianG2Tolerance(0.05) + setHessianGradientNCycles(2) + } + + /** + * + * strategy. + * + * @return a int. + */ + fun strategy(): Int { + return theStrategy + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserCovariance.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserCovariance.kt new file mode 100644 index 000000000..297588f8e --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserCovariance.kt @@ -0,0 +1,147 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * MnUserCovariance is the external covariance matrix designed for the + * interaction of the user. The result of the minimization (internal covariance + * matrix) is converted into the user representable format. It can also be used + * as input prior to the minimization. The size of the covariance matrix is + * according to the number of variable parameters (free and limited). + * + * @version $Id$ + * @author Darksnake + */ +class MnUserCovariance { + private var theData: DoubleArray + private var theNRow: Int + + private constructor(other: MnUserCovariance) { + theData = other.theData.clone() + theNRow = other.theNRow + } + + internal constructor() { + theData = DoubleArray(0) + theNRow = 0 + } + + /* + * covariance matrix is stored in upper triangular packed storage format, + * e.g. the elements in the array are arranged like + * {a(0,0), a(0,1), a(1,1), a(0,2), a(1,2), a(2,2), ...}, + * the size is nrow*(nrow+1)/2. + */ + internal constructor(data: DoubleArray, nrow: Int) { + require(data.size == nrow * (nrow + 1) / 2) { "Inconsistent arguments" } + theData = data + theNRow = nrow + } + + /** + * + * Constructor for MnUserCovariance. + * + * @param nrow a int. + */ + constructor(nrow: Int) { + theData = DoubleArray(nrow * (nrow + 1) / 2) + theNRow = nrow + } + + /** + * + * copy. + * + * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. + */ + fun copy(): MnUserCovariance { + return MnUserCovariance(this) + } + + fun data(): DoubleArray { + return theData + } + + /** + * + * get. + * + * @param row a int. + * @param col a int. + * @return a double. + */ + operator fun get(row: Int, col: Int): Double { + require(!(row >= theNRow || col >= theNRow)) + return if (row > col) { + theData[col + row * (row + 1) / 2] + } else { + theData[row + col * (col + 1) / 2] + } + } + + /** + * + * ncol. + * + * @return a int. + */ + fun ncol(): Int { + return theNRow + } + + /** + * + * nrow. + * + * @return a int. + */ + fun nrow(): Int { + return theNRow + } + + fun scale(f: Double) { + for (i in theData.indices) { + theData[i] *= f + } + } + + /** + * + * set. + * + * @param row a int. + * @param col a int. + * @param value a double. + */ + operator fun set(row: Int, col: Int, value: Double) { + require(!(row >= theNRow || col >= theNRow)) + if (row > col) { + theData[col + row * (row + 1) / 2] = value + } else { + theData[row + col * (col + 1) / 2] = value + } + } + + fun size(): Int { + return theData.size + } + + /** {@inheritDoc} */ + override fun toString(): String { + return MnPrint.toString(this) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserFcn.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserFcn.kt new file mode 100644 index 000000000..8198a41ab --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserFcn.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction + +/** + * + * @version $Id$ + */ +internal class MnUserFcn(fcn: MultiFunction?, errDef: Double, trafo: MnUserTransformation) : MnFcn(fcn, errDef) { + private val theTransform: MnUserTransformation = trafo + override fun value(v: RealVector): Double { + return super.value(theTransform.transform(v)) + } + +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameterState.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameterState.kt new file mode 100644 index 000000000..e80dd60a1 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameterState.kt @@ -0,0 +1,756 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.minuit.* + +/** + * The class MnUserParameterState contains the MnUserParameters and the + * MnUserCovariance. It can be created on input by the user, or by MINUIT itself + * as user representable format of the result of the minimization. + * + * @version $Id$ + * @author Darksnake + */ +class MnUserParameterState { + private var theCovariance: MnUserCovariance + private var theCovarianceValid = false + private var theEDM = 0.0 + private var theFVal = 0.0 + private var theGCCValid = false + private var theGlobalCC: MnGlobalCorrelationCoeff? = null + private var theIntCovariance: MnUserCovariance + private var theIntParameters: MutableList + private var theNFcn = 0 + private var theParameters: MnUserParameters + private var theValid: Boolean + + internal constructor() { + theValid = false + theCovarianceValid = false + theParameters = MnUserParameters() + theCovariance = MnUserCovariance() + theIntParameters = java.util.ArrayList() + theIntCovariance = MnUserCovariance() + } + + private constructor(other: MnUserParameterState) { + theValid = other.theValid + theCovarianceValid = other.theCovarianceValid + theGCCValid = other.theGCCValid + theFVal = other.theFVal + theEDM = other.theEDM + theNFcn = other.theNFcn + theParameters = other.theParameters.copy() + theCovariance = other.theCovariance + theGlobalCC = other.theGlobalCC + theIntParameters = java.util.ArrayList(other.theIntParameters) + theIntCovariance = other.theIntCovariance.copy() + } + + /** + * construct from user parameters (before minimization) + * @param par + * @param err + */ + internal constructor(par: DoubleArray, err: DoubleArray) { + theValid = true + theParameters = MnUserParameters(par, err) + theCovariance = MnUserCovariance() + theGlobalCC = MnGlobalCorrelationCoeff() + theIntParameters = java.util.ArrayList(par.size) + for (i in par.indices) { + theIntParameters.add(par[i]) + } + theIntCovariance = MnUserCovariance() + } + + internal constructor(par: MnUserParameters) { + theValid = true + theParameters = par + theCovariance = MnUserCovariance() + theGlobalCC = MnGlobalCorrelationCoeff() + theIntParameters = java.util.ArrayList(par.variableParameters()) + theIntCovariance = MnUserCovariance() + val i = 0 + for (ipar in par.parameters()) { + if (ipar.isConst() || ipar.isFixed()) { + continue + } + if (ipar.hasLimits()) { + theIntParameters.add(ext2int(ipar.number(), ipar.value())) + } else { + theIntParameters.add(ipar.value()) + } + } + } + + /** + * construct from user parameters + covariance (before minimization) + * @param nrow + * @param cov + */ + internal constructor(par: DoubleArray, cov: DoubleArray, nrow: Int) { + theValid = true + theCovarianceValid = true + theCovariance = MnUserCovariance(cov, nrow) + theGlobalCC = MnGlobalCorrelationCoeff() + theIntParameters = java.util.ArrayList(par.size) + theIntCovariance = MnUserCovariance(cov, nrow) + val err = DoubleArray(par.size) + for (i in par.indices) { + assert(theCovariance[i, i] > 0.0) + err[i] = sqrt(theCovariance[i, i]) + theIntParameters.add(par[i]) + } + theParameters = MnUserParameters(par, err) + assert(theCovariance.nrow() === variableParameters()) + } + + internal constructor(par: DoubleArray, cov: MnUserCovariance) { + theValid = true + theCovarianceValid = true + theCovariance = cov + theGlobalCC = MnGlobalCorrelationCoeff() + theIntParameters = java.util.ArrayList(par.size) + theIntCovariance = cov.copy() + require(!(theCovariance.nrow() !== variableParameters())) { "Bad covariance size" } + val err = DoubleArray(par.size) + for (i in par.indices) { + require(theCovariance[i, i] > 0.0) { "Bad covariance" } + err[i] = sqrt(theCovariance[i, i]) + theIntParameters.add(par[i]) + } + theParameters = MnUserParameters(par, err) + } + + internal constructor(par: MnUserParameters, cov: MnUserCovariance) { + theValid = true + theCovarianceValid = true + theParameters = par + theCovariance = cov + theGlobalCC = MnGlobalCorrelationCoeff() + theIntParameters = java.util.ArrayList() + theIntCovariance = cov.copy() + theIntCovariance.scale(0.5) + val i = 0 + for (ipar in par.parameters()) { + if (ipar.isConst() || ipar.isFixed()) { + continue + } + if (ipar.hasLimits()) { + theIntParameters.add(ext2int(ipar.number(), ipar.value())) + } else { + theIntParameters.add(ipar.value()) + } + } + assert(theCovariance.nrow() === variableParameters()) + } + + /** + * construct from internal parameters (after minimization) + * @param trafo + * @param up + */ + internal constructor(st: MinimumState, up: Double, trafo: MnUserTransformation) { + theValid = st.isValid() + theCovarianceValid = false + theGCCValid = false + theFVal = st.fval() + theEDM = st.edm() + theNFcn = st.nfcn() + theParameters = MnUserParameters() + theCovariance = MnUserCovariance() + theGlobalCC = MnGlobalCorrelationCoeff() + theIntParameters = java.util.ArrayList() + theIntCovariance = MnUserCovariance() + for (ipar in trafo.parameters()) { + if (ipar.isConst()) { + add(ipar.name(), ipar.value()) + } else if (ipar.isFixed()) { + add(ipar.name(), ipar.value(), ipar.error()) + if (ipar.hasLimits()) { + if (ipar.hasLowerLimit() && ipar.hasUpperLimit()) { + setLimits(ipar.name(), ipar.lowerLimit(), ipar.upperLimit()) + } else if (ipar.hasLowerLimit() && !ipar.hasUpperLimit()) { + setLowerLimit(ipar.name(), ipar.lowerLimit()) + } else { + setUpperLimit(ipar.name(), ipar.upperLimit()) + } + } + fix(ipar.name()) + } else if (ipar.hasLimits()) { + val i: Int = trafo.intOfExt(ipar.number()) + val err: Double = if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin().getEntry(i) + add(ipar.name(), + trafo.int2ext(i, st.vec().getEntry(i)), + trafo.int2extError(i, st.vec().getEntry(i), err)) + if (ipar.hasLowerLimit() && ipar.hasUpperLimit()) { + setLimits(ipar.name(), ipar.lowerLimit(), ipar.upperLimit()) + } else if (ipar.hasLowerLimit() && !ipar.hasUpperLimit()) { + setLowerLimit(ipar.name(), ipar.lowerLimit()) + } else { + setUpperLimit(ipar.name(), ipar.upperLimit()) + } + } else { + val i: Int = trafo.intOfExt(ipar.number()) + val err: Double = if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin().getEntry(i) + add(ipar.name(), st.vec().getEntry(i), err) + } + } + theCovarianceValid = st.error().isValid() + if (theCovarianceValid) { + theCovariance = trafo.int2extCovariance(st.vec(), st.error().invHessian()) + theIntCovariance = MnUserCovariance(st.error().invHessian().data().clone(), st.error().invHessian().nrow()) + theCovariance.scale(2.0 * up) + theGlobalCC = MnGlobalCorrelationCoeff(st.error().invHessian()) + theGCCValid = true + assert(theCovariance.nrow() === variableParameters()) + } + } + + /** + * add free parameter name, value, error + * + * @param err a double. + * @param val a double. + * @param name a [String] object. + */ + fun add(name: String, `val`: Double, err: Double) { + theParameters.add(name, `val`, err) + theIntParameters.add(`val`) + theCovarianceValid = false + theGCCValid = false + theValid = true + } + + /** + * add limited parameter name, value, lower bound, upper bound + * + * @param name a [String] object. + * @param val a double. + * @param low a double. + * @param err a double. + * @param up a double. + */ + fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { + theParameters.add(name, `val`, err, low, up) + theCovarianceValid = false + theIntParameters.add(ext2int(index(name), `val`)) + theGCCValid = false + theValid = true + } + + /** + * add const parameter name, value + * + * @param name a [String] object. + * @param val a double. + */ + fun add(name: String, `val`: Double) { + theParameters.add(name, `val`) + theValid = true + } + + /** + * + * copy. + * + * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. + */ + fun copy(): MnUserParameterState { + return MnUserParameterState(this) + } + + /** + * Covariance matrix in the external representation + * + * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. + */ + fun covariance(): MnUserCovariance { + return theCovariance + } + + /** + * Returns the expected vertival distance to the minimum (EDM) + * + * @return a double. + */ + fun edm(): Double { + return theEDM + } + + /** + * + * error. + * + * @param index a int. + * @return a double. + */ + fun error(index: Int): Double { + return theParameters.error(index) + } + + /** + * + * error. + * + * @param name a [String] object. + * @return a double. + */ + fun error(name: String?): Double { + return error(index(name)) + } + + /** + * + * errors. + * + * @return an array of double. + */ + fun errors(): DoubleArray { + return theParameters.errors() + } + + fun ext2int(i: Int, `val`: Double): Double { + return theParameters.trafo().ext2int(i, `val`) + } + + /** + * + * extOfInt. + * + * @param internal a int. + * @return a int. + */ + fun extOfInt(internal: Int): Int { + return theParameters.trafo().extOfInt(internal) + } + /// interaction via external number of parameter + /** + * + * fix. + * + * @param e a int. + */ + fun fix(e: Int) { + val i = intOfExt(e) + if (theCovarianceValid) { + theCovariance = MnCovarianceSqueeze.squeeze(theCovariance, i) + theIntCovariance = MnCovarianceSqueeze.squeeze(theIntCovariance, i) + } + theIntParameters.removeAt(i) + theParameters.fix(e) + theGCCValid = false + } + /// interaction via name of parameter + /** + * + * fix. + * + * @param name a [String] object. + */ + fun fix(name: String?) { + fix(index(name)) + } + + /** + * returns the function value at the minimum + * + * @return a double. + */ + fun fval(): Double { + return theFVal + } + + /** + * transformation internal <-> external + * @return + */ + fun getTransformation(): MnUserTransformation { + return theParameters.trafo() + } + + fun globalCC(): MnGlobalCorrelationCoeff? { + return theGlobalCC + } + + /** + * Returns + * true if the the state has a valid covariance, + * false otherwise. + * + * @return a boolean. + */ + fun hasCovariance(): Boolean { + return theCovarianceValid + } + + /** + * + * hasGlobalCC. + * + * @return a boolean. + */ + fun hasGlobalCC(): Boolean { + return theGCCValid + } + + /** + * convert name into external number of parameter + * + * @param name a [String] object. + * @return a int. + */ + fun index(name: String?): Int { + return theParameters.index(name) + } + + // transformation internal <-> external + fun int2ext(i: Int, `val`: Double): Double { + return theParameters.trafo().int2ext(i, `val`) + } + + fun intCovariance(): MnUserCovariance { + return theIntCovariance + } + + fun intOfExt(ext: Int): Int { + return theParameters.trafo().intOfExt(ext) + } + + /** + * Minuit internal representation + * @return + */ + fun intParameters(): List { + return theIntParameters + } + + /** + * Returns + * true if the the state is valid, + * false if not + * + * @return a boolean. + */ + fun isValid(): Boolean { + return theValid + } + + // facade: forward interface of MnUserParameters and MnUserTransformation + fun minuitParameters(): List { + return theParameters.parameters() + } + + /** + * convert external number into name of parameter + * + * @param index a int. + * @return a [String] object. + */ + fun name(index: Int): String { + return theParameters.name(index) + } + + /** + * Returns the number of function calls during the minimization. + * + * @return a int. + */ + fun nfcn(): Int { + return theNFcn + } + + fun parameter(i: Int): MinuitParameter { + return theParameters.parameter(i) + } + + //user external representation + fun parameters(): MnUserParameters { + return theParameters + } + + /** + * access to parameters and errors in column-wise representation + * + * @return an array of double. + */ + fun params(): DoubleArray { + return theParameters.params() + } + + /** + * + * precision. + * + * @return a [hep.dataforge.MINUIT.MnMachinePrecision] object. + */ + fun precision(): MnMachinePrecision { + return theParameters.precision() + } + + /** + * + * release. + * + * @param e a int. + */ + fun release(e: Int) { + theParameters.release(e) + theCovarianceValid = false + theGCCValid = false + val i = intOfExt(e) + if (parameter(e).hasLimits()) { + theIntParameters.add(i, ext2int(e, parameter(e).value())) + } else { + theIntParameters.add(i, parameter(e).value()) + } + } + + /** + * + * release. + * + * @param name a [String] object. + */ + fun release(name: String?) { + release(index(name)) + } + + /** + * + * removeLimits. + * + * @param e a int. + */ + fun removeLimits(e: Int) { + theParameters.removeLimits(e) + theCovarianceValid = false + theGCCValid = false + if (!parameter(e).isFixed() && !parameter(e).isConst()) { + theIntParameters[intOfExt(e)] = value(e) + } + } + + /** + * + * removeLimits. + * + * @param name a [String] object. + */ + fun removeLimits(name: String?) { + removeLimits(index(name)) + } + + /** + * + * setError. + * + * @param e a int. + * @param err a double. + * @param err a double. + */ + fun setError(e: Int, err: Double) { + theParameters.setError(e, err) + } + + /** + * + * setError. + * + * @param name a [String] object. + * @param err a double. + */ + fun setError(name: String?, err: Double) { + setError(index(name), err) + } + + /** + * + * setLimits. + * + * @param e a int. + * @param low a double. + * @param up a double. + */ + fun setLimits(e: Int, low: Double, up: Double) { + theParameters.setLimits(e, low, up) + theCovarianceValid = false + theGCCValid = false + if (!parameter(e).isFixed() && !parameter(e).isConst()) { + val i = intOfExt(e) + if (low < theIntParameters[i] && theIntParameters[i] < up) { + theIntParameters[i] = ext2int(e, theIntParameters[i]) + } else { + theIntParameters[i] = ext2int(e, 0.5 * (low + up)) + } + } + } + + /** + * + * setLimits. + * + * @param name a [String] object. + * @param low a double. + * @param up a double. + */ + fun setLimits(name: String?, low: Double, up: Double) { + setLimits(index(name), low, up) + } + + /** + * + * setLowerLimit. + * + * @param e a int. + * @param low a double. + */ + fun setLowerLimit(e: Int, low: Double) { + theParameters.setLowerLimit(e, low) + theCovarianceValid = false + theGCCValid = false + if (!parameter(e).isFixed() && !parameter(e).isConst()) { + val i = intOfExt(e) + if (low < theIntParameters[i]) { + theIntParameters[i] = ext2int(e, theIntParameters[i]) + } else { + theIntParameters[i] = ext2int(e, low + 0.5 * abs(low + 1.0)) + } + } + } + + /** + * + * setLowerLimit. + * + * @param name a [String] object. + * @param low a double. + */ + fun setLowerLimit(name: String?, low: Double) { + setLowerLimit(index(name), low) + } + + /** + * + * setPrecision. + * + * @param eps a double. + */ + fun setPrecision(eps: Double) { + theParameters.setPrecision(eps) + } + + /** + * + * setUpperLimit. + * + * @param e a int. + * @param up a double. + */ + fun setUpperLimit(e: Int, up: Double) { + theParameters.setUpperLimit(e, up) + theCovarianceValid = false + theGCCValid = false + if (!parameter(e).isFixed() && !parameter(e).isConst()) { + val i = intOfExt(e) + if (theIntParameters[i] < up) { + theIntParameters[i] = ext2int(e, theIntParameters[i]) + } else { + theIntParameters[i] = ext2int(e, up - 0.5 * abs(up + 1.0)) + } + } + } + + /** + * + * setUpperLimit. + * + * @param name a [String] object. + * @param up a double. + */ + fun setUpperLimit(name: String?, up: Double) { + setUpperLimit(index(name), up) + } + + /** + * + * setValue. + * + * @param e a int. + * @param val a double. + */ + fun setValue(e: Int, `val`: Double) { + theParameters.setValue(e, `val`) + if (!parameter(e).isFixed() && !parameter(e).isConst()) { + val i = intOfExt(e) + if (parameter(e).hasLimits()) { + theIntParameters[i] = ext2int(e, `val`) + } else { + theIntParameters[i] = `val` + } + } + } + + /** + * + * setValue. + * + * @param name a [String] object. + * @param val a double. + */ + fun setValue(name: String?, `val`: Double) { + setValue(index(name), `val`) + } + + /** {@inheritDoc} */ + override fun toString(): String { + return MnPrint.toString(this) + } + + /** + * + * value. + * + * @param index a int. + * @return a double. + */ + fun value(index: Int): Double { + return theParameters.value(index) + } + + /** + * + * value. + * + * @param name a [String] object. + * @return a double. + */ + fun value(name: String?): Double { + return value(index(name)) + } + + /** + * + * variableParameters. + * + * @return a int. + */ + fun variableParameters(): Int { + return theParameters.variableParameters() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameters.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameters.kt new file mode 100644 index 000000000..9bac54b25 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameters.kt @@ -0,0 +1,402 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * API class for the user interaction with the parameters. Serves as input to + * the minimizer as well as output from it; users can interact: fix/release + * parameters, set values and errors, etc.; parameters can be accessed via their + * parameter number or via their user-specified name. + * + * @version $Id$ + * @author Darksnake + */ +class MnUserParameters { + private var theTransformation: MnUserTransformation + + /** + * Creates a new instance of MnUserParameters + */ + constructor() { + theTransformation = MnUserTransformation() + } + + /** + * + * Constructor for MnUserParameters. + * + * @param par an array of double. + * @param err an array of double. + */ + constructor(par: DoubleArray, err: DoubleArray) { + theTransformation = MnUserTransformation(par, err) + } + + private constructor(other: MnUserParameters) { + theTransformation = other.theTransformation.copy() + } + + /** + * Add free parameter name, value, error + * + * + * When adding parameters, MINUIT assigns indices to each parameter which + * will be the same as in the double[] in the + * MultiFunction.valueOf(). That means the first parameter the user + * adds gets index 0, the second index 1, and so on. When calculating the + * function value inside FCN, MINUIT will call + * MultiFunction.valueOf() with the elements at their respective + * positions. + * + * @param err a double. + * @param val a double. + * @param name a [String] object. + */ + fun add(name: String, `val`: Double, err: Double) { + theTransformation.add(name, `val`, err) + } + + /** + * Add limited parameter name, value, lower bound, upper bound + * + * @param up a double. + * @param low a double. + * @param name a [String] object. + * @param val a double. + * @param err a double. + */ + fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { + theTransformation.add(name, `val`, err, low, up) + } + + /** + * Add const parameter name, value + * + * @param name a [String] object. + * @param val a double. + */ + fun add(name: String, `val`: Double) { + theTransformation.add(name, `val`) + } + + /** + * + * copy. + * + * @return a [hep.dataforge.MINUIT.MnUserParameters] object. + */ + fun copy(): MnUserParameters { + return MnUserParameters(this) + } + + /** + * + * error. + * + * @param index a int. + * @return a double. + */ + fun error(index: Int): Double { + return theTransformation.error(index) + } + + /** + * + * error. + * + * @param name a [String] object. + * @return a double. + */ + fun error(name: String?): Double { + return theTransformation.error(name) + } + + fun errors(): DoubleArray { + return theTransformation.errors() + } + /// interaction via external number of parameter + /** + * Fixes the specified parameter (so that the minimizer will no longer vary + * it) + * + * @param index a int. + */ + fun fix(index: Int) { + theTransformation.fix(index) + } + /// interaction via name of parameter + /** + * Fixes the specified parameter (so that the minimizer will no longer vary + * it) + * + * @param name a [String] object. + */ + fun fix(name: String?) { + theTransformation.fix(name) + } + + /** + * convert name into external number of parameter + * @param name + * @return + */ + fun index(name: String?): Int { + return theTransformation.index(name) + } + + /** + * convert external number into name of parameter + * @param index + * @return + */ + fun name(index: Int): String { + return theTransformation.name(index) + } + + /** + * access to single parameter + * @param index + * @return + */ + fun parameter(index: Int): MinuitParameter { + return theTransformation.parameter(index) + } + + /** + * access to parameters (row-wise) + * @return + */ + fun parameters(): List { + return theTransformation.parameters() + } + + /** + * access to parameters and errors in column-wise representation + * @return + */ + fun params(): DoubleArray { + return theTransformation.params() + } + + /** + * + * precision. + * + * @return a [hep.dataforge.MINUIT.MnMachinePrecision] object. + */ + fun precision(): MnMachinePrecision { + return theTransformation.precision() + } + + /** + * Releases the specified parameter (so that the minimizer can vary it) + * + * @param index a int. + */ + fun release(index: Int) { + theTransformation.release(index) + } + + /** + * Releases the specified parameter (so that the minimizer can vary it) + * + * @param name a [String] object. + */ + fun release(name: String?) { + theTransformation.release(name) + } + + /** + * + * removeLimits. + * + * @param index a int. + */ + fun removeLimits(index: Int) { + theTransformation.removeLimits(index) + } + + /** + * + * removeLimits. + * + * @param name a [String] object. + */ + fun removeLimits(name: String?) { + theTransformation.removeLimits(name) + } + + /** + * + * setError. + * + * @param index a int. + * @param err a double. + */ + fun setError(index: Int, err: Double) { + theTransformation.setError(index, err) + } + + /** + * + * setError. + * + * @param name a [String] object. + * @param err a double. + */ + fun setError(name: String?, err: Double) { + theTransformation.setError(name, err) + } + + /** + * Set the lower and upper bound on the specified variable. + * + * @param up a double. + * @param low a double. + * @param index a int. + */ + fun setLimits(index: Int, low: Double, up: Double) { + theTransformation.setLimits(index, low, up) + } + + /** + * Set the lower and upper bound on the specified variable. + * + * @param up a double. + * @param low a double. + * @param name a [String] object. + */ + fun setLimits(name: String?, low: Double, up: Double) { + theTransformation.setLimits(name, low, up) + } + + /** + * + * setLowerLimit. + * + * @param index a int. + * @param low a double. + */ + fun setLowerLimit(index: Int, low: Double) { + theTransformation.setLowerLimit(index, low) + } + + /** + * + * setLowerLimit. + * + * @param name a [String] object. + * @param low a double. + */ + fun setLowerLimit(name: String?, low: Double) { + theTransformation.setLowerLimit(name, low) + } + + /** + * + * setPrecision. + * + * @param eps a double. + */ + fun setPrecision(eps: Double) { + theTransformation.setPrecision(eps) + } + + /** + * + * setUpperLimit. + * + * @param index a int. + * @param up a double. + */ + fun setUpperLimit(index: Int, up: Double) { + theTransformation.setUpperLimit(index, up) + } + + /** + * + * setUpperLimit. + * + * @param name a [String] object. + * @param up a double. + */ + fun setUpperLimit(name: String?, up: Double) { + theTransformation.setUpperLimit(name, up) + } + + /** + * Set the value of parameter. The parameter in question may be variable, + * fixed, or constant, but must be defined. + * + * @param index a int. + * @param val a double. + */ + fun setValue(index: Int, `val`: Double) { + theTransformation.setValue(index, `val`) + } + + /** + * Set the value of parameter. The parameter in question may be variable, + * fixed, or constant, but must be defined. + * + * @param name a [String] object. + * @param val a double. + */ + fun setValue(name: String?, `val`: Double) { + theTransformation.setValue(name, `val`) + } + + /** {@inheritDoc} */ + override fun toString(): String { + return MnPrint.toString(this) + } + + fun trafo(): MnUserTransformation { + return theTransformation + } + + /** + * + * value. + * + * @param index a int. + * @return a double. + */ + fun value(index: Int): Double { + return theTransformation.value(index) + } + + /** + * + * value. + * + * @param name a [String] object. + * @return a double. + */ + fun value(name: String?): Double { + return theTransformation.value(name) + } + + /** + * + * variableParameters. + * + * @return a int. + */ + fun variableParameters(): Int { + return theTransformation.variableParameters() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserTransformation.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserTransformation.kt new file mode 100644 index 000000000..1066ac2da --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserTransformation.kt @@ -0,0 +1,390 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector + +/** + * knows how to andThen between user specified parameters (external) and + * internal parameters used for minimization + * + * Жуткий октопус, который занимается преобразованием внешних параметров во внутренние + * TODO по возможности отказаться от использования этого монстра + * @version $Id$ + */ +class MnUserTransformation { + private val nameMap: MutableMap = HashMap() + private var theCache: MutableList + private var theExtOfInt: MutableList + private var theParameters: MutableList + private var thePrecision: MnMachinePrecision + + constructor() { + thePrecision = MnMachinePrecision() + theParameters = java.util.ArrayList() + theExtOfInt = java.util.ArrayList() + theCache = java.util.ArrayList(0) + } + + private constructor(other: MnUserTransformation) { + thePrecision = other.thePrecision + theParameters = java.util.ArrayList(other.theParameters.size) + for (par in other.theParameters) { + theParameters.add(par.copy()) + } + theExtOfInt = java.util.ArrayList(other.theExtOfInt) + theCache = java.util.ArrayList(other.theCache) + } + + constructor(par: DoubleArray, err: DoubleArray) { + thePrecision = MnMachinePrecision() + theParameters = java.util.ArrayList(par.size) + theExtOfInt = java.util.ArrayList(par.size) + theCache = java.util.ArrayList(par.size) + for (i in par.indices) { + add("p$i", par[i], err[i]) + } + } + + /** + * add free parameter + * @param err + * @param val + */ + fun add(name: String, `val`: Double, err: Double) { + require(!nameMap.containsKey(name)) { "duplicate name: $name" } + nameMap[name] = theParameters.size + theExtOfInt.add(theParameters.size) + theCache.add(`val`) + theParameters.add(MinuitParameter(theParameters.size, name, `val`, err)) + } + + /** + * add limited parameter + * @param up + * @param low + */ + fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { + require(!nameMap.containsKey(name)) { "duplicate name: $name" } + nameMap[name] = theParameters.size + theExtOfInt.add(theParameters.size) + theCache.add(`val`) + theParameters.add(MinuitParameter(theParameters.size, name, `val`, err, low, up)) + } + + /** + * add parameter + * @param name + * @param val + */ + fun add(name: String, `val`: Double) { + require(!nameMap.containsKey(name)) { "duplicate name: $name" } + nameMap[name] = theParameters.size + theCache.add(`val`) + theParameters.add(MinuitParameter(theParameters.size, name, `val`)) + } + + /** + * + * copy. + * + * @return a [hep.dataforge.MINUIT.MnUserTransformation] object. + */ + fun copy(): MnUserTransformation { + return MnUserTransformation(this) + } + + fun dInt2Ext(i: Int, `val`: Double): Double { + var dd = 1.0 + val parm: MinuitParameter = theParameters[theExtOfInt[i]] + if (parm.hasLimits()) { + dd = if (parm.hasUpperLimit() && parm.hasLowerLimit()) { + theDoubleLimTrafo.dInt2Ext(`val`, + parm.upperLimit(), + parm.lowerLimit()) + } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) { + theUpperLimTrafo.dInt2Ext(`val`, parm.upperLimit()) + } else { + theLowerLimTrafo.dInt2Ext(`val`, parm.lowerLimit()) + } + } + return dd + } + + fun error(index: Int): Double { + return theParameters[index].error() + } + + fun error(name: String?): Double { + return error(index(name)) + } + + fun errors(): DoubleArray { + val result = DoubleArray(theParameters.size) + var i = 0 + for (parameter in theParameters) { + result[i++] = parameter.error() + } + return result + } + + fun ext2int(i: Int, `val`: Double): Double { + val parm: MinuitParameter = theParameters[i] + return if (parm.hasLimits()) { + if (parm.hasUpperLimit() && parm.hasLowerLimit()) { + theDoubleLimTrafo.ext2int(`val`, + parm.upperLimit(), + parm.lowerLimit(), + precision()) + } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) { + theUpperLimTrafo.ext2int(`val`, + parm.upperLimit(), + precision()) + } else { + theLowerLimTrafo.ext2int(`val`, + parm.lowerLimit(), + precision()) + } + } else `val` + } + + fun extOfInt(internal: Int): Int { + return theExtOfInt[internal] + } + + /** + * interaction via external number of parameter + * @param index + */ + fun fix(index: Int) { + val iind = intOfExt(index) + theExtOfInt.removeAt(iind) + theParameters[index].fix() + } + + /** + * interaction via name of parameter + * @param name + */ + fun fix(name: String?) { + fix(index(name)) + } + + /** + * convert name into external number of parameter + * @param name + * @return + */ + fun index(name: String?): Int { + return nameMap[name]!! + } + + fun int2ext(i: Int, `val`: Double): Double { + val parm: MinuitParameter = theParameters[theExtOfInt[i]] + return if (parm.hasLimits()) { + if (parm.hasUpperLimit() && parm.hasLowerLimit()) { + theDoubleLimTrafo.int2ext(`val`, + parm.upperLimit(), + parm.lowerLimit()) + } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) { + theUpperLimTrafo.int2ext(`val`, parm.upperLimit()) + } else { + theLowerLimTrafo.int2ext(`val`, parm.lowerLimit()) + } + } else `val` + } + + fun int2extCovariance(vec: RealVector, cov: MnAlgebraicSymMatrix): MnUserCovariance { + val result = MnUserCovariance(cov.nrow()) + for (i in 0 until vec.getDimension()) { + var dxdi = 1.0 + if (theParameters[theExtOfInt[i]].hasLimits()) { + dxdi = dInt2Ext(i, vec.getEntry(i)) + } + for (j in i until vec.getDimension()) { + var dxdj = 1.0 + if (theParameters[theExtOfInt[j]].hasLimits()) { + dxdj = dInt2Ext(j, vec.getEntry(j)) + } + result[i, j] = dxdi * cov[i, j] * dxdj + } + } + return result + } + + fun int2extError(i: Int, `val`: Double, err: Double): Double { + var dx = err + val parm: MinuitParameter = theParameters[theExtOfInt[i]] + if (parm.hasLimits()) { + val ui = int2ext(i, `val`) + var du1 = int2ext(i, `val` + dx) - ui + val du2 = int2ext(i, `val` - dx) - ui + if (parm.hasUpperLimit() && parm.hasLowerLimit()) { + if (dx > 1.0) { + du1 = parm.upperLimit() - parm.lowerLimit() + } + dx = 0.5 * (abs(du1) + abs(du2)) + } else { + dx = 0.5 * (abs(du1) + abs(du2)) + } + } + return dx + } + + fun intOfExt(ext: Int): Int { + for (iind in theExtOfInt.indices) { + if (ext == theExtOfInt[iind]) { + return iind + } + } + throw IllegalArgumentException("ext=$ext") + } + + /** + * convert external number into name of parameter + * @param index + * @return + */ + fun name(index: Int): String { + return theParameters[index].name() + } + + /** + * access to single parameter + * @param index + * @return + */ + fun parameter(index: Int): MinuitParameter { + return theParameters[index] + } + + fun parameters(): List { + return theParameters + } + + //access to parameters and errors in column-wise representation + fun params(): DoubleArray { + val result = DoubleArray(theParameters.size) + var i = 0 + for (parameter in theParameters) { + result[i++] = parameter.value() + } + return result + } + + fun precision(): MnMachinePrecision { + return thePrecision + } + + fun release(index: Int) { + require(!theExtOfInt.contains(index)) { "index=$index" } + theExtOfInt.add(index) + Collections.sort(theExtOfInt) + theParameters[index].release() + } + + fun release(name: String?) { + release(index(name)) + } + + fun removeLimits(index: Int) { + theParameters[index].removeLimits() + } + + fun removeLimits(name: String?) { + removeLimits(index(name)) + } + + fun setError(index: Int, err: Double) { + theParameters[index].setError(err) + } + + fun setError(name: String?, err: Double) { + setError(index(name), err) + } + + fun setLimits(index: Int, low: Double, up: Double) { + theParameters[index].setLimits(low, up) + } + + fun setLimits(name: String?, low: Double, up: Double) { + setLimits(index(name), low, up) + } + + fun setLowerLimit(index: Int, low: Double) { + theParameters[index].setLowerLimit(low) + } + + fun setLowerLimit(name: String?, low: Double) { + setLowerLimit(index(name), low) + } + + fun setPrecision(eps: Double) { + thePrecision.setPrecision(eps) + } + + fun setUpperLimit(index: Int, up: Double) { + theParameters[index].setUpperLimit(up) + } + + fun setUpperLimit(name: String?, up: Double) { + setUpperLimit(index(name), up) + } + + fun setValue(index: Int, `val`: Double) { + theParameters[index].setValue(`val`) + theCache[index] = `val` + } + + fun setValue(name: String?, `val`: Double) { + setValue(index(name), `val`) + } + + fun transform(pstates: RealVector): ArrayRealVector { + // FixMe: Worry about efficiency here + val result = ArrayRealVector(theCache.size) + for (i in 0 until result.getDimension()) { + result.setEntry(i, theCache[i]) + } + for (i in 0 until pstates.getDimension()) { + if (theParameters[theExtOfInt[i]].hasLimits()) { + result.setEntry(theExtOfInt[i], int2ext(i, pstates.getEntry(i))) + } else { + result.setEntry(theExtOfInt[i], pstates.getEntry(i)) + } + } + return result + } + + //forwarded interface + fun value(index: Int): Double { + return theParameters[index].value() + } + + fun value(name: String?): Double { + return value(index(name)) + } + + fun variableParameters(): Int { + return theExtOfInt.size + } + + companion object { + private val theDoubleLimTrafo: SinParameterTransformation = SinParameterTransformation() + private val theLowerLimTrafo: SqrtLowParameterTransformation = SqrtLowParameterTransformation() + private val theUpperLimTrafo: SqrtUpParameterTransformation = SqrtUpParameterTransformation() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUtils.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUtils.kt new file mode 100644 index 000000000..d9f3e1bd5 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUtils.kt @@ -0,0 +1,147 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector + +/** + * Utilities for operating on vectors and matrices + * + * @version $Id$ + */ +internal object MnUtils { + fun absoluteSumOfElements(m: MnAlgebraicSymMatrix): Double { + val data: DoubleArray = m.data() + var result = 0.0 + for (i in data.indices) { + result += abs(data[i]) + } + return result + } + + fun add(v1: RealVector, v2: RealVector?): RealVector { + return v1.add(v2) + } + + fun add(m1: MnAlgebraicSymMatrix, m2: MnAlgebraicSymMatrix): MnAlgebraicSymMatrix { + require(!(m1.size() !== m2.size())) { "Incompatible matrices" } + val result: MnAlgebraicSymMatrix = m1.copy() + val a: DoubleArray = result.data() + val b: DoubleArray = m2.data() + for (i in a.indices) { + a[i] += b[i] + } + return result + } + + fun div(m: MnAlgebraicSymMatrix?, scale: Double): MnAlgebraicSymMatrix { + return mul(m, 1 / scale) + } + + fun div(m: RealVector?, scale: Double): RealVector { + return mul(m, 1 / scale) + } + + fun innerProduct(v1: RealVector, v2: RealVector): Double { + require(!(v1.getDimension() !== v2.getDimension())) { "Incompatible vectors" } + var total = 0.0 + for (i in 0 until v1.getDimension()) { + total += v1.getEntry(i) * v2.getEntry(i) + } + return total + } + + fun mul(v1: RealVector, scale: Double): RealVector { + return v1.mapMultiply(scale) + } + + fun mul(m1: MnAlgebraicSymMatrix, scale: Double): MnAlgebraicSymMatrix { + val result: MnAlgebraicSymMatrix = m1.copy() + val a: DoubleArray = result.data() + for (i in a.indices) { + a[i] *= scale + } + return result + } + + fun mul(m1: MnAlgebraicSymMatrix, v1: RealVector): ArrayRealVector { + require(!(m1.nrow() !== v1.getDimension())) { "Incompatible arguments" } + val result = ArrayRealVector(m1.nrow()) + for (i in 0 until result.getDimension()) { + var total = 0.0 + for (k in 0 until result.getDimension()) { + total += m1[i, k] * v1.getEntry(k) + } + result.setEntry(i, total) + } + return result + } + + fun mul(m1: MnAlgebraicSymMatrix, m2: MnAlgebraicSymMatrix): MnAlgebraicSymMatrix { + require(!(m1.size() !== m2.size())) { "Incompatible matrices" } + val n: Int = m1.nrow() + val result = MnAlgebraicSymMatrix(n) + for (i in 0 until n) { + for (j in 0..i) { + var total = 0.0 + for (k in 0 until n) { + total += m1[i, k] * m2[k, j] + } + result[i, j] = total + } + } + return result + } + + fun outerProduct(v2: RealVector): MnAlgebraicSymMatrix { + // Fixme: check this. I am assuming this is just an outer-product of vector + // with itself. + val n: Int = v2.getDimension() + val result = MnAlgebraicSymMatrix(n) + val data: DoubleArray = v2.toArray() + for (i in 0 until n) { + for (j in 0..i) { + result[i, j] = data[i] * data[j] + } + } + return result + } + + fun similarity(avec: RealVector, mat: MnAlgebraicSymMatrix): Double { + val n: Int = avec.getDimension() + val tmp: RealVector = mul(mat, avec) + var result = 0.0 + for (i in 0 until n) { + result += tmp.getEntry(i) * avec.getEntry(i) + } + return result + } + + fun sub(v1: RealVector, v2: RealVector?): RealVector { + return v1.subtract(v2) + } + + fun sub(m1: MnAlgebraicSymMatrix, m2: MnAlgebraicSymMatrix): MnAlgebraicSymMatrix { + require(!(m1.size() !== m2.size())) { "Incompatible matrices" } + val result: MnAlgebraicSymMatrix = m1.copy() + val a: DoubleArray = result.data() + val b: DoubleArray = m2.data() + for (i in a.indices) { + a[i] -= b[i] + } + return result + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ModularFunctionMinimizer.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ModularFunctionMinimizer.kt new file mode 100644 index 000000000..f234bcd48 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ModularFunctionMinimizer.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import ru.inr.mass.maths.MultiFunction +import ru.inr.mass.minuit.* + +/** + * + * @version $Id$ + */ +abstract class ModularFunctionMinimizer { + abstract fun builder(): MinimumBuilder + fun minimize( + fcn: MultiFunction?, + st: MnUserParameterState, + strategy: MnStrategy, + maxfcn: Int, + toler: Double, + errorDef: Double, + useAnalyticalGradient: Boolean, + checkGradient: Boolean + ): FunctionMinimum { + var maxfcn = maxfcn + val mfcn = MnUserFcn(fcn, errorDef, st.getTransformation()) + val gc: GradientCalculator + var providesAllDerivs = true + /* + * Проверяем в явном виде, что все аналитические производные присутствуют + * TODO сделать возможность того, что часть производных задается аналитически, а часть численно + */for (i in 0 until fcn.getDimension()) { + if (!fcn.providesDeriv(i)) providesAllDerivs = false + } + gc = if (providesAllDerivs && useAnalyticalGradient) { + AnalyticalGradientCalculator(fcn, st.getTransformation(), checkGradient) + } else { + Numerical2PGradientCalculator(mfcn, st.getTransformation(), strategy) + } + val npar: Int = st.variableParameters() + if (maxfcn == 0) { + maxfcn = 200 + 100 * npar + 5 * npar * npar + } + val mnseeds: MinimumSeed = seedGenerator().generate(mfcn, gc, st, strategy) + return minimize(mfcn, gc, mnseeds, strategy, maxfcn, toler) + } + + fun minimize( + mfcn: MnFcn, + gc: GradientCalculator?, + seed: MinimumSeed?, + strategy: MnStrategy?, + maxfcn: Int, + toler: Double + ): FunctionMinimum { + return builder().minimum(mfcn, gc, seed, strategy, maxfcn, toler * mfcn.errorDef()) + } + + abstract fun seedGenerator(): MinimumSeedGenerator +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/NegativeG2LineSearch.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/NegativeG2LineSearch.kt new file mode 100644 index 000000000..2e9ce5813 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/NegativeG2LineSearch.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector +import ru.inr.mass.minuit.* + +/** + * In case that one of the components of the second derivative g2 calculated by + * the numerical gradient calculator is negative, a 1dim line search in the + * direction of that component is done in order to find a better position where + * g2 is again positive. + * + * @version $Id$ + */ +internal object NegativeG2LineSearch { + fun hasNegativeG2(grad: FunctionGradient, prec: MnMachinePrecision): Boolean { + for (i in 0 until grad.getGradient().getDimension()) { + if (grad.getGradientDerivative().getEntry(i) < prec.eps2()) { + return true + } + } + return false + } + + fun search(fcn: MnFcn, st: MinimumState, gc: GradientCalculator, prec: MnMachinePrecision): MinimumState { + val negG2 = hasNegativeG2(st.gradient(), prec) + if (!negG2) { + return st + } + val n: Int = st.parameters().vec().getDimension() + var dgrad: FunctionGradient = st.gradient() + var pa: MinimumParameters = st.parameters() + var iterate = false + var iter = 0 + do { + iterate = false + for (i in 0 until n) { + if (dgrad.getGradientDerivative().getEntry(i) < prec.eps2()) { + // do line search if second derivative negative + var step: RealVector = ArrayRealVector(n) + step.setEntry(i, dgrad.getStep().getEntry(i) * dgrad.getGradient().getEntry(i)) + if (abs(dgrad.getGradient().getEntry(i)) > prec.eps2()) { + step.setEntry(i, + step.getEntry(i) * (-1.0 / abs(dgrad.getGradient().getEntry(i)))) + } + val gdel: Double = step.getEntry(i) * dgrad.getGradient().getEntry(i) + val pp: MnParabolaPoint = MnLineSearch.search(fcn, pa, step, gdel, prec) + step = MnUtils.mul(step, pp.x()) + pa = MinimumParameters(MnUtils.add(pa.vec(), step), pp.y()) + dgrad = gc.gradient(pa, dgrad) + iterate = true + break + } + } + } while (iter++ < 2 * n && iterate) + val mat = MnAlgebraicSymMatrix(n) + for (i in 0 until n) { + mat[i, i] = if (abs(dgrad.getGradientDerivative() + .getEntry(i)) > prec.eps2() + ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0 + } + val err = MinimumError(mat, 1.0) + val edm: Double = VariableMetricEDMEstimator().estimate(dgrad, err) + return MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Numerical2PGradientCalculator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Numerical2PGradientCalculator.kt new file mode 100644 index 000000000..efa1d57af --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Numerical2PGradientCalculator.kt @@ -0,0 +1,122 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.RealVector +import ru.inr.mass.minuit.* + +/** + * + * @version $Id$ + */ +internal class Numerical2PGradientCalculator(fcn: MnFcn, par: MnUserTransformation, stra: MnStrategy) : + GradientCalculator { + private val theFcn: MnFcn = fcn + private val theStrategy: MnStrategy + private val theTransformation: MnUserTransformation + fun fcn(): MnFcn { + return theFcn + } + + fun gradTolerance(): Double { + return strategy().gradientTolerance() + } + + /** {@inheritDoc} */ + fun gradient(par: MinimumParameters): FunctionGradient { + val gc = InitialGradientCalculator(theFcn, theTransformation, theStrategy) + val gra: FunctionGradient = gc.gradient(par) + return gradient(par, gra) + } + + /** {@inheritDoc} */ + fun gradient(par: MinimumParameters, gradient: FunctionGradient): FunctionGradient { + require(par.isValid()) { "Parameters are invalid" } + val x: RealVector = par.vec().copy() + val fcnmin: Double = par.fval() + val dfmin: Double = 8.0 * precision().eps2() * (abs(fcnmin) + theFcn.errorDef()) + val vrysml: Double = 8.0 * precision().eps() * precision().eps() + val n: Int = x.getDimension() + val grd: RealVector = gradient.getGradient().copy() + val g2: RealVector = gradient.getGradientDerivative().copy() + val gstep: RealVector = gradient.getStep().copy() + for (i in 0 until n) { + val xtf: Double = x.getEntry(i) + val epspri: Double = precision().eps2() + abs(grd.getEntry(i) * precision().eps2()) + var stepb4 = 0.0 + for (j in 0 until ncycle()) { + val optstp: Double = sqrt(dfmin / (abs(g2.getEntry(i)) + epspri)) + var step: Double = max(optstp, abs(0.1 * gstep.getEntry(i))) + if (trafo().parameter(trafo().extOfInt(i)).hasLimits()) { + if (step > 0.5) { + step = 0.5 + } + } + val stpmax: Double = 10.0 * abs(gstep.getEntry(i)) + if (step > stpmax) { + step = stpmax + } + val stpmin: Double = + max(vrysml, 8.0 * abs(precision().eps2() * x.getEntry(i))) + if (step < stpmin) { + step = stpmin + } + if (abs((step - stepb4) / step) < stepTolerance()) { + break + } + gstep.setEntry(i, step) + stepb4 = step + x.setEntry(i, xtf + step) + val fs1: Double = theFcn.value(x) + x.setEntry(i, xtf - step) + val fs2: Double = theFcn.value(x) + x.setEntry(i, xtf) + val grdb4: Double = grd.getEntry(i) + grd.setEntry(i, 0.5 * (fs1 - fs2) / step) + g2.setEntry(i, (fs1 + fs2 - 2.0 * fcnmin) / step / step) + if (abs(grdb4 - grd.getEntry(i)) / (abs(grd.getEntry(i)) + dfmin / step) < gradTolerance()) { + break + } + } + } + return FunctionGradient(grd, g2, gstep) + } + + fun ncycle(): Int { + return strategy().gradientNCycles() + } + + fun precision(): MnMachinePrecision { + return theTransformation.precision() + } + + fun stepTolerance(): Double { + return strategy().gradientStepTolerance() + } + + fun strategy(): MnStrategy { + return theStrategy + } + + fun trafo(): MnUserTransformation { + return theTransformation + } + + init { + theTransformation = par + theStrategy = stra + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Range.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Range.kt new file mode 100644 index 000000000..ebeedf7e8 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Range.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * A class representing a pair of double (x,y) or (lower,upper) + * + * @version $Id$ + * @author Darksnake + */ +class Range +/** + * + * Constructor for Range. + * + * @param k a double. + * @param v a double. + */ + (k: Double, v: Double) : Pair(k, v) \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanBuilder.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanBuilder.kt new file mode 100644 index 000000000..b7e773924 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanBuilder.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector +import ru.inr.mass.minuit.* + +/** + * Performs a minimization using the simplex method of Nelder and Mead (ref. + * Comp. J. 7, 308 (1965)). + * + * @version $Id$ + */ +internal class ScanBuilder : MinimumBuilder { + /** {@inheritDoc} */ + fun minimum( + mfcn: MnFcn, + gc: GradientCalculator?, + seed: MinimumSeed, + stra: MnStrategy?, + maxfcn: Int, + toler: Double + ): FunctionMinimum { + val x: RealVector = seed.parameters().vec().copy() + val upst = MnUserParameterState(seed.state(), mfcn.errorDef(), seed.trafo()) + val scan = MnParameterScan(mfcn.fcn(), upst.parameters(), seed.fval()) + var amin: Double = scan.fval() + val n: Int = seed.trafo().variableParameters() + val dirin: RealVector = ArrayRealVector(n) + for (i in 0 until n) { + val ext: Int = seed.trafo().extOfInt(i) + scan.scan(ext) + if (scan.fval() < amin) { + amin = scan.fval() + x.setEntry(i, seed.trafo().ext2int(ext, scan.parameters().value(ext))) + } + dirin.setEntry(i, sqrt(2.0 * mfcn.errorDef() * seed.error().invHessian()[i, i])) + } + val mp = MinimumParameters(x, dirin, amin) + val st = MinimumState(mp, 0.0, mfcn.numOfCalls()) + val states: MutableList = java.util.ArrayList(1) + states.add(st) + return FunctionMinimum(seed, states, mfcn.errorDef()) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanMinimizer.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanMinimizer.kt new file mode 100644 index 000000000..e39a49c0d --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanMinimizer.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal class ScanMinimizer : ModularFunctionMinimizer() { + private val theBuilder: ScanBuilder + private val theSeedGenerator: SimplexSeedGenerator = SimplexSeedGenerator() + override fun builder(): MinimumBuilder { + return theBuilder + } + + override fun seedGenerator(): MinimumSeedGenerator { + return theSeedGenerator + } + + init { + theBuilder = ScanBuilder() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexBuilder.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexBuilder.kt new file mode 100644 index 000000000..8441a4177 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexBuilder.kt @@ -0,0 +1,179 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import space.kscience.kmath.optimization.minuit.MINUITPlugin +import ru.inr.mass.minuit.* + +/** + * + * @version $Id$ + */ +internal class SimplexBuilder : MinimumBuilder { + /** {@inheritDoc} */ + fun minimum( + mfcn: MnFcn, + gc: GradientCalculator?, + seed: MinimumSeed, + strategy: MnStrategy?, + maxfcn: Int, + minedm: Double + ): FunctionMinimum { + val prec: MnMachinePrecision = seed.precision() + val x: RealVector = seed.parameters().vec().copy() + val step: RealVector = MnUtils.mul(seed.gradient().getStep(), 10.0) + val n: Int = x.getDimension() + val wg = 1.0 / n + val alpha = 1.0 + val beta = 0.5 + val gamma = 2.0 + val rhomin = 4.0 + val rhomax = 8.0 + val rho1 = 1.0 + alpha + val rho2 = 1.0 + alpha * gamma + val simpl: MutableList> = java.util.ArrayList>(n + 1) + simpl.add(Pair(seed.fval(), x.copy())) + var jl = 0 + var jh = 0 + var amin: Double = seed.fval() + var aming: Double = seed.fval() + for (i in 0 until n) { + val dmin: Double = 8.0 * prec.eps2() * (abs(x.getEntry(i)) + prec.eps2()) + if (step.getEntry(i) < dmin) { + step.setEntry(i, dmin) + } + x.setEntry(i, x.getEntry(i) + step.getEntry(i)) + val tmp: Double = mfcn.value(x) + if (tmp < amin) { + amin = tmp + jl = i + 1 + } + if (tmp > aming) { + aming = tmp + jh = i + 1 + } + simpl.add(Pair(tmp, x.copy())) + x.setEntry(i, x.getEntry(i) - step.getEntry(i)) + } + val simplex = SimplexParameters(simpl, jh, jl) + do { + amin = simplex[jl].getFirst() + jl = simplex.jl() + jh = simplex.jh() + var pbar: RealVector = ArrayRealVector(n) + for (i in 0 until n + 1) { + if (i == jh) { + continue + } + pbar = MnUtils.add(pbar, MnUtils.mul(simplex[i].getSecond(), wg)) + } + val pstar: RealVector = + MnUtils.sub(MnUtils.mul(pbar, 1.0 + alpha), MnUtils.mul(simplex[jh].getSecond(), alpha)) + val ystar: Double = mfcn.value(pstar) + if (ystar > amin) { + if (ystar < simplex[jh].getFirst()) { + simplex.update(ystar, pstar) + if (jh != simplex.jh()) { + continue + } + } + val pstst: RealVector = + MnUtils.add(MnUtils.mul(simplex[jh].getSecond(), beta), MnUtils.mul(pbar, 1.0 - beta)) + val ystst: Double = mfcn.value(pstst) + if (ystst > simplex[jh].getFirst()) { + break + } + simplex.update(ystst, pstst) + continue + } + var pstst: RealVector = MnUtils.add(MnUtils.mul(pstar, gamma), MnUtils.mul(pbar, 1.0 - gamma)) + var ystst: Double = mfcn.value(pstst) + val y1: Double = (ystar - simplex[jh].getFirst()) * rho2 + val y2: Double = (ystst - simplex[jh].getFirst()) * rho1 + var rho = 0.5 * (rho2 * y1 - rho1 * y2) / (y1 - y2) + if (rho < rhomin) { + if (ystst < simplex[jl].getFirst()) { + simplex.update(ystst, pstst) + } else { + simplex.update(ystar, pstar) + } + continue + } + if (rho > rhomax) { + rho = rhomax + } + val prho: RealVector = + MnUtils.add(MnUtils.mul(pbar, rho), MnUtils.mul(simplex[jh].getSecond(), 1.0 - rho)) + val yrho: Double = mfcn.value(prho) + if (yrho < simplex[jl].getFirst() && yrho < ystst) { + simplex.update(yrho, prho) + continue + } + if (ystst < simplex[jl].getFirst()) { + simplex.update(ystst, pstst) + continue + } + if (yrho > simplex[jl].getFirst()) { + if (ystst < simplex[jl].getFirst()) { + simplex.update(ystst, pstst) + } else { + simplex.update(ystar, pstar) + } + continue + } + if (ystar > simplex[jh].getFirst()) { + pstst = MnUtils.add(MnUtils.mul(simplex[jh].getSecond(), beta), MnUtils.mul(pbar, 1 - beta)) + ystst = mfcn.value(pstst) + if (ystst > simplex[jh].getFirst()) { + break + } + simplex.update(ystst, pstst) + } + } while (simplex.edm() > minedm && mfcn.numOfCalls() < maxfcn) + amin = simplex[jl].getFirst() + jl = simplex.jl() + jh = simplex.jh() + var pbar: RealVector = ArrayRealVector(n) + for (i in 0 until n + 1) { + if (i == jh) { + continue + } + pbar = MnUtils.add(pbar, MnUtils.mul(simplex[i].getSecond(), wg)) + } + var ybar: Double = mfcn.value(pbar) + if (ybar < amin) { + simplex.update(ybar, pbar) + } else { + pbar = simplex[jl].getSecond() + ybar = simplex[jl].getFirst() + } + var dirin: RealVector = simplex.dirin() + // scale to sigmas on parameters werr^2 = dirin^2 * (up/edm) + dirin = MnUtils.mul(dirin, sqrt(mfcn.errorDef() / simplex.edm())) + val st = MinimumState(MinimumParameters(pbar, dirin, ybar), simplex.edm(), mfcn.numOfCalls()) + val states: MutableList = java.util.ArrayList(1) + states.add(st) + if (mfcn.numOfCalls() > maxfcn) { + MINUITPlugin.logStatic("Simplex did not converge, #fcn calls exhausted.") + return FunctionMinimum(seed, states, mfcn.errorDef(), MnReachedCallLimit()) + } + if (simplex.edm() > minedm) { + MINUITPlugin.logStatic("Simplex did not converge, edm > minedm.") + return FunctionMinimum(seed, states, mfcn.errorDef(), MnAboveMaxEdm()) + } + return FunctionMinimum(seed, states, mfcn.errorDef()) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexMinimizer.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexMinimizer.kt new file mode 100644 index 000000000..f4bbcc320 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexMinimizer.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal class SimplexMinimizer : ModularFunctionMinimizer() { + private val theBuilder: SimplexBuilder + private val theSeedGenerator: SimplexSeedGenerator = SimplexSeedGenerator() + + /** {@inheritDoc} */ + override fun builder(): MinimumBuilder { + return theBuilder + } + + /** {@inheritDoc} */ + override fun seedGenerator(): MinimumSeedGenerator { + return theSeedGenerator + } + + /** + * + * Constructor for SimplexMinimizer. + */ + init { + theBuilder = SimplexBuilder() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexParameters.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexParameters.kt new file mode 100644 index 000000000..fef6e2010 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexParameters.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector + +/** + * + * @version $Id$ + */ +internal class SimplexParameters(simpl: MutableList>, jh: Int, jl: Int) { + private var theJHigh: Int + private var theJLow: Int + private val theSimplexParameters: MutableList> + fun dirin(): ArrayRealVector { + val dirin = ArrayRealVector(theSimplexParameters.size - 1) + for (i in 0 until theSimplexParameters.size - 1) { + var pbig: Double = theSimplexParameters[0].getSecond().getEntry(i) + var plit = pbig + for (theSimplexParameter in theSimplexParameters) { + if (theSimplexParameter.getSecond().getEntry(i) < plit) { + plit = theSimplexParameter.getSecond().getEntry(i) + } + if (theSimplexParameter.getSecond().getEntry(i) > pbig) { + pbig = theSimplexParameter.getSecond().getEntry(i) + } + } + dirin.setEntry(i, pbig - plit) + } + return dirin + } + + fun edm(): Double { + return theSimplexParameters[jh()].getFirst() - theSimplexParameters[jl()].getFirst() + } + + operator fun get(i: Int): Pair { + return theSimplexParameters[i] + } + + fun jh(): Int { + return theJHigh + } + + fun jl(): Int { + return theJLow + } + + fun simplex(): List> { + return theSimplexParameters + } + + fun update(y: Double, p: RealVector?) { + theSimplexParameters.set(jh(), Pair(y, p)) + if (y < theSimplexParameters[jl()].getFirst()) { + theJLow = jh() + } + var jh = 0 + for (i in 1 until theSimplexParameters.size) { + if (theSimplexParameters[i].getFirst() > theSimplexParameters[jh].getFirst()) { + jh = i + } + } + theJHigh = jh + } + + init { + theSimplexParameters = simpl + theJHigh = jh + theJLow = jl + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexSeedGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexSeedGenerator.kt new file mode 100644 index 000000000..e5025ff3d --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexSeedGenerator.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import org.apache.commons.math3.linear.ArrayRealVector +import ru.inr.mass.minuit.* + +/** + * + * @version $Id$ + */ +internal class SimplexSeedGenerator : MinimumSeedGenerator { + /** {@inheritDoc} */ + fun generate(fcn: MnFcn, gc: GradientCalculator?, st: MnUserParameterState, stra: MnStrategy): MinimumSeed { + val n: Int = st.variableParameters() + val prec: MnMachinePrecision = st.precision() + + // initial starting values + val x: RealVector = ArrayRealVector(n) + for (i in 0 until n) { + x.setEntry(i, st.intParameters()[i]) + } + val fcnmin: Double = fcn.value(x) + val pa = MinimumParameters(x, fcnmin) + val igc = InitialGradientCalculator(fcn, st.getTransformation(), stra) + val dgrad: FunctionGradient = igc.gradient(pa) + val mat = MnAlgebraicSymMatrix(n) + val dcovar = 1.0 + for (i in 0 until n) { + mat[i, i] = if (abs(dgrad.getGradientDerivative() + .getEntry(i)) > prec.eps2() + ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0 + } + val err = MinimumError(mat, dcovar) + val edm: Double = VariableMetricEDMEstimator().estimate(dgrad, err) + val state = MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()) + return MinimumSeed(state, st.getTransformation()) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SinParameterTransformation.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SinParameterTransformation.kt new file mode 100644 index 000000000..821addef7 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SinParameterTransformation.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal class SinParameterTransformation { + fun dInt2Ext(value: Double, upper: Double, lower: Double): Double { + return 0.5 * abs((upper - lower) * cos(value)) + } + + fun ext2int(value: Double, upper: Double, lower: Double, prec: MnMachinePrecision): Double { + val piby2: Double = 2.0 * atan(1.0) + val distnn: Double = 8.0 * sqrt(prec.eps2()) + val vlimhi = piby2 - distnn + val vlimlo = -piby2 + distnn + val yy = 2.0 * (value - lower) / (upper - lower) - 1.0 + val yy2 = yy * yy + return if (yy2 > 1.0 - prec.eps2()) { + if (yy < 0.0) { + vlimlo + } else { + vlimhi + } + } else { + asin(yy) + } + } + + fun int2ext(value: Double, upper: Double, lower: Double): Double { + return lower + 0.5 * (upper - lower) * (sin(value) + 1.0) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtLowParameterTransformation.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtLowParameterTransformation.kt new file mode 100644 index 000000000..444b63847 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtLowParameterTransformation.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal class SqrtLowParameterTransformation { + // derivative of transformation from internal to external + fun dInt2Ext(value: Double, lower: Double): Double { + return value / sqrt(value * value + 1.0) + } + + // transformation from external to internal + fun ext2int(value: Double, lower: Double, prec: MnMachinePrecision): Double { + val yy = value - lower + 1.0 + val yy2 = yy * yy + return if (yy2 < 1.0 + prec.eps2()) { + 8 * sqrt(prec.eps2()) + } else { + sqrt(yy2 - 1) + } + } + + // transformation from internal to external + fun int2ext(value: Double, lower: Double): Double { + return lower - 1.0 + sqrt(value * value + 1.0) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtUpParameterTransformation.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtUpParameterTransformation.kt new file mode 100644 index 000000000..5774848bd --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtUpParameterTransformation.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal class SqrtUpParameterTransformation { + // derivative of transformation from internal to external + fun dInt2Ext(value: Double, upper: Double): Double { + return -value / sqrt(value * value + 1.0) + } + + // transformation from external to internal + fun ext2int(value: Double, upper: Double, prec: MnMachinePrecision): Double { + val yy = upper - value + 1.0 + val yy2 = yy * yy + return if (yy2 < 1.0 + prec.eps2()) { + 8 * sqrt(prec.eps2()) + } else { + sqrt(yy2 - 1) + } + } + + // transformation from internal to external + fun int2ext(value: Double, upper: Double): Double { + return upper + 1.0 - sqrt(value * value + 1.0) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricBuilder.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricBuilder.kt new file mode 100644 index 000000000..8362c5e7e --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricBuilder.kt @@ -0,0 +1,137 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +import space.kscience.kmath.optimization.minuit.MINUITPlugin +import ru.inr.mass.minuit.* + +/** + * + * @version $Id$ + */ +internal class VariableMetricBuilder : MinimumBuilder { + private val theErrorUpdator: DavidonErrorUpdator + private val theEstimator: VariableMetricEDMEstimator = VariableMetricEDMEstimator() + fun errorUpdator(): DavidonErrorUpdator { + return theErrorUpdator + } + + fun estimator(): VariableMetricEDMEstimator { + return theEstimator + } + + /** {@inheritDoc} */ + fun minimum( + fcn: MnFcn, + gc: GradientCalculator, + seed: MinimumSeed, + strategy: MnStrategy, + maxfcn: Int, + edmval: Double + ): FunctionMinimum { + val min: FunctionMinimum = minimum(fcn, gc, seed, maxfcn, edmval) + if (strategy.strategy() === 2 || strategy.strategy() === 1 && min.error().dcovar() > 0.05) { + val st: MinimumState = MnHesse(strategy).calculate(fcn, min.state(), min.seed().trafo(), 0) + min.add(st) + } + if (!min.isValid()) { + MINUITPlugin.logStatic("FunctionMinimum is invalid.") + } + return min + } + + fun minimum(fcn: MnFcn, gc: GradientCalculator, seed: MinimumSeed, maxfcn: Int, edmval: Double): FunctionMinimum { + var edmval = edmval + edmval *= 0.0001 + if (seed.parameters().vec().getDimension() === 0) { + return FunctionMinimum(seed, fcn.errorDef()) + } + val prec: MnMachinePrecision = seed.precision() + val result: MutableList = java.util.ArrayList(8) + var edm: Double = seed.state().edm() + if (edm < 0.0) { + MINUITPlugin.logStatic("VariableMetricBuilder: initial matrix not pos.def.") + if (seed.error().isPosDef()) { + throw RuntimeException("Something is wrong!") + } + return FunctionMinimum(seed, fcn.errorDef()) + } + result.add(seed.state()) + + // iterate until edm is small enough or max # of iterations reached + edm *= 1.0 + 3.0 * seed.error().dcovar() + var step: RealVector // = new ArrayRealVector(seed.gradient().getGradient().getDimension()); + do { + var s0: MinimumState = result[result.size - 1] + step = MnUtils.mul(MnUtils.mul(s0.error().invHessian(), s0.gradient().getGradient()), -1) + var gdel: Double = MnUtils.innerProduct(step, s0.gradient().getGradient()) + if (gdel > 0.0) { + MINUITPlugin.logStatic("VariableMetricBuilder: matrix not pos.def.") + MINUITPlugin.logStatic("gdel > 0: $gdel") + s0 = MnPosDef.test(s0, prec) + step = MnUtils.mul(MnUtils.mul(s0.error().invHessian(), s0.gradient().getGradient()), -1) + gdel = MnUtils.innerProduct(step, s0.gradient().getGradient()) + MINUITPlugin.logStatic("gdel: $gdel") + if (gdel > 0.0) { + result.add(s0) + return FunctionMinimum(seed, result, fcn.errorDef()) + } + } + val pp: MnParabolaPoint = MnLineSearch.search(fcn, s0.parameters(), step, gdel, prec) + if (abs(pp.y() - s0.fval()) < prec.eps()) { + MINUITPlugin.logStatic("VariableMetricBuilder: no improvement") + break //no improvement + } + val p = MinimumParameters(MnUtils.add(s0.vec(), MnUtils.mul(step, pp.x())), pp.y()) + val g: FunctionGradient = gc.gradient(p, s0.gradient()) + edm = estimator().estimate(g, s0.error()) + if (edm < 0.0) { + MINUITPlugin.logStatic("VariableMetricBuilder: matrix not pos.def.") + MINUITPlugin.logStatic("edm < 0") + s0 = MnPosDef.test(s0, prec) + edm = estimator().estimate(g, s0.error()) + if (edm < 0.0) { + result.add(s0) + return FunctionMinimum(seed, result, fcn.errorDef()) + } + } + val e: MinimumError = errorUpdator().update(s0, p, g) + result.add(MinimumState(p, e, g, edm, fcn.numOfCalls())) + // result[0] = MinimumState(p, e, g, edm, fcn.numOfCalls()); + edm *= 1.0 + 3.0 * e.dcovar() + } while (edm > edmval && fcn.numOfCalls() < maxfcn) + if (fcn.numOfCalls() >= maxfcn) { + MINUITPlugin.logStatic("VariableMetricBuilder: call limit exceeded.") + return FunctionMinimum(seed, result, fcn.errorDef(), MnReachedCallLimit()) + } + return if (edm > edmval) { + if (edm < abs(prec.eps2() * result[result.size - 1].fval())) { + MINUITPlugin.logStatic("VariableMetricBuilder: machine accuracy limits further improvement.") + FunctionMinimum(seed, result, fcn.errorDef()) + } else if (edm < 10.0 * edmval) { + FunctionMinimum(seed, result, fcn.errorDef()) + } else { + MINUITPlugin.logStatic("VariableMetricBuilder: finishes without convergence.") + MINUITPlugin.logStatic("VariableMetricBuilder: edm= $edm requested: $edmval") + FunctionMinimum(seed, result, fcn.errorDef(), MnAboveMaxEdm()) + } + } else FunctionMinimum(seed, result, fcn.errorDef()) + } + + init { + theErrorUpdator = DavidonErrorUpdator() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricEDMEstimator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricEDMEstimator.kt new file mode 100644 index 000000000..8fca4e6ee --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricEDMEstimator.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @author tonyj + * @version $Id$ + */ +internal class VariableMetricEDMEstimator { + fun estimate(g: FunctionGradient, e: MinimumError): Double { + if (e.invHessian().size() === 1) { + return 0.5 * g.getGradient().getEntry(0) * g.getGradient().getEntry(0) * e.invHessian()[0, 0] + } + val rho: Double = MnUtils.similarity(g.getGradient(), e.invHessian()) + return 0.5 * rho + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricMinimizer.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricMinimizer.kt new file mode 100644 index 000000000..2a13a5fff --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricMinimizer.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + +/** + * + * @version $Id$ + */ +internal class VariableMetricMinimizer : ModularFunctionMinimizer() { + private val theMinBuilder: VariableMetricBuilder + private val theMinSeedGen: MnSeedGenerator = MnSeedGenerator() + + /** {@inheritDoc} */ + override fun builder(): MinimumBuilder { + return theMinBuilder + } + + /** {@inheritDoc} */ + override fun seedGenerator(): MinimumSeedGenerator { + return theMinSeedGen + } + + /** + * + * Constructor for VariableMetricMinimizer. + */ + init { + theMinBuilder = VariableMetricBuilder() + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/package-info.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/package-info.kt new file mode 100644 index 000000000..22779da86 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/package-info.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.minuit + diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt new file mode 100644 index 000000000..02fd12dbc --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt @@ -0,0 +1,380 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.optimization.qow + +import space.kscience.kmath.data.ColumnarData +import space.kscience.kmath.data.XYErrorColumnarData +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.SymbolIndexer +import space.kscience.kmath.expressions.derivative +import space.kscience.kmath.linear.* +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.Field +import space.kscience.kmath.optimization.OptimizationFeature +import space.kscience.kmath.optimization.OptimizationProblemFactory +import space.kscience.kmath.optimization.OptimizationResult +import space.kscience.kmath.optimization.XYFit +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.DoubleL2Norm +import kotlin.math.pow + + +private typealias ParamSet = Map + +public fun interface FitLogger { + public fun log(block: () -> String) +} + +@OptIn(UnstableKMathAPI::class) +public class QowFit( + override val symbols: List, + private val space: LinearSpace, + private val solver: LinearSolver, +) : XYFit, SymbolIndexer { + + private var logger: FitLogger? = null + + private var startingPoint: Map = TODO() + private var covariance: Matrix? = TODO() + private val prior: DifferentiableExpression>? = TODO() + private var data: XYErrorColumnarData = TODO() + private var model: DifferentiableExpression> = TODO() + + private val features = HashSet() + + override fun update(result: OptimizationResult) { + TODO("Not yet implemented") + } + + override val algebra: Field + get() = TODO("Not yet implemented") + + override fun data( + dataSet: ColumnarData, + xSymbol: Symbol, + ySymbol: Symbol, + xErrSymbol: Symbol?, + yErrSymbol: Symbol?, + ) { + TODO("Not yet implemented") + } + + override fun model(model: (Double) -> DifferentiableExpression) { + TODO("Not yet implemented") + } + + private var x: Symbol = Symbol.x + + /** + * The signed distance from the model to the [i]-th point of data. + */ + private fun distance(i: Int, parameters: Map): Double = + model(parameters + (x to data.x[i])) - data.y[i] + + + /** + * The derivative of [distance] + * TODO use expressions instead + */ + private fun distanceDerivative(symbol: Symbol, i: Int, parameters: Map): Double = + model.derivative(symbol)(parameters + (x to data.x[i])) + + /** + * The dispersion of [i]-th data point + */ + private fun getDispersion(i: Int, parameters: Map): Double = data.yErr[i].pow(2) + + private fun getCovariance(weight: QoWeight): Matrix = solver.inverse(getEqDerivValues(weight)) + + /** + * Теоретическая ковариация весовых функций. + * + * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 + */ + private fun covarF(weight: QoWeight): Matrix = space.buildSymmetricMatrix(symbols.size) { k, l -> + (0 until data.size).sumOf { i -> weight.derivs[k, i] * weight.derivs[l, i] / weight.dispersion[i] } + } + + /** + * Экспериментальная ковариация весов. Формула (22) из + * http://arxiv.org/abs/physics/0604127 + * + * @param source + * @param set + * @param fitPars + * @param weight + * @return + */ + private fun covarFExp(weight: QoWeight, theta: Map): Matrix = space.run { + /* + * Важно! Если не делать предварителього вычисления этих производных, то + * количество вызывов функции будет dim^2 вместо dim Первый индекс - + * номер точки, второй - номер переменной, по которой берется производная + */ + val eqvalues = buildMatrix(data.size, symbols.size) { i, l -> + distance(i, theta) * weight.derivs[l, i] / weight.dispersion[i] + } + + buildMatrix(symbols.size, symbols.size) { k, l -> + (0 until data.size).sumOf { i -> eqvalues[i, l] * eqvalues[i, k] } + } + } + + /** + * производные уравнений для метода Ньютона + * + * @param source + * @param set + * @param fitPars + * @param weight + * @return + */ + private fun getEqDerivValues( + weight: QoWeight, theta: Map = weight.theta, + ): Matrix = space.run { + val fitDim = symbols.size + //Возвращает производную k-того Eq по l-тому параметру + val res = Array(fitDim) { DoubleArray(fitDim) } + val sderiv = buildMatrix(data.size, symbols.size) { i, l -> + distanceDerivative(symbols[l], i, theta) + } + + buildMatrix(symbols.size, symbols.size) { k, l -> + val base = (0 until data.size).sumOf { i -> + require(weight.dispersion[i] > 0) + sderiv[i, l] * weight.derivs[k, i] / weight.dispersion[i] + } + prior?.let { prior -> + //Check if this one is correct + val pi = prior(theta) + val deriv1 = prior.derivative(symbols[k])(theta) + val deriv2 = prior.derivative(symbols[l])(theta) + base + deriv1 * deriv2 / pi / pi + } ?: base + } + } + + + /** + * Значения уравнений метода квазиоптимальных весов + * + * @param source + * @param set + * @param fitPars + * @param weight + * @return + */ + private fun getEqValues(weight: QoWeight, theta: Map = weight.theta): Point { + val distances = DoubleBuffer(data.size) { i -> distance(i, theta) } + + return DoubleBuffer(symbols.size) { k -> + val base = (0 until data.size).sumOf { i -> distances[i] * weight.derivs[k, i] / weight.dispersion[i] } + //Поправка на априорную вероятность + prior?.let { prior -> + base - prior.derivative(symbols[k])(theta) / prior(theta) + } ?: base + } + } + + + /** + * The state of QOW fitter + * Created by Alexander Nozik on 17-Oct-16. + */ + private inner class QoWeight( + val theta: Map, + ) { + + init { + require(data.size > 0) { "The state does not contain data" } + } + + /** + * Derivatives of the spectrum over parameters. First index in the point number, second one - index of parameter + */ + val derivs: Matrix by lazy { + space.buildMatrix(data.size, symbols.size) { i, k -> + distanceDerivative(symbols[k], i, theta) + } + } + + /** + * Array of dispersions in each point + */ + val dispersion: Point by lazy { + DoubleBuffer(data.size) { i -> getDispersion(i, theta) } + } + + } + + private fun newtonianStep( + weight: QoWeight, + par: Map, + eqvalues: Point, + ): Map = space.run { + val start = par.toPoint() + val invJacob = solver.inverse(getEqDerivValues(weight, par)) + + val step = invJacob.dot(eqvalues) + return par + (start - step).toMap() + } + + private fun newtonianRun( + weight: QoWeight, + maxSteps: Int = 100, + tolerance: Double = 0.0, + fast: Boolean = false, + ): ParamSet { + + var dis: Double//норма невязки + // Для удобства работаем всегда с полным набором параметров + var par = startingPoint + + logger?.log { "Starting newtonian iteration from: \n\t$par" } + + var eqvalues = getEqValues(weight, par)//значения функций + + dis = DoubleL2Norm.norm(eqvalues)// невязка + logger?.log { "Starting discrepancy is $dis" } + var i = 0 + var flag = false + while (!flag) { + i++ + logger?.log { "Starting step number $i" } + + val currentSolution = if (fast) { + //Берет значения матрицы в той точке, где считается вес + newtonianStep(weight, weight.theta, eqvalues) + } else { + //Берет значения матрицы в точке par + newtonianStep(weight, par, eqvalues) + } + // здесь должен стоять учет границ параметров + logger?.log { "Parameter values after step are: \n\t$currentSolution" } + + eqvalues = getEqValues(weight, currentSolution) + val currentDis = DoubleL2Norm.norm(eqvalues)// невязка после шага + + logger?.log { "The discrepancy after step is: $currentDis." } + + if (currentDis >= dis && i > 1) { + //дополнительно проверяем, чтобы был сделан хотя бы один шаг + flag = true + logger?.log { "The discrepancy does not decrease. Stopping iteration." } + } else { + par = currentSolution + 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 par + } + + +// +// override fun run(state: FitState, parentLog: History?, meta: Meta): FitResult { +// val log = Chronicle("QOW", parentLog) +// val action = meta.getString(FIT_STAGE_TYPE, TASK_RUN) +// log.report("QOW fit engine started task '{}'", action) +// return when (action) { +// TASK_SINGLE -> makeRun(state, log, meta) +// TASK_COVARIANCE -> generateErrors(state, log, meta) +// TASK_RUN -> { +// var res = makeRun(state, log, meta) +// res = makeRun(res.optState().get(), log, meta) +// generateErrors(res.optState().get(), log, meta) +// } +// else -> throw IllegalArgumentException("Unknown task") +// } +// } + +// private fun makeRun(state: FitState, log: History, meta: Meta): FitResult { +// /*Инициализация объектов, задание исходных значений*/ +// log.report("Starting fit using quasioptimal weights method.") +// +// val fitPars = getFitPars(state, meta) +// +// val curWeight = QoWeight(state, fitPars, state.parameters) +// +// // вычисляем вес в allPar. Потом можно будет попробовать ручное задание веса +// log.report("The starting weight is: \n\t{}", +// MathUtils.toString(curWeight.theta)) +// +// //Стартовая точка такая же как и параметр веса +// /*Фитирование*/ +// val res = newtonianRun(state, curWeight, log, meta) +// +// /*Генерация результата*/ +// +// return FitResult.build(state.edit().setPars(res).build(), *fitPars) +// } + + /** + * generateErrors. + */ + private fun generateErrors(): Matrix { + logger?.log { """ + Starting errors estimation using quasioptimal weights method. The starting weight is: + ${curWeight.theta} + """.trimIndent()} + val curWeight = QoWeight(startingPoint) + + val covar = getCovariance(curWeight) + + val decomposition = EigenDecomposition(covar.matrix) + var valid = true + for (lambda in decomposition.realEigenvalues) { + if (lambda <= 0) { + log.report("The covariance matrix is not positive defined. Error estimation is not valid") + valid = false + } + } + } + + + override suspend fun optimize(): OptimizationResult { + val curWeight = QoWeight(startingPoint) + logger?.log { + """ + Starting fit using quasioptimal weights method. The starting weight is: + ${curWeight.theta} + """.trimIndent() + } + val res = newtonianRun(curWeight) + } + + + companion object : OptimizationProblemFactory { + override fun build(symbols: List): QowFit { + TODO("Not yet implemented") + } + + + /** + * Constant `QOW_ENGINE_NAME="QOW"` + */ + const val QOW_ENGINE_NAME = "QOW" + + /** + * Constant `QOW_METHOD_FAST="fast"` + */ + const val QOW_METHOD_FAST = "fast" + + + } +} + -- 2.34.1 From 7b6361e59d48d2ee12edbda6f99af91b1e38f0a5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 26 Apr 2021 15:02:19 +0300 Subject: [PATCH 002/102] [WIP] optimization refactor in process --- .../commons/optimization/CMOptimization.kt | 112 +++++---------- .../kmath/commons/optimization/cmFit.kt | 8 +- .../space/kscience/kmath/misc/Featured.kt | 4 +- .../space/kscience/kmath/misc/logging.kt | 14 ++ .../optimization/FunctionOptimization.kt | 130 +++++++----------- .../kmath/optimization/OptimizationProblem.kt | 6 + .../kscience/kmath/optimization/XYFit.kt | 34 ++++- .../kscience/kmath/optimization/qow/QowFit.kt | 4 - 8 files changed, 146 insertions(+), 166 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt index db9ba6f21..6bde14627 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt @@ -11,10 +11,8 @@ import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction 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.AbstractSimplex -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer -import space.kscience.kmath.expressions.* +import space.kscience.kmath.expressions.derivative +import space.kscience.kmath.expressions.withSymbols import space.kscience.kmath.misc.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.optimization.* @@ -24,107 +22,73 @@ public operator fun PointValuePair.component1(): DoubleArray = point public operator fun PointValuePair.component2(): Double = value public class CMOptimizerFactory(public val optimizerBuilder: () -> MultivariateOptimizer) : OptimizationFeature -//public class CMOptimizerData(public val ) +public class CMOptimizerData(public val data: List) : OptimizationFeature { + public constructor(vararg data: OptimizationData) : this(data.toList()) +} @OptIn(UnstableKMathAPI::class) public class CMOptimization : Optimizer> { override suspend fun process( - problem: FunctionOptimization - ): FunctionOptimization = withSymbols(problem.parameters){ - val cmOptimizer: MultivariateOptimizer = - problem.getFeature()?.optimizerBuilder?.invoke() ?: SimplexOptimizer() - + problem: FunctionOptimization, + ): FunctionOptimization = withSymbols(problem.parameters) { val convergenceChecker: ConvergenceChecker = SimpleValueChecker( DEFAULT_RELATIVE_TOLERANCE, DEFAULT_ABSOLUTE_TOLERANCE, DEFAULT_MAX_ITER ) + val cmOptimizer: MultivariateOptimizer = problem.getFeature()?.optimizerBuilder?.invoke() + ?: NonLinearConjugateGradientOptimizer( + NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, + convergenceChecker + ) + val optimizationData: HashMap, OptimizationData> = HashMap() fun addOptimizationData(data: OptimizationData) { optimizationData[data::class] = data } + addOptimizationData(MaxEval.unlimited()) addOptimizationData(InitialGuess(problem.initialGuess.toDoubleArray())) fun exportOptimizationData(): List = optimizationData.values.toList() - - /** - * Register no-deriv function instead of differentiable function - */ - /** - * Register no-deriv function instead of differentiable function - */ - fun noDerivFunction(expression: Expression): Unit { - val objectiveFunction = ObjectiveFunction { - val args = problem.initialGuess + it.toMap() - expression(args) - } - addOptimizationData(objectiveFunction) + val objectiveFunction = ObjectiveFunction { + val args = problem.initialGuess + it.toMap() + problem.expression(args) } + addOptimizationData(objectiveFunction) - public override fun function(expression: DifferentiableExpression>) { - noDerivFunction(expression) - val gradientFunction = ObjectiveFunctionGradient { - val args = startingPoint + it.toMap() - DoubleArray(symbols.size) { index -> - expression.derivative(symbols[index])(args) - } - } - addOptimizationData(gradientFunction) - if (optimizerBuilder == null) { - optimizerBuilder = { - NonLinearConjugateGradientOptimizer( - NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, - convergenceChecker - ) + val gradientFunction = ObjectiveFunctionGradient { + val args = problem.initialGuess + it.toMap() + DoubleArray(symbols.size) { index -> + problem.expression.derivative(symbols[index])(args) + } + } + addOptimizationData(gradientFunction) + + val logger = problem.getFeature() + + for (feature in problem.features) { + when (feature) { + is CMOptimizerData -> feature.data.forEach { addOptimizationData(it) } + is FunctionOptimizationTarget -> when(feature){ + FunctionOptimizationTarget.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE) + FunctionOptimizationTarget.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE) } + else -> logger?.log { "The feature $feature is unused in optimization" } } } - public fun simplex(simplex: AbstractSimplex) { - addOptimizationData(simplex) - //Set optimization builder to simplex if it is not present - if (optimizerBuilder == null) { - optimizerBuilder = { SimplexOptimizer(convergenceChecker) } - } - } - - public fun simplexSteps(steps: Map) { - simplex(NelderMeadSimplex(steps.toDoubleArray())) - } - - public fun goal(goalType: GoalType) { - addOptimizationData(goalType) - } - - public fun optimizer(block: () -> MultivariateOptimizer) { - optimizerBuilder = block - } - - override fun update(result: OptimizationResult) { - initialGuess(result.point) - } - - override suspend fun optimize(): OptimizationResult { - val optimizer = optimizerBuilder?.invoke() ?: error("Optimizer not defined") - val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray()) - return OptimizationResult(point.toMap(), value) - } - return@withSymbols TODO() + val (point, value) = cmOptimizer.optimize(*optimizationData.values.toTypedArray()) + return problem.withFeatures(FunctionOptimizationResult(point.toMap(), value)) } - public companion object : OptimizationProblemFactory { + public companion object { public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 public const val DEFAULT_MAX_ITER: Int = 1000 - - override fun build(symbols: List): CMOptimization = CMOptimization(symbols) } } - -public fun CMOptimization.initialGuess(vararg pairs: Pair): Unit = initialGuess(pairs.toMap()) -public fun CMOptimization.simplexSteps(vararg pairs: Pair): Unit = simplexSteps(pairs.toMap()) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt index 12d924063..9c0089b3d 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt @@ -17,22 +17,22 @@ import space.kscience.kmath.structures.asBuffer /** * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation */ -public fun FunctionOptimization.Companion.chiSquared( +public fun FunctionOptimization.Companion.chiSquaredExpression( x: Buffer, y: Buffer, yErr: Buffer, model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, -): DifferentiableExpression> = chiSquared(DerivativeStructureField, x, y, yErr, model) +): DifferentiableExpression> = chiSquaredExpression(DerivativeStructureField, x, y, yErr, model) /** * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation */ -public fun FunctionOptimization.Companion.chiSquared( +public fun FunctionOptimization.Companion.chiSquaredExpression( x: Iterable, y: Iterable, yErr: Iterable, model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, -): DifferentiableExpression> = chiSquared( +): DifferentiableExpression> = chiSquaredExpression( DerivativeStructureField, x.toList().asBuffer(), y.toList().asBuffer(), 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 157ff980b..a94efc788 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 @@ -17,7 +17,7 @@ public interface Featured { /** * A container for a set of features */ -public class FeatureSet private constructor(public val features: Map, Any>) : Featured { +public class FeatureSet private constructor(public val features: Map, F>) : Featured { @Suppress("UNCHECKED_CAST") override fun getFeature(type: KClass): T? = features[type] as? T @@ -31,6 +31,8 @@ public class FeatureSet private constructor(public val features: Map = FeatureSet(features + otherFeatures.associateBy { it::class }) + public operator fun iterator(): Iterator = features.values.iterator() + public companion object { public fun of(vararg features: F): FeatureSet = FeatureSet(features.associateBy { it::class }) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt new file mode 100644 index 000000000..d13840841 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.misc + +public interface Loggable { + public fun log(tag: String = INFO, block: () -> String) + + public companion object { + public const val INFO: String = "INFO" + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index 12ccea1d8..db613e236 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -15,91 +15,57 @@ import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.indices +public class FunctionOptimizationResult(point: Map, public val value: T) : OptimizationResult(point) -public class FunctionOptimization( +public enum class FunctionOptimizationTarget : OptimizationFeature { + MAXIMIZE, + MINIMIZE +} + +public class FunctionOptimization( override val features: FeatureSet, public val expression: DifferentiableExpression>, public val initialGuess: Map, public val parameters: Collection, - public val maximize: Boolean, -) : OptimizationProblem +) : OptimizationProblem{ + public companion object{ + /** + * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation + */ + public fun chiSquaredExpression( + autoDiff: AutoDiffProcessor>, + x: Buffer, + y: Buffer, + yErr: Buffer, + model: A.(I) -> I, + ): DifferentiableExpression> where A : ExtendedField, A : ExpressionAlgebra { + require(x.size == y.size) { "X and y buffers should be of the same size" } + require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } + + return autoDiff.process { + var sum = zero + + x.indices.forEach { + val xValue = const(x[it]) + val yValue = const(y[it]) + val yErrValue = const(yErr[it]) + val modelValue = model(xValue) + sum += ((yValue - modelValue) / yErrValue).pow(2) + } + + sum + } + } + } +} + + +public fun FunctionOptimization.withFeatures( + vararg newFeature: OptimizationFeature, +): FunctionOptimization = FunctionOptimization( + features.with(*newFeature), + expression, + initialGuess, + parameters +) -// -///** -// * A likelihood function optimization problem with provided derivatives -// */ -//public interface FunctionOptimizationBuilder { -// /** -// * The optimization direction. If true search for function maximum, if false, search for the minimum -// */ -// public var maximize: Boolean -// -// /** -// * Define the initial guess for the optimization problem -// */ -// public fun initialGuess(map: Map) -// -// /** -// * Set a differentiable expression as objective function as function and gradient provider -// */ -// public fun function(expression: DifferentiableExpression>) -// -// public companion object { -// /** -// * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation -// */ -// public fun chiSquared( -// autoDiff: AutoDiffProcessor>, -// x: Buffer, -// y: Buffer, -// yErr: Buffer, -// model: A.(I) -> I, -// ): DifferentiableExpression> where A : ExtendedField, A : ExpressionAlgebra { -// require(x.size == y.size) { "X and y buffers should be of the same size" } -// require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } -// -// return autoDiff.process { -// var sum = zero -// -// x.indices.forEach { -// val xValue = const(x[it]) -// val yValue = const(y[it]) -// val yErrValue = const(yErr[it]) -// val modelValue = model(xValue) -// sum += ((yValue - modelValue) / yErrValue).pow(2) -// } -// -// sum -// } -// } -// } -//} -// -///** -// * Define a chi-squared-based objective function -// */ -//public fun FunctionOptimization.chiSquared( -// autoDiff: AutoDiffProcessor>, -// x: Buffer, -// y: Buffer, -// yErr: Buffer, -// model: A.(I) -> I, -//) where A : ExtendedField, A : ExpressionAlgebra { -// val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) -// function(chiSquared) -// maximize = false -//} -// -///** -// * Optimize differentiable expression using specific [OptimizationProblemFactory] -// */ -//public suspend fun > DifferentiableExpression>.optimizeWith( -// factory: OptimizationProblemFactory, -// vararg symbols: Symbol, -// configuration: F.() -> Unit, -//): OptimizationResult { -// require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } -// val problem = factory(symbols.toList(), configuration) -// problem.function(this) -// return problem.optimize() -//} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt index 9a5420be6..0d2e3cb83 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -7,6 +7,8 @@ package space.kscience.kmath.optimization import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.Featured +import space.kscience.kmath.misc.Loggable +import space.kscience.kmath.misc.Symbol import kotlin.reflect.KClass public interface OptimizationFeature @@ -18,6 +20,10 @@ public interface OptimizationProblem : Featured { public inline fun OptimizationProblem.getFeature(): T? = getFeature(T::class) +public open class OptimizationResult(public val point: Map) : OptimizationFeature + +public class OptimizationLog(private val loggable: Loggable) : Loggable by loggable, OptimizationFeature + //public class OptimizationResult( // public val point: Map, // public val value: T, diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt index e4998c665..f1b6ef38d 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -14,9 +14,11 @@ import space.kscience.kmath.misc.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.Field +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.indices @UnstableKMathAPI -public interface XYFit : OptimizationProblem { +public interface XYFit : OptimizationProblem { public val algebra: Field @@ -42,4 +44,34 @@ public interface XYFit : OptimizationProblem { ): Unit where A : ExtendedField, A : ExpressionAlgebra = model { arg -> autoDiff.process { modelFunction(const(arg)) } } +} + +// +///** +// * Define a chi-squared-based objective function +// */ +//public fun FunctionOptimization.chiSquared( +// autoDiff: AutoDiffProcessor>, +// x: Buffer, +// y: Buffer, +// yErr: Buffer, +// model: A.(I) -> I, +//) where A : ExtendedField, A : ExpressionAlgebra { +// val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) +// function(chiSquared) +// maximize = false +//} + +/** + * Optimize differentiable expression using specific [OptimizationProblemFactory] + */ +public suspend fun > DifferentiableExpression>.optimizeWith( + factory: OptimizationProblemFactory, + vararg symbols: Symbol, + configuration: F.() -> Unit, +): OptimizationResult { + require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } + val problem = factory(symbols.toList(), configuration) + problem.function(this) + return problem.optimize() } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt index 02fd12dbc..d611adf50 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt @@ -27,10 +27,6 @@ import kotlin.math.pow private typealias ParamSet = Map -public fun interface FitLogger { - public fun log(block: () -> String) -} - @OptIn(UnstableKMathAPI::class) public class QowFit( override val symbols: List, -- 2.34.1 From 88e94a7fd9cc64dbb4d892b21cedef237bfd0045 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 24 May 2021 17:02:12 +0300 Subject: [PATCH 003/102] [WIP] Optimization --- .../kmath/commons/fit/fitWithAutoDiff.kt | 1 - .../commons/optimization/CMOptimization.kt | 103 ++++++++++-------- .../kmath/commons/optimization/cmFit.kt | 2 +- .../kmath/data/XYErrorColumnarData.kt | 6 +- .../kmath/integration/GaussIntegrator.kt | 4 +- .../kscience/kmath/integration/Integrand.kt | 10 +- .../integration/MultivariateIntegrand.kt | 16 +-- .../kmath/integration/SimpsonIntegrator.kt | 4 +- .../kmath/integration/SplineIntegrator.kt | 4 +- .../kmath/integration/UnivariateIntegrand.kt | 23 ++-- .../optimization/FunctionOptimization.kt | 10 +- .../kmath/optimization/OptimizationProblem.kt | 43 +++----- .../kscience/kmath/optimization/XYFit.kt | 21 ++-- .../kmath/optimization/minuit/Range.kt | 32 ------ .../kscience/kmath/optimization/qow/QowFit.kt | 6 +- 15 files changed, 119 insertions(+), 166 deletions(-) delete mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Range.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt index 5e64235e3..5660c76e8 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt @@ -8,7 +8,6 @@ package space.kscience.kmath.commons.fit import kotlinx.html.br import kotlinx.html.h3 import space.kscience.kmath.commons.optimization.chiSquared -import space.kscience.kmath.commons.optimization.minimize import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.expressions.symbol import space.kscience.kmath.optimization.FunctionOptimization diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt index 6bde14627..282f1670d 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt @@ -13,7 +13,6 @@ import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer import space.kscience.kmath.expressions.derivative import space.kscience.kmath.expressions.withSymbols -import space.kscience.kmath.misc.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.optimization.* import kotlin.reflect.KClass @@ -21,9 +20,15 @@ import kotlin.reflect.KClass public operator fun PointValuePair.component1(): DoubleArray = point public operator fun PointValuePair.component2(): Double = value -public class CMOptimizerFactory(public val optimizerBuilder: () -> MultivariateOptimizer) : OptimizationFeature +public class CMOptimizer(public val optimizerBuilder: () -> MultivariateOptimizer): OptimizationFeature{ + override fun toString(): String = "CMOptimizer($optimizerBuilder)" +} + public class CMOptimizerData(public val data: List) : OptimizationFeature { public constructor(vararg data: OptimizationData) : this(data.toList()) + + override fun toString(): String = "CMOptimizerData($data)" + } @OptIn(UnstableKMathAPI::class) @@ -31,59 +36,69 @@ public class CMOptimization : Optimizer> { override suspend fun process( problem: FunctionOptimization, - ): FunctionOptimization = withSymbols(problem.parameters) { - val convergenceChecker: ConvergenceChecker = SimpleValueChecker( - DEFAULT_RELATIVE_TOLERANCE, - DEFAULT_ABSOLUTE_TOLERANCE, - DEFAULT_MAX_ITER - ) + ): FunctionOptimization { + val startPoint = problem.getFeature>()?.point + ?: error("Starting point not defined in $problem") - val cmOptimizer: MultivariateOptimizer = problem.getFeature()?.optimizerBuilder?.invoke() - ?: NonLinearConjugateGradientOptimizer( - NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, - convergenceChecker + val parameters = problem.getFeature()?.symbols + ?: problem.getFeature>()?.point?.keys + ?:startPoint.keys + + + withSymbols(parameters) { + val convergenceChecker: ConvergenceChecker = SimpleValueChecker( + DEFAULT_RELATIVE_TOLERANCE, + DEFAULT_ABSOLUTE_TOLERANCE, + DEFAULT_MAX_ITER ) - val optimizationData: HashMap, OptimizationData> = HashMap() + val cmOptimizer: MultivariateOptimizer = problem.getFeature()?.optimizerBuilder?.invoke() + ?: NonLinearConjugateGradientOptimizer( + NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, + convergenceChecker + ) - fun addOptimizationData(data: OptimizationData) { - optimizationData[data::class] = data - } + val optimizationData: HashMap, OptimizationData> = HashMap() - addOptimizationData(MaxEval.unlimited()) - addOptimizationData(InitialGuess(problem.initialGuess.toDoubleArray())) - - fun exportOptimizationData(): List = optimizationData.values.toList() - - val objectiveFunction = ObjectiveFunction { - val args = problem.initialGuess + it.toMap() - problem.expression(args) - } - addOptimizationData(objectiveFunction) - - val gradientFunction = ObjectiveFunctionGradient { - val args = problem.initialGuess + it.toMap() - DoubleArray(symbols.size) { index -> - problem.expression.derivative(symbols[index])(args) + fun addOptimizationData(data: OptimizationData) { + optimizationData[data::class] = data } - } - addOptimizationData(gradientFunction) - val logger = problem.getFeature() + addOptimizationData(MaxEval.unlimited()) + addOptimizationData(InitialGuess(startPoint.toDoubleArray())) - for (feature in problem.features) { - when (feature) { - is CMOptimizerData -> feature.data.forEach { addOptimizationData(it) } - is FunctionOptimizationTarget -> when(feature){ - FunctionOptimizationTarget.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE) - FunctionOptimizationTarget.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE) + fun exportOptimizationData(): List = optimizationData.values.toList() + + val objectiveFunction = ObjectiveFunction { + val args = startPoint + it.toMap() + problem.expression(args) + } + addOptimizationData(objectiveFunction) + + val gradientFunction = ObjectiveFunctionGradient { + val args = startPoint + it.toMap() + DoubleArray(symbols.size) { index -> + problem.expression.derivative(symbols[index])(args) } - else -> logger?.log { "The feature $feature is unused in optimization" } } - } + addOptimizationData(gradientFunction) - val (point, value) = cmOptimizer.optimize(*optimizationData.values.toTypedArray()) - return problem.withFeatures(FunctionOptimizationResult(point.toMap(), value)) + val logger = problem.getFeature() + + for (feature in problem.features) { + when (feature) { + is CMOptimizerData -> feature.data.forEach { addOptimizationData(it) } + is FunctionOptimizationTarget -> when (feature) { + FunctionOptimizationTarget.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE) + FunctionOptimizationTarget.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE) + } + else -> logger?.log { "The feature $feature is unused in optimization" } + } + } + + val (point, value) = cmOptimizer.optimize(*optimizationData.values.toTypedArray()) + return problem.withFeatures(OptimizationResult(point.toMap()), OptimizationValue(value)) + } } public companion object { diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt index 9c0089b3d..f1095ef73 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt @@ -9,7 +9,7 @@ import org.apache.commons.math3.analysis.differentiation.DerivativeStructure import space.kscience.kmath.commons.expressions.DerivativeStructureField import space.kscience.kmath.expressions.DifferentiableExpression import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.optimization.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer 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 ea98e88b1..7199de888 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,10 +5,10 @@ package space.kscience.kmath.data -import space.kscience.kmath.misc.Symbol -import space.kscience.kmath.misc.Symbol.Companion.z +import space.kscience.kmath.data.XYErrorColumnarData.Companion +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.symbol import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.misc.symbol import space.kscience.kmath.structures.Buffer diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt index 283f97557..f794b075f 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 @@ -51,7 +51,7 @@ public class GaussIntegrator( } } - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand = with(algebra) { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = with(algebra) { val f = integrand.function val (points, weights) = buildRule(integrand) var res = zero @@ -95,7 +95,7 @@ public fun GaussIntegrator.integrate( val ranges = UnivariateIntegrandRanges( (0 until intervals).map { i -> (range.start + rangeSize * i)..(range.start + rangeSize * (i + 1)) to order } ) - return integrate( + return process( UnivariateIntegrand( function, IntegrationRange(range), diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt index f9c26e88b..dcf711c3b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt @@ -5,18 +5,20 @@ package space.kscience.kmath.integration +import space.kscience.kmath.misc.FeatureSet +import space.kscience.kmath.misc.Featured import kotlin.reflect.KClass public interface IntegrandFeature { override fun toString(): String } -public interface Integrand { - public val features: Set - public fun getFeature(type: KClass): T? +public interface Integrand : Featured { + public val features: FeatureSet + override fun getFeature(type: KClass): T? = features.getFeature(type) } -public inline fun Integrand.getFeature(): T? = getFeature(T::class) +public inline fun Integrand.getFeature(): T? = getFeature(T::class) public class IntegrandValue(public val value: T) : IntegrandFeature { override fun toString(): String = "Value($value)" diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt index 5ba411bf9..96b81aaa6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt @@ -6,29 +6,21 @@ package space.kscience.kmath.integration import space.kscience.kmath.linear.Point -import kotlin.reflect.KClass +import space.kscience.kmath.misc.FeatureSet public class MultivariateIntegrand internal constructor( - private val featureMap: Map, IntegrandFeature>, + override val features: FeatureSet, public val function: (Point) -> T, ) : Integrand { - override val features: Set get() = featureMap.values.toSet() - - @Suppress("UNCHECKED_CAST") - override fun getFeature(type: KClass): T? = featureMap[type] as? T - - public operator fun plus(pair: Pair, F>): MultivariateIntegrand = - MultivariateIntegrand(featureMap + pair, function) - public operator fun plus(feature: F): MultivariateIntegrand = - plus(feature::class to feature) + MultivariateIntegrand(features.with(feature), function) } @Suppress("FunctionName") public fun MultivariateIntegrand( vararg features: IntegrandFeature, function: (Point) -> T, -): MultivariateIntegrand = MultivariateIntegrand(features.associateBy { it::class }, function) +): MultivariateIntegrand = MultivariateIntegrand(FeatureSet.of(*features), function) public val MultivariateIntegrand.value: T? get() = getFeature>()?.value diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt index baa9d4af8..77f01101a 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 @@ -43,7 +43,7 @@ public class SimpsonIntegrator( return res } - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { val ranges = integrand.getFeature() return if (ranges != null) { val res = algebra.sum(ranges.ranges.map { integrateRange(integrand, it.first, it.second) }) @@ -89,7 +89,7 @@ public object DoubleSimpsonIntegrator : UnivariateIntegrator { return res } - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { val ranges = integrand.getFeature() return if (ranges != null) { val res = ranges.ranges.sumOf { integrateRange(integrand, it.first, it.second) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index 23d7bdd8d..54fa29e83 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 @@ -53,7 +53,7 @@ public class SplineIntegrator>( public val algebra: Field, public val bufferFactory: MutableBufferFactory, ) : UnivariateIntegrator { - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { val range = integrand.getFeature()?.range ?: 0.0..1.0 val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) @@ -80,7 +80,7 @@ public class SplineIntegrator>( */ @UnstableKMathAPI public object DoubleSplineIntegrator : UnivariateIntegrator { - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { val range = integrand.getFeature()?.range ?: 0.0..1.0 val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::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 e265f54e8..82fed30cd 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,33 +5,24 @@ package space.kscience.kmath.integration +import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer -import kotlin.reflect.KClass public class UnivariateIntegrand internal constructor( - private val featureMap: Map, IntegrandFeature>, + override val features: FeatureSet, public val function: (Double) -> T, ) : Integrand { - - override val features: Set get() = featureMap.values.toSet() - - @Suppress("UNCHECKED_CAST") - override fun getFeature(type: KClass): T? = featureMap[type] as? T - - public operator fun plus(pair: Pair, F>): UnivariateIntegrand = - UnivariateIntegrand(featureMap + pair, function) - public operator fun plus(feature: F): UnivariateIntegrand = - plus(feature::class to feature) + UnivariateIntegrand(features.with(feature), function) } @Suppress("FunctionName") public fun UnivariateIntegrand( function: (Double) -> T, vararg features: IntegrandFeature, -): UnivariateIntegrand = UnivariateIntegrand(features.associateBy { it::class }, function) +): UnivariateIntegrand = UnivariateIntegrand(FeatureSet.of(*features), function) public typealias UnivariateIntegrator = Integrator> @@ -79,7 +70,7 @@ public val UnivariateIntegrand.value: T get() = valueOrNull ?: erro public fun UnivariateIntegrator.integrate( vararg features: IntegrandFeature, function: (Double) -> T, -): UnivariateIntegrand = integrate(UnivariateIntegrand(function, *features)) +): UnivariateIntegrand = process(UnivariateIntegrand(function, *features)) /** * A shortcut method to integrate a [function] in [range] with additional [features]. @@ -90,7 +81,7 @@ public fun UnivariateIntegrator.integrate( range: ClosedRange, vararg features: IntegrandFeature, function: (Double) -> T, -): UnivariateIntegrand = integrate(UnivariateIntegrand(function, IntegrationRange(range), *features)) +): UnivariateIntegrand = process(UnivariateIntegrand(function, IntegrationRange(range), *features)) /** * A shortcut method to integrate a [function] in [range] with additional [features]. @@ -107,5 +98,5 @@ public fun UnivariateIntegrator.integrate( featureBuilder() add(IntegrationRange(range)) } - return integrate(UnivariateIntegrand(function, *features.toTypedArray())) + return process(UnivariateIntegrand(function, *features.toTypedArray())) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index db613e236..e5edb17e0 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -10,12 +10,13 @@ import space.kscience.kmath.expressions.DifferentiableExpression import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.ExpressionAlgebra import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.misc.Symbol import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.indices -public class FunctionOptimizationResult(point: Map, public val value: T) : OptimizationResult(point) +public class OptimizationValue(public val value: T) : OptimizationFeature{ + override fun toString(): String = "Value($value)" +} public enum class FunctionOptimizationTarget : OptimizationFeature { MAXIMIZE, @@ -25,9 +26,8 @@ public enum class FunctionOptimizationTarget : OptimizationFeature { public class FunctionOptimization( override val features: FeatureSet, public val expression: DifferentiableExpression>, - public val initialGuess: Map, - public val parameters: Collection, ) : OptimizationProblem{ + public companion object{ /** * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation @@ -65,7 +65,5 @@ public fun FunctionOptimization.withFeatures( ): FunctionOptimization = FunctionOptimization( features.with(*newFeature), expression, - initialGuess, - parameters ) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt index 0d2e3cb83..53b6af144 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -5,13 +5,15 @@ package space.kscience.kmath.optimization +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.Featured import space.kscience.kmath.misc.Loggable -import space.kscience.kmath.misc.Symbol import kotlin.reflect.KClass -public interface OptimizationFeature +public interface OptimizationFeature { + override fun toString(): String +} public interface OptimizationProblem : Featured { public val features: FeatureSet @@ -20,31 +22,22 @@ public interface OptimizationProblem : Featured { public inline fun OptimizationProblem.getFeature(): T? = getFeature(T::class) -public open class OptimizationResult(public val point: Map) : OptimizationFeature +public open class OptimizationStartPoint(public val point: Map) : OptimizationFeature { + override fun toString(): String = "StartPoint($point)" +} -public class OptimizationLog(private val loggable: Loggable) : Loggable by loggable, OptimizationFeature +public open class OptimizationResult(public val point: Map) : OptimizationFeature { + override fun toString(): String = "Result($point)" +} + +public class OptimizationLog(private val loggable: Loggable) : Loggable by loggable, OptimizationFeature { + override fun toString(): String = "Log($loggable)" +} + +public class OptimizationParameters(public val symbols: List): OptimizationFeature{ + override fun toString(): String = "Parameters($symbols)" +} -//public class OptimizationResult( -// public val point: Map, -// public val value: T, -// public val features: Set = emptySet(), -//) { -// override fun toString(): String { -// return "OptimizationResult(point=$point, value=$value)" -// } -//} -// -//public operator fun OptimizationResult.plus( -// feature: OptimizationFeature, -//): OptimizationResult = OptimizationResult(point, value, features + feature) -//public fun interface OptimizationProblemFactory> { -// public fun build(symbols: List): P -//} -// -//public operator fun > OptimizationProblemFactory.invoke( -// symbols: List, -// block: P.() -> Unit, -//): P = build(symbols).apply(block) public interface Optimizer

{ public suspend fun process(problem: P): P diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt index 637746a27..050f95a10 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -10,8 +10,6 @@ import space.kscience.kmath.expressions.* import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.Field -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices @UnstableKMathAPI public interface XYFit : OptimizationProblem { @@ -59,15 +57,16 @@ public interface XYFit : OptimizationProblem { //} /** - * Optimize differentiable expression using specific [OptimizationProblemFactory] + * Optimize differentiable expression using specific [Optimizer] */ public suspend fun > DifferentiableExpression>.optimizeWith( - factory: OptimizationProblemFactory, - vararg symbols: Symbol, - configuration: F.() -> Unit, -): OptimizationResult { - require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } - val problem = factory(symbols.toList(), configuration) - problem.function(this) - return problem.optimize() + optimizer: Optimizer, + startingPoint: Map, + vararg features: OptimizationFeature +): OptimizationProblem { +// require(startingPoint.isNotEmpty()) { "Must provide a list of symbols for optimization" } +// val problem = factory(symbols.toList(), configuration) +// problem.function(this) +// return problem.optimize() + val problem = FunctionOptimization() } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Range.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Range.kt deleted file mode 100644 index ebeedf7e8..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Range.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * A class representing a pair of double (x,y) or (lower,upper) - * - * @version $Id$ - * @author Darksnake - */ -class Range -/** - * - * Constructor for Range. - * - * @param k a double. - * @param v a double. - */ - (k: Double, v: Double) : Pair(k, v) \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt index d611adf50..2ae33d82f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt @@ -7,12 +7,8 @@ package space.kscience.kmath.optimization.qow import space.kscience.kmath.data.ColumnarData import space.kscience.kmath.data.XYErrorColumnarData -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Expression -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.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Field -- 2.34.1 From c240fa4a9efb55116571622fa57a5c3332a1a166 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 25 May 2021 16:42:23 +0300 Subject: [PATCH 004/102] [WIP] optimization refactoring --- .../kscience/kmath/data/XYColumnarData.kt | 21 +++++ .../kscience/kmath/expressions/Symbol.kt | 16 +++- .../optimization/FunctionOptimization.kt | 17 +++- .../kmath/optimization/OptimizationProblem.kt | 1 + .../kscience/kmath/optimization/XYFit.kt | 72 --------------- .../kmath/optimization/XYOptimization.kt | 92 +++++++++++++++++++ .../kscience/kmath/optimization/qow/QowFit.kt | 4 +- 7 files changed, 141 insertions(+), 82 deletions(-) delete mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt index 08bfd3ca3..2dc82c02e 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 @@ -45,6 +45,27 @@ public fun XYColumnarData(x: Buffer, y: Buffer): XYColum } } +/** + * Represent a [ColumnarData] as an [XYColumnarData]. The presence or respective columns is checked on creation. + */ +@UnstableKMathAPI +public fun ColumnarData.asXYData( + xSymbol: Symbol, + ySymbol: Symbol, +): XYColumnarData = object : XYColumnarData { + init { + requireNotNull(this@asXYData[xSymbol]){"The column with name $xSymbol is not present in $this"} + requireNotNull(this@asXYData[ySymbol]){"The column with name $ySymbol is not present in $this"} + } + override val size: Int get() = this@asXYData.size + override val x: Buffer get() = this@asXYData[xSymbol]!! + override val y: Buffer get() = this@asXYData[ySymbol]!! + override fun get(symbol: Symbol): Buffer? = when (symbol) { + Symbol.x -> x + Symbol.y -> y + else -> this@asXYData.get(symbol) + } +} /** * A zero-copy method to represent a [Structure2D] as a two-column x-y data. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt index 74dc7aedc..4cbdbf55b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt @@ -19,9 +19,12 @@ public interface Symbol : MST { public val identity: String public companion object { - public val x: StringSymbol = StringSymbol("x") - public val y: StringSymbol = StringSymbol("y") - public val z: StringSymbol = StringSymbol("z") + public val x: Symbol = Symbol("x") + public val xError: Symbol = Symbol("x.error") + public val y: Symbol = Symbol("y") + public val yError: Symbol = Symbol("y.error") + public val z: Symbol = Symbol("z") + public val zError: Symbol = Symbol("z.error") } } @@ -29,10 +32,15 @@ public interface Symbol : MST { * A [Symbol] with a [String] identity */ @JvmInline -public value class StringSymbol(override val identity: String) : Symbol { +internal value class StringSymbol(override val identity: String) : Symbol { override fun toString(): String = identity } +/** + * Create s Symbols with a string identity + */ +public fun Symbol(identity: String): Symbol = StringSymbol(identity) + /** * A delegate to create a symbol with a string identity in this scope */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index e5edb17e0..2c70da308 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -5,10 +5,7 @@ package space.kscience.kmath.optimization -import space.kscience.kmath.expressions.AutoDiffProcessor -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.ExpressionAlgebra +import space.kscience.kmath.expressions.* import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.structures.Buffer @@ -67,3 +64,15 @@ public fun FunctionOptimization.withFeatures( expression, ) +/** + * Optimize differentiable expression using specific [optimizer] form given [startingPoint] + */ +public suspend fun DifferentiableExpression>.optimizeWith( + optimizer: Optimizer>, + startingPoint: Map, + vararg features: OptimizationFeature, +): FunctionOptimization { + val problem = FunctionOptimization(FeatureSet.of(OptimizationStartPoint(startingPoint), *features), this) + return optimizer.process(problem) +} + diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt index 53b6af144..2594fa182 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -35,6 +35,7 @@ public class OptimizationLog(private val loggable: Loggable) : Loggable by logga } public class OptimizationParameters(public val symbols: List): OptimizationFeature{ + public constructor(vararg symbols: Symbol) : this(listOf(*symbols)) override fun toString(): String = "Parameters($symbols)" } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt deleted file mode 100644 index 050f95a10..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.data.ColumnarData -import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.Field - -@UnstableKMathAPI -public interface XYFit : OptimizationProblem { - - public val algebra: Field - - /** - * Set X-Y data for this fit optionally including x and y errors - */ - public fun data( - dataSet: ColumnarData, - xSymbol: Symbol, - ySymbol: Symbol, - xErrSymbol: Symbol? = null, - yErrSymbol: Symbol? = null, - ) - - public fun model(model: (T) -> DifferentiableExpression) - - /** - * Set the differentiable model for this fit - */ - public fun model( - autoDiff: AutoDiffProcessor>, - modelFunction: A.(I) -> I, - ): Unit where A : ExtendedField, A : ExpressionAlgebra = model { arg -> - autoDiff.process { modelFunction(const(arg)) } - } -} - -// -///** -// * Define a chi-squared-based objective function -// */ -//public fun FunctionOptimization.chiSquared( -// autoDiff: AutoDiffProcessor>, -// x: Buffer, -// y: Buffer, -// yErr: Buffer, -// model: A.(I) -> I, -//) where A : ExtendedField, A : ExpressionAlgebra { -// val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) -// function(chiSquared) -// maximize = false -//} - -/** - * Optimize differentiable expression using specific [Optimizer] - */ -public suspend fun > DifferentiableExpression>.optimizeWith( - optimizer: Optimizer, - startingPoint: Map, - vararg features: OptimizationFeature -): OptimizationProblem { -// require(startingPoint.isNotEmpty()) { "Must provide a list of symbols for optimization" } -// val problem = factory(symbols.toList(), configuration) -// problem.function(this) -// return problem.optimize() - val problem = FunctionOptimization() -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt new file mode 100644 index 000000000..dda95fcd7 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +@file:OptIn(UnstableKMathAPI::class) + +package space.kscience.kmath.optimization + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.FeatureSet +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke + +public fun interface PointToCurveDistance { + public fun distance(problem: XYOptimization, index: Int): DifferentiableExpression> + + public companion object { + public fun byY( + algebra: Field, + ): PointToCurveDistance = PointToCurveDistance { problem, index -> + algebra { + val x = problem.data.x[index] + val y = problem.data.y[index] + + val model = problem.model(args + (Symbol.x to x)) + model - y + } + } + + +// val default = PointToCurveDistance{args, data, index -> +// +// } + } +} + + +public class XYOptimization( + override val features: FeatureSet, + public val data: XYColumnarData, + public val model: DifferentiableExpression>, +) : OptimizationProblem + +// +//@UnstableKMathAPI +//public interface XYFit : OptimizationProblem { +// +// public val algebra: Field +// +// /** +// * Set X-Y data for this fit optionally including x and y errors +// */ +// public fun data( +// dataSet: ColumnarData, +// xSymbol: Symbol, +// ySymbol: Symbol, +// xErrSymbol: Symbol? = null, +// yErrSymbol: Symbol? = null, +// ) +// +// public fun model(model: (T) -> DifferentiableExpression) +// +// /** +// * Set the differentiable model for this fit +// */ +// public fun model( +// autoDiff: AutoDiffProcessor>, +// modelFunction: A.(I) -> I, +// ): Unit where A : ExtendedField, A : ExpressionAlgebra = model { arg -> +// autoDiff.process { modelFunction(const(arg)) } +// } +//} + +// +///** +// * Define a chi-squared-based objective function +// */ +//public fun FunctionOptimization.chiSquared( +// autoDiff: AutoDiffProcessor>, +// x: Buffer, +// y: Buffer, +// yErr: Buffer, +// model: A.(I) -> I, +//) where A : ExtendedField, A : ExpressionAlgebra { +// val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) +// function(chiSquared) +// maximize = false +//} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt index 2ae33d82f..c78aef401 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt @@ -15,7 +15,7 @@ import space.kscience.kmath.operations.Field import space.kscience.kmath.optimization.OptimizationFeature import space.kscience.kmath.optimization.OptimizationProblemFactory import space.kscience.kmath.optimization.OptimizationResult -import space.kscience.kmath.optimization.XYFit +import space.kscience.kmath.optimization.XYOptimization import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.DoubleL2Norm import kotlin.math.pow @@ -28,7 +28,7 @@ public class QowFit( override val symbols: List, private val space: LinearSpace, private val solver: LinearSolver, -) : XYFit, SymbolIndexer { +) : XYOptimization, SymbolIndexer { private var logger: FitLogger? = null -- 2.34.1 From c8621ee5b759cc364f94e1df3fbdf3262e6a7878 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 25 May 2021 21:11:57 +0300 Subject: [PATCH 005/102] [WIP] optimization refactoring --- .../commons/optimization/CMOptimization.kt | 2 +- .../optimization/FunctionOptimization.kt | 4 +- .../kmath/optimization/OptimizationProblem.kt | 4 -- .../kscience/kmath/optimization/Optimizer.kt | 10 +++ .../kmath/optimization/XYOptimization.kt | 62 +++++++++++++------ 5 files changed, 56 insertions(+), 26 deletions(-) create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt index 549683d60..2faee1f5d 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt @@ -35,7 +35,7 @@ public class CMOptimizerData(public val data: List) : Optimiza @OptIn(UnstableKMathAPI::class) public class CMOptimization : Optimizer> { - override suspend fun process( + override suspend fun optimize( problem: FunctionOptimization, ): FunctionOptimization { val startPoint = problem.getFeature>()?.point diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index ee75bfbd6..62288242a 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -67,12 +67,12 @@ public fun FunctionOptimization.withFeatures( /** * Optimize differentiable expression using specific [optimizer] form given [startingPoint] */ -public suspend fun DifferentiableExpression>.optimizeWith( +public suspend fun DifferentiableExpression.optimizeWith( optimizer: Optimizer>, startingPoint: Map, vararg features: OptimizationFeature, ): FunctionOptimization { val problem = FunctionOptimization(FeatureSet.of(OptimizationStartPoint(startingPoint), *features), this) - return optimizer.process(problem) + return optimizer.optimize(problem) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt index 2594fa182..739ce8ca5 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -40,7 +40,3 @@ public class OptimizationParameters(public val symbols: List): Optimizat } -public interface Optimizer

{ - public suspend fun process(problem: P): P -} - diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt new file mode 100644 index 000000000..ad1a16007 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.optimization + +public interface Optimizer

{ + public suspend fun optimize(problem: P): P +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt index dda95fcd7..7dc17f6d9 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt @@ -12,39 +12,63 @@ import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke +import kotlin.math.pow -public fun interface PointToCurveDistance { - public fun distance(problem: XYOptimization, index: Int): DifferentiableExpression> +public interface PointToCurveDistance : OptimizationFeature { + public fun distance(problem: XYOptimization, index: Int): DifferentiableExpression public companion object { - public fun byY( - algebra: Field, - ): PointToCurveDistance = PointToCurveDistance { problem, index -> - algebra { + public val byY: PointToCurveDistance = object : PointToCurveDistance { + override fun distance(problem: XYOptimization, index: Int): DifferentiableExpression { + val x = problem.data.x[index] val y = problem.data.y[index] - - val model = problem.model(args + (Symbol.x to x)) - model - y + return object : DifferentiableExpression { + override fun derivativeOrNull(symbols: List): Expression? = + problem.model.derivativeOrNull(symbols) + + override fun invoke(arguments: Map): Double = + problem.model(arguments + (Symbol.x to x)) - y + } } + + override fun toString(): String = "PointToCurveDistanceByY" + } - -// val default = PointToCurveDistance{args, data, index -> -// -// } } } - -public class XYOptimization( +public class XYOptimization( override val features: FeatureSet, - public val data: XYColumnarData, - public val model: DifferentiableExpression>, + public val data: XYColumnarData, + public val model: DifferentiableExpression, ) : OptimizationProblem + +public suspend fun Optimizer>.maximumLogLikelihood(problem: XYOptimization): XYOptimization { + val distanceBuilder = problem.getFeature() ?: PointToCurveDistance.byY + val likelihood: DifferentiableExpression = object : DifferentiableExpression { + override fun derivativeOrNull(symbols: List): Expression? { + TODO("Not yet implemented") + } + + override fun invoke(arguments: Map): Double { + var res = 0.0 + for (index in 0 until problem.data.size) { + val d = distanceBuilder.distance(problem, index).invoke(arguments) + val sigma: Double = TODO() + res -= (d / sigma).pow(2) + } + return res + } + + } + val functionOptimization = FunctionOptimization(problem.features, likelihood) + val result = optimize(functionOptimization) + return XYOptimization(result.features, problem.data, problem.model) +} + // //@UnstableKMathAPI //public interface XYFit : OptimizationProblem { -- 2.34.1 From 7f32348e7a1c1701288c35db3c0dd020baa6726b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 2 Jun 2021 21:10:05 +0300 Subject: [PATCH 006/102] Slight adjustment to tensor internals --- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 60 ++++++++----- .../kmath/tensors/core/internal/linUtils.kt | 87 ++++++++++--------- 2 files changed, 84 insertions(+), 63 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 1fd46bd57..f854beb29 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 @@ -5,8 +5,10 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.structures.indices import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra import space.kscience.kmath.tensors.api.Tensor @@ -813,28 +815,32 @@ public open class DoubleTensorAlgebra : val sTensor = zeros(commonShape + intArrayOf(min(n, m))) val vTensor = zeros(commonShape + intArrayOf(min(n, m), m)) - tensor.matrixSequence() - .zip( - uTensor.matrixSequence() - .zip( - sTensor.vectorSequence() - .zip(vTensor.matrixSequence()) - ) - ).forEach { (matrix, USV) -> - val matrixSize = matrix.shape.reduce { acc, i -> acc * i } - val curMatrix = DoubleTensor( - matrix.shape, - matrix.mutableBuffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize) - .toDoubleArray() - ) - svdHelper(curMatrix, USV, m, n, epsilon) - } + val matrices = tensor.matrices + val uTensors = uTensor.matrices + val sTensorVectors = sTensor.vectors + val vTensors = vTensor.matrices + + for (index in matrices.indices) { + val matrix = matrices[index] + val usv = Triple( + uTensors[index], + sTensorVectors[index], + vTensors[index] + ) + val matrixSize = matrix.shape.reduce { acc, i -> acc * i } + val curMatrix = DoubleTensor( + matrix.shape, + matrix.mutableBuffer.array() + .slice(matrix.bufferStart until matrix.bufferStart + matrixSize) + .toDoubleArray() + ) + svdHelper(curMatrix, usv, m, n, epsilon) + } return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) } - override fun Tensor.symEig(): Pair = - symEig(epsilon = 1e-15) + override fun Tensor.symEig(): Pair = symEig(epsilon = 1e-15) /** * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, @@ -846,12 +852,26 @@ public open class DoubleTensorAlgebra : */ public fun Tensor.symEig(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) + + fun MutableStructure2D.cleanSym(n: Int) { + for (i in 0 until n) { + for (j in 0 until n) { + if (i == j) { + this[i, j] = sign(this[i, j]) + } else { + this[i, j] = 0.0 + } + } + } + } + val (u, s, v) = tensor.svd(epsilon) val shp = s.shape + intArrayOf(1) val utv = u.transpose() dot v val n = s.shape.last() - for (matrix in utv.matrixSequence()) - cleanSymHelper(matrix.as2D(), n) + for (matrix in utv.matrixSequence()) { + matrix.as2D().cleanSym(n) + } val eig = (utv dot s.view(shp)).view(s.shape) return eig to v diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index 7d3617547..0434bf96f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -10,41 +10,54 @@ import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.structures.VirtualBuffer +import space.kscience.kmath.structures.asSequence +import space.kscience.kmath.tensors.core.BufferedTensor +import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.valueOrNull +import space.kscience.kmath.tensors.core.IntTensor import kotlin.math.abs import kotlin.math.min -import kotlin.math.sign import kotlin.math.sqrt +internal val BufferedTensor.vectors: VirtualBuffer> + get() { + val n = shape.size + val vectorOffset = shape[n - 1] + val vectorShape = intArrayOf(shape.last()) -internal fun BufferedTensor.vectorSequence(): Sequence> = sequence { - val n = shape.size - val vectorOffset = shape[n - 1] - val vectorShape = intArrayOf(shape.last()) - for (offset in 0 until numElements step vectorOffset) { - val vector = BufferedTensor(vectorShape, mutableBuffer, bufferStart + offset) - yield(vector) + return VirtualBuffer(numElements / vectorOffset) { index -> + val offset = index * vectorOffset + BufferedTensor(vectorShape, mutableBuffer, bufferStart + offset) + } } -} -internal fun BufferedTensor.matrixSequence(): Sequence> = sequence { - val n = shape.size - check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } - val matrixOffset = shape[n - 1] * shape[n - 2] - val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) - for (offset in 0 until numElements step matrixOffset) { - val matrix = BufferedTensor(matrixShape, mutableBuffer, bufferStart + offset) - yield(matrix) + +internal fun BufferedTensor.vectorSequence(): Sequence> = vectors.asSequence() + +/** + * A random access alternative to [matrixSequence] + */ +internal val BufferedTensor.matrices: VirtualBuffer> + get() { + val n = shape.size + check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } + val matrixOffset = shape[n - 1] * shape[n - 2] + val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) + + return VirtualBuffer(numElements / matrixOffset) { index -> + val offset = index * matrixOffset + BufferedTensor(matrixShape, mutableBuffer, bufferStart + offset) + } } -} + +internal fun BufferedTensor.matrixSequence(): Sequence> = matrices.asSequence() internal fun dotHelper( a: MutableStructure2D, b: MutableStructure2D, res: MutableStructure2D, - l: Int, m: Int, n: Int + l: Int, m: Int, n: Int, ) { for (i in 0 until l) { for (j in 0 until n) { @@ -60,7 +73,7 @@ internal fun dotHelper( internal fun luHelper( lu: MutableStructure2D, pivots: MutableStructure1D, - epsilon: Double + epsilon: Double, ): Boolean { val m = lu.rowNum @@ -122,7 +135,7 @@ internal fun BufferedTensor.setUpPivots(): IntTensor { internal fun DoubleTensorAlgebra.computeLU( tensor: DoubleTensor, - epsilon: Double + epsilon: Double, ): Pair? { checkSquareMatrix(tensor.shape) @@ -139,7 +152,7 @@ internal fun DoubleTensorAlgebra.computeLU( internal fun pivInit( p: MutableStructure2D, pivot: MutableStructure1D, - n: Int + n: Int, ) { for (i in 0 until n) { p[i, pivot[i]] = 1.0 @@ -150,7 +163,7 @@ internal fun luPivotHelper( l: MutableStructure2D, u: MutableStructure2D, lu: MutableStructure2D, - n: Int + n: Int, ) { for (i in 0 until n) { for (j in 0 until n) { @@ -170,7 +183,7 @@ internal fun luPivotHelper( internal fun choleskyHelper( a: MutableStructure2D, l: MutableStructure2D, - n: Int + n: Int, ) { for (i in 0 until n) { for (j in 0 until i) { @@ -200,7 +213,7 @@ internal fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructur internal fun luMatrixInv( lu: MutableStructure2D, pivots: MutableStructure1D, - invMatrix: MutableStructure2D + invMatrix: MutableStructure2D, ) { val m = lu.shape[0] @@ -227,7 +240,7 @@ internal fun luMatrixInv( internal fun DoubleTensorAlgebra.qrHelper( matrix: DoubleTensor, q: DoubleTensor, - r: MutableStructure2D + r: MutableStructure2D, ) { checkSquareMatrix(matrix.shape) val n = matrix.shape[0] @@ -280,12 +293,11 @@ internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10) internal fun DoubleTensorAlgebra.svdHelper( matrix: DoubleTensor, - USV: Pair, Pair, BufferedTensor>>, - m: Int, n: Int, epsilon: Double + USV: Triple, BufferedTensor, BufferedTensor>, + m: Int, n: Int, epsilon: Double, ) { val res = ArrayList>(0) - val (matrixU, SV) = USV - val (matrixS, matrixV) = SV + val (matrixU, matrixS, matrixV) = USV for (k in 0 until min(n, m)) { var a = matrix.copy() @@ -329,14 +341,3 @@ internal fun DoubleTensorAlgebra.svdHelper( matrixV.mutableBuffer.array()[matrixV.bufferStart + i] = vBuffer[i] } } - -internal fun cleanSymHelper(matrix: MutableStructure2D, n: Int) { - for (i in 0 until n) - for (j in 0 until n) { - if (i == j) { - matrix[i, j] = sign(matrix[i, j]) - } else { - matrix[i, j] = 0.0 - } - } -} -- 2.34.1 From 95c0b2d3f097dfaec47ab449004befce7e349472 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 8 Jun 2021 14:27:45 +0300 Subject: [PATCH 007/102] [WIP] optimization with QOW --- .gitignore | 2 + CHANGELOG.md | 3 + .../kscience/kmath/benchmarks/DotBenchmark.kt | 6 +- .../benchmarks/MatrixInverseBenchmark.kt | 4 +- .../kmath/ejml/codegen/ejmlCodegen.kt | 2 +- .../kscience/kmath/ast/kotlingradSupport.kt | 4 +- .../kotlin/space/kscience/kmath/ast/parser.kt | 4 +- .../kmath/asm/internal/mapIntrinsics.kt | 3 +- .../DerivativeStructureExpression.kt | 10 +- .../integration/CMGaussRuleIntegrator.kt | 6 +- .../kmath/commons/integration/CMIntegrator.kt | 2 +- .../kscience/kmath/commons/linear/CMMatrix.kt | 14 +- .../kscience/kmath/commons/linear/CMSolver.kt | 10 + .../{CMOptimization.kt => CMOptimizer.kt} | 66 +- .../kmath/commons/optimization/cmFit.kt | 75 -- .../commons/optimization/OptimizeTest.kt | 36 +- .../space/kscience/kmath/data/ColumnarData.kt | 3 + .../expressions/DifferentiableExpression.kt | 9 +- .../kscience/kmath/linear/LinearSolver.kt | 19 - .../kscience/kmath/linear/LinearSpace.kt | 30 +- .../kscience/kmath/linear/LupDecomposition.kt | 65 +- .../kscience/kmath/linear/MatrixBuilder.kt | 31 +- .../kscience/kmath/linear/MatrixWrapper.kt | 27 +- .../kscience/kmath/linear/VirtualMatrix.kt | 3 + .../space/kscience/kmath/linear/symmetric.kt | 34 - .../space/kscience/kmath/misc/Featured.kt | 27 +- .../space/kscience/kmath/misc/annotations.kt | 4 +- .../space/kscience/kmath/nd/StructureND.kt | 8 +- .../kmath/structures/BufferAccessor2D.kt | 18 +- .../kmath/linear/DoubleLUSolverTest.kt | 12 +- .../space/kscience/kmath/linear/MatrixTest.kt | 8 +- .../kmath/structures/NumberNDFieldTest.kt | 2 +- .../kscience/kmath/dimensions/Wrappers.kt | 2 +- .../space/kscience/kmath/ejml/_generated.kt | 995 ------------------ .../kscience/kmath/ejml/EjmlMatrixTest.kt | 6 +- .../space/kscience/kmath/real/RealMatrix.kt | 36 +- .../kotlin/space/kscience/kmath/real/dot.kt | 2 +- .../kaceince/kmath/real/DoubleMatrixTest.kt | 4 +- .../kaceince/kmath/real/DoubleVectorTest.kt | 2 +- .../kscience/kmath/integration/Integrand.kt | 5 +- .../kmath/kotlingrad/KotlingradExpression.kt | 31 +- .../optimization/FunctionOptimization.kt | 10 +- .../kmath/optimization/OptimizationBuilder.kt | 93 ++ .../kmath/optimization/OptimizationProblem.kt | 40 +- .../kscience/kmath/optimization/Optimizer.kt | 2 +- .../kmath/optimization/QowOptimizer.kt | 247 +++++ .../kmath/optimization/XYOptimization.kt | 115 +- .../kmath/optimization/qow => tmp}/QowFit.kt | 0 .../minuit/AnalyticalGradientCalculator.kt | 0 .../minuit/CombinedMinimizer.kt | 0 .../minuit/CombinedMinimumBuilder.kt | 1 + .../minuit/ContoursError.kt | 0 .../minuit/DavidonErrorUpdator.kt | 0 .../minuit/FunctionGradient.kt | 0 .../minuit/FunctionMinimum.kt | 1 + .../minuit/GradientCalculator.kt | 0 .../minuit/HessianGradientCalculator.kt | 0 .../minuit/InitialGradientCalculator.kt | 0 .../minuit/MINOSResult.kt | 0 .../minuit/MINUITFitter.kt | 0 .../minuit/MINUITPlugin.kt | 0 .../minuit/MINUITUtils.kt | 0 .../minuit/MinimumBuilder.kt | 2 + .../minuit/MinimumError.kt | 0 .../minuit/MinimumErrorUpdator.kt | 0 .../minuit/MinimumParameters.kt | 0 .../minuit/MinimumSeed.kt | 4 +- .../minuit/MinimumSeedGenerator.kt | 2 + .../minuit/MinimumState.kt | 0 .../optimization => tmp}/minuit/MinosError.kt | 0 .../minuit/MinuitParameter.kt | 0 .../minuit/MnAlgebraicSymMatrix.kt | 0 .../minuit/MnApplication.kt | 0 .../optimization => tmp}/minuit/MnContours.kt | 0 .../minuit/MnCovarianceSqueeze.kt | 0 .../optimization => tmp}/minuit/MnCross.kt | 0 .../optimization => tmp}/minuit/MnEigen.kt | 0 .../optimization => tmp}/minuit/MnFcn.kt | 0 .../minuit/MnFunctionCross.kt | 0 .../minuit/MnGlobalCorrelationCoeff.kt | 0 .../optimization => tmp}/minuit/MnHesse.kt | 0 .../minuit/MnLineSearch.kt | 0 .../minuit/MnMachinePrecision.kt | 0 .../optimization => tmp}/minuit/MnMigrad.kt | 0 .../optimization => tmp}/minuit/MnMinimize.kt | 0 .../optimization => tmp}/minuit/MnMinos.kt | 0 .../optimization => tmp}/minuit/MnParabola.kt | 0 .../minuit/MnParabolaFactory.kt | 0 .../minuit/MnParabolaPoint.kt | 0 .../minuit/MnParameterScan.kt | 0 .../optimization => tmp}/minuit/MnPlot.kt | 0 .../optimization => tmp}/minuit/MnPosDef.kt | 0 .../optimization => tmp}/minuit/MnPrint.kt | 0 .../optimization => tmp}/minuit/MnScan.kt | 0 .../minuit/MnSeedGenerator.kt | 1 + .../optimization => tmp}/minuit/MnSimplex.kt | 0 .../optimization => tmp}/minuit/MnStrategy.kt | 0 .../minuit/MnUserCovariance.kt | 0 .../optimization => tmp}/minuit/MnUserFcn.kt | 0 .../minuit/MnUserParameterState.kt | 0 .../minuit/MnUserParameters.kt | 0 .../minuit/MnUserTransformation.kt | 0 .../optimization => tmp}/minuit/MnUtils.kt | 0 .../minuit/ModularFunctionMinimizer.kt | 1 + .../minuit/NegativeG2LineSearch.kt | 0 .../minuit/Numerical2PGradientCalculator.kt | 0 .../minuit/ScanBuilder.kt | 1 + .../minuit/ScanMinimizer.kt | 0 .../minuit/SimplexBuilder.kt | 1 + .../minuit/SimplexMinimizer.kt | 0 .../minuit/SimplexParameters.kt | 0 .../minuit/SimplexSeedGenerator.kt | 1 + .../minuit/SinParameterTransformation.kt | 0 .../minuit/SqrtLowParameterTransformation.kt | 0 .../minuit/SqrtUpParameterTransformation.kt | 0 .../minuit/VariableMetricBuilder.kt | 1 + .../minuit/VariableMetricEDMEstimator.kt | 0 .../minuit/VariableMetricMinimizer.kt | 0 .../minuit/package-info.kt | 0 119 files changed, 804 insertions(+), 1349 deletions(-) rename kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/{CMOptimization.kt => CMOptimizer.kt} (63%) delete mode 100644 kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/symmetric.kt delete mode 100644 kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization/qow => tmp}/QowFit.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/AnalyticalGradientCalculator.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/CombinedMinimizer.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/CombinedMinimumBuilder.kt (97%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/ContoursError.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/DavidonErrorUpdator.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/FunctionGradient.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/FunctionMinimum.kt (99%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/GradientCalculator.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/HessianGradientCalculator.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/InitialGradientCalculator.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MINOSResult.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MINUITFitter.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MINUITPlugin.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MINUITUtils.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MinimumBuilder.kt (95%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MinimumError.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MinimumErrorUpdator.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MinimumParameters.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MinimumSeed.kt (95%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MinimumSeedGenerator.kt (95%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MinimumState.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MinosError.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MinuitParameter.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnAlgebraicSymMatrix.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnApplication.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnContours.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnCovarianceSqueeze.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnCross.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnEigen.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnFcn.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnFunctionCross.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnGlobalCorrelationCoeff.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnHesse.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnLineSearch.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnMachinePrecision.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnMigrad.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnMinimize.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnMinos.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnParabola.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnParabolaFactory.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnParabolaPoint.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnParameterScan.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnPlot.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnPosDef.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnPrint.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnScan.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnSeedGenerator.kt (98%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnSimplex.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnStrategy.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnUserCovariance.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnUserFcn.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnUserParameterState.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnUserParameters.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnUserTransformation.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/MnUtils.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/ModularFunctionMinimizer.kt (97%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/NegativeG2LineSearch.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/Numerical2PGradientCalculator.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/ScanBuilder.kt (97%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/ScanMinimizer.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/SimplexBuilder.kt (99%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/SimplexMinimizer.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/SimplexParameters.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/SimplexSeedGenerator.kt (97%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/SinParameterTransformation.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/SqrtLowParameterTransformation.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/SqrtUpParameterTransformation.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/VariableMetricBuilder.kt (98%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/VariableMetricEDMEstimator.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/VariableMetricMinimizer.kt (100%) rename kmath-stat/src/commonMain/{kotlin/space/kscience/kmath/optimization => tmp}/minuit/package-info.kt (100%) diff --git a/.gitignore b/.gitignore index d6c4af4e3..c5903368f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ out/ # Generated by javac -h and runtime *.class *.log + +/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 524d2a1de..e35153d81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Jupyter Notebook integration module (kmath-jupyter) - `@PerformancePitfall` annotation to mark possibly slow API - BigInt operation performance improvement and fixes by @zhelenskiy (#328) +- Unified architecture for Integration and Optimization using features. ### Changed - Exponential operations merged with hyperbolic functions @@ -35,6 +36,8 @@ - Remove Any restriction on polynomials - Add `out` variance to type parameters of `StructureND` and its implementations where possible - Rename `DifferentiableMstExpression` to `KotlingradExpression` +- `FeatureSet` now accepts only `Feature`. It is possible to override keys and use interfaces. +- Use `Symbol` factory function instead of `StringSymbol` ### Deprecated diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 2c5a03a97..698f1a702 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -23,8 +23,8 @@ internal class DotBenchmark { const val dim = 1000 //creating invertible matrix - val matrix1 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - val matrix2 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + val matrix1 = LinearSpace.double.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + val matrix2 = LinearSpace.double.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } val cmMatrix1 = CMLinearSpace { matrix1.toCM() } val cmMatrix2 = CMLinearSpace { matrix2.toCM() } @@ -63,7 +63,7 @@ internal class DotBenchmark { @Benchmark fun realDot(blackhole: Blackhole) { - LinearSpace.real { + LinearSpace.double { blackhole.consume(matrix1 dot matrix2) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt index 7bb32af28..ff67ccc84 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt @@ -25,7 +25,7 @@ internal class MatrixInverseBenchmark { private val random = Random(1224) private const val dim = 100 - private val space = LinearSpace.real + private val space = LinearSpace.double //creating invertible matrix private val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } @@ -35,7 +35,7 @@ internal class MatrixInverseBenchmark { @Benchmark fun kmathLupInversion(blackhole: Blackhole) { - blackhole.consume(LinearSpace.real.inverseWithLup(matrix)) + blackhole.consume(LinearSpace.double.inverseWithLup(matrix)) } @Benchmark diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt index 5da7d0f67..da1f45c1f 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 @@ -203,7 +203,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, public override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this @UnstableKMathAPI - public override fun getFeature(structure: Matrix<${type}>, type: KClass): F? { + public override fun computeFeature(structure: Matrix<${type}>, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt index 420b23f9f..88fd312c7 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.expressions.derivative import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.kotlingrad.toDiffExpression +import space.kscience.kmath.kotlingrad.toKotlingradExpression import space.kscience.kmath.operations.DoubleField /** @@ -20,7 +20,7 @@ fun main() { val x by symbol val actualDerivative = "x^2-4*x-44".parseMath() - .toDiffExpression(DoubleField) + .toKotlingradExpression(DoubleField) .derivative(x) diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt index 5201fec38..bfba08bbd 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt @@ -17,7 +17,7 @@ import com.github.h0tk3y.betterParse.lexer.regexToken import com.github.h0tk3y.betterParse.parser.ParseResult import com.github.h0tk3y.betterParse.parser.Parser import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.StringSymbol +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.FieldOperations import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.PowerOperations @@ -43,7 +43,7 @@ public object ArithmeticsEvaluator : Grammar() { private val ws: Token by regexToken("\\s+".toRegex(), ignore = true) private val number: Parser by num use { MST.Numeric(text.toDouble()) } - private val singular: Parser by id use { StringSymbol(text) } + private val singular: Parser by id use { Symbol(text) } private val unaryFunction: Parser by (id and -lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) .map { (id, term) -> MST.Unary(id.text, term) } diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt index 8f4daecf9..948e7eab9 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.asm.internal -import space.kscience.kmath.expressions.StringSymbol import space.kscience.kmath.expressions.Symbol /** @@ -15,4 +14,4 @@ import space.kscience.kmath.expressions.Symbol * * @author Iaroslav Postovalov */ -internal fun Map.getOrFail(key: String): V = getValue(StringSymbol(key)) +internal fun Map.getOrFail(key: String): V = getValue(Symbol(key)) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index 361027968..a7ee9ff3f 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -103,12 +103,12 @@ public class DerivativeStructureField( public override operator fun DerivativeStructure.minus(b: Number): DerivativeStructure = subtract(b.toDouble()) public override operator fun Number.plus(b: DerivativeStructure): DerivativeStructure = b + this public override operator fun Number.minus(b: DerivativeStructure): DerivativeStructure = b - this +} - public companion object : - AutoDiffProcessor> { - public override fun process(function: DerivativeStructureField.() -> DerivativeStructure): DifferentiableExpression = - DerivativeStructureExpression(function) - } +public object DSProcessor : AutoDiffProcessor { + public override fun differentiate( + function: DerivativeStructureField.() -> DerivativeStructure, + ): DerivativeStructureExpression = DerivativeStructureExpression(function) } /** diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt index 4e174723d..e0a2f4931 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt @@ -16,7 +16,7 @@ public class CMGaussRuleIntegrator( private var type: GaussRule = GaussRule.LEGANDRE, ) : UnivariateIntegrator { - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { val range = integrand.getFeature()?.range ?: error("Integration range is not provided") val integrator: GaussIntegrator = getIntegrator(range) @@ -76,8 +76,8 @@ public class CMGaussRuleIntegrator( numPoints: Int = 100, type: GaussRule = GaussRule.LEGANDRE, function: (Double) -> Double, - ): Double = CMGaussRuleIntegrator(numPoints, type).integrate( + ): Double = CMGaussRuleIntegrator(numPoints, type).process( UnivariateIntegrand(function, IntegrationRange(range)) - ).valueOrNull!! + ).value } } \ No newline at end of file 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 bcddccdc4..257429fa7 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 @@ -18,7 +18,7 @@ public class CMIntegrator( public val integratorBuilder: (Integrand) -> org.apache.commons.math3.analysis.integration.UnivariateIntegrator, ) : UnivariateIntegrator { - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { val integrator = integratorBuilder(integrand) val maxCalls = integrand.getFeature()?.maxCalls ?: defaultMaxCalls val remainingCalls = maxCalls - integrand.calls diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt index 11b097831..c6f1cd852 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 @@ -95,7 +95,7 @@ public object CMLinearSpace : LinearSpace { v * this @UnstableKMathAPI - override fun getFeature(structure: Matrix, type: KClass): F? { + override fun computeFeature(structure: Matrix, type: KClass): F? { //Return the feature if it is intrinsic to the structure structure.getFeature(type)?.let { return it } @@ -109,22 +109,22 @@ public object CMLinearSpace : LinearSpace { LupDecompositionFeature { private val lup by lazy { LUDecomposition(origin) } override val determinant: Double by lazy { lup.determinant } - override val l: Matrix by lazy { CMMatrix(lup.l) + LFeature } - override val u: Matrix by lazy { CMMatrix(lup.u) + UFeature } + override val l: Matrix by lazy> { CMMatrix(lup.l).withFeature(LFeature) } + override val u: Matrix by lazy> { CMMatrix(lup.u).withFeature(UFeature) } override val p: Matrix by lazy { CMMatrix(lup.p) } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { + override val l: Matrix by lazy> { val cholesky = CholeskyDecomposition(origin) - CMMatrix(cholesky.l) + LFeature + CMMatrix(cholesky.l).withFeature(LFeature) } } QRDecompositionFeature::class -> object : QRDecompositionFeature { private val qr by lazy { QRDecomposition(origin) } - override val q: Matrix by lazy { CMMatrix(qr.q) + OrthogonalFeature } - override val r: Matrix by lazy { CMMatrix(qr.r) + UFeature } + override val q: Matrix by lazy> { CMMatrix(qr.q).withFeature(OrthogonalFeature) } + override val r: Matrix by lazy> { CMMatrix(qr.r).withFeature(UFeature) } } SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt index ee602ca06..9085974ea 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.commons.linear import org.apache.commons.math3.linear.* +import space.kscience.kmath.linear.LinearSolver import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.Point @@ -44,3 +45,12 @@ public fun CMLinearSpace.inverse( a: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP, ): CMMatrix = solver(a, decomposition).inverse.wrap() + + +public fun CMLinearSpace.solver(decomposition: CMDecomposition): LinearSolver = object : LinearSolver { + override fun solve(a: Matrix, b: Matrix): Matrix = solve(a, b, decomposition) + + override fun solve(a: Matrix, b: Point): Point = solve(a, b, decomposition) + + override fun inverse(matrix: Matrix): Matrix = inverse(matrix, decomposition) +} \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt similarity index 63% rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt rename to kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt index 2faee1f5d..abf95daf6 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt @@ -2,7 +2,7 @@ * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ - +@file:OptIn(UnstableKMathAPI::class) package space.kscience.kmath.commons.optimization import org.apache.commons.math3.optim.* @@ -11,6 +11,10 @@ import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction 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.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 @@ -21,29 +25,61 @@ import kotlin.reflect.KClass public operator fun PointValuePair.component1(): DoubleArray = point public operator fun PointValuePair.component2(): Double = value -public class CMOptimizer(public val optimizerBuilder: () -> MultivariateOptimizer): OptimizationFeature{ +public class CMOptimizerEngine(public val optimizerBuilder: () -> MultivariateOptimizer) : OptimizationFeature { override fun toString(): String = "CMOptimizer($optimizerBuilder)" } -public class CMOptimizerData(public val data: List) : OptimizationFeature { - public constructor(vararg data: OptimizationData) : this(data.toList()) +/** + * Specify a Commons-maths optimization engine + */ +public fun FunctionOptimizationBuilder.cmEngine(optimizerBuilder: () -> MultivariateOptimizer) { + addFeature(CMOptimizerEngine(optimizerBuilder)) +} + +public class CMOptimizerData(public val data: List OptimizationData>) : OptimizationFeature { + public constructor(vararg data: (SymbolIndexer.() -> OptimizationData)) : this(data.toList()) override fun toString(): String = "CMOptimizerData($data)" +} +/** + * Specify Commons-maths optimization data. + */ +public fun FunctionOptimizationBuilder.cmOptimizationData(data: SymbolIndexer.() -> OptimizationData) { + updateFeature { + val newData = (it?.data ?: emptyList()) + data + CMOptimizerData(newData) + } +} + +public fun FunctionOptimizationBuilder.simplexSteps(vararg steps: Pair) { + //TODO use convergence checker from features + cmEngine { SimplexOptimizer(CMOptimizer.defaultConvergenceChecker) } + cmOptimizationData { NelderMeadSimplex(mapOf(*steps).toDoubleArray()) } } @OptIn(UnstableKMathAPI::class) -public class CMOptimization : Optimizer> { +public object CMOptimizer : Optimizer> { + + public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 + public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 + public const val DEFAULT_MAX_ITER: Int = 1000 + + public val defaultConvergenceChecker: SimpleValueChecker = SimpleValueChecker( + DEFAULT_RELATIVE_TOLERANCE, + DEFAULT_ABSOLUTE_TOLERANCE, + DEFAULT_MAX_ITER + ) + override suspend fun optimize( problem: FunctionOptimization, ): FunctionOptimization { - val startPoint = problem.getFeature>()?.point - ?: error("Starting point not defined in $problem") + val startPoint = problem.startPoint val parameters = problem.getFeature()?.symbols ?: problem.getFeature>()?.point?.keys - ?:startPoint.keys + ?: startPoint.keys withSymbols(parameters) { @@ -53,7 +89,7 @@ public class CMOptimization : Optimizer> { DEFAULT_MAX_ITER ) - val cmOptimizer: MultivariateOptimizer = problem.getFeature()?.optimizerBuilder?.invoke() + val cmOptimizer: MultivariateOptimizer = problem.getFeature()?.optimizerBuilder?.invoke() ?: NonLinearConjugateGradientOptimizer( NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, convergenceChecker @@ -68,7 +104,7 @@ public class CMOptimization : Optimizer> { addOptimizationData(MaxEval.unlimited()) addOptimizationData(InitialGuess(startPoint.toDoubleArray())) - fun exportOptimizationData(): List = optimizationData.values.toList() + //fun exportOptimizationData(): List = optimizationData.values.toList() val objectiveFunction = ObjectiveFunction { val args = startPoint + it.toMap() @@ -88,7 +124,9 @@ public class CMOptimization : Optimizer> { for (feature in problem.features) { when (feature) { - is CMOptimizerData -> feature.data.forEach { addOptimizationData(it) } + is CMOptimizerData -> feature.data.forEach { dataBuilder -> + addOptimizationData(dataBuilder()) + } is FunctionOptimizationTarget -> when (feature) { FunctionOptimizationTarget.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE) FunctionOptimizationTarget.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE) @@ -101,10 +139,4 @@ public class CMOptimization : Optimizer> { return problem.withFeatures(OptimizationResult(point.toMap()), OptimizationValue(value)) } } - - public companion object { - public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 - public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 - public const val DEFAULT_MAX_ITER: Int = 1000 - } } diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt deleted file mode 100644 index b1d7f5ca3..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.commons.optimization - -import org.apache.commons.math3.analysis.differentiation.DerivativeStructure -import space.kscience.kmath.commons.expressions.DerivativeStructureField -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.optimization.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer - -/** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation - */ -public fun FunctionOptimization.Companion.chiSquaredExpression( - x: Buffer, - y: Buffer, - yErr: Buffer, - model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, -): DifferentiableExpression = chiSquaredExpression(DerivativeStructureField, x, y, yErr, model) - -/** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation - */ -public fun FunctionOptimization.Companion.chiSquaredExpression( - x: Iterable, - y: Iterable, - yErr: Iterable, - model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, -): DifferentiableExpression = chiSquaredExpression( - DerivativeStructureField, - x.toList().asBuffer(), - y.toList().asBuffer(), - yErr.toList().asBuffer(), - model -) - -/** - * Optimize expression without derivatives - */ -public suspend fun Expression.optimize( - vararg symbols: Symbol, - configuration: CMOptimization.() -> Unit, -): OptimizationResult { - require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } - val problem = CMOptimization(symbols.toList(), configuration) - problem.noDerivFunction(this) - return problem.optimize() -} - -/** - * Optimize differentiable expression - */ -public suspend fun DifferentiableExpression.optimize( - vararg symbols: Symbol, - configuration: CMOptimization.() -> Unit, -): OptimizationResult = optimizeWith(CMOptimization, symbols = symbols, configuration) - -public suspend fun DifferentiableExpression.minimize( - vararg startPoint: Pair, - configuration: CMOptimization.() -> Unit = {}, -): OptimizationResult { - val symbols = startPoint.map { it.first }.toTypedArray() - return optimize(*symbols){ - maximize = false - initialGuess(startPoint.toMap()) - function(this@minimize) - configuration() - } -} \ No newline at end of file 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 b47d7da24..97761cfa2 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,43 +6,38 @@ 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.Symbol.Companion.x +import space.kscience.kmath.expressions.Symbol.Companion.y import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.optimization.FunctionOptimization +import space.kscience.kmath.optimization.* import space.kscience.kmath.stat.RandomGenerator import kotlin.math.pow import kotlin.test.Test internal class OptimizeTest { - val x by symbol - val y by symbol - val normal = DerivativeStructureExpression { - exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y) - .pow(2) / 2) + exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y).pow(2) / 2) } @Test - fun testGradientOptimization() = runBlocking{ - val result = normal.optimize(x, y) { - initialGuess(x to 1.0, y to 1.0) - //no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function - } - println(result.point) - println(result.value) + fun testGradientOptimization() = runBlocking { + val result = normal.optimizeWith(CMOptimizer, x to 1.0, y to 1.0) + println(result.resultPoint) + println(result.resultValue) } @Test - fun testSimplexOptimization() = runBlocking{ - val result = normal.optimize(x, y) { - initialGuess(x to 1.0, y to 1.0) + fun testSimplexOptimization() = runBlocking { + val result = normal.optimizeWith(CMOptimizer, x to 1.0, y to 1.0) { simplexSteps(x to 2.0, y to 0.5) //this sets simplex optimizer } - println(result.point) - println(result.value) + println(result.resultPoint) + println(result.resultValue) } @Test @@ -62,6 +57,11 @@ internal class OptimizeTest { val yErr = List(x.size) { sigma } + val model = DSProcessor.differentiate { x1 -> + val cWithDefault = bindSymbolOrNull(c) ?: one + bindSymbol(a) * x1.pow(2) + bindSymbol(b) * x1 + cWithDefault + } + val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 -> val cWithDefault = bindSymbolOrNull(c) ?: one bindSymbol(a) * x1.pow(2) + bindSymbol(b) * x1 + cWithDefault 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 88c14d311..e06b774fd 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 @@ -25,6 +25,9 @@ public interface ColumnarData { public operator fun get(symbol: Symbol): Buffer? } +@UnstableKMathAPI +public val ColumnarData<*>.indices: IntRange get() = 0 until size + /** * A zero-copy method to represent a [Structure2D] as a two-column x-y data. * There could more than two columns in the structure. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt index 011dc26e2..1782ff406 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt @@ -5,6 +5,8 @@ package space.kscience.kmath.expressions +import space.kscience.kmath.operations.Algebra + /** * Represents expression which structure can be differentiated. * @@ -63,7 +65,10 @@ public abstract class FirstDerivativeExpression : DifferentiableExpression /** * A factory that converts an expression in autodiff variables to a [DifferentiableExpression] + * @param T type of the constants for the expression + * @param I type of the actual expression state + * @param A type of expression algebra */ -public fun interface AutoDiffProcessor, out R : Expression> { - public fun process(function: A.() -> I): DifferentiableExpression +public fun interface AutoDiffProcessor> { + public fun differentiate(function: A.() -> I): DifferentiableExpression } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt index 9c3ffd819..288fabbaf 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt @@ -5,8 +5,6 @@ package space.kscience.kmath.linear -import space.kscience.kmath.nd.as1D - /** * A group of methods to solve for *X* in equation *X = A -1 · B*, where *A* and *B* are matrices or * vectors. @@ -30,20 +28,3 @@ public interface LinearSolver { public fun inverse(matrix: Matrix): Matrix } -/** - * Convert matrix to vector if it is possible. - */ -public fun Matrix.asVector(): Point = - if (this.colNum == 1) - as1D() - else - error("Can't convert matrix with more than one column to vector") - -/** - * Creates an n × 1 [VirtualMatrix], where n is the size of the given buffer. - * - * @param T the type of elements contained in the buffer. - * @receiver a buffer. - * @return the new matrix. - */ -public fun Point.asMatrix(): VirtualMatrix = VirtualMatrix(size, 1) { i, _ -> get(i) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index ec073ac48..94083f70d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt @@ -164,7 +164,7 @@ public interface LinearSpace> { public operator fun T.times(v: Point): Point = v * this /** - * Get a feature of the structure in this scope. Structure features take precedence other context features + * Compute a feature of the structure in this scope. Structure features take precedence other context features * * @param F the type of feature. * @param structure the structure. @@ -172,7 +172,7 @@ public interface LinearSpace> { * @return a feature object or `null` if it isn't present. */ @UnstableKMathAPI - public fun getFeature(structure: Matrix, type: KClass): F? = structure.getFeature(type) + public fun computeFeature(structure: Matrix, type: KClass): F? = structure.getFeature(type) public companion object { @@ -184,7 +184,7 @@ public interface LinearSpace> { bufferFactory: BufferFactory = Buffer.Companion::boxing, ): LinearSpace = BufferedLinearSpace(algebra, bufferFactory) - public val real: LinearSpace = buffered(DoubleField, ::DoubleBuffer) + public val double: LinearSpace = buffered(DoubleField, ::DoubleBuffer) /** * Automatic buffered matrix, unboxed if it is possible @@ -202,9 +202,27 @@ public interface LinearSpace> { * @return a feature object or `null` if it isn't present. */ @UnstableKMathAPI -public inline fun LinearSpace.getFeature(structure: Matrix): F? = - getFeature(structure, F::class) +public inline fun LinearSpace.computeFeature(structure: Matrix): F? = + computeFeature(structure, F::class) -public operator fun , R> LS.invoke(block: LS.() -> R): R = run(block) +public inline operator fun , R> LS.invoke(block: LS.() -> R): R = run(block) + +/** + * Convert matrix to vector if it is possible. + */ +public fun Matrix.asVector(): Point = + if (this.colNum == 1) + as1D() + else + error("Can't convert matrix with more than one column to vector") + +/** + * Creates an n × 1 [VirtualMatrix], where n is the size of the given buffer. + * + * @param T the type of elements contained in the buffer. + * @receiver a buffer. + * @return the new matrix. + */ +public fun Point.asMatrix(): VirtualMatrix = VirtualMatrix(size, 1) { i, _ -> get(i) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt index f3653d394..3b6208468 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,6 +5,7 @@ package space.kscience.kmath.linear +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.getFeature import space.kscience.kmath.operations.* @@ -34,7 +35,7 @@ public class LupDecomposition( j == i -> elementContext.one else -> elementContext.zero } - } + LFeature + }.withFeature(LFeature) /** @@ -44,7 +45,7 @@ public class LupDecomposition( */ override val u: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> if (j >= i) lu[i, j] else elementContext.zero - } + UFeature + }.withFeature(UFeature) /** * Returns the P rows permutation matrix. @@ -82,7 +83,7 @@ public fun > LinearSpace>.lup( val m = matrix.colNum val pivot = IntArray(matrix.rowNum) - //TODO just waits for KEEP-176 + //TODO just waits for multi-receivers BufferAccessor2D(matrix.rowNum, matrix.colNum, factory).run { elementAlgebra { val lu = create(matrix) @@ -156,10 +157,13 @@ public inline fun > LinearSpace>.lup( noinline checkSingular: (T) -> Boolean, ): LupDecomposition = lup(MutableBuffer.Companion::auto, matrix, checkSingular) -public fun LinearSpace.lup(matrix: Matrix): LupDecomposition = - lup(::DoubleBuffer, matrix) { it < 1e-11 } +public fun LinearSpace.lup( + matrix: Matrix, + singularityThreshold: Double = 1e-11, +): LupDecomposition = + lup(::DoubleBuffer, matrix) { it < singularityThreshold } -public fun LupDecomposition.solveWithLup( +internal fun LupDecomposition.solve( factory: MutableBufferFactory, matrix: Matrix, ): Matrix { @@ -207,41 +211,24 @@ public fun LupDecomposition.solveWithLup( } } -public inline fun LupDecomposition.solveWithLup(matrix: Matrix): Matrix = - solveWithLup(MutableBuffer.Companion::auto, matrix) - /** - * Solves a system of linear equations *ax = b** using LUP decomposition. + * Produce a generic solver based on LUP decomposition */ +@PerformancePitfall() @OptIn(UnstableKMathAPI::class) -public inline fun > LinearSpace>.solveWithLup( - a: Matrix, - b: Matrix, - noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, - noinline checkSingular: (T) -> Boolean, -): Matrix { - // Use existing decomposition if it is provided by matrix - val decomposition = a.getFeature() ?: lup(bufferFactory, a, checkSingular) - return decomposition.solveWithLup(bufferFactory, b) +public fun , F : Field> LinearSpace.lupSolver( + bufferFactory: MutableBufferFactory, + singularityCheck: (T) -> Boolean, +): LinearSolver = object : LinearSolver { + override fun solve(a: Matrix, b: Matrix): Matrix { + // Use existing decomposition if it is provided by matrix + val decomposition = a.getFeature() ?: lup(bufferFactory, a, singularityCheck) + return decomposition.solve(bufferFactory, b) + } + + override fun inverse(matrix: Matrix): Matrix = solve(matrix, one(matrix.rowNum, matrix.colNum)) } -public inline fun > LinearSpace>.inverseWithLup( - matrix: Matrix, - noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, - noinline checkSingular: (T) -> Boolean, -): Matrix = solveWithLup(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) - - -@OptIn(UnstableKMathAPI::class) -public fun LinearSpace.solveWithLup(a: Matrix, b: Matrix): Matrix { - // Use existing decomposition if it is provided by matrix - val bufferFactory: MutableBufferFactory = ::DoubleBuffer - val decomposition: LupDecomposition = a.getFeature() ?: lup(bufferFactory, a) { it < 1e-11 } - return decomposition.solveWithLup(bufferFactory, b) -} - -/** - * Inverses a square matrix using LUP decomposition. Non square matrix will throw a error. - */ -public fun LinearSpace.inverseWithLup(matrix: Matrix): Matrix = - solveWithLup(matrix, one(matrix.rowNum, matrix.colNum)) \ No newline at end of file +@PerformancePitfall +public fun LinearSpace.lupSolver(singularityThreshold: Double = 1e-11): LinearSolver = + lupSolver(::DoubleBuffer) { it < singularityThreshold } 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 72d22233a..029612bc5 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 @@ -7,6 +7,8 @@ package space.kscience.kmath.linear import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring +import space.kscience.kmath.structures.BufferAccessor2D +import space.kscience.kmath.structures.MutableBuffer public class MatrixBuilder>( public val linearSpace: LinearSpace, @@ -45,4 +47,31 @@ public inline fun LinearSpace>.column( crossinline builder: (Int) -> T, ): Matrix = buildMatrix(size, 1) { i, _ -> builder(i) } -public fun LinearSpace>.column(vararg values: T): Matrix = column(values.size, values::get) \ No newline at end of file +public fun LinearSpace>.column(vararg values: T): Matrix = column(values.size, values::get) + +public object SymmetricMatrixFeature : MatrixFeature + +/** + * Naive implementation of a symmetric matrix builder, that adds a [SymmetricMatrixFeature] tag. The resulting matrix contains + * full `size^2` number of elements, but caches elements during calls to save [builder] calls. [builder] is always called in the + * upper triangle region meaning that `i <= j` + */ +public fun > MatrixBuilder.symmetric( + builder: (i: Int, j: Int) -> T, +): Matrix { + require(columns == rows) { "In order to build symmetric matrix, number of rows $rows should be equal to number of columns $columns" } + return with(BufferAccessor2D(rows, rows, MutableBuffer.Companion::boxing)) { + val cache = factory(rows * rows) { null } + linearSpace.buildMatrix(rows, rows) { i, j -> + val cached = cache[i, j] + if (cached == null) { + val value = if (i <= j) builder(i, j) else builder(j, i) + cache[i, j] = value + cache[j, i] = value + value + } else { + cached + } + }.withFeature(SymmetricMatrixFeature) + } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt index 16aadab3b..df62c6fc0 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,6 +5,7 @@ package space.kscience.kmath.linear +import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.nd.getFeature @@ -18,7 +19,7 @@ import kotlin.reflect.KClass */ public class MatrixWrapper internal constructor( public val origin: Matrix, - public val features: Set, + public val features: FeatureSet, ) : Matrix by origin { /** @@ -27,8 +28,7 @@ public class MatrixWrapper internal constructor( @UnstableKMathAPI @Suppress("UNCHECKED_CAST") public override fun getFeature(type: KClass): F? = - features.singleOrNull(type::isInstance) as? F - ?: origin.getFeature(type) + features.getFeature(type) ?: origin.getFeature(type) public override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$features)" } @@ -44,20 +44,23 @@ public val Matrix.origin: Matrix /** * Add a single feature to a [Matrix] */ -public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixWrapper = if (this is MatrixWrapper) { - MatrixWrapper(origin, features + newFeature) +public fun Matrix.withFeature(newFeature: MatrixFeature): MatrixWrapper = if (this is MatrixWrapper) { + MatrixWrapper(origin, features.with(newFeature)) } else { - MatrixWrapper(this, setOf(newFeature)) + MatrixWrapper(this, FeatureSet.of(newFeature)) } +@Deprecated("To be replaced by withFeature") +public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixWrapper = withFeature(newFeature) + /** * Add a collection of features to a [Matrix] */ -public operator fun Matrix.plus(newFeatures: Collection): MatrixWrapper = +public fun Matrix.withFeatures(newFeatures: Iterable): MatrixWrapper = if (this is MatrixWrapper) { - MatrixWrapper(origin, features + newFeatures) + MatrixWrapper(origin, features.with(newFeatures)) } else { - MatrixWrapper(this, newFeatures.toSet()) + MatrixWrapper(this, FeatureSet.of(newFeatures)) } /** @@ -68,7 +71,7 @@ public fun LinearSpace>.one( columns: Int, ): Matrix = VirtualMatrix(rows, columns) { i, j -> if (i == j) elementAlgebra.one else elementAlgebra.zero -} + UnitFeature +}.withFeature(UnitFeature) /** @@ -79,7 +82,7 @@ public fun LinearSpace>.zero( columns: Int, ): Matrix = VirtualMatrix(rows, columns) { _, _ -> elementAlgebra.zero -} + ZeroFeature +}.withFeature(ZeroFeature) public class TransposedFeature(public val original: Matrix) : MatrixFeature @@ -90,4 +93,4 @@ public class TransposedFeature(public val original: Matrix) : Ma public fun Matrix.transpose(): Matrix = getFeature>()?.original ?: VirtualMatrix( colNum, rowNum, -) { i, j -> get(j, i) } + TransposedFeature(this) \ No newline at end of file +) { i, j -> get(j, i) }.withFeature(TransposedFeature(this)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt index 3751bd33b..fb2b1e547 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt @@ -20,3 +20,6 @@ public class VirtualMatrix( override operator fun get(i: Int, j: Int): T = generator(i, j) } + +public fun MatrixBuilder.virtual(generator: (i: Int, j: Int) -> T): VirtualMatrix = + VirtualMatrix(rows, columns, generator) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/symmetric.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/symmetric.kt deleted file mode 100644 index 04d9a9897..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/symmetric.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.structures.BufferAccessor2D -import space.kscience.kmath.structures.MutableBuffer - -public object SymmetricMatrixFeature : MatrixFeature - -/** - * Naive implementation of a symmetric matrix builder, that adds a [SymmetricMatrixFeature] tag. The resulting matrix contains - * full `size^2` number of elements, but caches elements during calls to save [builder] calls. [builder] is always called in the - * upper triangle region meaning that `i <= j` - */ -public fun > LS.buildSymmetricMatrix( - size: Int, - builder: (i: Int, j: Int) -> T, -): Matrix = BufferAccessor2D(size, size, MutableBuffer.Companion::boxing).run { - val cache = factory(size * size) { null } - buildMatrix(size, size) { i, j -> - val cached = cache[i, j] - if (cached == null) { - val value = if (i <= j) builder(i, j) else builder(j, i) - cache[i, j] = value - cache[j, i] = value - value - } else { - cached - } - } + SymmetricMatrixFeature -} \ No newline at end of file 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 a94efc788..648b6376f 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 @@ -11,29 +11,44 @@ import kotlin.reflect.KClass * A entity that contains a set of features defined by their types */ public interface Featured { - public fun getFeature(type: KClass): T? + public fun getFeature(type: FeatureKey): T? +} + +public typealias FeatureKey = KClass + +public interface Feature> { + + /** + * A key used for extraction + */ + @Suppress("UNCHECKED_CAST") + public val key: FeatureKey get() = this::class as FeatureKey } /** * A container for a set of features */ -public class FeatureSet private constructor(public val features: Map, F>) : Featured { +public class FeatureSet> private constructor(public val features: Map, F>) : Featured { @Suppress("UNCHECKED_CAST") - override fun getFeature(type: KClass): T? = features[type] as? T + override fun getFeature(type: FeatureKey): T? = features[type] as? T public inline fun getFeature(): T? = getFeature(T::class) - public fun with(feature: T, type: KClass = feature::class): FeatureSet = + public fun with(feature: T, type: FeatureKey = feature.key): FeatureSet = FeatureSet(features + (type to feature)) public fun with(other: FeatureSet): FeatureSet = FeatureSet(features + other.features) public fun with(vararg otherFeatures: F): FeatureSet = - FeatureSet(features + otherFeatures.associateBy { it::class }) + FeatureSet(features + otherFeatures.associateBy { it.key }) + + public fun with(otherFeatures: Iterable): FeatureSet = + FeatureSet(features + otherFeatures.associateBy { it.key }) public operator fun iterator(): Iterator = features.values.iterator() public companion object { - public fun of(vararg features: F): FeatureSet = FeatureSet(features.associateBy { it::class }) + public fun > of(vararg features: F): FeatureSet = FeatureSet(features.associateBy { it.key }) + public fun > of(features: Iterable): FeatureSet = FeatureSet(features.associateBy { it.key }) } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt index e521e6237..39b2779eb 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt @@ -12,7 +12,7 @@ package space.kscience.kmath.misc * in some way that may break some code. */ @MustBeDocumented -@Retention(value = AnnotationRetention.BINARY) +@Retention(value = AnnotationRetention.SOURCE) @RequiresOptIn("This API is unstable and could change in future", RequiresOptIn.Level.WARNING) public annotation class UnstableKMathAPI @@ -21,7 +21,7 @@ public annotation class UnstableKMathAPI * slow-down in some cases. Refer to the documentation and benchmark it to be sure. */ @MustBeDocumented -@Retention(value = AnnotationRetention.BINARY) +@Retention(value = AnnotationRetention.SOURCE) @RequiresOptIn( "Refer to the documentation to use this API in performance-critical code", RequiresOptIn.Level.WARNING diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index 7fc91e321..4962dcb7d 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,6 +5,8 @@ package space.kscience.kmath.nd +import space.kscience.kmath.misc.Feature +import space.kscience.kmath.misc.Featured import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer @@ -13,7 +15,7 @@ import kotlin.jvm.JvmName import kotlin.native.concurrent.ThreadLocal import kotlin.reflect.KClass -public interface StructureFeature +public interface StructureFeature : Feature /** * Represents n-dimensional structure, i.e. multidimensional container of items of the same type and size. The number @@ -24,7 +26,7 @@ public interface StructureFeature * * @param T the type of items. */ -public interface StructureND { +public interface StructureND : Featured { /** * The shape of structure, i.e. non-empty sequence of non-negative integers that specify sizes of dimensions of * this structure. @@ -57,7 +59,7 @@ public interface StructureND { * If the feature is not present, null is returned. */ @UnstableKMathAPI - public fun getFeature(type: KClass): F? = null + override fun getFeature(type: KClass): F? = null public companion object { /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt index d29c54d46..a96253939 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt @@ -14,30 +14,30 @@ import space.kscience.kmath.nd.as2D * A context that allows to operate on a [MutableBuffer] as on 2d array */ internal class BufferAccessor2D( - public val rowNum: Int, - public val colNum: Int, + val rowNum: Int, + val colNum: Int, val factory: MutableBufferFactory, ) { - public operator fun Buffer.get(i: Int, j: Int): T = get(i * colNum + j) + operator fun Buffer.get(i: Int, j: Int): T = get(i * colNum + j) - public operator fun MutableBuffer.set(i: Int, j: Int, value: T) { + operator fun MutableBuffer.set(i: Int, j: Int, value: T) { set(i * colNum + j, value) } - public inline fun create(crossinline init: (i: Int, j: Int) -> T): MutableBuffer = + inline fun create(crossinline init: (i: Int, j: Int) -> T): MutableBuffer = factory(rowNum * colNum) { offset -> init(offset / colNum, offset % colNum) } - public fun create(mat: Structure2D): MutableBuffer = create { i, j -> mat[i, j] } + fun create(mat: Structure2D): MutableBuffer = create { i, j -> mat[i, j] } //TODO optimize wrapper - public fun MutableBuffer.collect(): Structure2D = StructureND.buffered( + fun MutableBuffer.collect(): Structure2D = StructureND.buffered( DefaultStrides(intArrayOf(rowNum, colNum)), factory ) { (i, j) -> get(i, j) }.as2D() - public inner class Row(public val buffer: MutableBuffer, public val rowIndex: Int) : MutableBuffer { + inner class Row(val buffer: MutableBuffer, val rowIndex: Int) : MutableBuffer { override val size: Int get() = colNum override operator fun get(index: Int): T = buffer[rowIndex, index] @@ -54,5 +54,5 @@ internal class BufferAccessor2D( /** * Get row */ - public fun MutableBuffer.row(i: Int): Row = Row(this, i) + fun MutableBuffer.row(i: Int): Row = Row(this, i) } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt index 2d2a0952b..3be473e54 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 @@ -22,14 +22,14 @@ class DoubleLUSolverTest { @Test fun testInvertOne() { - val matrix = LinearSpace.real.one(2, 2) - val inverted = LinearSpace.real.inverseWithLup(matrix) + val matrix = LinearSpace.double.one(2, 2) + val inverted = LinearSpace.double.lupSolver().inverse(matrix) assertMatrixEquals(matrix, inverted) } @Test fun testDecomposition() { - LinearSpace.real.run { + LinearSpace.double.run { val matrix = matrix(2, 2)( 3.0, 1.0, 2.0, 3.0 @@ -46,14 +46,14 @@ class DoubleLUSolverTest { @Test fun testInvert() { - val matrix = LinearSpace.real.matrix(2, 2)( + val matrix = LinearSpace.double.matrix(2, 2)( 3.0, 1.0, 1.0, 3.0 ) - val inverted = LinearSpace.real.inverseWithLup(matrix) + val inverted = LinearSpace.double.lupSolver().inverse(matrix) - val expected = LinearSpace.real.matrix(2, 2)( + val expected = LinearSpace.double.matrix(2, 2)( 0.375, -0.125, -0.125, 0.375 ) 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 170f9caf4..feae07c1e 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 @@ -19,14 +19,14 @@ import kotlin.test.assertTrue class MatrixTest { @Test fun testTranspose() { - val matrix = LinearSpace.real.one(3, 3) + val matrix = LinearSpace.double.one(3, 3) val transposed = matrix.transpose() assertTrue { StructureND.contentEquals(matrix, transposed) } } @Test fun testBuilder() { - val matrix = LinearSpace.real.matrix(2, 3)( + val matrix = LinearSpace.double.matrix(2, 3)( 1.0, 0.0, 0.0, 0.0, 1.0, 2.0 ) @@ -48,7 +48,7 @@ class MatrixTest { infix fun Matrix.pow(power: Int): Matrix { var res = this repeat(power - 1) { - res = LinearSpace.real.run { res dot this@pow } + res = LinearSpace.double.run { res dot this@pow } } return res } @@ -61,7 +61,7 @@ class MatrixTest { val firstMatrix = StructureND.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D() val secondMatrix = StructureND.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D() - LinearSpace.real.run { + LinearSpace.double.run { // val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() } // val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() } val result = firstMatrix dot secondMatrix 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 fb51553f7..8a03115b5 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 @@ -40,7 +40,7 @@ class NumberNDFieldTest { @Test fun testGeneration() { - val array = LinearSpace.real.buildMatrix(3, 3) { i, j -> + val array = LinearSpace.double.buildMatrix(3, 3) { i, j -> (i * 10 + j).toDouble() } diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt index 2ebcc454d..91ab6a5d6 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt @@ -151,7 +151,7 @@ public value class DMatrixContext>(public val context: context.run { (this@transpose as Matrix).transpose() }.coerce() public companion object { - public val real: DMatrixContext = DMatrixContext(LinearSpace.real) + public val real: DMatrixContext = DMatrixContext(LinearSpace.double) } } 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 deleted file mode 100644 index 139c55697..000000000 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt +++ /dev/null @@ -1,995 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */ - -package space.kscience.kmath.ejml - -import org.ejml.data.* -import org.ejml.dense.row.CommonOps_DDRM -import org.ejml.dense.row.CommonOps_FDRM -import org.ejml.dense.row.factory.DecompositionFactory_DDRM -import org.ejml.dense.row.factory.DecompositionFactory_FDRM -import org.ejml.sparse.FillReducing -import org.ejml.sparse.csc.CommonOps_DSCC -import org.ejml.sparse.csc.CommonOps_FSCC -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.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 -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.FloatBuffer -import kotlin.reflect.KClass -import kotlin.reflect.cast - -/** - * [EjmlVector] specialization for [Double]. - */ -public class EjmlDoubleVector(public override val origin: M) : EjmlVector(origin) { - init { - require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } - } - - public override operator fun get(index: Int): Double = origin[0, index] -} - -/** - * [EjmlVector] specialization for [Float]. - */ -public class EjmlFloatVector(public override val origin: M) : EjmlVector(origin) { - init { - require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } - } - - public override operator fun get(index: Int): Float = origin[0, index] -} - -/** - * [EjmlMatrix] specialization for [Double]. - */ -public class EjmlDoubleMatrix(public override val origin: M) : EjmlMatrix(origin) { - public override operator fun get(i: Int, j: Int): Double = origin[i, j] -} - -/** - * [EjmlMatrix] specialization for [Float]. - */ -public class EjmlFloatMatrix(public override val origin: M) : EjmlMatrix(origin) { - public override operator fun get(i: Int, j: Int): Float = origin[i, j] -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_DDRM], [DecompositionFactory_DDRM] operations and - * [DMatrixRMaj] matrices. - */ -public object EjmlLinearSpaceDDRM : EjmlLinearSpace() { - /** - * The [DoubleField] reference. - */ - public override val elementAlgebra: DoubleField get() = DoubleField - - @Suppress("UNCHECKED_CAST") - public override fun Matrix.toEjml(): EjmlDoubleMatrix = when { - this is EjmlDoubleMatrix<*> && origin is DMatrixRMaj -> this as EjmlDoubleMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - public override fun Point.toEjml(): EjmlDoubleVector = when { - this is EjmlDoubleVector<*> && origin is DMatrixRMaj -> this as EjmlDoubleVector - else -> EjmlDoubleVector(DMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - public override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double, - ): EjmlDoubleMatrix = DMatrixRMaj(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - public override fun buildVector( - size: Int, - initializer: DoubleField.(Int) -> Double, - ): EjmlDoubleVector = EjmlDoubleVector(DMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlDoubleMatrix(this) - private fun T.wrapVector() = EjmlDoubleVector(this) - - public override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - public override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - CommonOps_DDRM.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - public override fun Matrix.dot(vector: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - CommonOps_DDRM.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - public override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - public override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - public override fun Point.unaryMinus(): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - public override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - public override fun Point.plus(other: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - public override fun Point.minus(other: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - public override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - - public override fun Point.times(value: Double): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - public override fun Double.times(v: Point): EjmlDoubleVector = v * this - - @UnstableKMathAPI - public override fun getFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - InverseMatrixFeature::class -> object : InverseMatrixFeature { - override val inverse: Matrix by lazy { - val res = origin.copy() - CommonOps_DDRM.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature { - override val determinant: Double by lazy { CommonOps_DDRM.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { - private val svd by lazy { - DecompositionFactory_DDRM.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point by lazy { DoubleBuffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix() + LFeature - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature { - private val lup by lazy { - DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lup.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix() + UFeature - } - - override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } - } - - else -> null - }?.let(type::cast) - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) - return EjmlDoubleVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_FDRM], [DecompositionFactory_FDRM] operations and - * [FMatrixRMaj] matrices. - */ -public object EjmlLinearSpaceFDRM : EjmlLinearSpace() { - /** - * The [FloatField] reference. - */ - public override val elementAlgebra: FloatField get() = FloatField - - @Suppress("UNCHECKED_CAST") - public override fun Matrix.toEjml(): EjmlFloatMatrix = when { - this is EjmlFloatMatrix<*> && origin is FMatrixRMaj -> this as EjmlFloatMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - public override fun Point.toEjml(): EjmlFloatVector = when { - this is EjmlFloatVector<*> && origin is FMatrixRMaj -> this as EjmlFloatVector - else -> EjmlFloatVector(FMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - public override fun buildMatrix( - rows: Int, - columns: Int, - initializer: FloatField.(i: Int, j: Int) -> Float, - ): EjmlFloatMatrix = FMatrixRMaj(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - public override fun buildVector( - size: Int, - initializer: FloatField.(Int) -> Float, - ): EjmlFloatVector = EjmlFloatVector(FMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlFloatMatrix(this) - private fun T.wrapVector() = EjmlFloatVector(this) - - public override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - public override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - CommonOps_FDRM.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - public override fun Matrix.dot(vector: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - CommonOps_FDRM.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - public override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - public override operator fun Matrix.times(value: Float): EjmlFloatMatrix { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - public override fun Point.unaryMinus(): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - public override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - public override fun Point.plus(other: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - public override fun Point.minus(other: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - public override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - - public override fun Point.times(value: Float): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - public override fun Float.times(v: Point): EjmlFloatVector = v * this - - @UnstableKMathAPI - public override fun getFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - InverseMatrixFeature::class -> object : InverseMatrixFeature { - override val inverse: Matrix by lazy { - val res = origin.copy() - CommonOps_FDRM.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature { - override val determinant: Float by lazy { CommonOps_FDRM.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { - private val svd by lazy { - DecompositionFactory_FDRM.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point by lazy { FloatBuffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_FDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix() + LFeature - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature { - private val lup by lazy { - DecompositionFactory_FDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lup.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix() + UFeature - } - - override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } - } - - else -> null - }?.let(type::cast) - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) - return EjmlFloatVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_DSCC], [DecompositionFactory_DSCC] operations and - * [DMatrixSparseCSC] matrices. - */ -public object EjmlLinearSpaceDSCC : EjmlLinearSpace() { - /** - * The [DoubleField] reference. - */ - public override val elementAlgebra: DoubleField get() = DoubleField - - @Suppress("UNCHECKED_CAST") - public override fun Matrix.toEjml(): EjmlDoubleMatrix = when { - this is EjmlDoubleMatrix<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - public override fun Point.toEjml(): EjmlDoubleVector = when { - this is EjmlDoubleVector<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleVector - else -> EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - public override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double, - ): EjmlDoubleMatrix = DMatrixSparseCSC(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - public override fun buildVector( - size: Int, - initializer: DoubleField.(Int) -> Double, - ): EjmlDoubleVector = EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlDoubleMatrix(this) - private fun T.wrapVector() = EjmlDoubleVector(this) - - public override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - public override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - public override fun Matrix.dot(vector: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - public override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - public override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - public override fun Point.unaryMinus(): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - public override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - public override fun Point.plus(other: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - public override fun Point.minus(other: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - public override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - - public override fun Point.times(value: Double): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - public override fun Double.times(v: Point): EjmlDoubleVector = v * this - - @UnstableKMathAPI - public override fun getFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as DMatrix).wrapMatrix() + LFeature - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { - private val lu by lazy { - DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lu.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix() + UFeature - } - - override val inverse: Matrix by lazy { - var a = origin - val inverse = DMatrixRMaj(1, 1) - val solver = LinearSolverFactory_DSCC.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_DDRM.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: Double by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - } - - else -> null - }?.let(type::cast) - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) - return EjmlDoubleVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_FSCC], [DecompositionFactory_FSCC] operations and - * [FMatrixSparseCSC] matrices. - */ -public object EjmlLinearSpaceFSCC : EjmlLinearSpace() { - /** - * The [FloatField] reference. - */ - public override val elementAlgebra: FloatField get() = FloatField - - @Suppress("UNCHECKED_CAST") - public override fun Matrix.toEjml(): EjmlFloatMatrix = when { - this is EjmlFloatMatrix<*> && origin is FMatrixSparseCSC -> this as EjmlFloatMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - public override fun Point.toEjml(): EjmlFloatVector = when { - this is EjmlFloatVector<*> && origin is FMatrixSparseCSC -> this as EjmlFloatVector - else -> EjmlFloatVector(FMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - public override fun buildMatrix( - rows: Int, - columns: Int, - initializer: FloatField.(i: Int, j: Int) -> Float, - ): EjmlFloatMatrix = FMatrixSparseCSC(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - public override fun buildVector( - size: Int, - initializer: FloatField.(Int) -> Float, - ): EjmlFloatVector = EjmlFloatVector(FMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlFloatMatrix(this) - private fun T.wrapVector() = EjmlFloatVector(this) - - public override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - public override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - public override fun Matrix.dot(vector: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - public override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - public override operator fun Matrix.times(value: Float): EjmlFloatMatrix { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - public override fun Point.unaryMinus(): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - public override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - public override fun Point.plus(other: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - public override fun Point.minus(other: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - public override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - - public override fun Point.times(value: Float): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - public override fun Float.times(v: Point): EjmlFloatVector = v * this - - @UnstableKMathAPI - public override fun getFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_FSCC.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as FMatrix).wrapMatrix() + LFeature - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { - private val lu by lazy { - DecompositionFactory_FSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lu.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix() + UFeature - } - - override val inverse: Matrix by lazy { - var a = origin - val inverse = FMatrixRMaj(1, 1) - val solver = LinearSolverFactory_FSCC.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_FDRM.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: Float by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - } - - else -> null - }?.let(type::cast) - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) - return EjmlFloatVector(res) - } -} - diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt index 50675bdac..6055ae1d8 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,7 +11,7 @@ import org.ejml.dense.row.RandomMatrices_DDRM import org.ejml.dense.row.factory.DecompositionFactory_DDRM import space.kscience.kmath.linear.DeterminantFeature import space.kscience.kmath.linear.LupDecompositionFeature -import space.kscience.kmath.linear.getFeature +import space.kscience.kmath.linear.computeFeature import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND @@ -59,9 +59,9 @@ internal class EjmlMatrixTest { fun features() { val m = randomMatrix val w = EjmlDoubleMatrix(m) - val det: DeterminantFeature = EjmlLinearSpaceDDRM.getFeature(w) ?: fail() + val det: DeterminantFeature = EjmlLinearSpaceDDRM.computeFeature(w) ?: fail() assertEquals(CommonOps_DDRM.det(m), det.determinant) - val lup: LupDecompositionFeature = EjmlLinearSpaceDDRM.getFeature(w) ?: fail() + val lup: LupDecompositionFeature = EjmlLinearSpaceDDRM.computeFeature(w) ?: fail() val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols) .also { it.decompose(m.copy()) } diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt index 8023236ea..38e5b4beb 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 @@ -32,18 +32,18 @@ import kotlin.math.pow public typealias RealMatrix = Matrix public fun realMatrix(rowNum: Int, colNum: Int, initializer: DoubleField.(i: Int, j: Int) -> Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum, initializer) + LinearSpace.double.buildMatrix(rowNum, colNum, initializer) @OptIn(UnstableKMathAPI::class) public fun realMatrix(rowNum: Int, colNum: Int): MatrixBuilder = - LinearSpace.real.matrix(rowNum, colNum) + LinearSpace.double.matrix(rowNum, colNum) public fun Array.toMatrix(): RealMatrix { - return LinearSpace.real.buildMatrix(size, this[0].size) { row, col -> this@toMatrix[row][col] } + return LinearSpace.double.buildMatrix(size, this[0].size) { row, col -> this@toMatrix[row][col] } } public fun Sequence.toMatrix(): RealMatrix = toList().let { - LinearSpace.real.buildMatrix(it.size, it[0].size) { row, col -> it[row][col] } + LinearSpace.double.buildMatrix(it.size, it[0].size) { row, col -> it[row][col] } } public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix = @@ -56,37 +56,37 @@ public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix = */ public operator fun RealMatrix.times(double: Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> get(row, col) * double } public operator fun RealMatrix.plus(double: Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> get(row, col) + double } public operator fun RealMatrix.minus(double: Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> get(row, col) - double } public operator fun RealMatrix.div(double: Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> get(row, col) / double } public operator fun Double.times(matrix: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + LinearSpace.double.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@times * matrix[row, col] } public operator fun Double.plus(matrix: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + LinearSpace.double.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@plus + matrix[row, col] } public operator fun Double.minus(matrix: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + LinearSpace.double.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@minus - matrix[row, col] } @@ -101,20 +101,20 @@ public operator fun Double.minus(matrix: RealMatrix): RealMatrix = @UnstableKMathAPI public operator fun RealMatrix.times(other: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> this@times[row, col] * other[row, col] } + LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> this@times[row, col] * other[row, col] } public operator fun RealMatrix.plus(other: RealMatrix): RealMatrix = - LinearSpace.real.run { this@plus + other } + LinearSpace.double.run { this@plus + other } public operator fun RealMatrix.minus(other: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> this@minus[row, col] - other[row, col] } + LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> this@minus[row, col] - other[row, col] } /* * Operations on columns */ public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) -> Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum + 1) { row, col -> + LinearSpace.double.buildMatrix(rowNum, colNum + 1) { row, col -> if (col < colNum) get(row, col) else @@ -122,7 +122,7 @@ public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) - } public fun RealMatrix.extractColumns(columnRange: IntRange): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, columnRange.count()) { row, col -> + LinearSpace.double.buildMatrix(rowNum, columnRange.count()) { row, col -> this@extractColumns[row, columnRange.first + col] } @@ -155,14 +155,14 @@ public fun RealMatrix.max(): Double? = elements().map { (_, value) -> value }.ma public fun RealMatrix.average(): Double = elements().map { (_, value) -> value }.average() public inline fun RealMatrix.map(crossinline transform: (Double) -> Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { i, j -> + LinearSpace.double.buildMatrix(rowNum, colNum) { i, j -> transform(get(i, j)) } /** * Inverse a square real matrix using LUP decomposition */ -public fun RealMatrix.inverseWithLup(): RealMatrix = LinearSpace.real.inverseWithLup(this) +public fun RealMatrix.inverseWithLup(): RealMatrix = LinearSpace.double.lupSolver().inverse(this) //extended operations diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt index b79e5030c..395c94838 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt @@ -12,6 +12,6 @@ import space.kscience.kmath.linear.Matrix /** * Optimized dot product for real matrices */ -public infix fun Matrix.dot(other: Matrix): Matrix = LinearSpace.real.run { +public infix fun Matrix.dot(other: Matrix): Matrix = LinearSpace.double.run { this@dot dot other } \ No newline at end of file diff --git a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt index b3e129c2e..5a80ee677 100644 --- a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt @@ -65,7 +65,7 @@ internal class DoubleMatrixTest { 4.0, 6.0, 2.0 ) val matrix2 = (matrix1 * 2.5 + 1.0 - 2.0) / 2.0 - val expectedResult = LinearSpace.real.matrix(2, 3)( + val expectedResult = LinearSpace.double.matrix(2, 3)( 0.75, -0.5, 3.25, 4.5, 7.0, 2.0 ) @@ -160,7 +160,7 @@ internal class DoubleMatrixTest { @Test fun testAllElementOperations() { - val matrix1 = LinearSpace.real.matrix(2, 4)( + val matrix1 = LinearSpace.double.matrix(2, 4)( -1.0, 0.0, 3.0, 15.0, 4.0, -6.0, 7.0, -11.0 ) diff --git a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt index 9de54381c..ec7b536ba 100644 --- a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt @@ -35,7 +35,7 @@ internal class DoubleVectorTest { val vector2 = DoubleBuffer(5) { 5 - it.toDouble() } val matrix1 = vector1.asMatrix() val matrix2 = vector2.asMatrix().transpose() - val product = LinearSpace.real.run { matrix1 dot matrix2 } + val product = LinearSpace.double.run { matrix1 dot matrix2 } assertEquals(5.0, product[1, 0]) assertEquals(6.0, product[2, 2]) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt index dcf711c3b..f90159c81 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt @@ -5,11 +5,12 @@ package space.kscience.kmath.integration +import space.kscience.kmath.misc.Feature import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.Featured import kotlin.reflect.KClass -public interface IntegrandFeature { +public interface IntegrandFeature : Feature { override fun toString(): String } @@ -18,7 +19,7 @@ public interface Integrand : Featured { override fun getFeature(type: KClass): T? = features.getFeature(type) } -public inline fun Integrand.getFeature(): T? = getFeature(T::class) +public inline fun Integrand.getFeature(): T? = getFeature(T::class) public class IntegrandValue(public val value: T) : IntegrandFeature { override fun toString(): String = "Value($value)" diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt index 4294462c0..a59c301cf 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt @@ -27,19 +27,30 @@ public class KotlingradExpression>( ) : SpecialDifferentiableExpression> { public override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) - public override fun derivativeOrNull(symbols: List): KotlingradExpression = - KotlingradExpression( - algebra, - symbols.map(Symbol::identity) - .map(MstNumericAlgebra::bindSymbol) - .map>>(Symbol::toSVar) - .fold(mst.toSFun(), SFun>::d) - .toMst(), - ) + public override fun derivativeOrNull( + symbols: List, + ): KotlingradExpression = KotlingradExpression( + algebra, + symbols.map(Symbol::identity) + .map(MstNumericAlgebra::bindSymbol) + .map>>(Symbol::toSVar) + .fold(mst.toSFun(), SFun>::d) + .toMst(), + ) +} + +/** + * A diff processor using [MST] to Kotlingrad converter + */ +public class KotlingradProcessor>( + public val algebra: A, +) : AutoDiffProcessor { + override fun differentiate(function: MstExtendedField.() -> MST): DifferentiableExpression = + MstExtendedField.function().toKotlingradExpression(algebra) } /** * Wraps this [MST] into [KotlingradExpression]. */ -public fun > MST.toDiffExpression(algebra: A): KotlingradExpression = +public fun > MST.toKotlingradExpression(algebra: A): KotlingradExpression = KotlingradExpression(algebra, this) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index 62288242a..4d4f99b71 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -23,7 +23,7 @@ public enum class FunctionOptimizationTarget : OptimizationFeature { public class FunctionOptimization( override val features: FeatureSet, public val expression: DifferentiableExpression, -) : OptimizationProblem{ +) : OptimizationProblem{ public companion object{ /** @@ -56,7 +56,6 @@ public class FunctionOptimization( } } - public fun FunctionOptimization.withFeatures( vararg newFeature: OptimizationFeature, ): FunctionOptimization = FunctionOptimization( @@ -68,7 +67,7 @@ public fun FunctionOptimization.withFeatures( * Optimize differentiable expression using specific [optimizer] form given [startingPoint] */ public suspend fun DifferentiableExpression.optimizeWith( - optimizer: Optimizer>, + optimizer: Optimizer>, startingPoint: Map, vararg features: OptimizationFeature, ): FunctionOptimization { @@ -76,3 +75,8 @@ public suspend fun DifferentiableExpression.optimizeWith( return optimizer.optimize(problem) } +public val FunctionOptimization.resultValueOrNull:T? + get() = getFeature>()?.point?.let { expression(it) } + +public val FunctionOptimization.resultValue: T + get() = resultValueOrNull ?: error("Result is not present in $this") \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt new file mode 100644 index 000000000..7d52ae26e --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt @@ -0,0 +1,93 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.FeatureSet + +public abstract class OptimizationBuilder> { + public val features: ArrayList = ArrayList() + + public fun addFeature(feature: OptimizationFeature) { + features.add(feature) + } + + public inline fun updateFeature(update: (T?) -> T) { + val existing = features.find { it.key == T::class } as? T + val new = update(existing) + if (existing != null) { + features.remove(existing) + } + addFeature(new) + } + + public abstract fun build(): R +} + +public fun OptimizationBuilder.startAt(startingPoint: Map) { + addFeature(OptimizationStartPoint(startingPoint)) +} + +public class FunctionOptimizationBuilder( + private val expression: DifferentiableExpression, +) : OptimizationBuilder>() { + override fun build(): FunctionOptimization = FunctionOptimization(FeatureSet.of(features), expression) +} + +public fun FunctionOptimization( + expression: DifferentiableExpression, + builder: FunctionOptimizationBuilder.() -> Unit, +): FunctionOptimization = FunctionOptimizationBuilder(expression).apply(builder).build() + +public suspend fun DifferentiableExpression.optimizeWith( + optimizer: Optimizer>, + startingPoint: Map, + builder: FunctionOptimizationBuilder.() -> Unit = {}, +): FunctionOptimization { + val problem = FunctionOptimization(this) { + startAt(startingPoint) + builder() + } + return optimizer.optimize(problem) +} + +public suspend fun DifferentiableExpression.optimizeWith( + optimizer: Optimizer>, + vararg startingPoint: Pair, + builder: FunctionOptimizationBuilder.() -> Unit = {}, +): FunctionOptimization { + val problem = FunctionOptimization(this) { + startAt(mapOf(*startingPoint)) + builder() + } + return optimizer.optimize(problem) +} + + +public class XYOptimizationBuilder( + public val data: XYColumnarData, + public val model: DifferentiableExpression, +) : OptimizationBuilder() { + + public var pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY + public var pointWeight: PointWeight = PointWeight.byYSigma + + override fun build(): XYOptimization = XYOptimization( + FeatureSet.of(features), + data, + model, + pointToCurveDistance, + pointWeight + ) +} + +public fun XYOptimization( + data: XYColumnarData, + model: DifferentiableExpression, + builder: XYOptimizationBuilder.() -> Unit, +): XYOptimization = XYOptimizationBuilder(data, model).apply(builder).build() \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt index 739ce8ca5..b42be4035 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -5,37 +5,61 @@ package space.kscience.kmath.optimization +import space.kscience.kmath.expressions.DifferentiableExpression import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.misc.Featured -import space.kscience.kmath.misc.Loggable +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.misc.* import kotlin.reflect.KClass -public interface OptimizationFeature { +public interface OptimizationFeature : Feature { + // enforce toString override override fun toString(): String } -public interface OptimizationProblem : Featured { +public interface OptimizationProblem : Featured { public val features: FeatureSet - override fun getFeature(type: KClass): T? = features.getFeature(type) + override fun getFeature(type: KClass): F? = features.getFeature(type) } -public inline fun OptimizationProblem.getFeature(): T? = getFeature(T::class) +public inline fun OptimizationProblem<*>.getFeature(): F? = getFeature(F::class) public open class OptimizationStartPoint(public val point: Map) : OptimizationFeature { override fun toString(): String = "StartPoint($point)" } + +public interface OptimizationPrior : OptimizationFeature, DifferentiableExpression { + override val key: FeatureKey get() = OptimizationPrior::class +} + +public class OptimizationCovariance(public val covariance: Matrix) : OptimizationFeature { + override fun toString(): String = "Covariance($covariance)" +} + +/** + * Get the starting point for optimization. Throws error if not defined. + */ +public val OptimizationProblem.startPoint: Map + get() = getFeature>()?.point + ?: error("Starting point not defined in $this") + public open class OptimizationResult(public val point: Map) : OptimizationFeature { override fun toString(): String = "Result($point)" } +public val OptimizationProblem.resultPointOrNull: Map? + get() = getFeature>()?.point + +public val OptimizationProblem.resultPoint: Map + get() = resultPointOrNull ?: error("Result is not present in $this") + public class OptimizationLog(private val loggable: Loggable) : Loggable by loggable, OptimizationFeature { override fun toString(): String = "Log($loggable)" } -public class OptimizationParameters(public val symbols: List): OptimizationFeature{ +public class OptimizationParameters(public val symbols: List) : OptimizationFeature { public constructor(vararg symbols: Symbol) : this(listOf(*symbols)) + override fun toString(): String = "Parameters($symbols)" } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt index ad1a16007..78385a99b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt @@ -5,6 +5,6 @@ package space.kscience.kmath.optimization -public interface Optimizer

{ +public interface Optimizer> { public suspend fun optimize(problem: P): P } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt new file mode 100644 index 000000000..acfc7e445 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt @@ -0,0 +1,247 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.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.linear.* +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.DoubleL2Norm + + +/** + * An optimizer based onf Fyodor Tkachev's quasi-optimal weights method. + * See [the article](http://arxiv.org/abs/physics/0604127). + */ +@UnstableKMathAPI +public class QowOptimizer : Optimizer { + + private val linearSpace: LinearSpace = LinearSpace.double + private val solver: LinearSolver = linearSpace.lupSolver() + + @OptIn(UnstableKMathAPI::class) + private inner class QoWeight( + val problem: XYOptimization, + val parameters: Map, + ) : Map by parameters, SymbolIndexer { + override val symbols: List = parameters.keys.toList() + + val data get() = problem.data + + /** + * 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) { i, k -> + problem.distance(i).derivative(symbols[k])(parameters) + } + } + + /** + * Array of dispersions in each point + */ + val dispersion: Point by lazy { + DoubleBuffer(problem.data.size) { i -> + problem.weight(i).invoke(parameters) + } + } + + val prior: DifferentiableExpression? get() = problem.getFeature>() + } + + /** + * The signed distance from the model to the [i]-th point of data. + */ + private fun QoWeight.distance(i: Int, parameters: Map): Double = problem.distance(i)(parameters) + + + /** + * The derivative of [distance] + */ + private fun QoWeight.distanceDerivative(symbol: Symbol, i: Int, parameters: Map): Double = + problem.distance(i).derivative(symbol)(parameters) + + /** + * Теоретическая ковариация весовых функций. + * + * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 + */ + private fun QoWeight.covarF(): Matrix = + linearSpace.matrix(size, size).symmetric { k, l -> + (0 until data.size).sumOf { i -> derivs[k, i] * derivs[l, i] / dispersion[i] } + } + + /** + * Экспериментальная ковариация весов. Формула (22) из + * http://arxiv.org/abs/physics/0604127 + */ + private fun QoWeight.covarFExp(theta: Map): Matrix = + with(linearSpace) { + /* + * Важно! Если не делать предварителього вычисления этих производных, то + * количество вызывов функции будет dim^2 вместо dim Первый индекс - + * номер точки, второй - номер переменной, по которой берется производная + */ + val eqvalues = linearSpace.buildMatrix(data.size, size) { i, l -> + distance(i, theta) * derivs[l, i] / dispersion[i] + } + + buildMatrix(size, size) { k, l -> + (0 until data.size).sumOf { i -> eqvalues[i, l] * eqvalues[i, k] } + } + } + + /** + * Equation derivatives for Newton run + */ + private fun QoWeight.getEqDerivValues( + theta: Map = parameters, + ): Matrix = with(linearSpace) { + val fitDim = size + //Возвращает производную k-того Eq по l-тому параметру + //val res = Array(fitDim) { DoubleArray(fitDim) } + val sderiv = buildMatrix(data.size, size) { i, l -> + distanceDerivative(symbols[l], i, theta) + } + + buildMatrix(size, size) { k, l -> + val base = (0 until data.size).sumOf { i -> + require(dispersion[i] > 0) + sderiv[i, l] * derivs[k, i] / dispersion[i] + } + prior?.let { prior -> + //Check if this one is correct + val pi = prior(theta) + val deriv1 = prior.derivative(symbols[k])(theta) + val deriv2 = prior.derivative(symbols[l])(theta) + base + deriv1 * deriv2 / pi / pi + } ?: base + } + } + + + /** + * Значения уравнений метода квазиоптимальных весов + */ + private fun QoWeight.getEqValues(theta: Map = this): Point { + val distances = DoubleBuffer(data.size) { i -> distance(i, theta) } + + return DoubleBuffer(size) { k -> + val base = (0 until data.size).sumOf { i -> distances[i] * derivs[k, i] / dispersion[i] } + //Поправка на априорную вероятность + prior?.let { prior -> + base - prior.derivative(symbols[k])(theta) / prior(theta) + } ?: base + } + } + + + private fun QoWeight.newtonianStep( + theta: Map, + eqvalues: Point, + ): QoWeight = linearSpace { + with(this@newtonianStep) { + val start = theta.toPoint() + val invJacob = solver.inverse(this@newtonianStep.getEqDerivValues(theta)) + + val step = invJacob.dot(eqvalues) + return QoWeight(problem, theta + (start - step).toMap()) + } + } + + private fun QoWeight.newtonianRun( + maxSteps: Int = 100, + tolerance: Double = 0.0, + fast: Boolean = false, + ): QoWeight { + + val logger = problem.getFeature() + + var dis: Double//норма невязки + // Для удобства работаем всегда с полным набором параметров + var par = problem.startPoint + + logger?.log { "Starting newtonian iteration from: \n\t$par" } + + var eqvalues = getEqValues(par)//значения функций + + dis = DoubleL2Norm.norm(eqvalues)// невязка + logger?.log { "Starting discrepancy is $dis" } + var i = 0 + var flag = false + while (!flag) { + i++ + logger?.log { "Starting step number $i" } + + val currentSolution = if (fast) { + //Берет значения матрицы в той точке, где считается вес + newtonianStep(this, eqvalues) + } else { + //Берет значения матрицы в точке par + newtonianStep(par, eqvalues) + } + // здесь должен стоять учет границ параметров + logger?.log { "Parameter values after step are: \n\t$currentSolution" } + + eqvalues = getEqValues(currentSolution) + val currentDis = DoubleL2Norm.norm(eqvalues)// невязка после шага + + logger?.log { "The discrepancy after step is: $currentDis." } + + if (currentDis >= dis && i > 1) { + //дополнительно проверяем, чтобы был сделан хотя бы один шаг + flag = true + logger?.log { "The discrepancy does not decrease. Stopping iteration." } + } else { + par = currentSolution + 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 { + val logger = problem.getFeature() + + logger?.log { + """ + Starting errors estimation using quasioptimal weights method. The starting weight is: + ${problem.startPoint} + """.trimIndent() + } + + val covar = solver.inverse(getEqDerivValues()) + //TODO fix eigenvalues check +// val decomposition = EigenDecomposition(covar.matrix) +// var valid = true +// for (lambda in decomposition.realEigenvalues) { +// if (lambda <= 0) { +// logger?.log { "The covariance matrix is not positive defined. Error estimation is not valid" } +// valid = false +// } +// } + return covar + } + + override suspend fun optimize(problem: XYOptimization): XYOptimization { + val initialWeight = QoWeight(problem, problem.startPoint) + val res = initialWeight.newtonianRun() + return res.problem.withFeature(OptimizationResult(res.parameters)) + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt index 7dc17f6d9..68c0c77eb 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt @@ -7,13 +7,21 @@ package space.kscience.kmath.optimization 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.FeatureSet import space.kscience.kmath.misc.UnstableKMathAPI +import kotlin.math.PI +import kotlin.math.ln import kotlin.math.pow +import kotlin.math.sqrt +/** + * Specify the way to compute distance from point to the curve as DifferentiableExpression + */ public interface PointToCurveDistance : OptimizationFeature { public fun distance(problem: XYOptimization, index: Int): DifferentiableExpression @@ -33,42 +41,107 @@ public interface PointToCurveDistance : OptimizationFeature { } override fun toString(): String = "PointToCurveDistanceByY" - } - } } +/** + * Compute a wight of the point. The more the weight, the more impact this point will have on the fit. + * By default uses Dispersion^-1 + */ +public interface PointWeight : OptimizationFeature { + public fun weight(problem: XYOptimization, index: Int): DifferentiableExpression + + public companion object { + public fun bySigma(sigmaSymbol: Symbol): PointWeight = object : PointWeight { + override fun weight(problem: XYOptimization, index: Int): DifferentiableExpression = + object : DifferentiableExpression { + override fun invoke(arguments: Map): Double { + return problem.data[sigmaSymbol]?.get(index)?.pow(-2) ?: 1.0 + } + + override fun derivativeOrNull(symbols: List): Expression = Expression { 0.0 } + } + + override fun toString(): String = "PointWeightBySigma($sigmaSymbol)" + + } + + public val byYSigma: PointWeight = bySigma(Symbol.yError) + } +} + +/** + * An optimization for XY data. + */ public class XYOptimization( override val features: FeatureSet, public val data: XYColumnarData, public val model: DifferentiableExpression, -) : OptimizationProblem + internal val pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, + internal val pointWeight: PointWeight = PointWeight.byYSigma, +) : OptimizationProblem { + public fun distance(index: Int): DifferentiableExpression = pointToCurveDistance.distance(this, index) + public fun weight(index: Int): DifferentiableExpression = pointWeight.weight(this, index) +} -public suspend fun Optimizer>.maximumLogLikelihood(problem: XYOptimization): XYOptimization { - val distanceBuilder = problem.getFeature() ?: PointToCurveDistance.byY - val likelihood: DifferentiableExpression = object : DifferentiableExpression { - override fun derivativeOrNull(symbols: List): Expression? { - TODO("Not yet implemented") +public fun XYOptimization.withFeature(vararg features: OptimizationFeature): XYOptimization { + return XYOptimization(this.features.with(*features), data, model, pointToCurveDistance, pointWeight) +} + +private val oneOver2Pi = 1.0 / sqrt(2 * PI) + +internal fun XYOptimization.likelihood(): DifferentiableExpression = object : DifferentiableExpression { + override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> + data.indices.sumOf { index -> + + val d = distance(index)(arguments) + val weight = weight(index)(arguments) + val weightDerivative = weight(index)(arguments) + + // -1 / (sqrt(2 PI) * sigma) + 2 (x-mu)/ 2 sigma^2 * d mu/ d theta - (x-mu)^2 / 2 * d w/ d theta + return@sumOf -oneOver2Pi * sqrt(weight) + //offset derivative + d * model.derivative(symbols)(arguments) * weight - //model derivative + d.pow(2) * weightDerivative / 2 //weight derivative } - - override fun invoke(arguments: Map): Double { - var res = 0.0 - for (index in 0 until problem.data.size) { - val d = distanceBuilder.distance(problem, index).invoke(arguments) - val sigma: Double = TODO() - res -= (d / sigma).pow(2) - } - return res - } - } - val functionOptimization = FunctionOptimization(problem.features, likelihood) - val result = optimize(functionOptimization) + + override fun invoke(arguments: Map): Double { + return data.indices.sumOf { index -> + val d = distance(index)(arguments) + val weight = weight(index)(arguments) + //1/sqrt(2 PI sigma^2) - (x-mu)^2/ (2 * sigma^2) + oneOver2Pi * ln(weight) - d.pow(2) * weight + } / 2 + } + +} + +/** + * Optimize given XY (least squares) [problem] using this function [Optimizer]. + * The problem is treated as maximum likelihood problem and is done via maximizing logarithmic likelihood, respecting + * possible weight dependency on the model and parameters. + */ +public suspend fun Optimizer>.maximumLogLikelihood(problem: XYOptimization): XYOptimization { + val functionOptimization = FunctionOptimization(problem.features, problem.likelihood()) + val result = optimize(functionOptimization.withFeatures(FunctionOptimizationTarget.MAXIMIZE)) return XYOptimization(result.features, problem.data, problem.model) } +public suspend fun Optimizer>.maximumLogLikelihood( + data: XYColumnarData, + model: DifferentiableExpression, + builder: XYOptimizationBuilder.() -> Unit, +): XYOptimization = maximumLogLikelihood(XYOptimization(data, model, builder)) + +//public suspend fun XYColumnarData.fitWith( +// optimizer: XYOptimization, +// problemBuilder: XYOptimizationBuilder.() -> Unit = {}, +// +//) + + // //@UnstableKMathAPI //public interface XYFit : OptimizationProblem { diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt b/kmath-stat/src/commonMain/tmp/QowFit.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/qow/QowFit.kt rename to kmath-stat/src/commonMain/tmp/QowFit.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/AnalyticalGradientCalculator.kt b/kmath-stat/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/AnalyticalGradientCalculator.kt rename to kmath-stat/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimizer.kt b/kmath-stat/src/commonMain/tmp/minuit/CombinedMinimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimizer.kt rename to kmath-stat/src/commonMain/tmp/minuit/CombinedMinimizer.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimumBuilder.kt b/kmath-stat/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt similarity index 97% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimumBuilder.kt rename to kmath-stat/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt index a2f0a644a..8c5452575 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/CombinedMinimumBuilder.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt @@ -16,6 +16,7 @@ package ru.inr.mass.minuit import space.kscience.kmath.optimization.minuit.MINUITPlugin +import space.kscience.kmath.optimization.minuit.MinimumSeed /** * diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ContoursError.kt b/kmath-stat/src/commonMain/tmp/minuit/ContoursError.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ContoursError.kt rename to kmath-stat/src/commonMain/tmp/minuit/ContoursError.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/DavidonErrorUpdator.kt b/kmath-stat/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/DavidonErrorUpdator.kt rename to kmath-stat/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionGradient.kt b/kmath-stat/src/commonMain/tmp/minuit/FunctionGradient.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionGradient.kt rename to kmath-stat/src/commonMain/tmp/minuit/FunctionGradient.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionMinimum.kt b/kmath-stat/src/commonMain/tmp/minuit/FunctionMinimum.kt similarity index 99% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionMinimum.kt rename to kmath-stat/src/commonMain/tmp/minuit/FunctionMinimum.kt index 56908f00d..e43523291 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/FunctionMinimum.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/FunctionMinimum.kt @@ -16,6 +16,7 @@ package ru.inr.mass.minuit import ru.inr.mass.minuit.* +import space.kscience.kmath.optimization.minuit.MinimumSeed /** * Result of the minimization. diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/GradientCalculator.kt b/kmath-stat/src/commonMain/tmp/minuit/GradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/GradientCalculator.kt rename to kmath-stat/src/commonMain/tmp/minuit/GradientCalculator.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/HessianGradientCalculator.kt b/kmath-stat/src/commonMain/tmp/minuit/HessianGradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/HessianGradientCalculator.kt rename to kmath-stat/src/commonMain/tmp/minuit/HessianGradientCalculator.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/InitialGradientCalculator.kt b/kmath-stat/src/commonMain/tmp/minuit/InitialGradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/InitialGradientCalculator.kt rename to kmath-stat/src/commonMain/tmp/minuit/InitialGradientCalculator.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINOSResult.kt b/kmath-stat/src/commonMain/tmp/minuit/MINOSResult.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINOSResult.kt rename to kmath-stat/src/commonMain/tmp/minuit/MINOSResult.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITFitter.kt b/kmath-stat/src/commonMain/tmp/minuit/MINUITFitter.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITFitter.kt rename to kmath-stat/src/commonMain/tmp/minuit/MINUITFitter.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITPlugin.kt b/kmath-stat/src/commonMain/tmp/minuit/MINUITPlugin.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITPlugin.kt rename to kmath-stat/src/commonMain/tmp/minuit/MINUITPlugin.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITUtils.kt b/kmath-stat/src/commonMain/tmp/minuit/MINUITUtils.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MINUITUtils.kt rename to kmath-stat/src/commonMain/tmp/minuit/MINUITUtils.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumBuilder.kt b/kmath-stat/src/commonMain/tmp/minuit/MinimumBuilder.kt similarity index 95% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumBuilder.kt rename to kmath-stat/src/commonMain/tmp/minuit/MinimumBuilder.kt index eadeeb91d..7d918c339 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumBuilder.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/MinimumBuilder.kt @@ -15,6 +15,8 @@ */ package ru.inr.mass.minuit +import space.kscience.kmath.optimization.minuit.MinimumSeed + /** * * @version $Id$ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumError.kt b/kmath-stat/src/commonMain/tmp/minuit/MinimumError.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumError.kt rename to kmath-stat/src/commonMain/tmp/minuit/MinimumError.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumErrorUpdator.kt b/kmath-stat/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumErrorUpdator.kt rename to kmath-stat/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumParameters.kt b/kmath-stat/src/commonMain/tmp/minuit/MinimumParameters.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumParameters.kt rename to kmath-stat/src/commonMain/tmp/minuit/MinimumParameters.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeed.kt b/kmath-stat/src/commonMain/tmp/minuit/MinimumSeed.kt similarity index 95% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeed.kt rename to kmath-stat/src/commonMain/tmp/minuit/MinimumSeed.kt index aef672bb7..53a78da75 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeed.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/MinimumSeed.kt @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ru.inr.mass.minuit +package space.kscience.kmath.optimization.minuit + +import ru.inr.mass.minuit.* /** * diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeedGenerator.kt b/kmath-stat/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt similarity index 95% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeedGenerator.kt rename to kmath-stat/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt index bd04c1a45..e152559b5 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumSeedGenerator.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt @@ -15,6 +15,8 @@ */ package ru.inr.mass.minuit +import space.kscience.kmath.optimization.minuit.MinimumSeed + /** * base class for seed generators (starting values); the seed generator prepares * initial starting values from the input (MnUserParameterState) for the diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumState.kt b/kmath-stat/src/commonMain/tmp/minuit/MinimumState.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinimumState.kt rename to kmath-stat/src/commonMain/tmp/minuit/MinimumState.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinosError.kt b/kmath-stat/src/commonMain/tmp/minuit/MinosError.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinosError.kt rename to kmath-stat/src/commonMain/tmp/minuit/MinosError.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinuitParameter.kt b/kmath-stat/src/commonMain/tmp/minuit/MinuitParameter.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MinuitParameter.kt rename to kmath-stat/src/commonMain/tmp/minuit/MinuitParameter.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnAlgebraicSymMatrix.kt b/kmath-stat/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnAlgebraicSymMatrix.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnApplication.kt b/kmath-stat/src/commonMain/tmp/minuit/MnApplication.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnApplication.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnApplication.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnContours.kt b/kmath-stat/src/commonMain/tmp/minuit/MnContours.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnContours.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnContours.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCovarianceSqueeze.kt b/kmath-stat/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCovarianceSqueeze.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCross.kt b/kmath-stat/src/commonMain/tmp/minuit/MnCross.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnCross.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnCross.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnEigen.kt b/kmath-stat/src/commonMain/tmp/minuit/MnEigen.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnEigen.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnEigen.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFcn.kt b/kmath-stat/src/commonMain/tmp/minuit/MnFcn.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFcn.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnFcn.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFunctionCross.kt b/kmath-stat/src/commonMain/tmp/minuit/MnFunctionCross.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnFunctionCross.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnFunctionCross.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnGlobalCorrelationCoeff.kt b/kmath-stat/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnGlobalCorrelationCoeff.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnHesse.kt b/kmath-stat/src/commonMain/tmp/minuit/MnHesse.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnHesse.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnHesse.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnLineSearch.kt b/kmath-stat/src/commonMain/tmp/minuit/MnLineSearch.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnLineSearch.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnLineSearch.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMachinePrecision.kt b/kmath-stat/src/commonMain/tmp/minuit/MnMachinePrecision.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMachinePrecision.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnMachinePrecision.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMigrad.kt b/kmath-stat/src/commonMain/tmp/minuit/MnMigrad.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMigrad.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnMigrad.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinimize.kt b/kmath-stat/src/commonMain/tmp/minuit/MnMinimize.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinimize.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnMinimize.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinos.kt b/kmath-stat/src/commonMain/tmp/minuit/MnMinos.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnMinos.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnMinos.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabola.kt b/kmath-stat/src/commonMain/tmp/minuit/MnParabola.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabola.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnParabola.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaFactory.kt b/kmath-stat/src/commonMain/tmp/minuit/MnParabolaFactory.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaFactory.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnParabolaFactory.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaPoint.kt b/kmath-stat/src/commonMain/tmp/minuit/MnParabolaPoint.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParabolaPoint.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnParabolaPoint.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParameterScan.kt b/kmath-stat/src/commonMain/tmp/minuit/MnParameterScan.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnParameterScan.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnParameterScan.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPlot.kt b/kmath-stat/src/commonMain/tmp/minuit/MnPlot.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPlot.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnPlot.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPosDef.kt b/kmath-stat/src/commonMain/tmp/minuit/MnPosDef.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPosDef.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnPosDef.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPrint.kt b/kmath-stat/src/commonMain/tmp/minuit/MnPrint.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnPrint.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnPrint.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnScan.kt b/kmath-stat/src/commonMain/tmp/minuit/MnScan.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnScan.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnScan.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSeedGenerator.kt b/kmath-stat/src/commonMain/tmp/minuit/MnSeedGenerator.kt similarity index 98% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSeedGenerator.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnSeedGenerator.kt index cc3f9547e..a42edf4f1 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSeedGenerator.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/MnSeedGenerator.kt @@ -17,6 +17,7 @@ package ru.inr.mass.minuit import space.kscience.kmath.optimization.minuit.MINUITPlugin import ru.inr.mass.minuit.* +import space.kscience.kmath.optimization.minuit.MinimumSeed /** * diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSimplex.kt b/kmath-stat/src/commonMain/tmp/minuit/MnSimplex.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnSimplex.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnSimplex.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnStrategy.kt b/kmath-stat/src/commonMain/tmp/minuit/MnStrategy.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnStrategy.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnStrategy.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserCovariance.kt b/kmath-stat/src/commonMain/tmp/minuit/MnUserCovariance.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserCovariance.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnUserCovariance.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserFcn.kt b/kmath-stat/src/commonMain/tmp/minuit/MnUserFcn.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserFcn.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnUserFcn.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameterState.kt b/kmath-stat/src/commonMain/tmp/minuit/MnUserParameterState.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameterState.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnUserParameterState.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameters.kt b/kmath-stat/src/commonMain/tmp/minuit/MnUserParameters.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserParameters.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnUserParameters.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserTransformation.kt b/kmath-stat/src/commonMain/tmp/minuit/MnUserTransformation.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUserTransformation.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnUserTransformation.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUtils.kt b/kmath-stat/src/commonMain/tmp/minuit/MnUtils.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/MnUtils.kt rename to kmath-stat/src/commonMain/tmp/minuit/MnUtils.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ModularFunctionMinimizer.kt b/kmath-stat/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt similarity index 97% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ModularFunctionMinimizer.kt rename to kmath-stat/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt index f234bcd48..84130d24f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ModularFunctionMinimizer.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt @@ -17,6 +17,7 @@ package ru.inr.mass.minuit import ru.inr.mass.maths.MultiFunction import ru.inr.mass.minuit.* +import space.kscience.kmath.optimization.minuit.MinimumSeed /** * diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/NegativeG2LineSearch.kt b/kmath-stat/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/NegativeG2LineSearch.kt rename to kmath-stat/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Numerical2PGradientCalculator.kt b/kmath-stat/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/Numerical2PGradientCalculator.kt rename to kmath-stat/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanBuilder.kt b/kmath-stat/src/commonMain/tmp/minuit/ScanBuilder.kt similarity index 97% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanBuilder.kt rename to kmath-stat/src/commonMain/tmp/minuit/ScanBuilder.kt index b7e773924..57f910a26 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanBuilder.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/ScanBuilder.kt @@ -17,6 +17,7 @@ package ru.inr.mass.minuit import org.apache.commons.math3.linear.ArrayRealVector import ru.inr.mass.minuit.* +import space.kscience.kmath.optimization.minuit.MinimumSeed /** * Performs a minimization using the simplex method of Nelder and Mead (ref. diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanMinimizer.kt b/kmath-stat/src/commonMain/tmp/minuit/ScanMinimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/ScanMinimizer.kt rename to kmath-stat/src/commonMain/tmp/minuit/ScanMinimizer.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexBuilder.kt b/kmath-stat/src/commonMain/tmp/minuit/SimplexBuilder.kt similarity index 99% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexBuilder.kt rename to kmath-stat/src/commonMain/tmp/minuit/SimplexBuilder.kt index 8441a4177..0b10155ff 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexBuilder.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/SimplexBuilder.kt @@ -17,6 +17,7 @@ package ru.inr.mass.minuit import space.kscience.kmath.optimization.minuit.MINUITPlugin import ru.inr.mass.minuit.* +import space.kscience.kmath.optimization.minuit.MinimumSeed /** * diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexMinimizer.kt b/kmath-stat/src/commonMain/tmp/minuit/SimplexMinimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexMinimizer.kt rename to kmath-stat/src/commonMain/tmp/minuit/SimplexMinimizer.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexParameters.kt b/kmath-stat/src/commonMain/tmp/minuit/SimplexParameters.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexParameters.kt rename to kmath-stat/src/commonMain/tmp/minuit/SimplexParameters.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexSeedGenerator.kt b/kmath-stat/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt similarity index 97% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexSeedGenerator.kt rename to kmath-stat/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt index e5025ff3d..577545fc3 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SimplexSeedGenerator.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt @@ -17,6 +17,7 @@ package ru.inr.mass.minuit import org.apache.commons.math3.linear.ArrayRealVector import ru.inr.mass.minuit.* +import space.kscience.kmath.optimization.minuit.MinimumSeed /** * diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SinParameterTransformation.kt b/kmath-stat/src/commonMain/tmp/minuit/SinParameterTransformation.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SinParameterTransformation.kt rename to kmath-stat/src/commonMain/tmp/minuit/SinParameterTransformation.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtLowParameterTransformation.kt b/kmath-stat/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtLowParameterTransformation.kt rename to kmath-stat/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtUpParameterTransformation.kt b/kmath-stat/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/SqrtUpParameterTransformation.kt rename to kmath-stat/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricBuilder.kt b/kmath-stat/src/commonMain/tmp/minuit/VariableMetricBuilder.kt similarity index 98% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricBuilder.kt rename to kmath-stat/src/commonMain/tmp/minuit/VariableMetricBuilder.kt index 8362c5e7e..edc6783b6 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricBuilder.kt +++ b/kmath-stat/src/commonMain/tmp/minuit/VariableMetricBuilder.kt @@ -17,6 +17,7 @@ package ru.inr.mass.minuit import space.kscience.kmath.optimization.minuit.MINUITPlugin import ru.inr.mass.minuit.* +import space.kscience.kmath.optimization.minuit.MinimumSeed /** * diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricEDMEstimator.kt b/kmath-stat/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricEDMEstimator.kt rename to kmath-stat/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricMinimizer.kt b/kmath-stat/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/VariableMetricMinimizer.kt rename to kmath-stat/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/package-info.kt b/kmath-stat/src/commonMain/tmp/minuit/package-info.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/minuit/package-info.kt rename to kmath-stat/src/commonMain/tmp/minuit/package-info.kt -- 2.34.1 From 3ba12f49993d03e9af6bd59b97186e72e78799f6 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 9 Jul 2021 14:11:26 +0300 Subject: [PATCH 008/102] Generic Buffer Algebra --- CHANGELOG.md | 1 + .../kscience/kmath/structures/buffers.kt | 22 +++ .../kmath/operations/BufferAlgebra.kt | 146 ++++++++++++++++++ .../kmath/structures/DoubleBufferField.kt | 4 + 4 files changed, 173 insertions(+) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index e35153d81..8c4f5b547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ - Use `Symbol` factory function instead of `StringSymbol` ### Deprecated +- Specialized `DoubleBufferAlgebra` ### Removed - Nearest in Domain. To be implemented in geometry package. diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt new file mode 100644 index 000000000..eabb16701 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.structures + +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.bufferAlgebra +import space.kscience.kmath.operations.produce + +inline fun MutableBuffer.Companion.same( + n: Int, + value: R +): MutableBuffer = auto(n) { value } + + +fun main() { + with(DoubleField.bufferAlgebra(5)) { + println(number(2.0) + produce(1, 2, 3, 4, 5)) + } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt new file mode 100644 index 000000000..9f4d741fd --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -0,0 +1,146 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.operations + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferFactory +import space.kscience.kmath.structures.DoubleBuffer + +/** + * An algebra over [Buffer] + */ +@UnstableKMathAPI +public interface BufferAlgebra> : Algebra> { + public val bufferFactory: BufferFactory + public val elementAlgebra: A + + //TODO move to multi-receiver inline extension + public fun Buffer.map(block: (T) -> T): Buffer = bufferFactory(size) { block(get(it)) } + + public fun Buffer.zip(other: Buffer, block: (left: T, right: T) -> T): Buffer { + require(size == other.size) { "Incompatible buffer sizes. left: $size, right: ${other.size}" } + return bufferFactory(size) { block(this[it], other[it]) } + } + + override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { + val operationFunction = elementAlgebra.unaryOperationFunction(operation) + return { arg -> bufferFactory(arg.size) { operationFunction(arg[it]) } } + } + + override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { + val operationFunction = elementAlgebra.binaryOperationFunction(operation) + return { left, right -> + bufferFactory(left.size) { operationFunction(left[it], right[it]) } + } + } +} + +@UnstableKMathAPI +public fun > BufferAlgebra.sin(arg: Buffer): Buffer = + arg.map(elementAlgebra::sin) + +@UnstableKMathAPI +public fun > BufferAlgebra.cos(arg: Buffer): Buffer = + arg.map(elementAlgebra::cos) + +@UnstableKMathAPI +public fun > BufferAlgebra.tan(arg: Buffer): Buffer = + arg.map(elementAlgebra::tan) + +@UnstableKMathAPI +public fun > BufferAlgebra.asin(arg: Buffer): Buffer = + arg.map(elementAlgebra::asin) + +@UnstableKMathAPI +public fun > BufferAlgebra.acos(arg: Buffer): Buffer = + arg.map(elementAlgebra::acos) + +@UnstableKMathAPI +public fun > BufferAlgebra.atan(arg: Buffer): Buffer = + arg.map(elementAlgebra::atan) + +@UnstableKMathAPI +public fun > BufferAlgebra.exp(arg: Buffer): Buffer = + arg.map(elementAlgebra::exp) + +@UnstableKMathAPI +public fun > BufferAlgebra.ln(arg: Buffer): Buffer = + arg.map(elementAlgebra::ln) + +@UnstableKMathAPI +public fun > BufferAlgebra.sinh(arg: Buffer): Buffer = + arg.map(elementAlgebra::sinh) + +@UnstableKMathAPI +public fun > BufferAlgebra.cosh(arg: Buffer): Buffer = + arg.map(elementAlgebra::cosh) + +@UnstableKMathAPI +public fun > BufferAlgebra.tanh(arg: Buffer): Buffer = + arg.map(elementAlgebra::tanh) + +@UnstableKMathAPI +public fun > BufferAlgebra.asinh(arg: Buffer): Buffer = + arg.map(elementAlgebra::asinh) + +@UnstableKMathAPI +public fun > BufferAlgebra.acosh(arg: Buffer): Buffer = + arg.map(elementAlgebra::acosh) + +@UnstableKMathAPI +public fun > BufferAlgebra.atanh(arg: Buffer): Buffer = + arg.map(elementAlgebra::atanh) + +@UnstableKMathAPI +public fun > BufferAlgebra.pow(arg: Buffer, pow: Number): Buffer = + with(elementAlgebra) { arg.map { power(it, pow) } } + + +@UnstableKMathAPI +public class BufferField>( + override val bufferFactory: BufferFactory, + override val elementAlgebra: A, + public val size: Int +) : BufferAlgebra, Field> { + + public fun produce(vararg elements: T): Buffer { + require(elements.size == size) { "Expected $size elements but found ${elements.size}" } + return bufferFactory(size) { elements[it] } + } + + override val zero: Buffer = bufferFactory(size) { elementAlgebra.zero } + override val one: Buffer = bufferFactory(size) { elementAlgebra.one } + + + override fun add(a: Buffer, b: Buffer): Buffer = a.zip(b, elementAlgebra::add) + override fun multiply(a: Buffer, b: Buffer): Buffer = a.zip(b, elementAlgebra::multiply) + override fun divide(a: Buffer, b: Buffer): Buffer = a.zip(b, elementAlgebra::divide) + + override fun scale(a: Buffer, value: Double): Buffer = with(elementAlgebra) { a.map { scale(it, value) } } + override fun Buffer.unaryMinus(): Buffer = with(elementAlgebra) { map { -it } } + + override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { + return super.unaryOperationFunction(operation) + } + + override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { + return super.binaryOperationFunction(operation) + } +} + +//Double buffer specialization + +@UnstableKMathAPI +public fun BufferField.produce(vararg elements: Number): Buffer { + require(elements.size == size) { "Expected $size elements but found ${elements.size}" } + return bufferFactory(size) { elements[it].toDouble() } +} + +@UnstableKMathAPI +public fun DoubleField.bufferAlgebra(size: Int): BufferField = + BufferField(::DoubleBuffer, DoubleField, size) + diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt index e438995dd..c65a0a48a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt @@ -6,6 +6,8 @@ package space.kscience.kmath.structures import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.ExtendedFieldOperations import space.kscience.kmath.operations.Norm @@ -14,6 +16,7 @@ import kotlin.math.* /** * [ExtendedFieldOperations] over [DoubleBuffer]. */ +@Deprecated("To be replaced by generic BufferAlgebra") public object DoubleBufferFieldOperations : ExtendedFieldOperations> { override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { DoubleBuffer(size) { -array[it] } @@ -172,6 +175,7 @@ public object DoubleL2Norm : Norm, Double> { * * @property size the size of buffers to operate on. */ +@Deprecated("To be replaced by generic BufferAlgebra") public class DoubleBufferField(public val size: Int) : ExtendedField>, Norm, Double> { public override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } public override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } -- 2.34.1 From 9b8da4cdcc07648dbd337a2aa254e1338325a966 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 12 Aug 2021 20:28:45 +0300 Subject: [PATCH 009/102] Fix JS bug with null cast --- .../kotlin/space/kscience/kmath/misc/Featured.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 648b6376f..be1c8380c 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 @@ -16,13 +16,14 @@ public interface Featured { public typealias FeatureKey = KClass -public interface Feature> { +public interface Feature> { /** * A key used for extraction */ @Suppress("UNCHECKED_CAST") - public val key: FeatureKey get() = this::class as FeatureKey + public val key: FeatureKey + get() = this::class as FeatureKey } /** @@ -30,7 +31,7 @@ public interface Feature> { */ public class FeatureSet> private constructor(public val features: Map, F>) : Featured { @Suppress("UNCHECKED_CAST") - override fun getFeature(type: FeatureKey): T? = features[type] as? T + override fun getFeature(type: FeatureKey): T? = features[type]?.let { it as T } public inline fun getFeature(): T? = getFeature(T::class) @@ -49,6 +50,7 @@ public class FeatureSet> private constructor(public val features: public companion object { public fun > of(vararg features: F): FeatureSet = FeatureSet(features.associateBy { it.key }) - public fun > of(features: Iterable): FeatureSet = FeatureSet(features.associateBy { it.key }) + public fun > of(features: Iterable): FeatureSet = + FeatureSet(features.associateBy { it.key }) } } -- 2.34.1 From aaa298616d2668f80062079ede547f4228246b5e Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 16 Aug 2021 09:55:03 +0300 Subject: [PATCH 010/102] QOW is working more or less --- examples/build.gradle.kts | 1 + .../fitWithAutoDiff.kt => fit/chiSquared.kt} | 13 +- .../kotlin/space/kscience/kmath/fit/qowFit.kt | 105 ++++++++++ .../kmath/functions/matrixIntegration.kt | 2 +- kmath-commons/build.gradle.kts | 1 + .../kmath/commons/optimization/CMOptimizer.kt | 7 +- .../DerivativeStructureExpressionTest.kt | 4 +- .../commons/optimization/OptimizeTest.kt | 3 +- .../kscience/kmath/data/XYColumnarData.kt | 20 +- .../kmath/data/XYErrorColumnarData.kt | 25 ++- .../kscience/kmath/expressions/Expression.kt | 7 +- .../kmath/expressions/specialExpressions.kt | 17 +- .../space/kscience/kmath/misc/Featured.kt | 7 +- .../space/kscience/kmath/misc/logging.kt | 14 +- .../kmath/expressions/ExpressionFieldTest.kt | 6 +- .../kmath/integration/GaussIntegrator.kt | 3 +- .../kmath/interpolation/Interpolator.kt | 6 +- kmath-optimization/build.gradle.kts | 20 ++ .../optimization/FunctionOptimization.kt | 33 ++- .../kmath/optimization/OptimizationBuilder.kt | 8 +- .../kmath/optimization/OptimizationProblem.kt | 0 .../kscience/kmath/optimization/Optimizer.kt | 0 .../kmath/optimization/QowOptimizer.kt | 72 +++---- .../kscience/kmath/optimization/XYFit.kt | 125 ++++++++++++ .../kmath/optimization/logLikelihood.kt | 66 ++++++ kmath-stat/build.gradle.kts | 3 +- .../kmath/optimization/XYOptimization.kt | 189 ------------------ settings.gradle.kts | 1 + 28 files changed, 477 insertions(+), 281 deletions(-) rename examples/src/main/kotlin/space/kscience/kmath/{commons/fit/fitWithAutoDiff.kt => fit/chiSquared.kt} (91%) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt create mode 100644 kmath-optimization/build.gradle.kts rename {kmath-stat => kmath-optimization}/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt (65%) rename {kmath-stat => kmath-optimization}/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt (94%) rename {kmath-stat => kmath-optimization}/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt (77%) create mode 100644 kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt create mode 100644 kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt delete mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 4cc6fecc0..d06005321 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { implementation(project(":kmath-coroutines")) implementation(project(":kmath-commons")) implementation(project(":kmath-complex")) + implementation(project(":kmath-optimization")) implementation(project(":kmath-stat")) implementation(project(":kmath-viktor")) implementation(project(":kmath-dimensions")) diff --git a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt similarity index 91% rename from examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt rename to examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt index 8d95ebb4a..c1070de52 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt @@ -3,19 +3,17 @@ * 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.commons.fit +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.binding import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.optimization.FunctionOptimizationTarget -import space.kscience.kmath.optimization.optimizeWith -import space.kscience.kmath.optimization.resultPoint -import space.kscience.kmath.optimization.resultValue +import space.kscience.kmath.optimization.* import space.kscience.kmath.real.DoubleVector import space.kscience.kmath.real.map import space.kscience.kmath.real.step @@ -25,6 +23,7 @@ import space.kscience.kmath.structures.toList import space.kscience.plotly.* import space.kscience.plotly.models.ScatterMode import space.kscience.plotly.models.TraceValues +import kotlin.math.abs import kotlin.math.pow import kotlin.math.sqrt @@ -45,7 +44,7 @@ operator fun TraceValues.invoke(vector: DoubleVector) { */ suspend fun main() { //A generator for a normally distributed values - val generator = NormalDistribution(2.0, 7.0) + val generator = NormalDistribution(0.0, 1.0) //A chain/flow of random values with the given seed val chain = generator.sample(RandomGenerator.default(112667)) @@ -56,7 +55,7 @@ suspend fun main() { //Perform an operation on each x value (much more effective, than numpy) - val y = x.map { + val y = x.map { it -> val value = it.pow(2) + it + 1 value + chain.next() * sqrt(value) } diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt new file mode 100644 index 000000000..944f80697 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.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.binding +import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.optimization.QowOptimizer +import space.kscience.kmath.optimization.fitWith +import space.kscience.kmath.optimization.resultPoint +import space.kscience.kmath.real.map +import space.kscience.kmath.real.step +import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.structures.asIterable +import space.kscience.kmath.structures.toList +import space.kscience.plotly.* +import space.kscience.plotly.models.ScatterMode +import kotlin.math.abs +import kotlin.math.pow +import kotlin.math.sqrt + +// Forward declaration of symbols that will be used in expressions. +private val a by symbol +private val b by symbol +private val c by symbol + + +/** + * Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules. + */ +suspend fun main() { + //A generator for a normally distributed values + val generator = NormalDistribution(0.0, 1.0) + + //A chain/flow of random values with the given seed + val chain = generator.sample(RandomGenerator.default(112667)) + + + //Create a uniformly distributed x values like numpy.arrange + val x = 1.0..100.0 step 1.0 + + + //Perform an operation on each x value (much more effective, than numpy) + val y = x.map { it -> + val value = it.pow(2) + it + 100 + value + chain.next() * sqrt(value) + } + // this will also work, but less effective: + // val y = x.pow(2)+ x + 1 + chain.nextDouble() + + // create same errors for all xs + val yErr = y.map { sqrt(abs(it)) } + require(yErr.asIterable().all { it > 0 }) { "All errors must be strictly positive" } + + val result = XYErrorColumnarData.of(x, y, yErr).fitWith( + QowOptimizer, + DSProcessor, + mapOf(a to 1.0, b to 1.2, c to 99.0) + ) { 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 + } + + //display a page with plot and numerical results + val page = Plotly.page { + plot { + scatter { + mode = ScatterMode.markers + x(x) + y(y) + error_y { + array = yErr.toList() + } + name = "data" + } + scatter { + mode = ScatterMode.lines + x(x) + y(x.map { result.model(result.resultPoint + (Symbol.x to it)) }) + name = "fit" + } + } + br() + h3 { + +"Fit result: ${result.resultPoint}" + } +// h3 { +// +"Chi2/dof = ${result.resultValue / (x.size - 3)}" +// } + } + + page.makeFile() +} 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 2619d3d74..e5ba29d73 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -22,7 +22,7 @@ fun main(): Unit = DoubleField { } //Define a function in a nd space - val function: (Double) -> StructureND = { x: Double -> 3 * number(x).pow(2) + 2 * diagonal(x) + 1 } + val function: (Double) -> StructureND = { x: Double -> 3 * x.pow(2) + 2 * diagonal(x) + 1 } //get the result of the integration val result = gaussIntegrator.integrate(0.0..10.0, function = function) diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index a208c956c..96c17a215 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -9,6 +9,7 @@ dependencies { api(project(":kmath-core")) api(project(":kmath-complex")) api(project(":kmath-coroutines")) + api(project(":kmath-optimization")) api(project(":kmath-stat")) api(project(":kmath-functions")) api("org.apache.commons:commons-math3:3.6.1") 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 abf95daf6..11eb6fba8 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 @@ -18,6 +18,7 @@ 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 import kotlin.reflect.KClass @@ -108,15 +109,17 @@ public object CMOptimizer : Optimizer> { val objectiveFunction = ObjectiveFunction { val args = startPoint + it.toMap() - problem.expression(args) + val res = problem.expression(args) + res } addOptimizationData(objectiveFunction) val gradientFunction = ObjectiveFunctionGradient { val args = startPoint + it.toMap() - DoubleArray(symbols.size) { index -> + val res = DoubleArray(symbols.size) { index -> problem.expression.derivative(symbols[index])(args) } + res } addOptimizationData(gradientFunction) 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 3c57f5467..56252ab34 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 @@ -42,8 +42,8 @@ internal class AutoDiffTest { @Test fun autoDifTest() { val f = DerivativeStructureExpression { - val x by binding() - val y by binding() + 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 170fceceb..facbf3a9a 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 @@ -15,6 +15,7 @@ import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol import space.kscience.kmath.optimization.* import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.map import kotlin.math.pow @@ -58,7 +59,7 @@ internal class OptimizeTest { it.pow(2) + it + 1 + chain.next() } - val yErr = List(x.size) { sigma }.asBuffer() + val yErr = DoubleBuffer(x.size) { sigma } val chi2 = DSProcessor.chiSquaredExpression( x, y, yErr 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 bd0e13b9d..2fce772cc 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 @@ -32,19 +32,21 @@ public interface XYColumnarData : ColumnarData { Symbol.y -> y else -> null } -} -@Suppress("FunctionName") -@UnstableKMathAPI -public fun XYColumnarData(x: Buffer, y: Buffer): XYColumnarData { - require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } - return object : XYColumnarData { - override val size: Int = x.size - override val x: Buffer = x - override val y: Buffer = y + public companion object{ + @UnstableKMathAPI + public fun of(x: Buffer, y: Buffer): XYColumnarData { + require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } + return object : XYColumnarData { + override val size: Int = x.size + override val x: Buffer = x + override val y: Buffer = y + } + } } } + /** * Represent a [ColumnarData] as an [XYColumnarData]. The presence or respective columns is checked on creation. */ 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 7199de888..8ddd6406f 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,15 +5,13 @@ package space.kscience.kmath.data -import space.kscience.kmath.data.XYErrorColumnarData.Companion import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer /** - * A [ColumnarData] with additional [Companion.yErr] column for an [Symbol.y] error + * A [ColumnarData] with additional [Symbol.yError] column for an [Symbol.y] error * Inherits [XYColumnarData]. */ @UnstableKMathAPI @@ -23,11 +21,24 @@ public interface XYErrorColumnarData : XYColumnarData = when (symbol) { Symbol.x -> x Symbol.y -> y - Companion.yErr -> yErr + Symbol.yError -> yErr else -> error("A column for symbol $symbol not found") } - public companion object{ - public val yErr: Symbol by symbol + public companion object { + public fun of( + x: Buffer, y: Buffer, yErr: Buffer + ): XYErrorColumnarData { + require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } + require(y.size == yErr.size) { "Buffer size mismatch. y buffer size is ${x.size}, yErr buffer size is ${y.size}" } + + return object : XYErrorColumnarData { + override val size: Int = x.size + override val x: Buffer = x + override val y: Buffer = y + override val yErr: Buffer = yErr + } + } } -} \ No newline at end of file +} + 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 5105c2bec..e94cb98eb 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 @@ -68,6 +68,7 @@ public interface ExpressionAlgebra : Algebra { /** * Bind a symbol by name inside the [ExpressionAlgebra] */ -public fun ExpressionAlgebra.binding(): ReadOnlyProperty = ReadOnlyProperty { _, property -> - bindSymbol(property.name) ?: error("A variable with name ${property.name} does not exist") -} +public val ExpressionAlgebra.binding: ReadOnlyProperty + get() = ReadOnlyProperty { _, property -> + bindSymbol(property.name) ?: error("A variable with name ${property.name} does not exist") + } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt index ede4a779c..6b17dfca5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt @@ -7,13 +7,18 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asIterable import space.kscience.kmath.structures.indices +import kotlin.jvm.JvmName /** * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic * differentiation. + * + * **WARNING** All elements of [yErr] must be positive. */ -public fun AutoDiffProcessor.chiSquaredExpression( +@JvmName("genericChiSquaredExpression") +public fun , I : Any, A> AutoDiffProcessor.chiSquaredExpression( x: Buffer, y: Buffer, yErr: Buffer, @@ -35,4 +40,14 @@ public fun AutoDiffProcessor.chiSquaredExpression sum } +} + +public fun AutoDiffProcessor.chiSquaredExpression( + x: Buffer, + y: Buffer, + yErr: Buffer, + model: A.(I) -> I, +): DifferentiableExpression where A : ExtendedField, A : ExpressionAlgebra { + require(yErr.asIterable().all { it > 0.0 }) { "All errors must be strictly positive" } + return chiSquaredExpression(x, y, yErr, model) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt index be1c8380c..29b7caec6 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 @@ -5,6 +5,7 @@ package space.kscience.kmath.misc +import kotlin.jvm.JvmInline import kotlin.reflect.KClass /** @@ -29,7 +30,8 @@ public interface Feature> { /** * A container for a set of features */ -public class FeatureSet> private constructor(public val features: Map, F>) : Featured { +@JvmInline +public value class FeatureSet> private constructor(public val features: Map, F>) : Featured { @Suppress("UNCHECKED_CAST") override fun getFeature(type: FeatureKey): T? = features[type]?.let { it as T } @@ -48,6 +50,9 @@ public class FeatureSet> private constructor(public val features: public operator fun iterator(): Iterator = features.values.iterator() + override fun toString(): String = features.values.joinToString(prefix = "[ ", postfix = " ]") + + public companion object { public fun > of(vararg features: F): FeatureSet = FeatureSet(features.associateBy { it.key }) public fun > of(features: Iterable): FeatureSet = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt index d13840841..9dfc564c3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt @@ -5,10 +5,18 @@ package space.kscience.kmath.misc -public interface Loggable { - public fun log(tag: String = INFO, block: () -> String) +import space.kscience.kmath.misc.Loggable.Companion.INFO + +public fun interface Loggable { + public fun log(tag: String, block: () -> String) public companion object { public const val INFO: String = "INFO" + + public val console: Loggable = Loggable { tag, block -> + println("[$tag] ${block()}") + } } -} \ No newline at end of file +} + +public fun Loggable.log(block: () -> String): Unit = log(INFO, block) \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt index 4d1b00b3d..80c5943cf 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt @@ -16,7 +16,7 @@ class ExpressionFieldTest { @Test fun testExpression() { val expression = with(FunctionalExpressionField(DoubleField)) { - val x by binding() + val x by binding x * x + 2 * x + one } @@ -27,7 +27,7 @@ class ExpressionFieldTest { @Test fun separateContext() { fun FunctionalExpressionField.expression(): Expression { - val x by binding() + val x by binding return x * x + 2 * x + one } @@ -38,7 +38,7 @@ class ExpressionFieldTest { @Test fun valueExpression() { val expressionBuilder: FunctionalExpressionField.() -> Expression = { - val x by binding() + val x by binding x * x + 2 * x + one } 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 9b938394a..9785d7744 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 @@ -73,7 +73,8 @@ public class GaussIntegrator( } /** - * Create a Gauss-Legendre integrator for this field. + * Create a Gauss integrator for this field. By default, uses Legendre rule to compute points and weights. + * Custom rules could be provided by [GaussIntegratorRuleFactory] feature. * @see [GaussIntegrator] */ public val Field.gaussIntegrator: GaussIntegrator get() = GaussIntegrator(this) 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 f4a0abd5d..b13adefa5 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 @@ -42,20 +42,20 @@ public fun > PolynomialInterpolator.interpolatePolynomials( x: Buffer, y: Buffer, ): PiecewisePolynomial { - val pointSet = XYColumnarData(x, y) + val pointSet = XYColumnarData.of(x, y) return interpolatePolynomials(pointSet) } public fun > PolynomialInterpolator.interpolatePolynomials( data: Map, ): PiecewisePolynomial { - val pointSet = XYColumnarData(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) + val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) return interpolatePolynomials(pointSet) } public fun > PolynomialInterpolator.interpolatePolynomials( data: List>, ): PiecewisePolynomial { - val pointSet = XYColumnarData(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) + val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) return interpolatePolynomials(pointSet) } diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts new file mode 100644 index 000000000..ca013b2f4 --- /dev/null +++ b/kmath-optimization/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + id("ru.mipt.npm.gradle.mpp") + id("ru.mipt.npm.gradle.native") +} + +kscience { + useAtomic() +} + +kotlin.sourceSets { + commonMain { + dependencies { + api(project(":kmath-coroutines")) + } + } +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt similarity index 65% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt rename to kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index 1af6c4bda..02602b068 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -5,13 +5,11 @@ package space.kscience.kmath.optimization -import space.kscience.kmath.expressions.* +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices -public class OptimizationValue(public val value: T) : OptimizationFeature{ +public class OptimizationValue(public val value: T) : OptimizationFeature { override fun toString(): String = "Value($value)" } @@ -23,9 +21,28 @@ public enum class FunctionOptimizationTarget : OptimizationFeature { public class FunctionOptimization( override val features: FeatureSet, public val expression: DifferentiableExpression, -) : OptimizationProblem{ +) : OptimizationProblem { - public companion object + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as FunctionOptimization<*> + + if (features != other.features) return false + if (expression != other.expression) return false + + return true + } + + override fun hashCode(): Int { + var result = features.hashCode() + result = 31 * result + expression.hashCode() + return result + } + + override fun toString(): String = "FunctionOptimization(features=$features)" } public fun FunctionOptimization.withFeatures( @@ -47,7 +64,7 @@ public suspend fun DifferentiableExpression.optimizeWith( return optimizer.optimize(problem) } -public val FunctionOptimization.resultValueOrNull:T? +public val FunctionOptimization.resultValueOrNull: T? get() = getFeature>()?.point?.let { expression(it) } public val FunctionOptimization.resultValue: T diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt similarity index 94% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt rename to kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt index 7d52ae26e..10a25c029 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt @@ -72,15 +72,15 @@ public suspend fun DifferentiableExpression.optimizeWith( public class XYOptimizationBuilder( public val data: XYColumnarData, public val model: DifferentiableExpression, -) : OptimizationBuilder() { +) : OptimizationBuilder() { public var pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY public var pointWeight: PointWeight = PointWeight.byYSigma - override fun build(): XYOptimization = XYOptimization( - FeatureSet.of(features), + override fun build(): XYFit = XYFit( data, model, + FeatureSet.of(features), pointToCurveDistance, pointWeight ) @@ -90,4 +90,4 @@ public fun XYOptimization( data: XYColumnarData, model: DifferentiableExpression, builder: XYOptimizationBuilder.() -> Unit, -): XYOptimization = XYOptimizationBuilder(data, model).apply(builder).build() \ No newline at end of file +): XYFit = XYOptimizationBuilder(data, model).apply(builder).build() \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt rename to kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt rename to kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt similarity index 77% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt rename to kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt index 365c58952..f0969d2f6 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.expressions.SymbolIndexer import space.kscience.kmath.expressions.derivative 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.structures.DoubleBuffer import space.kscience.kmath.structures.DoubleL2Norm @@ -21,14 +22,14 @@ import space.kscience.kmath.structures.DoubleL2Norm * See [the article](http://arxiv.org/abs/physics/0604127). */ @UnstableKMathAPI -public class QowOptimizer : Optimizer { +public object QowOptimizer : Optimizer { private val linearSpace: LinearSpace = LinearSpace.double private val solver: LinearSolver = linearSpace.lupSolver() @OptIn(UnstableKMathAPI::class) - private inner class QoWeight( - val problem: XYOptimization, + private class QoWeight( + val problem: XYFit, val parameters: Map, ) : Map by parameters, SymbolIndexer { override val symbols: List = parameters.keys.toList() @@ -39,8 +40,8 @@ public class QowOptimizer : Optimizer { * 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) { i, k -> - problem.distance(i).derivative(symbols[k])(parameters) + linearSpace.buildMatrix(problem.data.size, symbols.size) { d, s -> + problem.distance(d).derivative(symbols[s])(parameters) } } @@ -48,25 +49,27 @@ public class QowOptimizer : Optimizer { * Array of dispersions in each point */ val dispersion: Point by lazy { - DoubleBuffer(problem.data.size) { i -> - problem.weight(i).invoke(parameters) + DoubleBuffer(problem.data.size) { d -> + problem.weight(d).invoke(parameters) } } val prior: DifferentiableExpression? get() = problem.getFeature>() + + override fun toString(): String = parameters.toString() } /** - * The signed distance from the model to the [i]-th point of data. + * The signed distance from the model to the [d]-th point of data. */ - private fun QoWeight.distance(i: Int, parameters: Map): Double = problem.distance(i)(parameters) + private fun QoWeight.distance(d: Int, parameters: Map): Double = problem.distance(d)(parameters) /** * The derivative of [distance] */ - private fun QoWeight.distanceDerivative(symbol: Symbol, i: Int, parameters: Map): Double = - problem.distance(i).derivative(symbol)(parameters) + private fun QoWeight.distanceDerivative(symbol: Symbol, d: Int, parameters: Map): Double = + problem.distance(d).derivative(symbol)(parameters) /** * Теоретическая ковариация весовых функций. @@ -74,8 +77,8 @@ public class QowOptimizer : Optimizer { * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 */ private fun QoWeight.covarF(): Matrix = - linearSpace.matrix(size, size).symmetric { k, l -> - (0 until data.size).sumOf { i -> derivs[k, i] * derivs[l, i] / dispersion[i] } + linearSpace.matrix(size, size).symmetric { s1, s2 -> + (0 until data.size).sumOf { d -> derivs[d, s1] * derivs[d, s2] / dispersion[d] } } /** @@ -89,12 +92,12 @@ public class QowOptimizer : Optimizer { * количество вызывов функции будет dim^2 вместо dim Первый индекс - * номер точки, второй - номер переменной, по которой берется производная */ - val eqvalues = linearSpace.buildMatrix(data.size, size) { i, l -> - distance(i, theta) * derivs[l, i] / dispersion[i] + val eqvalues = linearSpace.buildMatrix(data.size, size) { d, s -> + distance(d, theta) * derivs[d, s] / dispersion[d] } - buildMatrix(size, size) { k, l -> - (0 until data.size).sumOf { i -> eqvalues[i, l] * eqvalues[i, k] } + buildMatrix(size, size) { s1, s2 -> + (0 until data.size).sumOf { d -> eqvalues[d, s2] * eqvalues[d, s1] } } } @@ -106,20 +109,20 @@ public class QowOptimizer : Optimizer { ): Matrix = with(linearSpace) { //Возвращает производную k-того Eq по l-тому параметру //val res = Array(fitDim) { DoubleArray(fitDim) } - val sderiv = buildMatrix(data.size, size) { i, l -> - distanceDerivative(symbols[l], i, theta) + val sderiv = buildMatrix(data.size, size) { d, s -> + distanceDerivative(symbols[s], d, theta) } - buildMatrix(size, size) { k, l -> - val base = (0 until data.size).sumOf { i -> - require(dispersion[i] > 0) - sderiv[i, l] * derivs[k, i] / dispersion[i] + buildMatrix(size, size) { s1, s2 -> + val base = (0 until data.size).sumOf { d -> + require(dispersion[d] > 0) + sderiv[d, s2] * derivs[d, s1] / dispersion[d] } prior?.let { prior -> //Check if this one is correct val pi = prior(theta) - val deriv1 = prior.derivative(symbols[k])(theta) - val deriv2 = prior.derivative(symbols[l])(theta) + val deriv1 = prior.derivative(symbols[s1])(theta) + val deriv2 = prior.derivative(symbols[s2])(theta) base + deriv1 * deriv2 / pi / pi } ?: base } @@ -130,13 +133,13 @@ public class QowOptimizer : Optimizer { * Значения уравнений метода квазиоптимальных весов */ private fun QoWeight.getEqValues(theta: Map = this): Point { - val distances = DoubleBuffer(data.size) { i -> distance(i, theta) } + val distances = DoubleBuffer(data.size) { d -> distance(d, theta) } - return DoubleBuffer(size) { k -> - val base = (0 until data.size).sumOf { i -> distances[i] * derivs[k, i] / dispersion[i] } + return DoubleBuffer(size) { s -> + val base = (0 until data.size).sumOf { d -> distances[d] * derivs[d, s] / dispersion[d] } //Поправка на априорную вероятность prior?.let { prior -> - base - prior.derivative(symbols[k])(theta) / prior(theta) + base - prior.derivative(symbols[s])(theta) / prior(theta) } ?: base } } @@ -163,15 +166,15 @@ public class QowOptimizer : Optimizer { val logger = problem.getFeature() - var dis: Double//норма невязки - // Для удобства работаем всегда с полным набором параметров + 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 eqvalues = getEqValues(par)//значения функций + var eqvalues = getEqValues(par) //Values of the weight functions - dis = DoubleL2Norm.norm(eqvalues)// невязка + dis = DoubleL2Norm.norm(eqvalues) // discrepancy logger?.log { "Starting discrepancy is $dis" } var i = 0 var flag = false @@ -238,7 +241,8 @@ public class QowOptimizer : Optimizer { return covar } - override suspend fun optimize(problem: XYOptimization): XYOptimization { + override suspend fun optimize(problem: XYFit): XYFit { + val qowSteps = 2 val initialWeight = QoWeight(problem, problem.startPoint) val res = initialWeight.newtonianRun() return res.problem.withFeature(OptimizationResult(res.parameters)) 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 new file mode 100644 index 000000000..cbd765923 --- /dev/null +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -0,0 +1,125 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +@file:OptIn(UnstableKMathAPI::class) + +package space.kscience.kmath.optimization + +import space.kscience.kmath.data.XYColumnarData +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 + +/** + * Specify the way to compute distance from point to the curve as DifferentiableExpression + */ +public interface PointToCurveDistance : OptimizationFeature { + public fun distance(problem: XYFit, index: Int): DifferentiableExpression + + public companion object { + public val byY: PointToCurveDistance = object : PointToCurveDistance { + override fun distance(problem: XYFit, index: Int): DifferentiableExpression { + val x = problem.data.x[index] + val y = problem.data.y[index] + + return object : DifferentiableExpression { + override fun derivativeOrNull( + symbols: List + ): Expression? = problem.model.derivativeOrNull(symbols)?.let { derivExpression -> + Expression { arguments -> + derivExpression.invoke(arguments + (Symbol.x to x)) + } + } + + override fun invoke(arguments: Map): Double = + problem.model(arguments + (Symbol.x to x)) - y + } + } + + override fun toString(): String = "PointToCurveDistanceByY" + } + } +} + +/** + * Compute a wight of the point. The more the weight, the more impact this point will have on the fit. + * By default, uses Dispersion^-1 + */ +public interface PointWeight : OptimizationFeature { + public fun weight(problem: XYFit, index: Int): DifferentiableExpression + + public companion object { + public fun bySigma(sigmaSymbol: Symbol): PointWeight = object : PointWeight { + override fun weight(problem: XYFit, index: Int): DifferentiableExpression = + object : DifferentiableExpression { + override fun invoke(arguments: Map): Double { + return problem.data[sigmaSymbol]?.get(index)?.pow(-2) ?: 1.0 + } + + override fun derivativeOrNull(symbols: List): Expression = Expression { 0.0 } + } + + override fun toString(): String = "PointWeightBySigma($sigmaSymbol)" + + } + + public val byYSigma: PointWeight = bySigma(Symbol.yError) + } +} + +/** + * A fit problem for X-Y-Yerr data. Also known as "least-squares" problem. + */ +public class XYFit( + public val data: XYColumnarData, + public val model: DifferentiableExpression, + override val features: FeatureSet, + internal val pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, + internal val pointWeight: PointWeight = PointWeight.byYSigma, +) : OptimizationProblem { + public fun distance(index: Int): DifferentiableExpression = pointToCurveDistance.distance(this, index) + + public fun weight(index: Int): DifferentiableExpression = pointWeight.weight(this, index) +} + +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( + 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 = processor.differentiate { + val x = bindSymbol(xSymbol) + model(x) + } + + var actualFeatures = FeatureSet.of(*features, OptimizationStartPoint(startingPoint)) + + if (actualFeatures.getFeature() == null) { + actualFeatures = actualFeatures.with(OptimizationLog(Loggable.console)) + } + val problem = XYFit( + this, + modelExpression, + actualFeatures, + pointToCurveDistance, + pointWeight + ) + return optimizer.optimize(problem) +} \ No newline at end of file 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 new file mode 100644 index 000000000..6701887a2 --- /dev/null +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.optimization + +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 +import kotlin.math.sqrt + + +private val oneOver2Pi = 1.0 / sqrt(2 * PI) + +@UnstableKMathAPI +internal fun XYFit.logLikelihood(): DifferentiableExpression = object : DifferentiableExpression { + override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> + data.indices.sumOf { index -> + val d = distance(index)(arguments) + val weight = weight(index)(arguments) + val weightDerivative = weight(index)(arguments) + + // -1 / (sqrt(2 PI) * sigma) + 2 (x-mu)/ 2 sigma^2 * d mu/ d theta - (x-mu)^2 / 2 * d w/ d theta + return@sumOf -oneOver2Pi * sqrt(weight) + //offset derivative + d * model.derivative(symbols)(arguments) * weight - //model derivative + d.pow(2) * weightDerivative / 2 //weight derivative + } + } + + override fun invoke(arguments: Map): Double { + return data.indices.sumOf { index -> + val d = distance(index)(arguments) + val weight = weight(index)(arguments) + //1/sqrt(2 PI sigma^2) - (x-mu)^2/ (2 * sigma^2) + oneOver2Pi * ln(weight) - d.pow(2) * weight + } / 2 + } + +} + +/** + * Optimize given XY (least squares) [problem] using this function [Optimizer]. + * The problem is treated as maximum likelihood problem and is done via maximizing logarithmic likelihood, respecting + * possible weight dependency on the model and parameters. + */ +@UnstableKMathAPI +public suspend fun Optimizer>.maximumLogLikelihood(problem: XYFit): XYFit { + val functionOptimization = FunctionOptimization(problem.features, problem.logLikelihood()) + val result = optimize(functionOptimization.withFeatures(FunctionOptimizationTarget.MAXIMIZE)) + return XYFit(problem.data, problem.model, result.features) +} + +@UnstableKMathAPI +public suspend fun Optimizer>.maximumLogLikelihood( + data: XYColumnarData, + model: DifferentiableExpression, + builder: XYOptimizationBuilder.() -> Unit, +): XYFit = maximumLogLikelihood(XYOptimization(data, model, builder)) diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index e3e396b6f..41a1666f8 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.mpp") id("ru.mipt.npm.gradle.native") } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt deleted file mode 100644 index 68c0c77eb..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYOptimization.kt +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.optimization - -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.FeatureSet -import space.kscience.kmath.misc.UnstableKMathAPI -import kotlin.math.PI -import kotlin.math.ln -import kotlin.math.pow -import kotlin.math.sqrt - -/** - * Specify the way to compute distance from point to the curve as DifferentiableExpression - */ -public interface PointToCurveDistance : OptimizationFeature { - public fun distance(problem: XYOptimization, index: Int): DifferentiableExpression - - public companion object { - public val byY: PointToCurveDistance = object : PointToCurveDistance { - override fun distance(problem: XYOptimization, index: Int): DifferentiableExpression { - - val x = problem.data.x[index] - val y = problem.data.y[index] - return object : DifferentiableExpression { - override fun derivativeOrNull(symbols: List): Expression? = - problem.model.derivativeOrNull(symbols) - - override fun invoke(arguments: Map): Double = - problem.model(arguments + (Symbol.x to x)) - y - } - } - - override fun toString(): String = "PointToCurveDistanceByY" - } - } -} - -/** - * Compute a wight of the point. The more the weight, the more impact this point will have on the fit. - * By default uses Dispersion^-1 - */ -public interface PointWeight : OptimizationFeature { - public fun weight(problem: XYOptimization, index: Int): DifferentiableExpression - - public companion object { - public fun bySigma(sigmaSymbol: Symbol): PointWeight = object : PointWeight { - override fun weight(problem: XYOptimization, index: Int): DifferentiableExpression = - object : DifferentiableExpression { - override fun invoke(arguments: Map): Double { - return problem.data[sigmaSymbol]?.get(index)?.pow(-2) ?: 1.0 - } - - override fun derivativeOrNull(symbols: List): Expression = Expression { 0.0 } - } - - override fun toString(): String = "PointWeightBySigma($sigmaSymbol)" - - } - - public val byYSigma: PointWeight = bySigma(Symbol.yError) - } -} - -/** - * An optimization for XY data. - */ -public class XYOptimization( - override val features: FeatureSet, - public val data: XYColumnarData, - public val model: DifferentiableExpression, - internal val pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, - internal val pointWeight: PointWeight = PointWeight.byYSigma, -) : OptimizationProblem { - public fun distance(index: Int): DifferentiableExpression = pointToCurveDistance.distance(this, index) - - public fun weight(index: Int): DifferentiableExpression = pointWeight.weight(this, index) -} - -public fun XYOptimization.withFeature(vararg features: OptimizationFeature): XYOptimization { - return XYOptimization(this.features.with(*features), data, model, pointToCurveDistance, pointWeight) -} - -private val oneOver2Pi = 1.0 / sqrt(2 * PI) - -internal fun XYOptimization.likelihood(): DifferentiableExpression = object : DifferentiableExpression { - override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> - data.indices.sumOf { index -> - - val d = distance(index)(arguments) - val weight = weight(index)(arguments) - val weightDerivative = weight(index)(arguments) - - // -1 / (sqrt(2 PI) * sigma) + 2 (x-mu)/ 2 sigma^2 * d mu/ d theta - (x-mu)^2 / 2 * d w/ d theta - return@sumOf -oneOver2Pi * sqrt(weight) + //offset derivative - d * model.derivative(symbols)(arguments) * weight - //model derivative - d.pow(2) * weightDerivative / 2 //weight derivative - } - } - - override fun invoke(arguments: Map): Double { - return data.indices.sumOf { index -> - val d = distance(index)(arguments) - val weight = weight(index)(arguments) - //1/sqrt(2 PI sigma^2) - (x-mu)^2/ (2 * sigma^2) - oneOver2Pi * ln(weight) - d.pow(2) * weight - } / 2 - } - -} - -/** - * Optimize given XY (least squares) [problem] using this function [Optimizer]. - * The problem is treated as maximum likelihood problem and is done via maximizing logarithmic likelihood, respecting - * possible weight dependency on the model and parameters. - */ -public suspend fun Optimizer>.maximumLogLikelihood(problem: XYOptimization): XYOptimization { - val functionOptimization = FunctionOptimization(problem.features, problem.likelihood()) - val result = optimize(functionOptimization.withFeatures(FunctionOptimizationTarget.MAXIMIZE)) - return XYOptimization(result.features, problem.data, problem.model) -} - -public suspend fun Optimizer>.maximumLogLikelihood( - data: XYColumnarData, - model: DifferentiableExpression, - builder: XYOptimizationBuilder.() -> Unit, -): XYOptimization = maximumLogLikelihood(XYOptimization(data, model, builder)) - -//public suspend fun XYColumnarData.fitWith( -// optimizer: XYOptimization, -// problemBuilder: XYOptimizationBuilder.() -> Unit = {}, -// -//) - - -// -//@UnstableKMathAPI -//public interface XYFit : OptimizationProblem { -// -// public val algebra: Field -// -// /** -// * Set X-Y data for this fit optionally including x and y errors -// */ -// public fun data( -// dataSet: ColumnarData, -// xSymbol: Symbol, -// ySymbol: Symbol, -// xErrSymbol: Symbol? = null, -// yErrSymbol: Symbol? = null, -// ) -// -// public fun model(model: (T) -> DifferentiableExpression) -// -// /** -// * Set the differentiable model for this fit -// */ -// public fun model( -// autoDiff: AutoDiffProcessor>, -// modelFunction: A.(I) -> I, -// ): Unit where A : ExtendedField, A : ExpressionAlgebra = model { arg -> -// autoDiff.process { modelFunction(const(arg)) } -// } -//} - -// -///** -// * Define a chi-squared-based objective function -// */ -//public fun FunctionOptimization.chiSquared( -// autoDiff: AutoDiffProcessor>, -// x: Buffer, -// y: Buffer, -// yErr: Buffer, -// model: A.(I) -> I, -//) where A : ExtendedField, A : ExpressionAlgebra { -// val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) -// function(chiSquared) -// maximize = false -//} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index f05092bb1..d1cbbe74c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,6 +26,7 @@ include( ":kmath-histograms", ":kmath-commons", ":kmath-viktor", + ":kmath-optimization", ":kmath-stat", ":kmath-nd4j", ":kmath-dimensions", -- 2.34.1 From 8d33d6beabf859a75317d087dd4adf70051b6c1a Mon Sep 17 00:00:00 2001 From: darksnake Date: Mon, 16 Aug 2021 16:40:56 +0300 Subject: [PATCH 011/102] Fixed QOW optimization --- .../kotlin/space/kscience/kmath/fit/qowFit.kt | 11 +++++---- .../kmath/optimization/QowOptimizer.kt | 2 +- .../kscience/kmath/optimization/XYFit.kt | 23 ++++++++++++++++++- .../kmath/optimization/logLikelihood.kt | 2 +- 4 files changed, 30 insertions(+), 8 deletions(-) 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 944f80697..04764d763 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt @@ -14,6 +14,7 @@ import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.binding import space.kscience.kmath.expressions.symbol 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.real.map @@ -50,7 +51,7 @@ suspend fun main() { //Perform an operation on each x value (much more effective, than numpy) val y = x.map { it -> - val value = it.pow(2) + it + 100 + val value = it.pow(2) + it + 1 value + chain.next() * sqrt(value) } // this will also work, but less effective: @@ -63,7 +64,7 @@ suspend fun main() { val result = XYErrorColumnarData.of(x, y, yErr).fitWith( QowOptimizer, DSProcessor, - mapOf(a to 1.0, b to 1.2, c to 99.0) + mapOf(a to 0.9, b to 1.2, c to 2.0) ) { arg -> //bind variables to autodiff context val a by binding @@ -96,9 +97,9 @@ suspend fun main() { h3 { +"Fit result: ${result.resultPoint}" } -// h3 { -// +"Chi2/dof = ${result.resultValue / (x.size - 3)}" -// } + h3 { + +"Chi2/dof = ${result.chiSquaredOrNull!! / (x.size - 3)}" + } } page.makeFile() 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 f0969d2f6..4fe8520da 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 @@ -50,7 +50,7 @@ public object QowOptimizer : Optimizer { */ val dispersion: Point by lazy { DoubleBuffer(problem.data.size) { d -> - problem.weight(d).invoke(parameters) + 1.0/problem.weight(d).invoke(parameters) } } 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 cbd765923..07fea3126 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 @@ -7,6 +7,7 @@ package space.kscience.kmath.optimization 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 @@ -81,6 +82,7 @@ public class XYFit( override val features: FeatureSet, internal val pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, internal val pointWeight: PointWeight = PointWeight.byYSigma, + public val xSymbol: Symbol = Symbol.x, ) : OptimizationProblem { public fun distance(index: Int): DifferentiableExpression = pointToCurveDistance.distance(this, index) @@ -119,7 +121,26 @@ public suspend fun XYColumnarData.fitWith( modelExpression, actualFeatures, pointToCurveDistance, - pointWeight + pointWeight, + xSymbol ) return optimizer.optimize(problem) +} + +/** + * Compute chi squared value for completed fit. Return null for incomplete fit + */ +public val XYFit.chiSquaredOrNull: Double? get() { + val result = resultPointOrNull ?: return null + + 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 mu = model.invoke(result + (xSymbol to x) ) + + ((y - mu)/yErr).pow(2) + } } \ No newline at end of file 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 6701887a2..b4cb2f1cf 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 @@ -26,7 +26,7 @@ internal fun XYFit.logLikelihood(): DifferentiableExpression = object : data.indices.sumOf { index -> val d = distance(index)(arguments) val weight = weight(index)(arguments) - val weightDerivative = weight(index)(arguments) + val weightDerivative = weight(index).derivative(symbols)(arguments) // -1 / (sqrt(2 PI) * sigma) + 2 (x-mu)/ 2 sigma^2 * d mu/ d theta - (x-mu)^2 / 2 * d w/ d theta return@sumOf -oneOver2Pi * sqrt(weight) + //offset derivative -- 2.34.1 From 69aad2424d0816f291dce7913d606391e6739c0b Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 27 Feb 2021 14:17:32 +0700 Subject: [PATCH 012/102] Proof-of-concept for dynamic units framework --- examples/build.gradle.kts | 4 +- .../kotlin/space/kscience/kmath/units/main.kt | 37 +++ .../kotlin/space/kscience/kmath/units/perf.kt | 33 +++ .../kmath/integration/SplineIntegrator.kt | 2 + kmath-units/build.gradle.kts | 15 + .../space/kscience/kmath/units/units.kt | 276 ++++++++++++++++++ settings.gradle.kts | 1 + 7 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/units/main.kt create mode 100644 examples/src/main/kotlin/space/kscience/kmath/units/perf.kt create mode 100644 kmath-units/build.gradle.kts create mode 100644 kmath-units/src/commonMain/kotlin/space/kscience/kmath/units/units.kt diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 4cc6fecc0..22e71ad46 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -27,6 +27,7 @@ dependencies { implementation(project(":kmath-nd4j")) implementation(project(":kmath-tensors")) implementation(project(":kmath-symja")) + implementation(project(":kmath-units")) implementation(project(":kmath-for-real")) implementation("org.nd4j:nd4j-native:1.0.0-beta7") @@ -52,12 +53,13 @@ kotlin.sourceSets.all { with(languageSettings) { useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") + useExperimentalAnnotation("kotlin.time.ExperimentalTime") useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } } tasks.withType { - kotlinOptions{ + kotlinOptions { jvmTarget = "11" freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" } diff --git a/examples/src/main/kotlin/space/kscience/kmath/units/main.kt b/examples/src/main/kotlin/space/kscience/kmath/units/main.kt new file mode 100644 index 000000000..0aaeaf1cb --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/units/main.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.units + +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.units.* + +fun main() { + var res = with(DoubleField.measurement()) { + val a = (2.0 * kg) / (3.0 * m) / (2.0 * with(MeasureAlgebra) { s * s }) + val b = (23.0 * Pa) + a + b + } + + println(res) + + res = with(DoubleField.measurement()) { + val a = (2.0 * G(m)) + (3.0 * M(m)) + val b = (3.0 * au) + a + b + } + + println(res) + + res = with(DoubleField.measurement()) { + val P = 100000.0 * Pa + val V = 0.0227 * (m pow 3) + val nu = 1.0 * mol + val T = 273.0 * K + P * V / (nu * T) + } + + println(res) +} diff --git a/examples/src/main/kotlin/space/kscience/kmath/units/perf.kt b/examples/src/main/kotlin/space/kscience/kmath/units/perf.kt new file mode 100644 index 000000000..dcd3b335b --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/units/perf.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.units + +import space.kscience.kmath.operations.DoubleField +import kotlin.random.Random +import kotlin.time.measureTime + +fun main() { + var rng = Random(0) + var sum1 = 0.0 + + measureTime { + repeat(10000000) { sum1 += rng.nextDouble() } + }.also(::println) + + println(sum1) + + rng = Random(0) + + with(DoubleField.measurement()) { + var sum2 = 0.0 * Pa + + measureTime { + repeat(10000000) { sum2 += rng.nextDouble() * Pa } + }.also(::println) + + println(sum2) + } +} 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 65a3d5e82..6581d5dd8 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 @@ -10,6 +10,7 @@ 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.DoubleField import space.kscience.kmath.operations.Field @@ -23,6 +24,7 @@ import space.kscience.kmath.structures.map /** * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact */ +@PerformancePitfall @UnstableKMathAPI public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) diff --git a/kmath-units/build.gradle.kts b/kmath-units/build.gradle.kts new file mode 100644 index 000000000..11b0d0300 --- /dev/null +++ b/kmath-units/build.gradle.kts @@ -0,0 +1,15 @@ +import ru.mipt.npm.gradle.Maturity + +plugins { + id("ru.mipt.npm.gradle.mpp") +} + +kotlin.sourceSets.commonMain { + dependencies { + api(project(":kmath-core")) + } +} + +readme { + maturity = Maturity.PROTOTYPE +} diff --git a/kmath-units/src/commonMain/kotlin/space/kscience/kmath/units/units.kt b/kmath-units/src/commonMain/kotlin/space/kscience/kmath/units/units.kt new file mode 100644 index 000000000..a414a9fe2 --- /dev/null +++ b/kmath-units/src/commonMain/kotlin/space/kscience/kmath/units/units.kt @@ -0,0 +1,276 @@ +package space.kscience.kmath.units + +import space.kscience.kmath.operations.* +import kotlin.jvm.JvmName +import kotlin.math.PI +import kotlin.math.pow + +/** + * Represents base units of International System of Units. + */ +public enum class BaseUnits { + /** + * The base unit of time. + */ + SECOND, + + /** + * The base unit of length. + */ + METER, + + /** + * The base unit of mass. + */ + KILOGRAM, + + /** + * The base unit of electric current. + */ + AMPERE, + + /** + * The base unit of thermodynamic temperature. + */ + KELVIN, + + /** + * The base unit of amount of substance. + */ + MOLE, + + /** + * The base unit of luminous intensity. + */ + CANDELA; +} + +/** + * Represents a unit. + * + * @property chain chain of multipliers consisting of [BaseUnits] unit and its power. + * @property multiplier a scalar to multiply an element applied to this unit. + */ +public data class Measure internal constructor( + val chain: Map = emptyMap(), + val multiplier: Double = 1.0, +) + +internal fun Measure(vararg chain: Pair, multiplier: Double = 1.0): Measure = + Measure(mapOf(*chain), multiplier) + +public data class Measurement(val measure: Measure, val value: T) + +public object MeasureAlgebra : Algebra { + public const val MULTIPLY_OPERATION: String = "*" + public const val DIVIDE_OPERATION: String = "/" + + public fun multiply(a: Measure, b: Measure): Measure { + val newChain = mutableMapOf() + + a.chain.forEach { (k, v) -> + val cur = newChain[k] + if (cur != null) newChain[k] = cur + v + else newChain[k] = v + } + + b.chain.forEach { (k, v) -> + val cur = newChain[k] + if (cur != null) newChain[k] = cur + v + else newChain[k] = v + } + + return Measure(newChain, a.multiplier * b.multiplier) + } + + public fun divide(a: Measure, b: Measure): Measure = + multiply(a, b.copy(chain = b.chain.mapValues { (_, v) -> -v })) + + public operator fun Measure.times(b: Measure): Measure = multiply(this, b) + public operator fun Measure.div(b: Measure): Measure = divide(this, b) + + override fun binaryOperationFunction(operation: String): (left: Measure, right: Measure) -> Measure = + when (operation) { + MULTIPLY_OPERATION -> ::multiply + DIVIDE_OPERATION -> ::divide + else -> super.binaryOperationFunction(operation) + } +} + +/** + * A measure for dimensionless quantities with multiplier `1.0`. + */ +public val pure: Measure = Measure() + +/** + * A measure for [BaseUnits.METER] of power `1.0` with multiplier `1.0`. + */ +public val m: Measure = Measure(BaseUnits.METER to 1) + +/** + * A measure for [BaseUnits.KILOGRAM] of power `1.0` with multiplier `1.0`. + */ +public val kg: Measure = Measure(BaseUnits.KILOGRAM to 1) + +/** + * A measure for [BaseUnits.SECOND] of power `1.0` with multiplier `1.0`. + */ +@get:JvmName("s-seconds") +public val s: Measure = Measure(BaseUnits.SECOND to 1) + +/** + * A measure for [BaseUnits.AMPERE] of power `1.0` with multiplier `1.0`. + */ +public val A: Measure = Measure(BaseUnits.AMPERE to 1) + +/** + * A measure for [BaseUnits.KELVIN] of power `1.0` with multiplier `1.0`. + */ +public val K: Measure = Measure(BaseUnits.KELVIN to 1) + +/** + * A measure for [BaseUnits.MOLE] of power `1.0` with multiplier `1.0`. + */ +public val mol: Measure = Measure(BaseUnits.MOLE to 1) + +/** + * A measure for [BaseUnits.CANDELA] of power `1.0` with multiplier `1.0`. + */ +public val cd: Measure = Measure(BaseUnits.CANDELA to 1) + +public val rad: Measure = pure +public val sr: Measure = pure +public val degC: Measure = K +public val Hz: Measure = MeasureAlgebra { pure / s } +public val N: Measure = MeasureAlgebra { kg * m * (pure / (s * s)) } +public val J: Measure = MeasureAlgebra { N * m } +public val W: Measure = MeasureAlgebra { J / s } +public val Pa: Measure = MeasureAlgebra { N / (m * m) } +public val lm: Measure = MeasureAlgebra { cd * sr } +public val lx: Measure = MeasureAlgebra { lm / (m * m) } +public val C: Measure = MeasureAlgebra { A * s } +public val V: Measure = MeasureAlgebra { J / C } +public val Ohm: Measure = MeasureAlgebra { V / A } +public val F: Measure = MeasureAlgebra { C / V } +public val Wb: Measure = MeasureAlgebra { kg * m * m * (pure / (s * s)) * (pure / A) } + +@get:JvmName("T-tesla") +public val T: Measure = MeasureAlgebra { Wb / (m * m) } + +@get:JvmName("H-henry") +public val H: Measure = MeasureAlgebra { kg * m * m * (pure / (s * s)) * (pure / (A * A)) } + +public val S: Measure = MeasureAlgebra { pure / Ohm } +public val Bq: Measure = MeasureAlgebra { pure / s } +public val Gy: Measure = MeasureAlgebra { J / kg } +public val Sv: Measure = MeasureAlgebra { J / kg } +public val kat: Measure = MeasureAlgebra { mol / s } + +public val g: Measure = Measure(BaseUnits.KILOGRAM to 1, multiplier = 0.001) +public val min: Measure = Measure(BaseUnits.SECOND to 1, multiplier = 60.0) +public val h: Measure = Measure(BaseUnits.SECOND to 1, multiplier = 3600.0) +public val d: Measure = Measure(BaseUnits.SECOND to 1, multiplier = 86_400.0) +public val au: Measure = Measure(BaseUnits.METER to 1, multiplier = 149_597_870_700.0) +public val deg: Measure = Measure(multiplier = PI / 180.0) +public val arcMin: Measure = Measure(multiplier = PI / 10_800.0) +public val arcS: Measure = Measure(multiplier = PI / 648_000.0) +public val ha: Measure = Measure(BaseUnits.METER to 2, multiplier = 10000.0) +public val l: Measure = Measure(BaseUnits.METER to 3, multiplier = 0.001) +public val t: Measure = Measure(BaseUnits.KILOGRAM to 1, multiplier = 1000.0) +public val Da: Measure = Measure(BaseUnits.KILOGRAM to 1, multiplier = 1.660_539_040_202_020 * 10e-27) +public val eV: Measure = J.copy(multiplier = 1.602_176_634 * 10e-19) + +public fun Y(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e24) +public fun Z(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e21) +public fun E(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e18) +public fun P(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e15) +public fun T(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e12) +public fun G(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e9) +public fun M(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e6) +public fun k(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e3) +public fun h(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e2) +public fun da(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e1) + +public fun y(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-24) +public fun z(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-21) +public fun a(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-18) +public fun f(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-15) +public fun p(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-12) +public fun n(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-9) +public fun u(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-6) +public fun m(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-3) +public fun c(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-2) +public fun d(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-1) + +public infix fun Measure.pow(power: Int): Measure = + copy(chain = chain.mapValues { (_, v) -> IntRing.power(v, power.toUInt()) }, multiplier = multiplier.pow(power)) + +public open class MeasurementAlgebra(public open val algebra: Algebra) : Algebra> { + public operator fun T.times(m: Measure): Measurement = Measurement(m, this) + public operator fun Measurement.times(m: Measure): Measurement = + copy(measure = MeasureAlgebra { measure * m }) + + public override fun bindSymbol(value: String): Measurement = algebra.bindSymbol(value) * pure +} + +public fun Algebra.measurement(): MeasurementAlgebra = MeasurementAlgebra(this) + +public open class MeasurementSpace(public override val algebra: A) : MeasurementAlgebra(algebra), + Group>, ScaleOperations> where A : Group, A : ScaleOperations { + public override val zero: Measurement + get() = Measurement(pure, algebra.zero) + + public override fun add(a: Measurement, b: Measurement): Measurement { + require(a.measure.chain == b.measure.chain) { + "The units are incompatible. The chains are ${a.measure.chain} and ${b.measure.chain}" + } + + return a.copy(value = algebra { a.value * a.measure.multiplier + b.value * b.measure.multiplier }) + } + + public override fun scale(a: Measurement, value: Double): Measurement = + Measurement(a.measure, algebra { a.value * value }) + + override fun Measurement.unaryMinus(): Measurement = copy(value = algebra { -value }) +} + +public fun A.measurement(): MeasurementSpace where A : Group, A : ScaleOperations = MeasurementSpace(this) + +public open class MeasurementRing(override val algebra: A) : MeasurementSpace(algebra), + Ring> where A : ScaleOperations, A : Ring { + public override val one: Measurement + get() = Measurement(pure, algebra.one) + + public override fun multiply(a: Measurement, b: Measurement): Measurement = + Measurement(MeasureAlgebra { a.measure * b.measure }, algebra { a.value * b.value }) +} + +public fun A.measurement(): MeasurementRing where A : Ring, A : ScaleOperations = MeasurementRing(this) + +public open class MeasurementField(public override val algebra: Field) : MeasurementRing>(algebra), + Field> { + public override fun divide(a: Measurement, b: Measurement): Measurement = + Measurement(MeasureAlgebra { a.measure / b.measure }, algebra { a.value / b.value }) +} + +public fun Field.measurement(): MeasurementField = MeasurementField(this) + +public open class MeasurementExtendedField(public override val algebra: ExtendedField) : + MeasurementField(algebra), + ExtendedField> { + public override fun number(value: Number): Measurement = Measurement(pure, algebra.number(value)) + public override fun sin(arg: Measurement): Measurement = Measurement(arg.measure, algebra.sin(arg.value)) + public override fun cos(arg: Measurement): Measurement = Measurement(arg.measure, algebra.cos(arg.value)) + public override fun tan(arg: Measurement): Measurement = Measurement(arg.measure, algebra.tan(arg.value)) + public override fun asin(arg: Measurement): Measurement = Measurement(arg.measure, algebra.asin(arg.value)) + public override fun acos(arg: Measurement): Measurement = Measurement(arg.measure, algebra.acos(arg.value)) + public override fun atan(arg: Measurement): Measurement = Measurement(arg.measure, algebra.atan(arg.value)) + + public override fun power(arg: Measurement, pow: Number): Measurement = + (this as Field>).power(arg, pow.toInt()) + + public override fun exp(arg: Measurement): Measurement = Measurement(arg.measure, algebra.exp(arg.value)) + public override fun ln(arg: Measurement): Measurement = Measurement(arg.measure, algebra.ln(arg.value)) +} + +public fun ExtendedField.measurement(): MeasurementExtendedField = MeasurementExtendedField(this) diff --git a/settings.gradle.kts b/settings.gradle.kts index f05092bb1..b2f40300c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,6 +36,7 @@ include( ":kmath-kotlingrad", ":kmath-tensors", ":kmath-jupyter", + ":kmath-units", ":kmath-symja", ":kmath-jafama", ":examples", -- 2.34.1 From 7e0820d861763535e5c163215feb6d3f3bb86432 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 21 Aug 2021 19:58:06 +0700 Subject: [PATCH 013/102] Add debug property for dumping classes generated with ASM --- .../kscience/kmath/asm/internal/AsmBuilder.kt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index de7da30df..418d6141b 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -14,9 +14,11 @@ import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.MST import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType +import java.nio.file.Paths import java.util.stream.Collectors.toMap import kotlin.contracts.InvocationKind import kotlin.contracts.contract +import kotlin.io.path.writeBytes /** * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. @@ -194,15 +196,18 @@ internal class AsmBuilder( visitEnd() } - val cls = classLoader.defineClass(className, classWriter.toByteArray()) - // java.io.File("dump.class").writeBytes(classWriter.toByteArray()) + val binary = classWriter.toByteArray() + val cls = classLoader.defineClass(className, binary) + + if (System.getProperty("space.kscience.communicator.prettyapi.dump.generated.classes") == "1") + Paths.get("$className.class").writeBytes(binary) + val l = MethodHandles.publicLookup() - if (hasConstants) - l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java)) - .invoke(constants.toTypedArray()) as Expression + (if (hasConstants) + l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java))(constants.toTypedArray()) else - l.findConstructor(cls, MethodType.methodType(Void.TYPE)).invoke() as Expression + l.findConstructor(cls, MethodType.methodType(Void.TYPE))()) as Expression } /** -- 2.34.1 From 8581b32448e92e94cac04866426377beddc2f2a3 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 27 Aug 2021 18:13:54 +0300 Subject: [PATCH 014/102] Apply suggestions from code review Co-authored-by: Iaroslav Postovalov <38042667+CommanderTvis@users.noreply.github.com> --- .gitignore | 2 -- .../src/main/kotlin/space/kscience/kmath/structures/buffers.kt | 2 +- kmath-optimization/build.gradle.kts | 2 +- .../space/kscience/kmath/optimization/OptimizationBuilder.kt | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index c5903368f..d6c4af4e3 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,3 @@ out/ # Generated by javac -h and runtime *.class *.log - -/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt index eabb16701..0f7fdc46a 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt @@ -19,4 +19,4 @@ fun main() { with(DoubleField.bufferAlgebra(5)) { println(number(2.0) + produce(1, 2, 3, 4, 5)) } -} \ No newline at end of file +} diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts index ca013b2f4..68b82ad65 100644 --- a/kmath-optimization/build.gradle.kts +++ b/kmath-optimization/build.gradle.kts @@ -17,4 +17,4 @@ kotlin.sourceSets { readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL -} \ 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 10a25c029..416d0195d 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 @@ -11,7 +11,7 @@ import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.FeatureSet public abstract class OptimizationBuilder> { - public val features: ArrayList = ArrayList() + public val features: MutableList = ArrayList() public fun addFeature(feature: OptimizationFeature) { features.add(feature) -- 2.34.1 From 55ea3658b99a26200475fd705f208cd4acdc9f8b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 27 Aug 2021 18:16:24 +0300 Subject: [PATCH 015/102] Update CHANGELOG.md Co-authored-by: Iaroslav Postovalov <38042667+CommanderTvis@users.noreply.github.com> --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eadf5877d..ec3f5252a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,6 @@ - Extended operations for ND4J fields - Jupyter Notebook integration module (kmath-jupyter) - `@PerformancePitfall` annotation to mark possibly slow API -- BigInt operation performance improvement and fixes by @zhelenskiy (#328) - Unified architecture for Integration and Optimization using features. - `BigInt` operation performance improvement and fixes by @zhelenskiy (#328) - Integration between `MST` and Symja `IExpr` -- 2.34.1 From 49ec5d15549daaf3848a09f9f3c6f441803587d6 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 19 Sep 2021 20:48:36 +0300 Subject: [PATCH 016/102] Refactor ND builders to suit new discoverability pattern --- .../kmath/benchmarks/NDFieldBenchmark.kt | 6 +- .../kmath/benchmarks/ViktorBenchmark.kt | 9 +- .../kmath/benchmarks/ViktorLogBenchmark.kt | 9 +- docs/diagrams/core.puml | 1020 +++++++++++++++++ .../kmath/functions/matrixIntegration.kt | 4 +- .../kscience/kmath/operations/ComplexDemo.kt | 12 +- .../kscience/kmath/structures/ComplexND.kt | 10 +- .../kscience/kmath/structures/NDField.kt | 12 +- .../kmath/structures/StreamDoubleFieldND.kt | 2 +- gradle.properties | 2 + .../kscience/kmath/complex/ComplexFieldND.kt | 5 +- kmath-core/build.gradle.kts | 7 + .../kmath/linear/BufferedLinearSpace.kt | 7 +- .../kscience/kmath/nd/BufferAlgebraND.kt | 43 +- .../space/kscience/kmath/nd/DoubleFieldND.kt | 4 +- .../space/kscience/kmath/nd/ShortRingND.kt | 2 +- .../space/kscience/kmath/operations/BigInt.kt | 3 +- .../kscience/kmath/structures/NDFieldTest.kt | 8 +- .../kmath/structures/NumberNDFieldTest.kt | 10 +- .../kmath/histogram/DoubleHistogramSpace.kt | 3 +- .../kscience/kmath/jupyter/KMathJupyter.kt | 1 - .../kmath/optimization/QowOptimizer.kt | 22 +- settings.gradle.kts | 4 +- 23 files changed, 1130 insertions(+), 75 deletions(-) create mode 100644 docs/diagrams/core.puml 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 0cd9a46ab..fbf4bdaba 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -46,8 +46,8 @@ internal class NDFieldBenchmark { private companion object { private const val dim = 1000 private const val n = 100 - private val autoField = AlgebraND.auto(DoubleField, dim, dim) - private val specializedField = AlgebraND.real(dim, dim) - private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) + private val autoField = DoubleField.autoNd(dim, dim) + private val specializedField = DoubleField.nd(dim, dim) + private val genericField = DoubleField.nd(Buffer.Companion::boxing, dim, dim) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index 1ddc79cf8..6ea64ba3c 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -10,10 +10,9 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.auto -import space.kscience.kmath.nd.real +import space.kscience.kmath.nd.autoNd +import space.kscience.kmath.nd.nd import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.viktor.ViktorNDField @@ -59,8 +58,8 @@ internal class ViktorBenchmark { private const val n = 100 // automatically build context most suited for given type. - private val autoField = AlgebraND.auto(DoubleField, dim, dim) - private val realField = AlgebraND.real(dim, dim) + private val autoField = DoubleField.autoNd(dim, dim) + private val realField = DoubleField.nd(dim, dim) private val viktorField = ViktorNDField(dim, dim) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index 8622e8f30..afe44ea99 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -10,9 +10,8 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.AlgebraND -import space.kscience.kmath.nd.auto -import space.kscience.kmath.nd.real +import space.kscience.kmath.nd.autoNd +import space.kscience.kmath.nd.nd import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.viktor.ViktorFieldND @@ -51,8 +50,8 @@ internal class ViktorLogBenchmark { private const val n = 100 // automatically build context most suited for given type. - private val autoField = AlgebraND.auto(DoubleField, dim, dim) - private val realNdField = AlgebraND.real(dim, dim) + private val autoField = DoubleField.autoNd(dim, dim) + private val realNdField = DoubleField.nd(dim, dim) private val viktorField = ViktorFieldND(intArrayOf(dim, dim)) } } diff --git a/docs/diagrams/core.puml b/docs/diagrams/core.puml new file mode 100644 index 000000000..87f8f2e2d --- /dev/null +++ b/docs/diagrams/core.puml @@ -0,0 +1,1020 @@ +@startuml +interface "ColumnarData" { + size: Int +} +interface "XYColumnarData" { + x: Buffer + y: Buffer +} +interface "XYErrorColumnarData" { + yErr: Buffer +} +interface "XYZColumnarData" { + z: Buffer +} +interface "Domain" { + dimension: Int +} +interface "DoubleDomain" { + +} +class "HyperSquareDomain" { + lower: Buffer + upper: Buffer +} +class "UnconstrainedDomain" { + dimension: Int +} +class "UnivariateDomain" { + range: ClosedFloatingPointRange +} +interface "DifferentiableExpression" { + +} +interface "SpecialDifferentiableExpression" { + +} +abstract "FirstDerivativeExpression" { + +} +interface "AutoDiffProcessor" { + +} +interface "Expression" { + +} +interface "ExpressionAlgebra" { + +} +abstract "FunctionalExpressionAlgebra" { + algebra: A +} +class "FunctionalExpressionGroup" { + algebra: A +} +class "FunctionalExpressionRing" { + algebra: A +} +class "FunctionalExpressionField" { + algebra: A +} +class "FunctionalExpressionExtendedField" { + algebra: A +} +interface "MST" { + +} +class "Numeric" { + value: Number +} +class "Unary" { + operation: String + value: MST +} +class "Binary" { + operation: String + left: MST + right: MST +} +class "InnerAlgebra" { + algebra: Algebra + arguments: Map +} +class "MstNumericAlgebra" { + number() + bindSymbolOrNull() + bindSymbol() + unaryOperationFunction() + binaryOperationFunction() +} +class "MstGroup" { + zero: MST.Numericnumber() + bindSymbolOrNull() + add() + unaryPlus() + unaryMinus() + minus() + scale() + binaryOperationFunction() + unaryOperationFunction() +} +class "MstRing" { + zero: MST.Numeric + one: MST.Numericnumber() + bindSymbolOrNull() + add() + scale() + multiply() + unaryPlus() + unaryMinus() + minus() + binaryOperationFunction() + unaryOperationFunction() +} +class "MstField" { + zero: MST.Numeric + one: MST.NumericbindSymbolOrNull() + number() + add() + scale() + multiply() + divide() + unaryPlus() + unaryMinus() + minus() + binaryOperationFunction() + unaryOperationFunction() +} +class "MstExtendedField" { + zero: MST.Numeric + one: MST.NumericbindSymbolOrNull() + number() + sin() + cos() + tan() + asin() + acos() + atan() + sinh() + cosh() + tanh() + asinh() + acosh() + atanh() + add() + sqrt() + scale() + multiply() + divide() + unaryPlus() + unaryMinus() + minus() + power() + exp() + ln() + binaryOperationFunction() + unaryOperationFunction() +} +class "MstLogicAlgebra" { + bindSymbolOrNull() + const() + not() + and() + or() + xor() +} +class "AutoDiffValue" { + value: T +} +class "DerivationResult" { + value: T + derivativeValues: Map + context: Field +} +class "SimpleAutoDiffField" { + context: F + bindings: Map +} +class "AutoDiffVariableWithDerivative" { + identity: String + value: T + d: T +} +class "SimpleAutoDiffExpression" { + field: F + function: SimpleAutoDiffField +} +class "SimpleAutoDiffExtendedField" { + context: F + bindings: Map +} +interface "Symbol" { + identity: String +} +class "StringSymbol" { + identity: String +} +interface "SymbolIndexer" { + symbols: List +} +class "SimpleSymbolIndexer" { + symbols: List +} +class "BufferedLinearSpace" { + elementAlgebra: A + bufferFactory: BufferFactory +} +interface "LinearSolver" { + +} +interface "LinearSpace" { + elementAlgebra: A +} +class "LupDecomposition" { + context: LinearSpace + elementContext: Field + lu: Matrix + pivot: IntArray + even: Boolean +} +class "MatrixBuilder" { + linearSpace: LinearSpace + rows: Int + columns: Int +} +class "SymmetricMatrixFeature" { + +} +interface "MatrixFeature" { + +} +interface "DiagonalFeature" { + +} +class "ZeroFeature" { + +} +class "UnitFeature" { + +} +interface "InverseMatrixFeature" { + inverse: Matrix +} +interface "DeterminantFeature" { + determinant: T +} +class "LFeature" { + +} +class "UFeature" { + +} +interface "LUDecompositionFeature" { + l: Matrix + u: Matrix +} +interface "LupDecompositionFeature" { + l: Matrix + u: Matrix + p: Matrix +} +class "OrthogonalFeature" { + +} +interface "QRDecompositionFeature" { + q: Matrix + r: Matrix +} +interface "CholeskyDecompositionFeature" { + l: Matrix +} +interface "SingularValueDecompositionFeature" { + u: Matrix + s: Matrix + v: Matrix + singularValues: Point +} +class "MatrixWrapper" { + origin: Matrix + features: FeatureSet +} +class "TransposedFeature" { + original: Matrix +} +class "VirtualMatrix" { + rowNum: Int + colNum: Int + generator: (i:Int,j:Int)->T +} +class "UnstableKMathAPI" { + +} +class "PerformancePitfall" { + message: String +} +interface "Featured" { + +} +interface "Feature" { + key: FeatureKey +} +class "FeatureSet" { + features: Map +} +interface "Loggable" { + +} +class "ShapeMismatchException" { + expected: IntArray + actual: IntArray +} +interface "AlgebraND" { + shape: IntArray + elementContext: C +} +interface "GroupND" { + +} +interface "RingND" { + +} +interface "FieldND" { + +} +interface "BufferAlgebraND" { + strides: Strides + bufferFactory: BufferFactory + buffer: Buffer +} +class "BufferedGroupND" { + shape: IntArray + elementContext: A + bufferFactory: BufferFactory +} +class "BufferedRingND" { + shape: IntArray + elementContext: R + bufferFactory: BufferFactory +} +class "BufferedFieldND" { + shape: IntArray + elementContext: R + bufferFactory: BufferFactory +} +class "BufferND" { + strides: Strides + buffer: Buffer +} +class "MutableBufferND" { + strides: Strides + mutableBuffer: MutableBuffer +} +class "DoubleFieldND" { + shape: IntArray +} +class "ShortRingND" { + shape: IntArray +} +interface "Structure1D" { + dimension: Int +} +interface "MutableStructure1D" { + +} +class "Structure1DWrapper" { + structure: StructureND +} +class "MutableStructure1DWrapper" { + structure: MutableStructureND +} +class "Buffer1DWrapper" { + buffer: Buffer +} +class "MutableBuffer1DWrapper" { + buffer: MutableBuffer +} +interface "Structure2D" { + rowNum: Int + colNum: Int + shape: IntArray + rows: List + columns: List +} +interface "MutableStructure2D" { + rows: List + columns: List +} +class "Structure2DWrapper" { + structure: StructureND +} +class "MutableStructure2DWrapper" { + structure: MutableStructureND +} +interface "StructureFeature" { + +} +interface "StructureND" { + shape: IntArray + dimension: Int +} +interface "MutableStructureND" { + +} +interface "Strides" { + shape: IntArray + strides: IntArray + linearSize: Int +} +class "DefaultStrides" { + shape: IntArray +} +class "KMathContext" { + +} +interface "Algebra" { + +} +interface "GroupOperations" { + +} +interface "Group" { + zero: T +} +interface "RingOperations" { + +} +interface "Ring" { + one: T +} +interface "FieldOperations" { + +} +interface "Field" { + +} +interface "AlgebraElement" { + context: C +} +interface "GroupElement" { + +} +interface "RingElement" { + +} +interface "FieldElement" { + +} +class "BigIntField" { + zero: BigInt + one: BigIntnumber() + unaryMinus() + add() + scale() + multiply() + divide() + unaryPlus() + unaryMinus() +} +class "BigInt" { + sign: Byte + magnitude: Magnitude +} +interface "BufferAlgebra" { + bufferFactory: BufferFactory + elementAlgebra: A +} +class "BufferField" { + bufferFactory: BufferFactory + elementAlgebra: A + size: Int +} +interface "LogicAlgebra" { + +} +class "BooleanAlgebra" { + const() + not() + and() + or() + xor() +} +interface "ExtendedFieldOperations" { + +} +interface "ExtendedField" { + +} +class "DoubleField" { + zero: Double + one: Doublenumber() + binaryOperationFunction() + add() + multiply() + divide() + scale() + sin() + cos() + tan() + acos() + asin() + atan() + sinh() + cosh() + tanh() + asinh() + acosh() + atanh() + sqrt() + power() + exp() + ln() + norm() + unaryMinus() + plus() + minus() + times() + div() +} +class "FloatField" { + zero: Float + one: Floatnumber() + binaryOperationFunction() + add() + scale() + multiply() + divide() + sin() + cos() + tan() + acos() + asin() + atan() + sinh() + cosh() + tanh() + asinh() + acosh() + atanh() + sqrt() + power() + exp() + ln() + norm() + unaryMinus() + plus() + minus() + times() + div() +} +class "IntRing" { + zero: Int + one: Intnumber() + add() + multiply() + norm() + unaryMinus() + plus() + minus() + times() +} +class "ShortRing" { + zero: Short + one: Shortnumber() + add() + multiply() + norm() + unaryMinus() + plus() + minus() + times() +} +class "ByteRing" { + zero: Byte + one: Bytenumber() + add() + multiply() + norm() + unaryMinus() + plus() + minus() + times() +} +class "LongRing" { + zero: Long + one: Longnumber() + add() + multiply() + norm() + unaryMinus() + plus() + minus() + times() +} +interface "NumericAlgebra" { + +} +interface "ScaleOperations" { + +} +interface "NumbersAddOperations" { + +} +interface "TrigonometricOperations" { + +} +interface "PowerOperations" { + +} +interface "ExponentialOperations" { + +} +interface "Norm" { + +} +interface "Buffer" { + size: Int +} +interface "MutableBuffer" { + +} +class "ListBuffer" { + list: List +} +class "MutableListBuffer" { + list: MutableList +} +class "ArrayBuffer" { + array: Array +} +class "ReadOnlyBuffer" { + buffer: MutableBuffer +} +class "VirtualBuffer" { + size: Int + generator: (Int)->T +} +class "BufferAccessor2D" { + rowNum: Int + colNum: Int + factory: MutableBufferFactory +} +class "Row" { + buffer: MutableBuffer + rowIndex: Int +} +class "DoubleBuffer" { + array: DoubleArray +} +class "DoubleBufferFieldOperations" { + unaryMinus() + add() + multiply() + divide() + sin() + cos() + tan() + asin() + acos() + atan() + sinh() + cosh() + tanh() + asinh() + acosh() + atanh() + power() + exp() + ln() +} +class "DoubleL2Norm" { + norm() +} +class "DoubleBufferField" { + size: Int +} +enum "ValueFlag" { + NAN + MISSING + NEGATIVE_INFINITY + POSITIVE_INFINITY +} +interface "FlaggedBuffer" { + +} +class "FlaggedDoubleBuffer" { + values: DoubleArray + flags: ByteArray +} +class "FloatBuffer" { + array: FloatArray +} +class "IntBuffer" { + array: IntArray +} +class "LongBuffer" { + array: LongArray +} +class "MemoryBuffer" { + memory: Memory + spec: MemorySpec +} +class "MutableMemoryBuffer" { + memory: Memory + spec: MemorySpec +} +class "ShortBuffer" { + array: ShortArray +} +class "ExpressionFieldTest" { + x +} +class "InterpretTest" { + +} +class "SimpleAutoDiffTest" { + x + y + z +} +class "DoubleLUSolverTest" { + +} +class "MatrixTest" { + +} +class "CumulativeKtTest" { + +} +class "BigIntAlgebraTest" { + +} +class "BigIntConstructorTest" { + +} +class "BigIntConversionsTest" { + +} +class "BigIntOperationsTest" { + +} +class "DoubleFieldTest" { + +} +class "NDFieldTest" { + +} +class "NumberNDFieldTest" { + algebra + array1 + array2 +} +class "L2Norm" { + norm() +} +interface "AlgebraicVerifier" { + algebra: A +} +class "FieldVerifier" { + algebra: A + a: T + b: T + c: T + x: Number +} +class "RingVerifier" { + algebra: A + a: T + b: T + c: T + x: Number +} +class "SpaceVerifier" { + algebra: S + a: T + b: T + c: T + x: Number +} +class "JBigIntegerField" { + zero: BigInteger + one: BigIntegernumber() + add() + minus() + multiply() + unaryMinus() +} +abstract "JBigDecimalFieldBase" { + mathContext: MathContext +} +class "JBigDecimalField" { + mathContext: MathContext +} +"ColumnarData" <|--- XYColumnarData +"XYColumnarData" <|--- XYErrorColumnarData +"XYColumnarData" <|--- XYZColumnarData +"Domain" <|--- DoubleDomain +"DoubleDomain" <|--- HyperSquareDomain +"DoubleDomain" <|--- UnconstrainedDomain +"DoubleDomain" <|--- UnivariateDomain +"Expression" <|--- DifferentiableExpression +"DifferentiableExpression" <|--- SpecialDifferentiableExpression +"DifferentiableExpression" <|--- FirstDerivativeExpression +"Algebra" <|--- ExpressionAlgebra +"ExpressionAlgebra" <|--- FunctionalExpressionAlgebra +"FunctionalExpressionAlgebra" <|--- FunctionalExpressionGroup +"Group" <|--- FunctionalExpressionGroup +"FunctionalExpressionGroup" <|--- FunctionalExpressionRing +"Ring" <|--- FunctionalExpressionRing +"FunctionalExpressionRing" <|--- FunctionalExpressionField +"Field" <|--- FunctionalExpressionField +"ScaleOperations" <|--- FunctionalExpressionField +"FunctionalExpressionField" <|--- FunctionalExpressionExtendedField +"ExtendedField" <|--- FunctionalExpressionExtendedField +"MST" <|--- Numeric +"MST" <|--- Unary +"MST" <|--- Binary +"NumericAlgebra" <|--- InnerAlgebra +"NumericAlgebra" <|--- MstNumericAlgebra +"Group" <|--- MstGroup +"NumericAlgebra" <|--- MstGroup +"ScaleOperations" <|--- MstGroup +"Ring" <|--- MstRing +"NumbersAddOperations" <|--- MstRing +"ScaleOperations" <|--- MstRing +"Field" <|--- MstField +"NumbersAddOperations" <|--- MstField +"ScaleOperations" <|--- MstField +"ExtendedField" <|--- MstExtendedField +"NumericAlgebra" <|--- MstExtendedField +"LogicAlgebra" <|--- MstLogicAlgebra +"Field" <|--- SimpleAutoDiffField +"ExpressionAlgebra" <|--- SimpleAutoDiffField +"NumbersAddOperations" <|--- SimpleAutoDiffField +"AutoDiffValue" <|--- AutoDiffVariableWithDerivative +"Symbol" <|--- AutoDiffVariableWithDerivative +"FirstDerivativeExpression" <|--- SimpleAutoDiffExpression +"ExtendedField" <|--- SimpleAutoDiffExtendedField +"ScaleOperations" <|--- SimpleAutoDiffExtendedField +'"" <|--- SimpleAutoDiffExtendedField +"SimpleAutoDiffField" <|--- SimpleAutoDiffExtendedField +"MST" <|--- Symbol +"Symbol" <|--- StringSymbol +"SymbolIndexer" <|--- SimpleSymbolIndexer +"LinearSpace" <|--- BufferedLinearSpace +"LupDecompositionFeature" <|--- LupDecomposition +"DeterminantFeature" <|--- LupDecomposition +"MatrixFeature" <|--- SymmetricMatrixFeature +"StructureFeature" <|--- MatrixFeature +"MatrixFeature" <|--- DiagonalFeature +"DiagonalFeature" <|--- ZeroFeature +"DiagonalFeature" <|--- UnitFeature +"MatrixFeature" <|--- InverseMatrixFeature +"MatrixFeature" <|--- DeterminantFeature +"MatrixFeature" <|--- LFeature +"MatrixFeature" <|--- UFeature +"MatrixFeature" <|--- LUDecompositionFeature +"MatrixFeature" <|--- LupDecompositionFeature +"MatrixFeature" <|--- OrthogonalFeature +"MatrixFeature" <|--- QRDecompositionFeature +"MatrixFeature" <|--- CholeskyDecompositionFeature +"MatrixFeature" <|--- SingularValueDecompositionFeature +'"Matrixbyorigin{ +' +' +' @UnstableKMathAPI +' @Suppress +'overridefungetFeature:F? = +'features.getFeature +' +'overridefuntoString" +'}" <|--- MatrixWrapper +"MatrixFeature" <|--- TransposedFeature +"Matrix" <|--- VirtualMatrix +"Featured" <|--- FeatureSet +"RuntimeException" <|--- ShapeMismatchException +"Group" <|--- GroupND +"AlgebraND" <|--- GroupND +"Ring" <|--- RingND +"GroupND" <|--- RingND +"Field" <|--- FieldND +"RingND" <|--- FieldND +"AlgebraND" <|--- BufferAlgebraND +"GroupND" <|--- BufferedGroupND +"BufferAlgebraND" <|--- BufferedGroupND +"BufferedGroupND" <|--- BufferedRingND +"RingND" <|--- BufferedRingND +"BufferedRingND" <|--- BufferedFieldND +"FieldND" <|--- BufferedFieldND +"StructureND" <|--- BufferND +"MutableStructureND" <|--- MutableBufferND +"BufferND" <|--- MutableBufferND +"BufferedFieldND" <|--- DoubleFieldND +'" +'" <|--- DoubleFieldND +'"NumbersAddOperations" <|--- DoubleFieldND +'" +'" <|--- DoubleFieldND +'"ScaleOperations" <|--- DoubleFieldND +'" +'" <|--- DoubleFieldND +"ExtendedField" <|--- DoubleFieldND +"BufferedRingND" <|--- ShortRingND +'" +'" <|--- ShortRingND +"NumbersAddOperations" <|--- ShortRingND +"StructureND" <|--- Structure1D +"Buffer" <|--- Structure1D +"Structure1D" <|--- MutableStructure1D +"MutableStructureND" <|--- MutableStructure1D +"MutableBuffer" <|--- MutableStructure1D +"Structure1D" <|--- Structure1DWrapper +"MutableStructure1D" <|--- MutableStructure1DWrapper +"Structure1D" <|--- Buffer1DWrapper +"MutableStructure1D" <|--- MutableBuffer1DWrapper +"StructureND" <|--- Structure2D +"Structure2D" <|--- MutableStructure2D +"MutableStructureND" <|--- MutableStructure2D +"Structure2D" <|--- Structure2DWrapper +"MutableStructure2D" <|--- MutableStructure2DWrapper +"Feature" <|--- StructureFeature +"Featured" <|--- StructureND +"StructureND" <|--- MutableStructureND +"Strides" <|--- DefaultStrides +"Algebra" <|--- GroupOperations +"GroupOperations" <|--- Group +"GroupOperations" <|--- RingOperations +"Group" <|--- Ring +"RingOperations" <|--- Ring +"RingOperations" <|--- FieldOperations +"Ring" <|--- Field +"FieldOperations" <|--- Field +"ScaleOperations" <|--- Field +"NumericAlgebra" <|--- Field +"AlgebraElement" <|--- GroupElement +"GroupElement" <|--- RingElement +"RingElement" <|--- FieldElement +"Field" <|--- BigIntField +"NumbersAddOperations" <|--- BigIntField +"ScaleOperations" <|--- BigIntField +"Comparable" <|--- BigInt +"Algebra" <|--- BufferAlgebra +"BufferAlgebra" <|--- BufferField +"Field" <|--- BufferField +"Algebra" <|--- LogicAlgebra +"LogicAlgebra" <|--- BooleanAlgebra +"FieldOperations" <|--- ExtendedFieldOperations +'" +'" <|--- ExtendedFieldOperations +'"TrigonometricOperations" <|--- ExtendedFieldOperations +'" +'" <|--- ExtendedFieldOperations +'"PowerOperations" <|--- ExtendedFieldOperations +'" +'" <|--- ExtendedFieldOperations +"ExponentialOperations" <|--- ExtendedFieldOperations +"ExtendedFieldOperations" <|--- ExtendedField +"Field" <|--- ExtendedField +"NumericAlgebra" <|--- ExtendedField +"ScaleOperations" <|--- ExtendedField +"ExtendedField" <|--- DoubleField +"Norm" <|--- DoubleField +"ScaleOperations" <|--- DoubleField +"ExtendedField" <|--- FloatField +"Norm" <|--- FloatField +"Ring" <|--- IntRing +"Norm" <|--- IntRing +"NumericAlgebra" <|--- IntRing +"Ring" <|--- ShortRing +"Norm" <|--- ShortRing +"NumericAlgebra" <|--- ShortRing +"Ring" <|--- ByteRing +"Norm" <|--- ByteRing +"NumericAlgebra" <|--- ByteRing +"Ring" <|--- LongRing +"Norm" <|--- LongRing +"NumericAlgebra" <|--- LongRing +"Algebra" <|--- NumericAlgebra +"Algebra" <|--- ScaleOperations +"Ring" <|--- NumbersAddOperations +"NumericAlgebra" <|--- NumbersAddOperations +"Algebra" <|--- TrigonometricOperations +"Algebra" <|--- PowerOperations +"Algebra" <|--- ExponentialOperations +"Buffer" <|--- MutableBuffer +"Buffer" <|--- ListBuffer +"MutableBuffer" <|--- MutableListBuffer +"MutableBuffer" <|--- ArrayBuffer +"Buffer" <|--- ReadOnlyBuffer +"Buffer" <|--- VirtualBuffer +"MutableBuffer" <|--- Row +"MutableBuffer" <|--- DoubleBuffer +"ExtendedFieldOperations" <|--- DoubleBufferFieldOperations +"Norm" <|--- DoubleL2Norm +"ExtendedField" <|--- DoubleBufferField +"Norm" <|--- DoubleBufferField +"Buffer" <|--- FlaggedBuffer +"FlaggedBuffer" <|--- FlaggedDoubleBuffer +'" +'" <|--- FlaggedDoubleBuffer +"Buffer" <|--- FlaggedDoubleBuffer +"MutableBuffer" <|--- FloatBuffer +"MutableBuffer" <|--- IntBuffer +"MutableBuffer" <|--- LongBuffer +"Buffer" <|--- MemoryBuffer +"MemoryBuffer" <|--- MutableMemoryBuffer +'" +'" <|--- MutableMemoryBuffer +"MutableBuffer" <|--- MutableMemoryBuffer +"MutableBuffer" <|--- ShortBuffer +"Norm" <|--- L2Norm +"RingVerifier" <|--- FieldVerifier +"SpaceVerifier" <|--- RingVerifier +"AlgebraicVerifier" <|--- SpaceVerifier +"Ring" <|--- JBigIntegerField +"NumericAlgebra" <|--- JBigIntegerField +"Field" <|--- JBigDecimalFieldBase +"PowerOperations" <|--- JBigDecimalFieldBase +"NumericAlgebra" <|--- JBigDecimalFieldBase +"ScaleOperations" <|--- JBigDecimalFieldBase +"JBigDecimalFieldBase" <|--- JBigDecimalField +@enduml \ 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 569a57070..d932fdb9f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -9,12 +9,12 @@ import space.kscience.kmath.integration.gaussIntegrator import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.nd +import space.kscience.kmath.nd.withNd import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke fun main(): Unit = DoubleField { - nd(2, 2) { + withNd(2, 2) { //Produce a diagonal StructureND fun diagonal(v: Double) = produce { (i, j) -> diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt index eefc6e896..8b511f961 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt @@ -6,18 +6,20 @@ package space.kscience.kmath.operations import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.complex -import space.kscience.kmath.nd.AlgebraND +import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.complex.withNd +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.autoNd fun main() { // 2d element - val element = AlgebraND.complex(2, 2).produce { (i, j) -> - Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble()) + val element = ComplexField.autoNd(2, 2).produce { (i, j) -> + Complex(i - j, i + j) } println(element) // 1d element operation - val result = with(AlgebraND.complex(8)) { + val result: StructureND = ComplexField.withNd(8) { val a = produce { (it) -> i * it - it.toDouble() } val b = 3 val c = Complex(1.0, 1.0) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt index 752e00bdf..c591f5682 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt @@ -9,10 +9,10 @@ package space.kscience.kmath.structures import space.kscience.kmath.complex.* import space.kscience.kmath.linear.transpose -import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as2D -import space.kscience.kmath.nd.real +import space.kscience.kmath.nd.nd +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import kotlin.system.measureTimeMillis @@ -20,8 +20,8 @@ fun main() { val dim = 1000 val n = 1000 - val realField = AlgebraND.real(dim, dim) - val complexField: ComplexFieldND = AlgebraND.complex(dim, dim) + val realField = DoubleField.nd(dim, dim) + val complexField: ComplexFieldND = ComplexField.nd(dim, dim) val realTime = measureTimeMillis { realField { @@ -49,7 +49,7 @@ fun main() { fun complexExample() { //Create a context for 2-d structure with complex values ComplexField { - nd(4, 8) { + withNd(4, 8) { //a constant real-valued structure val x = one * 2.5 operator fun Number.plus(other: Complex) = Complex(this.toDouble() + other.re, other.im) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt index c842960be..c9cafbba8 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -8,7 +8,9 @@ package space.kscience.kmath.structures import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import org.nd4j.linalg.factory.Nd4j -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.autoNd +import space.kscience.kmath.nd.nd import space.kscience.kmath.nd4j.Nd4jArrayField import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke @@ -31,17 +33,17 @@ fun main() { val n = 1000 // automatically build context most suited for given type. - val autoField = AlgebraND.auto(DoubleField, dim, dim) + val autoField = DoubleField.autoNd(dim, dim) // specialized nd-field for Double. It works as generic Double field as well. - val realField = AlgebraND.real(dim, dim) + val realField = DoubleField.nd(dim, dim) //A generic boxing field. It should be used for objects, not primitives. - val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) + val boxingField = DoubleField.nd(Buffer.Companion::boxing, dim, dim) // Nd4j specialized field. val nd4jField = Nd4jArrayField.real(dim, dim) //viktor field val viktorField = ViktorNDField(dim, dim) //parallel processing based on Java Streams - val parallelField = AlgebraND.realWithStream(dim, dim) + val parallelField = DoubleField.ndStreaming(dim, dim) measureAndPrint("Boxing addition") { boxingField { 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 e443a588d..b1248bd0f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -105,4 +105,4 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND): BufferND = arg.map { atanh(it) } } -fun AlgebraND.Companion.realWithStream(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(shape) +fun DoubleField.ndStreaming(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(shape) diff --git a/gradle.properties b/gradle.properties index b97db1c54..49bbf36dd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,6 +7,8 @@ kotlin.code.style=official kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.mpp.stability.nowarn=true kotlin.native.enableDependencyPropagation=false +kotlin.jupyter.add.scanner=false + org.gradle.configureondemand=true org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G org.gradle.parallel=true 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 ae4e05631..41bcb83df 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 @@ -6,7 +6,6 @@ package space.kscience.kmath.complex import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.BufferND import space.kscience.kmath.nd.BufferedFieldND import space.kscience.kmath.nd.StructureND @@ -113,12 +112,12 @@ public inline fun BufferedFieldND.produceInline(initializ } -public fun AlgebraND.Companion.complex(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape) +public fun ComplexField.nd(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape) /** * Produce a context for n-dimensional operations inside this real field */ -public inline fun ComplexField.nd(vararg shape: Int, action: ComplexFieldND.() -> R): R { +public inline fun ComplexField.withNd(vararg shape: Int, action: ComplexFieldND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return ComplexFieldND(shape).action() } diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 564d06f49..e4436c1df 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -2,6 +2,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") id("ru.mipt.npm.gradle.native") +// id("com.xcporter.metaview") version "0.0.5" } kotlin.sourceSets { @@ -12,6 +13,12 @@ kotlin.sourceSets { } } +//generateUml { +// classTree { +// +// } +//} + readme { description = "Core classes, algebra definitions, basic linear algebra" maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT 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 5471cb925..14235515c 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 @@ -6,7 +6,10 @@ package space.kscience.kmath.linear import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.BufferedRingND +import space.kscience.kmath.nd.as2D +import space.kscience.kmath.nd.nd +import space.kscience.kmath.nd.unwrap import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer @@ -23,7 +26,7 @@ public class BufferedLinearSpace>( private fun ndRing( rows: Int, cols: Int, - ): BufferedRingND = AlgebraND.ring(elementAlgebra, bufferFactory, rows, cols) + ): BufferedRingND = elementAlgebra.nd(bufferFactory, rows, cols) override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix = ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() 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 9ece51ff8..b01beb02d 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 @@ -5,11 +5,13 @@ package space.kscience.kmath.nd +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import kotlin.contracts.InvocationKind import kotlin.contracts.contract +import kotlin.jvm.JvmName public interface BufferAlgebraND> : AlgebraND { public val strides: Strides @@ -85,58 +87,61 @@ public open class BufferedFieldND>( } // group factories -public fun > AlgebraND.Companion.group( - space: A, +public fun > A.nd( bufferFactory: BufferFactory, vararg shape: Int, -): BufferedGroupND = BufferedGroupND(shape, space, bufferFactory) +): BufferedGroupND = BufferedGroupND(shape, this, bufferFactory) -public inline fun , R> A.ndGroup( +@JvmName("withNdGroup") +public inline fun , R> A.withNd( noinline bufferFactory: BufferFactory, vararg shape: Int, action: BufferedGroupND.() -> R, ): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return AlgebraND.group(this, bufferFactory, *shape).run(action) + return nd(bufferFactory, *shape).run(action) } //ring factories -public fun > AlgebraND.Companion.ring( - ring: A, +public fun > A.nd( bufferFactory: BufferFactory, vararg shape: Int, -): BufferedRingND = BufferedRingND(shape, ring, bufferFactory) +): BufferedRingND = BufferedRingND(shape, this, bufferFactory) -public inline fun , R> A.ndRing( +@JvmName("withNdRing") +public inline fun , R> A.withNd( noinline bufferFactory: BufferFactory, vararg shape: Int, action: BufferedRingND.() -> R, ): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return AlgebraND.ring(this, bufferFactory, *shape).run(action) + return nd(bufferFactory, *shape).run(action) } //field factories -public fun > AlgebraND.Companion.field( - field: A, +public fun > A.nd( bufferFactory: BufferFactory, vararg shape: Int, -): BufferedFieldND = BufferedFieldND(shape, field, bufferFactory) +): BufferedFieldND = BufferedFieldND(shape, this, bufferFactory) +/** + * Create a [FieldND] for this [Field] inferring proper buffer factory from the type + */ +@UnstableKMathAPI @Suppress("UNCHECKED_CAST") -public inline fun > AlgebraND.Companion.auto( - field: A, +public inline fun > A.autoNd( vararg shape: Int, -): FieldND = when (field) { +): FieldND = when (this) { DoubleField -> DoubleFieldND(shape) as FieldND - else -> BufferedFieldND(shape, field, Buffer.Companion::auto) + else -> BufferedFieldND(shape, this, Buffer.Companion::auto) } -public inline fun , R> A.ndField( +@JvmName("withNdField") +public inline fun , R> A.withNd( noinline bufferFactory: BufferFactory, vararg shape: Int, action: BufferedFieldND.() -> R, ): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return AlgebraND.field(this, bufferFactory, *shape).run(action) + return nd(bufferFactory, *shape).run(action) } \ No newline at end of file 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 a448e351e..fed4aca0b 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 @@ -103,12 +103,12 @@ public class DoubleFieldND( override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } } -public fun AlgebraND.Companion.real(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) +public fun DoubleField.nd(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) /** * Produce a context for n-dimensional operations inside this real field */ -public inline fun DoubleField.nd(vararg shape: Int, action: DoubleFieldND.() -> R): R { +public inline fun DoubleField.withNd(vararg shape: Int, action: DoubleFieldND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return DoubleFieldND(shape).run(action) } 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 f96978cfc..5b6e2cd22 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 @@ -34,7 +34,7 @@ public class ShortRingND( public inline fun BufferedRingND.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND = BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) -public inline fun ShortRing.nd(vararg shape: Int, action: ShortRingND.() -> R): R { +public inline fun ShortRing.withNd(vararg shape: Int, action: ShortRingND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return ShortRingND(shape).run(action) } 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 2dd61270d..02741e6ab 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 @@ -6,7 +6,6 @@ package space.kscience.kmath.operations import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.BufferedRingND import space.kscience.kmath.operations.BigInt.Companion.BASE import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE @@ -533,5 +532,5 @@ public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigIn public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer = boxing(size, initializer) -public fun AlgebraND.Companion.bigInt(vararg shape: Int): BufferedRingND = +public fun BigIntField.nd(vararg shape: Int): BufferedRingND = BufferedRingND(shape, BigIntField, Buffer.Companion::bigInt) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt index f623b00e8..6d4531f41 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt @@ -5,9 +5,9 @@ package space.kscience.kmath.structures -import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.real +import space.kscience.kmath.nd.nd +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import space.kscience.kmath.testutils.FieldVerifier import kotlin.test.Test @@ -16,12 +16,12 @@ import kotlin.test.assertEquals internal class NDFieldTest { @Test fun verify() { - (AlgebraND.real(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } + (DoubleField.nd(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } } @Test fun testStrides() { - val ndArray = AlgebraND.real(10, 10).produce { (it[0] + it[1]).toDouble() } + val ndArray = DoubleField.nd(10, 10).produce { (it[0] + it[1]).toDouble() } assertEquals(ndArray[5, 5], 10.0) } } 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 1803fff71..1045933b7 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 @@ -7,7 +7,11 @@ package space.kscience.kmath.structures 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.combine +import space.kscience.kmath.nd.get +import space.kscience.kmath.nd.nd +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.invoke import kotlin.math.abs @@ -17,7 +21,7 @@ import kotlin.test.assertEquals @Suppress("UNUSED_VARIABLE") class NumberNDFieldTest { - val algebra = AlgebraND.real(3, 3) + val algebra = DoubleField.nd(3, 3) val array1 = algebra.produce { (i, j) -> (i + j).toDouble() } val array2 = algebra.produce { (i, j) -> (i - j).toDouble() } @@ -83,7 +87,7 @@ class NumberNDFieldTest { @Test fun testInternalContext() { algebra { - (AlgebraND.real(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } } + (DoubleField.nd(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } } } } } diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt index 27b14b65e..37ab8a1b2 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt @@ -9,6 +9,7 @@ import space.kscience.kmath.domains.Domain import space.kscience.kmath.domains.HyperSquareDomain import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.* import kotlin.math.floor @@ -28,7 +29,7 @@ public class DoubleHistogramSpace( public val dimension: Int get() = lower.size private val shape = IntArray(binNums.size) { binNums[it] + 2 } - override val histogramValueSpace: DoubleFieldND = AlgebraND.real(*shape) + override val histogramValueSpace: DoubleFieldND = DoubleField.nd(*shape) override val strides: Strides get() = histogramValueSpace.strides private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] } 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 d7438bf0f..e646d2bd0 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 @@ -11,7 +11,6 @@ import kotlinx.html.stream.createHTML import kotlinx.html.unsafe import org.jetbrains.kotlinx.jupyter.api.DisplayResult import org.jetbrains.kotlinx.jupyter.api.HTML -import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer 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 4fe8520da..00df0944f 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 @@ -16,6 +16,14 @@ import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.DoubleL2Norm +public class QowRuns(public val runs: Int) : OptimizationFeature { + init { + require(runs >= 1) { "Number of runs must be more than zero" } + } + + override fun toString(): String = "QowRuns(runs=$runs)" +} + /** * An optimizer based onf Fyodor Tkachev's quasi-optimal weights method. @@ -56,7 +64,7 @@ public object QowOptimizer : Optimizer { val prior: DifferentiableExpression? get() = problem.getFeature>() - override fun toString(): String = parameters.toString() + override fun toString(): String = parameters.toString() } /** @@ -242,9 +250,15 @@ public object QowOptimizer : Optimizer { } override suspend fun optimize(problem: XYFit): XYFit { - val qowSteps = 2 - val initialWeight = QoWeight(problem, problem.startPoint) - val res = initialWeight.newtonianRun() + val qowRuns = problem.getFeature()?.runs ?: 2 + + + var qow = QoWeight(problem, problem.startPoint) + var res = qow.newtonianRun() + repeat(qowRuns - 1) { + qow = QoWeight(problem, res.parameters) + res = qow.newtonianRun() + } return res.problem.withFeature(OptimizationResult(res.parameters)) } } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index d1cbbe74c..0fc77b38e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,11 +5,11 @@ pluginManagement { gradlePluginPortal() } - val kotlinVersion = "1.5.21" + val kotlinVersion = "1.5.30" plugins { id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - id("ru.mipt.npm.gradle.project") version "0.10.2" + id("ru.mipt.npm.gradle.project") version "0.10.3" kotlin("multiplatform") version kotlinVersion kotlin("plugin.allopen") version kotlinVersion } -- 2.34.1 From 546d56aeee3615d66fcbfda22d7e27329eb711ca Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 19 Sep 2021 21:13:07 +0300 Subject: [PATCH 017/102] Refactor buffer builders to suit new discoverability pattern --- CHANGELOG.md | 1 + .../space/kscience/kmath/operations/ComplexDemo.kt | 4 ++-- .../kotlin/space/kscience/kmath/complex/Complex.kt | 2 ++ .../kotlin/space/kscience/kmath/operations/BigInt.kt | 10 ++++++++++ .../space/kscience/kmath/operations/numbers.kt | 12 ++++++++++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec3f5252a..19b7dae32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - Rename `DifferentiableMstExpression` to `KotlingradExpression` - `FeatureSet` now accepts only `Feature`. It is possible to override keys and use interfaces. - Use `Symbol` factory function instead of `StringSymbol` +- New discoverability pattern: `.algebra.` ### Deprecated - Specialized `DoubleBufferAlgebra` diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt index 8b511f961..743f05b13 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt @@ -7,13 +7,13 @@ package space.kscience.kmath.operations import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.complex.nd import space.kscience.kmath.complex.withNd import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.autoNd fun main() { // 2d element - val element = ComplexField.autoNd(2, 2).produce { (i, j) -> + val element = ComplexField.nd(2, 2).produce { (i, j) -> Complex(i - j, i + j) } println(element) 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 08bd12205..793587492 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 @@ -203,6 +203,8 @@ public data class Complex(val re: Double, val im: Double) { } } +public val Complex.Companion.algebra: ComplexField get() = ComplexField + /** * Creates a complex number with real part equal to this real. 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 02741e6ab..9797027c7 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 @@ -526,11 +526,21 @@ public fun String.parseBigInteger(): BigInt? { } } +public val BigInt.algebra: BigIntField get() = BigIntField + +@Deprecated("Use BigInt::buffer") public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer = boxing(size, initializer) +public inline fun BigInt.buffer(size: Int, initializer: (Int) -> BigInt): Buffer = + Buffer.boxing(size, initializer) + +@Deprecated("Use BigInt::mutableBuffer") public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer = boxing(size, initializer) +public inline fun BigInt.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer = + Buffer.boxing(size, initializer) + public fun BigIntField.nd(vararg shape: Int): BufferedRingND = BufferedRingND(shape, BigIntField, Buffer.Companion::bigInt) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index e75d815cf..c90553aaa 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -107,6 +107,8 @@ public object DoubleField : ExtendedField, Norm, ScaleOp override inline fun Double.div(b: Double): Double = this / b } +public val Double.Companion.algebra: DoubleField get() = DoubleField + /** * A field for [Float] without boxing. Does not produce appropriate field element. */ @@ -158,6 +160,8 @@ public object FloatField : ExtendedField, Norm { override inline fun Float.div(b: Float): Float = this / b } +public val Float.Companion.algebra: FloatField get() = FloatField + /** * A field for [Int] without boxing. Does not produce corresponding ring element. */ @@ -180,6 +184,8 @@ public object IntRing : Ring, Norm, NumericAlgebra { override inline fun Int.times(b: Int): Int = this * b } +public val Int.Companion.algebra: IntRing get() = IntRing + /** * A field for [Short] without boxing. Does not produce appropriate ring element. */ @@ -202,6 +208,8 @@ public object ShortRing : Ring, Norm, NumericAlgebra override inline fun Short.times(b: Short): Short = (this * b).toShort() } +public val Short.Companion.algebra: ShortRing get() = ShortRing + /** * A field for [Byte] without boxing. Does not produce appropriate ring element. */ @@ -224,6 +232,8 @@ public object ByteRing : Ring, Norm, NumericAlgebra { override inline fun Byte.times(b: Byte): Byte = (this * b).toByte() } +public val Byte.Companion.algebra: ByteRing get() = ByteRing + /** * A field for [Double] without boxing. Does not produce appropriate ring element. */ @@ -245,3 +255,5 @@ public object LongRing : Ring, Norm, NumericAlgebra { override inline fun Long.minus(b: Long): Long = (this - b) override inline fun Long.times(b: Long): Long = (this * b) } + +public val Long.Companion.algebra: LongRing get() = LongRing -- 2.34.1 From 9fcc1b3af27ad348b44d6fc073d9cef832f7786b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 19 Sep 2021 21:17:26 +0300 Subject: [PATCH 018/102] Split Buffer.kt for better readability --- .../kscience/kmath/structures/ArrayBuffer.kt | 32 ++++ .../space/kscience/kmath/structures/Buffer.kt | 164 ------------------ .../kscience/kmath/structures/ListBuffer.kt | 58 +++++++ .../kmath/structures/MutableBuffer.kt | 97 +++++++++++ 4 files changed, 187 insertions(+), 164 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt new file mode 100644 index 000000000..d49f70355 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.structures + +/** + * [MutableBuffer] implementation over [Array]. + * + * @param T the type of elements contained in the buffer. + * @property array The underlying array. + */ +public class ArrayBuffer(internal val array: Array) : MutableBuffer { + // Can't inline because array is invariant + override val size: Int get() = array.size + + override operator fun get(index: Int): T = array[index] + + override operator fun set(index: Int, value: T) { + array[index] = value + } + + override operator fun iterator(): Iterator = array.iterator() + override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf()) +} + + +/** + * Returns an [ArrayBuffer] that wraps the original array. + */ +public fun Array.asBuffer(): ArrayBuffer = ArrayBuffer(this) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index 6a97d18c2..c22a4ba39 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -98,170 +98,6 @@ public interface Buffer { */ public val Buffer<*>.indices: IntRange get() = 0 until size -/** - * A generic mutable random-access structure for both primitives and objects. - * - * @param T the type of elements contained in the buffer. - */ -public interface MutableBuffer : Buffer { - /** - * Sets the array element at the specified [index] to the specified [value]. - */ - public operator fun set(index: Int, value: T) - - /** - * Returns a shallow copy of the buffer. - */ - public fun copy(): MutableBuffer - - public companion object { - /** - * Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer = - DoubleBuffer(size, initializer) - - /** - * Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer = - ShortBuffer(size, initializer) - - /** - * Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer = - IntBuffer(size, initializer) - - /** - * Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer = - LongBuffer(size, initializer) - - - /** - * Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer = - FloatBuffer(size, initializer) - - - /** - * Create a boxing mutable buffer of given type - */ - public inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = - MutableListBuffer(MutableList(size, initializer)) - - /** - * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used - * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer = - when (type) { - Double::class -> double(size) { initializer(it) as Double } as MutableBuffer - Short::class -> short(size) { initializer(it) as Short } as MutableBuffer - Int::class -> int(size) { initializer(it) as Int } as MutableBuffer - Float::class -> float(size) { initializer(it) as Float } as MutableBuffer - Long::class -> long(size) { initializer(it) as Long } as MutableBuffer - else -> boxing(size, initializer) - } - - /** - * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used - * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = - auto(T::class, size, initializer) - } -} - -/** - * [Buffer] implementation over [List]. - * - * @param T the type of elements contained in the buffer. - * @property list The underlying list. - */ -public class ListBuffer(public val list: List) : Buffer { - - public constructor(size: Int, initializer: (Int) -> T) : this(List(size, initializer)) - - override val size: Int get() = list.size - - override operator fun get(index: Int): T = list[index] - override operator fun iterator(): Iterator = list.iterator() -} - -/** - * Returns an [ListBuffer] that wraps the original list. - */ -public fun List.asBuffer(): ListBuffer = ListBuffer(this) - -/** - * [MutableBuffer] implementation over [MutableList]. - * - * @param T the type of elements contained in the buffer. - * @property list The underlying list. - */ -@JvmInline -public value class MutableListBuffer(public val list: MutableList) : MutableBuffer { - - public constructor(size: Int, initializer: (Int) -> T) : this(MutableList(size, initializer)) - - override val size: Int get() = list.size - - override operator fun get(index: Int): T = list[index] - - override operator fun set(index: Int, value: T) { - list[index] = value - } - - override operator fun iterator(): Iterator = list.iterator() - override fun copy(): MutableBuffer = MutableListBuffer(ArrayList(list)) -} - -/** - * Returns an [MutableListBuffer] that wraps the original list. - */ -public fun MutableList.asMutableBuffer(): MutableListBuffer = MutableListBuffer(this) - -/** - * [MutableBuffer] implementation over [Array]. - * - * @param T the type of elements contained in the buffer. - * @property array The underlying array. - */ -public class ArrayBuffer(internal val array: Array) : MutableBuffer { - // Can't inline because array is invariant - override val size: Int get() = array.size - - override operator fun get(index: Int): T = array[index] - - override operator fun set(index: Int, value: T) { - array[index] = value - } - - override operator fun iterator(): Iterator = array.iterator() - override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf()) -} - - -/** - * Returns an [ArrayBuffer] that wraps the original array. - */ -public fun Array.asBuffer(): ArrayBuffer = ArrayBuffer(this) - /** * Immutable wrapper for [MutableBuffer]. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt new file mode 100644 index 000000000..fdba68d19 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.structures + +import kotlin.jvm.JvmInline + +/** + * [Buffer] implementation over [List]. + * + * @param T the type of elements contained in the buffer. + * @property list The underlying list. + */ +public class ListBuffer(public val list: List) : Buffer { + + public constructor(size: Int, initializer: (Int) -> T) : this(List(size, initializer)) + + override val size: Int get() = list.size + + override operator fun get(index: Int): T = list[index] + override operator fun iterator(): Iterator = list.iterator() +} + + +/** + * Returns an [ListBuffer] that wraps the original list. + */ +public fun List.asBuffer(): ListBuffer = ListBuffer(this) + +/** + * [MutableBuffer] implementation over [MutableList]. + * + * @param T the type of elements contained in the buffer. + * @property list The underlying list. + */ +@JvmInline +public value class MutableListBuffer(public val list: MutableList) : MutableBuffer { + + public constructor(size: Int, initializer: (Int) -> T) : this(MutableList(size, initializer)) + + override val size: Int get() = list.size + + override operator fun get(index: Int): T = list[index] + + override operator fun set(index: Int, value: T) { + list[index] = value + } + + override operator fun iterator(): Iterator = list.iterator() + override fun copy(): MutableBuffer = MutableListBuffer(ArrayList(list)) +} + +/** + * Returns an [MutableListBuffer] that wraps the original list. + */ +public fun MutableList.asMutableBuffer(): MutableListBuffer = MutableListBuffer(this) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt new file mode 100644 index 000000000..97185b918 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt @@ -0,0 +1,97 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.structures + +import kotlin.reflect.KClass + +/** + * A generic mutable random-access structure for both primitives and objects. + * + * @param T the type of elements contained in the buffer. + */ +public interface MutableBuffer : Buffer { + /** + * Sets the array element at the specified [index] to the specified [value]. + */ + public operator fun set(index: Int, value: T) + + /** + * Returns a shallow copy of the buffer. + */ + public fun copy(): MutableBuffer + + public companion object { + /** + * Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer = + DoubleBuffer(size, initializer) + + /** + * Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer = + ShortBuffer(size, initializer) + + /** + * Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer = + IntBuffer(size, initializer) + + /** + * Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer = + LongBuffer(size, initializer) + + + /** + * Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer = + FloatBuffer(size, initializer) + + + /** + * Create a boxing mutable buffer of given type + */ + public inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = + MutableListBuffer(MutableList(size, initializer)) + + /** + * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used + * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. + * + * The [size] is specified, and each element is calculated by calling the specified [initializer] function. + */ + @Suppress("UNCHECKED_CAST") + public inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer = + when (type) { + Double::class -> double(size) { initializer(it) as Double } as MutableBuffer + Short::class -> short(size) { initializer(it) as Short } as MutableBuffer + Int::class -> int(size) { initializer(it) as Int } as MutableBuffer + Float::class -> float(size) { initializer(it) as Float } as MutableBuffer + Long::class -> long(size) { initializer(it) as Long } as MutableBuffer + else -> boxing(size, initializer) + } + + /** + * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used + * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. + * + * The [size] is specified, and each element is calculated by calling the specified [initializer] function. + */ + @Suppress("UNCHECKED_CAST") + public inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = + auto(T::class, size, initializer) + } +} \ No newline at end of file -- 2.34.1 From 89eebbecb76280586f39646bc08cf6a6975bdae7 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 21 Sep 2021 21:24:27 +0300 Subject: [PATCH 019/102] Fix EJML inversion issue --- CHANGELOG.md | 1 + benchmarks/build.gradle.kts | 10 +++++ .../kscience/kmath/benchmarks/DotBenchmark.kt | 11 +++-- .../benchmarks/MatrixInverseBenchmark.kt | 15 ++++--- .../kmath/benchmarks/NDFieldBenchmark.kt | 10 +++-- .../kmath/benchmarks/ViktorBenchmark.kt | 8 ++-- .../kmath/benchmarks/ViktorLogBenchmark.kt | 8 ++-- .../kmath/functions/matrixIntegration.kt | 8 ++-- .../kscience/kmath/operations/ComplexDemo.kt | 31 -------------- .../kscience/kmath/operations/complexDemo.kt | 41 +++++++++++++++++++ .../kscience/kmath/structures/ComplexND.kt | 8 ++-- .../kscience/kmath/structures/NDField.kt | 10 ++--- .../kscience/kmath/structures/buffers.kt | 4 +- .../kscience/kmath/commons/linear/CMMatrix.kt | 6 ++- .../kscience/kmath/commons/linear/CMSolver.kt | 12 +++--- .../kscience/kmath/complex/ComplexFieldND.kt | 9 +++- .../kmath/linear/BufferedLinearSpace.kt | 19 +++++---- .../kscience/kmath/linear/LinearSpace.kt | 21 ++++++---- .../kscience/kmath/linear/LupDecomposition.kt | 6 +-- .../kscience/kmath/linear/MatrixWrapper.kt | 9 ++-- .../kscience/kmath/nd/BufferAlgebraND.kt | 20 ++++----- .../space/kscience/kmath/nd/DoubleFieldND.kt | 4 +- .../space/kscience/kmath/nd/ShortRingND.kt | 2 +- .../space/kscience/kmath/nd/Structure1D.kt | 6 ++- .../space/kscience/kmath/nd/Structure2D.kt | 2 - .../space/kscience/kmath/nd/StructureND.kt | 23 +++++++++-- .../kmath/operations/BufferAlgebra.kt | 24 +++++++---- .../kscience/kmath/structures/ArrayBuffer.kt | 2 + .../space/kscience/kmath/structures/Buffer.kt | 7 ++++ .../kmath/structures/BufferAccessor2D.kt | 2 + .../kmath/structures/FlaggedBuffer.kt | 8 +++- .../kscience/kmath/structures/ListBuffer.kt | 2 + .../kscience/kmath/structures/MemoryBuffer.kt | 2 + .../kscience/kmath/structures/NDFieldTest.kt | 6 +-- .../kmath/structures/NumberNDFieldTest.kt | 6 +-- .../kscience/kmath/streaming/RingBuffer.kt | 2 + .../kscience/kmath/ejml/EjmlLinearSpace.kt | 6 +++ .../kscience/kmath/ejml/EjmlMatrixTest.kt | 25 +++++++++-- .../space/kscience/kmath/real/RealMatrix.kt | 37 +++++++++-------- .../kotlin/space/kscience/kmath/real/dot.kt | 5 ++- .../kmath/integration/SplineIntegrator.kt | 2 + .../kmath/histogram/DoubleHistogramSpace.kt | 2 +- .../kscience/kmath/viktor/ViktorBuffer.kt | 6 ++- 43 files changed, 284 insertions(+), 164 deletions(-) delete mode 100644 examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt create mode 100644 examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 19b7dae32..c27dafeb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ - `FeatureSet` now accepts only `Feature`. It is possible to override keys and use interfaces. - Use `Symbol` factory function instead of `StringSymbol` - New discoverability pattern: `.algebra.` +- Adjusted commons-math API for linear solvers to match conventions. ### Deprecated - Specialized `DoubleBufferAlgebra` diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index d96c5a8b6..fa72dc8ee 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -105,6 +105,16 @@ benchmark { commonConfiguration() include("JafamaBenchmark") } + + configurations.register("viktor") { + commonConfiguration() + include("ViktorBenchmark") + } + + configurations.register("viktorLog") { + commonConfiguration() + include("ViktorLogBenchmark") + } } // Fix kotlinx-benchmarks bug diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 7806cd06c..6373d1ce5 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -13,7 +13,10 @@ import space.kscience.kmath.commons.linear.CMLinearSpace import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.invoke +import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.structures.Buffer import kotlin.random.Random @State(Scope.Benchmark) @@ -35,7 +38,7 @@ internal class DotBenchmark { @Benchmark fun cmDot(blackhole: Blackhole) { - CMLinearSpace.run { + CMLinearSpace { blackhole.consume(cmMatrix1 dot cmMatrix2) } } @@ -56,14 +59,14 @@ internal class DotBenchmark { @Benchmark fun bufferedDot(blackhole: Blackhole) { - LinearSpace.auto(DoubleField).invoke { + with(DoubleField.linearSpace(Buffer.Companion::auto)) { blackhole.consume(matrix1 dot matrix2) } } @Benchmark - fun realDot(blackhole: Blackhole) { - LinearSpace.double { + fun doubleDot(blackhole: Blackhole) { + with(Double.algebra.linearSpace) { blackhole.consume(matrix1 dot matrix2) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt index 21d7ca41c..5d331af9a 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt @@ -10,13 +10,12 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import space.kscience.kmath.commons.linear.CMLinearSpace -import space.kscience.kmath.commons.linear.inverse +import space.kscience.kmath.commons.linear.lupSolver import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM -import space.kscience.kmath.linear.InverseMatrixFeature -import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.invoke +import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.lupSolver -import space.kscience.kmath.nd.getFeature +import space.kscience.kmath.operations.algebra import kotlin.random.Random @State(Scope.Benchmark) @@ -25,7 +24,7 @@ internal class MatrixInverseBenchmark { private val random = Random(1224) private const val dim = 100 - private val space = LinearSpace.double + private val space = Double.algebra.linearSpace //creating invertible matrix private val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } @@ -35,20 +34,20 @@ internal class MatrixInverseBenchmark { @Benchmark fun kmathLupInversion(blackhole: Blackhole) { - blackhole.consume(LinearSpace.double.lupSolver().inverse(matrix)) + blackhole.consume(Double.algebra.linearSpace.lupSolver().inverse(matrix)) } @Benchmark fun cmLUPInversion(blackhole: Blackhole) { CMLinearSpace { - blackhole.consume(inverse(matrix)) + blackhole.consume(lupSolver().inverse(matrix)) } } @Benchmark fun ejmlInverse(blackhole: Blackhole) { EjmlLinearSpaceDDRM { - blackhole.consume(matrix.getFeature>()?.inverse) + blackhole.consume(matrix.toEjml().inverse()) } } } 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 fbf4bdaba..f72bc3ba0 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -9,7 +9,9 @@ import kotlinx.benchmark.Benchmark import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.autoNdAlgebra +import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.Buffer @@ -46,8 +48,8 @@ internal class NDFieldBenchmark { private companion object { private const val dim = 1000 private const val n = 100 - private val autoField = DoubleField.autoNd(dim, dim) - private val specializedField = DoubleField.nd(dim, dim) - private val genericField = DoubleField.nd(Buffer.Companion::boxing, dim, dim) + private val autoField = DoubleField.autoNdAlgebra(dim, dim) + private val specializedField = DoubleField.ndAlgebra(dim, dim) + private val genericField = DoubleField.ndAlgebra(Buffer.Companion::boxing, dim, dim) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index 6ea64ba3c..b97a05a52 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -11,8 +11,8 @@ import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.autoNd -import space.kscience.kmath.nd.nd +import space.kscience.kmath.nd.autoNdAlgebra +import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.viktor.ViktorNDField @@ -58,8 +58,8 @@ internal class ViktorBenchmark { private const val n = 100 // automatically build context most suited for given type. - private val autoField = DoubleField.autoNd(dim, dim) - private val realField = DoubleField.nd(dim, dim) + private val autoField = DoubleField.autoNdAlgebra(dim, dim) + private val realField = DoubleField.ndAlgebra(dim, dim) private val viktorField = ViktorNDField(dim, dim) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index afe44ea99..91e9dcd76 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -10,8 +10,8 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.autoNd -import space.kscience.kmath.nd.nd +import space.kscience.kmath.nd.autoNdAlgebra +import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.viktor.ViktorFieldND @@ -50,8 +50,8 @@ internal class ViktorLogBenchmark { private const val n = 100 // automatically build context most suited for given type. - private val autoField = DoubleField.autoNd(dim, dim) - private val realNdField = DoubleField.nd(dim, dim) + private val autoField = DoubleField.autoNdAlgebra(dim, dim) + private val realNdField = DoubleField.ndAlgebra(dim, dim) private val viktorField = ViktorFieldND(intArrayOf(dim, dim)) } } 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 d932fdb9f..93b5671fe 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -9,12 +9,12 @@ import space.kscience.kmath.integration.gaussIntegrator import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.withNd -import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.nd.withNdAlgebra +import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.invoke -fun main(): Unit = DoubleField { - withNd(2, 2) { +fun main(): Unit = Double.algebra { + withNdAlgebra(2, 2) { //Produce a diagonal StructureND fun diagonal(v: Double) = produce { (i, j) -> diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt deleted file mode 100644 index 743f05b13..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.ComplexField -import space.kscience.kmath.complex.nd -import space.kscience.kmath.complex.withNd -import space.kscience.kmath.nd.StructureND - -fun main() { - // 2d element - val element = ComplexField.nd(2, 2).produce { (i, j) -> - Complex(i - j, i + j) - } - println(element) - - // 1d element operation - val result: StructureND = ComplexField.withNd(8) { - val a = produce { (it) -> i * it - it.toDouble() } - val b = 3 - val c = Complex(1.0, 1.0) - - (a pow b) + c - } - - println(result) -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt new file mode 100644 index 000000000..319221bcc --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.operations + +import space.kscience.kmath.complex.Complex +import space.kscience.kmath.complex.algebra +import space.kscience.kmath.complex.bufferAlgebra +import space.kscience.kmath.complex.ndAlgebra +import space.kscience.kmath.nd.BufferND +import space.kscience.kmath.nd.StructureND + +fun main() = Complex.algebra { + val complex = 2 + 2 * i + println(complex * 8 - 5 * i) + + //flat buffer + val buffer = bufferAlgebra(8).run { + buffer { Complex(it, -it) }.map { Complex(it.im, it.re) } + } + println(buffer) + + + // 2d element + val element: BufferND = ndAlgebra(2, 2).produce { (i, j) -> + Complex(i - j, i + j) + } + println(element) + + // 1d element operation + val result: StructureND = ndAlgebra(8).run { + val a = produce { (it) -> i * it - it.toDouble() } + val b = 3 + val c = Complex(1.0, 1.0) + + (a pow b) + c + } + println(result) +} diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt index c591f5682..d4554b3ba 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt @@ -11,7 +11,7 @@ import space.kscience.kmath.complex.* import space.kscience.kmath.linear.transpose import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as2D -import space.kscience.kmath.nd.nd +import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import kotlin.system.measureTimeMillis @@ -20,8 +20,8 @@ fun main() { val dim = 1000 val n = 1000 - val realField = DoubleField.nd(dim, dim) - val complexField: ComplexFieldND = ComplexField.nd(dim, dim) + val realField = DoubleField.ndAlgebra(dim, dim) + val complexField: ComplexFieldND = ComplexField.ndAlgebra(dim, dim) val realTime = measureTimeMillis { realField { @@ -49,7 +49,7 @@ fun main() { fun complexExample() { //Create a context for 2-d structure with complex values ComplexField { - withNd(4, 8) { + withNdAlgebra(4, 8) { //a constant real-valued structure val x = one * 2.5 operator fun Number.plus(other: Complex) = Complex(this.toDouble() + other.re, other.im) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt index c9cafbba8..5b0e2eb30 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -9,8 +9,8 @@ import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import org.nd4j.linalg.factory.Nd4j import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.autoNd -import space.kscience.kmath.nd.nd +import space.kscience.kmath.nd.autoNdAlgebra +import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd4j.Nd4jArrayField import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke @@ -33,11 +33,11 @@ fun main() { val n = 1000 // automatically build context most suited for given type. - val autoField = DoubleField.autoNd(dim, dim) + val autoField = DoubleField.autoNdAlgebra(dim, dim) // specialized nd-field for Double. It works as generic Double field as well. - val realField = DoubleField.nd(dim, dim) + val realField = DoubleField.ndAlgebra(dim, dim) //A generic boxing field. It should be used for objects, not primitives. - val boxingField = DoubleField.nd(Buffer.Companion::boxing, dim, dim) + val boxingField = DoubleField.ndAlgebra(Buffer.Companion::boxing, dim, dim) // Nd4j specialized field. val nd4jField = Nd4jArrayField.real(dim, dim) //viktor field diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt index 0f7fdc46a..d78141507 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt @@ -6,8 +6,8 @@ package space.kscience.kmath.structures import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.buffer import space.kscience.kmath.operations.bufferAlgebra -import space.kscience.kmath.operations.produce inline fun MutableBuffer.Companion.same( n: Int, @@ -17,6 +17,6 @@ inline fun MutableBuffer.Companion.same( fun main() { with(DoubleField.bufferAlgebra(5)) { - println(number(2.0) + produce(1, 2, 3, 4, 5)) + println(number(2.0) + buffer(1, 2, 3, 4, 5)) } } 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 7defd6841..14e7fc365 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 @@ -10,6 +10,7 @@ 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 import space.kscience.kmath.structures.DoubleBuffer import kotlin.reflect.KClass import kotlin.reflect.cast @@ -21,12 +22,15 @@ public class CMMatrix(public val origin: RealMatrix) : Matrix { override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) } -public class CMVector(public val origin: RealVector) : Point { +@JvmInline +public value class CMVector(public val origin: RealVector) : Point { override val size: Int get() = origin.dimension override operator fun get(index: Int): Double = origin.getEntry(index) override operator fun iterator(): Iterator = origin.toArray().iterator() + + override fun toString(): String = Buffer.toString(this) } public fun RealVector.toPoint(): CMVector = CMVector(this) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt index b9fbc07ae..d1fb441b0 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt @@ -18,7 +18,7 @@ public enum class CMDecomposition { CHOLESKY } -public fun CMLinearSpace.solver( +private fun CMLinearSpace.solver( a: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP, ): DecompositionSolver = when (decomposition) { @@ -48,9 +48,11 @@ public fun CMLinearSpace.inverse( public fun CMLinearSpace.solver(decomposition: CMDecomposition): LinearSolver = object : LinearSolver { - override fun solve(a: Matrix, b: Matrix): Matrix = solve(a, b, decomposition) + override fun solve(a: Matrix, b: Matrix): Matrix = solver(a, decomposition).solve(b.toCM().origin).wrap() - override fun solve(a: Matrix, b: Point): Point = solve(a, b, decomposition) + override fun solve(a: Matrix, b: Point): Point = solver(a, decomposition).solve(b.toCM().origin).toPoint() - override fun inverse(matrix: Matrix): Matrix = inverse(matrix, decomposition) -} \ No newline at end of file + override fun inverse(matrix: Matrix): Matrix = solver(matrix, decomposition).inverse.wrap() +} + +public fun CMLinearSpace.lupSolver(): LinearSolver = solver((CMDecomposition.LUP)) \ No newline at end of file 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 41bcb83df..29e790d16 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 @@ -9,8 +9,10 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.BufferND import space.kscience.kmath.nd.BufferedFieldND import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.BufferField import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.bufferAlgebra import space.kscience.kmath.structures.Buffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -111,13 +113,16 @@ public inline fun BufferedFieldND.produceInline(initializ return BufferND(strides, buffer) } +@UnstableKMathAPI +public fun ComplexField.bufferAlgebra(size: Int): BufferField = + bufferAlgebra(Buffer.Companion::complex, size) -public fun ComplexField.nd(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape) +public fun ComplexField.ndAlgebra(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape) /** * Produce a context for n-dimensional operations inside this real field */ -public inline fun ComplexField.withNd(vararg shape: Int, action: ComplexFieldND.() -> R): R { +public inline fun ComplexField.withNdAlgebra(vararg shape: Int, action: ComplexFieldND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return ComplexFieldND(shape).action() } 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 14235515c..5f17de607 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 @@ -8,17 +8,15 @@ package space.kscience.kmath.linear import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.BufferedRingND import space.kscience.kmath.nd.as2D -import space.kscience.kmath.nd.nd +import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd.unwrap +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.VirtualBuffer -import space.kscience.kmath.structures.indices +import space.kscience.kmath.structures.* -public class BufferedLinearSpace>( +public class BufferedLinearSpace>( override val elementAlgebra: A, private val bufferFactory: BufferFactory, ) : LinearSpace { @@ -26,7 +24,7 @@ public class BufferedLinearSpace>( private fun ndRing( rows: Int, cols: Int, - ): BufferedRingND = elementAlgebra.nd(bufferFactory, rows, cols) + ): BufferedRingND = elementAlgebra.ndAlgebra(bufferFactory, rows, cols) override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix = ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() @@ -92,3 +90,10 @@ public class BufferedLinearSpace>( unwrap().map { it * value }.as2D() } } + + +public fun > A.linearSpace(bufferFactory: BufferFactory): BufferedLinearSpace = + BufferedLinearSpace(this, bufferFactory) + +public val DoubleField.linearSpace: BufferedLinearSpace + get() = BufferedLinearSpace(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index e94e984b3..1d8985b59 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 @@ -6,8 +6,13 @@ package space.kscience.kmath.linear import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.* +import space.kscience.kmath.nd.MutableStructure2D +import space.kscience.kmath.nd.Structure2D +import space.kscience.kmath.nd.StructureFeature +import space.kscience.kmath.nd.as1D +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.DoubleBuffer @@ -34,7 +39,7 @@ public typealias Point = Buffer * @param T the type of items in the matrices. * @param A the type of ring over [T]. */ -public interface LinearSpace> { +public interface LinearSpace> { public val elementAlgebra: A /** @@ -172,7 +177,8 @@ public interface LinearSpace> { * @return a feature object or `null` if it isn't present. */ @UnstableKMathAPI - public fun computeFeature(structure: Matrix, type: KClass): F? = structure.getFeature(type) + public fun computeFeature(structure: Matrix, type: KClass): F? = + structure.getFeature(type) public companion object { @@ -184,6 +190,7 @@ public interface LinearSpace> { bufferFactory: BufferFactory = Buffer.Companion::boxing, ): LinearSpace = BufferedLinearSpace(algebra, bufferFactory) + @Deprecated("use DoubleField.linearSpace") public val double: LinearSpace = buffered(DoubleField, ::DoubleBuffer) /** @@ -213,10 +220,8 @@ public inline operator fun , R> LS.invoke(block: LS.() -> * Convert matrix to vector if it is possible. */ public fun Matrix.asVector(): Point = - if (this.colNum == 1) - as1D() - else - error("Can't convert matrix with more than one column to vector") + if (this.colNum == 1) as1D() + else error("Can't convert matrix with more than one column to vector") /** * Creates an n × 1 [VirtualMatrix], where n is the size of the given buffer. 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 34fc661ed..95dd6d45c 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,9 +5,7 @@ package space.kscience.kmath.linear -import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.getFeature import space.kscience.kmath.operations.* import space.kscience.kmath.structures.BufferAccessor2D import space.kscience.kmath.structures.DoubleBuffer @@ -214,7 +212,6 @@ internal fun LupDecomposition.solve( /** * Produce a generic solver based on LUP decomposition */ -@PerformancePitfall() @OptIn(UnstableKMathAPI::class) public fun , F : Field> LinearSpace.lupSolver( bufferFactory: MutableBufferFactory, @@ -222,13 +219,12 @@ public fun , F : Field> LinearSpace.lupSolver( ): LinearSolver = object : LinearSolver { override fun solve(a: Matrix, b: Matrix): Matrix { // Use existing decomposition if it is provided by matrix - val decomposition = a.getFeature() ?: lup(bufferFactory, a, singularityCheck) + val decomposition = computeFeature(a) ?: lup(bufferFactory, a, singularityCheck) return decomposition.solve(bufferFactory, b) } override fun inverse(matrix: Matrix): Matrix = solve(matrix, one(matrix.rowNum, matrix.colNum)) } -@PerformancePitfall public fun LinearSpace.lupSolver(singularityThreshold: Double = 1e-11): LinearSolver = lupSolver(::DoubleBuffer) { it < singularityThreshold } 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 3ba4e8648..a40c0384c 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 @@ -8,7 +8,6 @@ package space.kscience.kmath.linear import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.nd.getFeature import space.kscience.kmath.operations.Ring import kotlin.reflect.KClass @@ -26,7 +25,6 @@ public class MatrixWrapper internal constructor( * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the * criteria. */ - @UnstableKMathAPI @Suppress("UNCHECKED_CAST") override fun getFeature(type: KClass): F? = features.getFeature(type) ?: origin.getFeature(type) @@ -90,8 +88,7 @@ public class TransposedFeature(public val original: Matrix) : Ma /** * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` */ +@Suppress("UNCHECKED_CAST") @OptIn(UnstableKMathAPI::class) -public fun Matrix.transpose(): Matrix = getFeature>()?.original ?: VirtualMatrix( - colNum, - rowNum, -) { i, j -> get(j, i) }.withFeature(TransposedFeature(this)) +public fun Matrix.transpose(): Matrix = getFeature(TransposedFeature::class)?.original as? Matrix + ?: VirtualMatrix(colNum, rowNum) { i, j -> get(j, i) }.withFeature(TransposedFeature(this)) 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 b01beb02d..ae72f3689 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 @@ -87,39 +87,39 @@ public open class BufferedFieldND>( } // group factories -public fun > A.nd( +public fun > A.ndAlgebra( bufferFactory: BufferFactory, vararg shape: Int, ): BufferedGroupND = BufferedGroupND(shape, this, bufferFactory) @JvmName("withNdGroup") -public inline fun , R> A.withNd( +public inline fun , R> A.withNdAlgebra( noinline bufferFactory: BufferFactory, vararg shape: Int, action: BufferedGroupND.() -> R, ): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return nd(bufferFactory, *shape).run(action) + return ndAlgebra(bufferFactory, *shape).run(action) } //ring factories -public fun > A.nd( +public fun > A.ndAlgebra( bufferFactory: BufferFactory, vararg shape: Int, ): BufferedRingND = BufferedRingND(shape, this, bufferFactory) @JvmName("withNdRing") -public inline fun , R> A.withNd( +public inline fun , R> A.withNdAlgebra( noinline bufferFactory: BufferFactory, vararg shape: Int, action: BufferedRingND.() -> R, ): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return nd(bufferFactory, *shape).run(action) + return ndAlgebra(bufferFactory, *shape).run(action) } //field factories -public fun > A.nd( +public fun > A.ndAlgebra( bufferFactory: BufferFactory, vararg shape: Int, ): BufferedFieldND = BufferedFieldND(shape, this, bufferFactory) @@ -129,7 +129,7 @@ public fun > A.nd( */ @UnstableKMathAPI @Suppress("UNCHECKED_CAST") -public inline fun > A.autoNd( +public inline fun > A.autoNdAlgebra( vararg shape: Int, ): FieldND = when (this) { DoubleField -> DoubleFieldND(shape) as FieldND @@ -137,11 +137,11 @@ public inline fun > A.autoNd( } @JvmName("withNdField") -public inline fun , R> A.withNd( +public inline fun , R> A.withNdAlgebra( noinline bufferFactory: BufferFactory, vararg shape: Int, action: BufferedFieldND.() -> R, ): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return nd(bufferFactory, *shape).run(action) + return ndAlgebra(bufferFactory, *shape).run(action) } \ No newline at end of file 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 fed4aca0b..0c7d4d5d1 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 @@ -103,12 +103,12 @@ public class DoubleFieldND( override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } } -public fun DoubleField.nd(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) +public fun DoubleField.ndAlgebra(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) /** * Produce a context for n-dimensional operations inside this real field */ -public inline fun DoubleField.withNd(vararg shape: Int, action: DoubleFieldND.() -> R): R { +public inline fun DoubleField.withNdAlgebra(vararg shape: Int, action: DoubleFieldND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return DoubleFieldND(shape).run(action) } 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 5b6e2cd22..b56bef230 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 @@ -34,7 +34,7 @@ public class ShortRingND( public inline fun BufferedRingND.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND = BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) -public inline fun ShortRing.withNd(vararg shape: Int, action: ShortRingND.() -> R): R { +public inline fun ShortRing.withNdAlgebra(vararg shape: Int, action: ShortRingND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return ShortRingND(shape).run(action) } 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 d0e2354d2..91cd5abe9 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 @@ -67,12 +67,14 @@ private class MutableStructure1DWrapper(val structure: MutableStructureND) structure[intArrayOf(index)] = value } - @PerformancePitfall + @OptIn(PerformancePitfall::class) override fun copy(): MutableBuffer = structure .elements() .map(Pair::second) .toMutableList() .asMutableBuffer() + + override fun toString(): String = Buffer.toString(this) } @@ -107,6 +109,8 @@ internal class MutableBuffer1DWrapper(val buffer: MutableBuffer) : Mutable } override fun copy(): MutableBuffer = buffer.copy() + + override fun toString(): String = Buffer.toString(this) } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index 7fb8ea251..57836a9ef 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 @@ -6,7 +6,6 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableListBuffer import space.kscience.kmath.structures.VirtualBuffer @@ -108,7 +107,6 @@ private value class Structure2DWrapper(val structure: StructureND) : S override operator fun get(i: Int, j: Int): T = structure[i, j] - @UnstableKMathAPI override fun getFeature(type: KClass): F? = structure.getFeature(type) @PerformancePitfall 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 0675f5baf..6123336ba 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 @@ -9,12 +9,12 @@ 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.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import kotlin.jvm.JvmName +import kotlin.math.abs import kotlin.native.concurrent.ThreadLocal import kotlin.reflect.KClass @@ -61,7 +61,6 @@ public interface StructureND : Featured { * Feature is some additional structure information that allows to access it special properties or hints. * If the feature is not present, `null` is returned. */ - @UnstableKMathAPI override fun getFeature(type: KClass): F? = null public companion object { @@ -80,6 +79,22 @@ public interface StructureND : Featured { return st1.elements().all { (index, value) -> value == st2[index] } } + @PerformancePitfall + public fun contentEquals( + st1: StructureND, + st2: StructureND, + tolerance: Double = 1e-11 + ): Boolean { + if (st1 === st2) return true + + // fast comparison of buffers if possible + if (st1 is BufferND && st2 is BufferND && st1.strides == st2.strides) + return Buffer.contentEquals(st1.buffer, st2.buffer) + + //element by element comparison if it could not be avoided + return st1.elements().all { (index, value) -> abs(value - st2[index]) < tolerance } + } + /** * Debug output to string */ @@ -196,8 +211,8 @@ public fun > LinearSpace>.contentEquals( */ public operator fun StructureND.get(vararg index: Int): T = get(index) -@UnstableKMathAPI -public inline fun StructureND<*>.getFeature(): T? = getFeature(T::class) +//@UnstableKMathAPI +//public inline fun StructureND<*>.getFeature(): T? = getFeature(T::class) /** * Represents mutable [StructureND]. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt index 9f4d741fd..e82b62c1b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -17,6 +17,12 @@ import space.kscience.kmath.structures.DoubleBuffer public interface BufferAlgebra> : Algebra> { public val bufferFactory: BufferFactory public val elementAlgebra: A + public val size: Int + + public fun buffer(vararg elements: T): Buffer { + require(elements.size == size) { "Expected $size elements but found ${elements.size}" } + return bufferFactory(size) { elements[it] } + } //TODO move to multi-receiver inline extension public fun Buffer.map(block: (T) -> T): Buffer = bufferFactory(size) { block(get(it)) } @@ -39,6 +45,11 @@ public interface BufferAlgebra> : Algebra> { } } +@UnstableKMathAPI +public fun BufferField.buffer(initializer: (Int) -> T): Buffer { + return bufferFactory(size, initializer) +} + @UnstableKMathAPI public fun > BufferAlgebra.sin(arg: Buffer): Buffer = arg.map(elementAlgebra::sin) @@ -104,14 +115,9 @@ public fun > BufferAlgebra.pow(arg: Buffer, p public class BufferField>( override val bufferFactory: BufferFactory, override val elementAlgebra: A, - public val size: Int + override val size: Int ) : BufferAlgebra, Field> { - public fun produce(vararg elements: T): Buffer { - require(elements.size == size) { "Expected $size elements but found ${elements.size}" } - return bufferFactory(size) { elements[it] } - } - override val zero: Buffer = bufferFactory(size) { elementAlgebra.zero } override val one: Buffer = bufferFactory(size) { elementAlgebra.one } @@ -135,11 +141,15 @@ public class BufferField>( //Double buffer specialization @UnstableKMathAPI -public fun BufferField.produce(vararg elements: Number): Buffer { +public fun BufferField.buffer(vararg elements: Number): Buffer { require(elements.size == size) { "Expected $size elements but found ${elements.size}" } return bufferFactory(size) { elements[it].toDouble() } } +@UnstableKMathAPI +public fun > A.bufferAlgebra(bufferFactory: BufferFactory, size: Int): BufferField = + BufferField(bufferFactory, this, size) + @UnstableKMathAPI public fun DoubleField.bufferAlgebra(size: Int): BufferField = BufferField(::DoubleBuffer, DoubleField, size) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt index d49f70355..393ee99d6 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt @@ -23,6 +23,8 @@ public class ArrayBuffer(internal val array: Array) : MutableBuffer { override operator fun iterator(): Iterator = array.iterator() override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf()) + + override fun toString(): String = Buffer.toString(this) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index c22a4ba39..fc23169ca 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -45,7 +45,12 @@ public interface Buffer { */ public operator fun iterator(): Iterator + override fun toString(): String + public companion object { + + public fun toString(buffer: Buffer<*>): String = buffer.asSequence().joinToString(prefix = "[", separator = ", ", postfix = "]") + /** * Check the element-by-element match of content of two buffers. */ @@ -126,6 +131,8 @@ public class VirtualBuffer(override val size: Int, private val generator: } override operator fun iterator(): Iterator = (0 until size).asSequence().map(generator).iterator() + + override fun toString(): String = Buffer.toString(this) } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt index 005a693eb..d6a48f42d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt @@ -49,6 +49,8 @@ internal class BufferAccessor2D( override fun copy(): MutableBuffer = factory(colNum) { get(it) } override operator fun iterator(): Iterator = (0 until colNum).map(::get).iterator() + override fun toString(): String = Buffer.toString(this) + } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt index 665558829..700a4f17f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt @@ -53,8 +53,10 @@ public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, Valu /** * A [Double] buffer that supports flags for each value like `NaN` or Missing. */ -public class FlaggedDoubleBuffer(public val values: DoubleArray, public val flags: ByteArray) : FlaggedBuffer, - Buffer { +public class FlaggedDoubleBuffer( + public val values: DoubleArray, + public val flags: ByteArray +) : FlaggedBuffer, Buffer { init { require(values.size == flags.size) { "Values and flags must have the same dimensions" } } @@ -68,6 +70,8 @@ public class FlaggedDoubleBuffer(public val values: DoubleArray, public val flag override operator fun iterator(): Iterator = values.indices.asSequence().map { if (isValid(it)) values[it] else null }.iterator() + + override fun toString(): String = Buffer.toString(this) } public inline fun FlaggedDoubleBuffer.forEachValid(block: (Double) -> Unit) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt index fdba68d19..666722177 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt @@ -21,6 +21,8 @@ public class ListBuffer(public val list: List) : Buffer { override operator fun get(index: Int): T = list[index] override operator fun iterator(): Iterator = list.iterator() + + override fun toString(): String = Buffer.toString(this) } 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 996785570..3e08dbbb1 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 @@ -22,6 +22,8 @@ public open class MemoryBuffer(protected val memory: Memory, protected override operator fun get(index: Int): T = reader.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) + public companion object { public fun create(spec: MemorySpec, size: Int): MemoryBuffer = MemoryBuffer(Memory.allocate(size * spec.objectSize), spec) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt index 6d4531f41..05a67ab09 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.structures import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.nd +import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import space.kscience.kmath.testutils.FieldVerifier @@ -16,12 +16,12 @@ import kotlin.test.assertEquals internal class NDFieldTest { @Test fun verify() { - (DoubleField.nd(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } + (DoubleField.ndAlgebra(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } } @Test fun testStrides() { - val ndArray = DoubleField.nd(10, 10).produce { (it[0] + it[1]).toDouble() } + val ndArray = DoubleField.ndAlgebra(10, 10).produce { (it[0] + it[1]).toDouble() } assertEquals(ndArray[5, 5], 10.0) } } 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 1045933b7..b2982b335 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 @@ -10,7 +10,7 @@ import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.combine import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.nd +import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.invoke @@ -21,7 +21,7 @@ import kotlin.test.assertEquals @Suppress("UNUSED_VARIABLE") class NumberNDFieldTest { - val algebra = DoubleField.nd(3, 3) + val algebra = DoubleField.ndAlgebra(3, 3) val array1 = algebra.produce { (i, j) -> (i + j).toDouble() } val array2 = algebra.produce { (i, j) -> (i - j).toDouble() } @@ -87,7 +87,7 @@ class NumberNDFieldTest { @Test fun testInternalContext() { algebra { - (DoubleField.nd(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } } + (DoubleField.ndAlgebra(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } } } } } diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt index 4b12b031d..573b406e2 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt @@ -69,6 +69,8 @@ public class RingBuffer( @Suppress("NOTHING_TO_INLINE") private inline fun Int.forward(n: Int): Int = (this + n) % (buffer.size) + override fun toString(): String = Buffer.toString(this) + public companion object { public inline fun build(size: Int, empty: T): RingBuffer { val buffer = MutableBuffer.auto(size) { empty } as MutableBuffer 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 022a7874e..4a53af60d 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,9 +5,12 @@ package space.kscience.kmath.ejml +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 /** @@ -36,4 +39,7 @@ public abstract class EjmlLinearSpace, out M : org.ejml ): EjmlMatrix public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector + + @UnstableKMathAPI + public fun EjmlMatrix.inverse(): Structure2D = computeFeature(this, InverseMatrixFeature::class)?.inverse as Structure2D } 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 5667815ac..5b8b2af98 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 @@ -9,12 +9,11 @@ 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.linear.DeterminantFeature -import space.kscience.kmath.linear.LupDecompositionFeature -import space.kscience.kmath.linear.computeFeature +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.operations.algebra import kotlin.random.Random import kotlin.random.asJavaRandom import kotlin.test.* @@ -82,4 +81,24 @@ internal class EjmlMatrixTest { val m = randomMatrix assertSame(m, EjmlDoubleMatrix(m).origin) } + + @Test + fun inverse() = EjmlLinearSpaceDDRM { + val random = Random(1224) + val dim = 20 + + val space = Double.algebra.linearSpace + + //creating invertible matrix + val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 } + val matrix = space { l dot u } + val inverted = matrix.toEjml().inverse() + + val res = matrix dot inverted + + println(StructureND.toString(res)) + + assertTrue { StructureND.contentEquals(one(dim, dim), res, 1e-3) } + } } 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 098beb2cf..88932d59b 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 @@ -12,6 +12,7 @@ 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.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asIterable @@ -32,18 +33,18 @@ import kotlin.math.pow public typealias RealMatrix = Matrix public fun realMatrix(rowNum: Int, colNum: Int, initializer: DoubleField.(i: Int, j: Int) -> Double): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, colNum, initializer) + Double.algebra.linearSpace.buildMatrix(rowNum, colNum, initializer) @OptIn(UnstableKMathAPI::class) public fun realMatrix(rowNum: Int, colNum: Int): MatrixBuilder = - LinearSpace.double.matrix(rowNum, colNum) + Double.algebra.linearSpace.matrix(rowNum, colNum) public fun Array.toMatrix(): RealMatrix { - return LinearSpace.double.buildMatrix(size, this[0].size) { row, col -> this@toMatrix[row][col] } + return Double.algebra.linearSpace.buildMatrix(size, this[0].size) { row, col -> this@toMatrix[row][col] } } public fun Sequence.toMatrix(): RealMatrix = toList().let { - LinearSpace.double.buildMatrix(it.size, it[0].size) { row, col -> it[row][col] } + Double.algebra.linearSpace.buildMatrix(it.size, it[0].size) { row, col -> it[row][col] } } public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix = @@ -56,37 +57,37 @@ public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix = */ public operator fun RealMatrix.times(double: Double): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> + Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> get(row, col) * double } public operator fun RealMatrix.plus(double: Double): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> + Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> get(row, col) + double } public operator fun RealMatrix.minus(double: Double): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> + Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> get(row, col) - double } public operator fun RealMatrix.div(double: Double): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> + Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> get(row, col) / double } public operator fun Double.times(matrix: RealMatrix): RealMatrix = - LinearSpace.double.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + Double.algebra.linearSpace.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@times * matrix[row, col] } public operator fun Double.plus(matrix: RealMatrix): RealMatrix = - LinearSpace.double.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + Double.algebra.linearSpace.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@plus + matrix[row, col] } public operator fun Double.minus(matrix: RealMatrix): RealMatrix = - LinearSpace.double.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + Double.algebra.linearSpace.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@minus - matrix[row, col] } @@ -101,20 +102,20 @@ public operator fun Double.minus(matrix: RealMatrix): RealMatrix = @UnstableKMathAPI public operator fun RealMatrix.times(other: RealMatrix): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> this@times[row, col] * other[row, col] } + Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> this@times[row, col] * other[row, col] } public operator fun RealMatrix.plus(other: RealMatrix): RealMatrix = - LinearSpace.double.run { this@plus + other } + Double.algebra.linearSpace.run { this@plus + other } public operator fun RealMatrix.minus(other: RealMatrix): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, colNum) { row, col -> this@minus[row, col] - other[row, col] } + Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> this@minus[row, col] - other[row, col] } /* * Operations on columns */ public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) -> Double): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, colNum + 1) { row, col -> + Double.algebra.linearSpace.buildMatrix(rowNum, colNum + 1) { row, col -> if (col < colNum) get(row, col) else @@ -122,7 +123,7 @@ public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) - } public fun RealMatrix.extractColumns(columnRange: IntRange): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, columnRange.count()) { row, col -> + Double.algebra.linearSpace.buildMatrix(rowNum, columnRange.count()) { row, col -> this@extractColumns[row, columnRange.first + col] } @@ -155,14 +156,14 @@ public fun RealMatrix.max(): Double? = elements().map { (_, value) -> value }.ma public fun RealMatrix.average(): Double = elements().map { (_, value) -> value }.average() public inline fun RealMatrix.map(crossinline transform: (Double) -> Double): RealMatrix = - LinearSpace.double.buildMatrix(rowNum, colNum) { i, j -> + Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { i, j -> transform(get(i, j)) } /** * Inverse a square real matrix using LUP decomposition */ -public fun RealMatrix.inverseWithLup(): RealMatrix = LinearSpace.double.lupSolver().inverse(this) +public fun RealMatrix.inverseWithLup(): RealMatrix = Double.algebra.linearSpace.lupSolver().inverse(this) //extended operations diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt index ca2db8131..883a63f46 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt @@ -5,13 +5,14 @@ package space.kscience.kmath.real -import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.linear.linearSpace +import space.kscience.kmath.operations.algebra /** * Optimized dot product for real matrices */ -public infix fun Matrix.dot(other: Matrix): Matrix = LinearSpace.double.run { +public infix fun Matrix.dot(other: Matrix): Matrix = Double.algebra.linearSpace.run { this@dot dot other } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index c99f3ff99..662cdf3d7 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 @@ -10,6 +10,7 @@ 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.DoubleField import space.kscience.kmath.operations.Field @@ -23,6 +24,7 @@ import space.kscience.kmath.structures.map /** * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact */ +@OptIn(PerformancePitfall::class) @UnstableKMathAPI public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt index 37ab8a1b2..5446f05f8 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt @@ -29,7 +29,7 @@ public class DoubleHistogramSpace( public val dimension: Int get() = lower.size private val shape = IntArray(binNums.size) { binNums[it] + 2 } - override val histogramValueSpace: DoubleFieldND = DoubleField.nd(*shape) + override val histogramValueSpace: DoubleFieldND = DoubleField.ndAlgebra(*shape) override val strides: Strides get() = histogramValueSpace.strides private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] } diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt index caebd9783..32fb65b8a 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt @@ -6,10 +6,12 @@ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64FlatArray +import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer @Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") -public class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { +@JvmInline +public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { override val size: Int get() = flatArray.size @@ -21,4 +23,6 @@ public class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer = ViktorBuffer(flatArray.copy().flatten()) override operator fun iterator(): Iterator = flatArray.data.iterator() + + override fun toString(): String = Buffer.toString(this) } -- 2.34.1 From 974d73e25c3e5c44956848a2b877cdc20f7c7436 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 22 Sep 2021 22:09:46 +0300 Subject: [PATCH 020/102] Adjust benchmarks. --- .../kmath/benchmarks/BigIntBenchmark.kt | 29 +++++++++--- .../kscience/kmath/benchmarks/DotBenchmark.kt | 44 +++++++++---------- .../kscience/kmath/linear/dotPerformance.kt | 34 ++++++++++++++ 3 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt 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 6f501dedb..f2b2d4d7a 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt @@ -11,7 +11,10 @@ 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.operations.* +import space.kscience.kmath.operations.BigIntField +import space.kscience.kmath.operations.JBigIntegerField +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.parseBigInteger import java.math.BigInteger @@ -19,12 +22,24 @@ import java.math.BigInteger @State(Scope.Benchmark) internal class BigIntBenchmark { + val kmSmallNumber = BigIntField.number(100) + val jvmSmallNumber = JBigIntegerField.number(100) val kmNumber = BigIntField.number(Int.MAX_VALUE) val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE) - val largeKmNumber = BigIntField { number(11).pow(100_000U) } - val largeJvmNumber: BigInteger = JBigIntegerField { number(11).pow(100_000) } + val kmLargeNumber = BigIntField { number(11).pow(100_000U) } + val jvmLargeNumber: BigInteger = JBigIntegerField { number(11).pow(100_000) } val bigExponent = 50_000 + @Benchmark + fun kmSmallAdd(blackhole: Blackhole) = BigIntField { + blackhole.consume(kmSmallNumber + kmSmallNumber + kmSmallNumber) + } + + @Benchmark + fun jvmSmallAdd(blackhole: Blackhole) = JBigIntegerField { + blackhole.consume(jvmSmallNumber + jvmSmallNumber + jvmSmallNumber) + } + @Benchmark fun kmAdd(blackhole: Blackhole) = BigIntField { blackhole.consume(kmNumber + kmNumber + kmNumber) @@ -37,12 +52,12 @@ internal class BigIntBenchmark { @Benchmark fun kmAddLarge(blackhole: Blackhole) = BigIntField { - blackhole.consume(largeKmNumber + largeKmNumber + largeKmNumber) + blackhole.consume(kmLargeNumber + kmLargeNumber + kmLargeNumber) } @Benchmark fun jvmAddLarge(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(largeJvmNumber + largeJvmNumber + largeJvmNumber) + blackhole.consume(jvmLargeNumber + jvmLargeNumber + jvmLargeNumber) } @Benchmark @@ -52,7 +67,7 @@ internal class BigIntBenchmark { @Benchmark fun kmMultiplyLarge(blackhole: Blackhole) = BigIntField { - blackhole.consume(largeKmNumber*largeKmNumber) + blackhole.consume(kmLargeNumber*kmLargeNumber) } @Benchmark @@ -62,7 +77,7 @@ internal class BigIntBenchmark { @Benchmark fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(largeJvmNumber*largeJvmNumber) + blackhole.consume(jvmLargeNumber*jvmLargeNumber) } @Benchmark diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 6373d1ce5..33cb57c6f 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -11,7 +11,6 @@ import kotlinx.benchmark.Scope import kotlinx.benchmark.State import space.kscience.kmath.commons.linear.CMLinearSpace import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM -import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.operations.DoubleField @@ -26,8 +25,12 @@ internal class DotBenchmark { const val dim = 1000 //creating invertible matrix - val matrix1 = LinearSpace.double.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - val matrix2 = LinearSpace.double.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + val matrix1 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> + if (i <= j) random.nextDouble() else 0.0 + } + val matrix2 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> + if (i <= j) random.nextDouble() else 0.0 + } val cmMatrix1 = CMLinearSpace { matrix1.toCM() } val cmMatrix2 = CMLinearSpace { matrix2.toCM() } @@ -37,37 +40,32 @@ internal class DotBenchmark { } @Benchmark - fun cmDot(blackhole: Blackhole) { - CMLinearSpace { - blackhole.consume(cmMatrix1 dot cmMatrix2) - } + fun cmDotWithConversion(blackhole: Blackhole) = CMLinearSpace { + blackhole.consume(matrix1 dot matrix2) } @Benchmark - fun ejmlDot(blackhole: Blackhole) { - EjmlLinearSpaceDDRM { - blackhole.consume(ejmlMatrix1 dot ejmlMatrix2) - } + fun cmDot(blackhole: Blackhole) = CMLinearSpace { + blackhole.consume(cmMatrix1 dot cmMatrix2) } @Benchmark - fun ejmlDotWithConversion(blackhole: Blackhole) { - EjmlLinearSpaceDDRM { - blackhole.consume(matrix1 dot matrix2) - } + fun ejmlDot(blackhole: Blackhole) = EjmlLinearSpaceDDRM { + blackhole.consume(ejmlMatrix1 dot ejmlMatrix2) } @Benchmark - fun bufferedDot(blackhole: Blackhole) { - with(DoubleField.linearSpace(Buffer.Companion::auto)) { - blackhole.consume(matrix1 dot matrix2) - } + fun ejmlDotWithConversion(blackhole: Blackhole) = EjmlLinearSpaceDDRM { + blackhole.consume(matrix1 dot matrix2) } @Benchmark - fun doubleDot(blackhole: Blackhole) { - with(Double.algebra.linearSpace) { - blackhole.consume(matrix1 dot matrix2) - } + fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace(Buffer.Companion::auto)) { + blackhole.consume(matrix1 dot matrix2) + } + + @Benchmark + fun doubleDot(blackhole: Blackhole) = with(Double.algebra.linearSpace) { + blackhole.consume(matrix1 dot matrix2) } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt new file mode 100644 index 000000000..31762b6d8 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.linear + +import space.kscience.kmath.operations.algebra +import kotlin.random.Random +import kotlin.system.measureTimeMillis + +fun main() { + val random = Random(12224) + val dim = 1000 + + //creating invertible matrix + val matrix1 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> + if (i <= j) random.nextDouble() else 0.0 + } + val matrix2 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> + if (i <= j) random.nextDouble() else 0.0 + } + + val time = measureTimeMillis { + with(Double.algebra.linearSpace) { + repeat(10) { + val res = matrix1 dot matrix2 + } + } + } + + println(time) + +} \ No newline at end of file -- 2.34.1 From 64781a6785dd2aef35ab3e99e2bb8a22413ad297 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 23 Sep 2021 21:44:18 +0300 Subject: [PATCH 021/102] Move Minuit tmp classes to optimization --- {kmath-stat => kmath-optimization}/src/commonMain/tmp/QowFit.kt | 0 .../src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt | 0 .../src/commonMain/tmp/minuit/CombinedMinimizer.kt | 0 .../src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt | 0 .../src/commonMain/tmp/minuit/ContoursError.kt | 0 .../src/commonMain/tmp/minuit/DavidonErrorUpdator.kt | 0 .../src/commonMain/tmp/minuit/FunctionGradient.kt | 0 .../src/commonMain/tmp/minuit/FunctionMinimum.kt | 0 .../src/commonMain/tmp/minuit/GradientCalculator.kt | 0 .../src/commonMain/tmp/minuit/HessianGradientCalculator.kt | 0 .../src/commonMain/tmp/minuit/InitialGradientCalculator.kt | 0 .../src/commonMain/tmp/minuit/MINOSResult.kt | 0 .../src/commonMain/tmp/minuit/MINUITFitter.kt | 0 .../src/commonMain/tmp/minuit/MINUITPlugin.kt | 0 .../src/commonMain/tmp/minuit/MINUITUtils.kt | 0 .../src/commonMain/tmp/minuit/MinimumBuilder.kt | 0 .../src/commonMain/tmp/minuit/MinimumError.kt | 0 .../src/commonMain/tmp/minuit/MinimumErrorUpdator.kt | 0 .../src/commonMain/tmp/minuit/MinimumParameters.kt | 0 .../src/commonMain/tmp/minuit/MinimumSeed.kt | 0 .../src/commonMain/tmp/minuit/MinimumSeedGenerator.kt | 0 .../src/commonMain/tmp/minuit/MinimumState.kt | 0 .../src/commonMain/tmp/minuit/MinosError.kt | 0 .../src/commonMain/tmp/minuit/MinuitParameter.kt | 0 .../src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt | 0 .../src/commonMain/tmp/minuit/MnApplication.kt | 0 .../src/commonMain/tmp/minuit/MnContours.kt | 0 .../src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt | 0 .../src/commonMain/tmp/minuit/MnCross.kt | 0 .../src/commonMain/tmp/minuit/MnEigen.kt | 0 .../src/commonMain/tmp/minuit/MnFcn.kt | 0 .../src/commonMain/tmp/minuit/MnFunctionCross.kt | 0 .../src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt | 0 .../src/commonMain/tmp/minuit/MnHesse.kt | 0 .../src/commonMain/tmp/minuit/MnLineSearch.kt | 0 .../src/commonMain/tmp/minuit/MnMachinePrecision.kt | 0 .../src/commonMain/tmp/minuit/MnMigrad.kt | 0 .../src/commonMain/tmp/minuit/MnMinimize.kt | 0 .../src/commonMain/tmp/minuit/MnMinos.kt | 0 .../src/commonMain/tmp/minuit/MnParabola.kt | 0 .../src/commonMain/tmp/minuit/MnParabolaFactory.kt | 0 .../src/commonMain/tmp/minuit/MnParabolaPoint.kt | 0 .../src/commonMain/tmp/minuit/MnParameterScan.kt | 0 .../src/commonMain/tmp/minuit/MnPlot.kt | 0 .../src/commonMain/tmp/minuit/MnPosDef.kt | 0 .../src/commonMain/tmp/minuit/MnPrint.kt | 0 .../src/commonMain/tmp/minuit/MnScan.kt | 0 .../src/commonMain/tmp/minuit/MnSeedGenerator.kt | 0 .../src/commonMain/tmp/minuit/MnSimplex.kt | 0 .../src/commonMain/tmp/minuit/MnStrategy.kt | 0 .../src/commonMain/tmp/minuit/MnUserCovariance.kt | 0 .../src/commonMain/tmp/minuit/MnUserFcn.kt | 0 .../src/commonMain/tmp/minuit/MnUserParameterState.kt | 0 .../src/commonMain/tmp/minuit/MnUserParameters.kt | 0 .../src/commonMain/tmp/minuit/MnUserTransformation.kt | 0 .../src/commonMain/tmp/minuit/MnUtils.kt | 0 .../src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt | 0 .../src/commonMain/tmp/minuit/NegativeG2LineSearch.kt | 0 .../src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt | 0 .../src/commonMain/tmp/minuit/ScanBuilder.kt | 0 .../src/commonMain/tmp/minuit/ScanMinimizer.kt | 0 .../src/commonMain/tmp/minuit/SimplexBuilder.kt | 0 .../src/commonMain/tmp/minuit/SimplexMinimizer.kt | 0 .../src/commonMain/tmp/minuit/SimplexParameters.kt | 0 .../src/commonMain/tmp/minuit/SimplexSeedGenerator.kt | 0 .../src/commonMain/tmp/minuit/SinParameterTransformation.kt | 0 .../src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt | 0 .../src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt | 0 .../src/commonMain/tmp/minuit/VariableMetricBuilder.kt | 0 .../src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt | 0 .../src/commonMain/tmp/minuit/VariableMetricMinimizer.kt | 0 .../src/commonMain/tmp/minuit/package-info.kt | 0 72 files changed, 0 insertions(+), 0 deletions(-) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/QowFit.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/CombinedMinimizer.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/ContoursError.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/FunctionGradient.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/FunctionMinimum.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/GradientCalculator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/HessianGradientCalculator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/InitialGradientCalculator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MINOSResult.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MINUITFitter.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MINUITPlugin.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MINUITUtils.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MinimumBuilder.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MinimumError.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MinimumParameters.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MinimumSeed.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MinimumState.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MinosError.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MinuitParameter.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnApplication.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnContours.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnCross.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnEigen.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnFcn.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnFunctionCross.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnHesse.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnLineSearch.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnMachinePrecision.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnMigrad.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnMinimize.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnMinos.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnParabola.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnParabolaFactory.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnParabolaPoint.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnParameterScan.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnPlot.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnPosDef.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnPrint.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnScan.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnSeedGenerator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnSimplex.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnStrategy.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnUserCovariance.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnUserFcn.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnUserParameterState.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnUserParameters.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnUserTransformation.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/MnUtils.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/ScanBuilder.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/ScanMinimizer.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/SimplexBuilder.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/SimplexMinimizer.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/SimplexParameters.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/SinParameterTransformation.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/VariableMetricBuilder.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt (100%) rename {kmath-stat => kmath-optimization}/src/commonMain/tmp/minuit/package-info.kt (100%) diff --git a/kmath-stat/src/commonMain/tmp/QowFit.kt b/kmath-optimization/src/commonMain/tmp/QowFit.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/QowFit.kt rename to kmath-optimization/src/commonMain/tmp/QowFit.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/CombinedMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/CombinedMinimizer.kt rename to kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimizer.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt rename to kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/ContoursError.kt b/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/ContoursError.kt rename to kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt b/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/FunctionGradient.kt b/kmath-optimization/src/commonMain/tmp/minuit/FunctionGradient.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/FunctionGradient.kt rename to kmath-optimization/src/commonMain/tmp/minuit/FunctionGradient.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/FunctionMinimum.kt b/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/FunctionMinimum.kt rename to kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/GradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/GradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/GradientCalculator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/GradientCalculator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/HessianGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/HessianGradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/HessianGradientCalculator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/HessianGradientCalculator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/InitialGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/InitialGradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/InitialGradientCalculator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/InitialGradientCalculator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MINOSResult.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINOSResult.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MINOSResult.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MINOSResult.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MINUITFitter.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MINUITFitter.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MINUITPlugin.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MINUITPlugin.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MINUITUtils.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITUtils.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MINUITUtils.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MINUITUtils.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MinimumBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MinimumBuilder.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MinimumError.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumError.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MinimumError.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MinimumError.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MinimumParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumParameters.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MinimumParameters.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MinimumParameters.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MinimumSeed.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeed.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MinimumSeed.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MinimumSeed.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MinimumState.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumState.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MinimumState.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MinimumState.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MinosError.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinosError.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MinosError.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MinosError.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MinuitParameter.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MinuitParameter.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnApplication.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnApplication.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnContours.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnContours.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnCross.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnCross.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnCross.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnCross.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnEigen.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnEigen.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnEigen.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnEigen.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnFcn.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnFcn.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnFcn.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnFcn.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnFunctionCross.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnFunctionCross.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnHesse.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnHesse.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnLineSearch.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnLineSearch.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnMachinePrecision.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMachinePrecision.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnMachinePrecision.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnMachinePrecision.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnMigrad.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnMigrad.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnMinimize.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnMinimize.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnMinos.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnMinos.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnParabola.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParabola.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnParabola.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnParabola.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnParabolaFactory.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaFactory.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnParabolaFactory.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnParabolaFactory.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnParabolaPoint.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaPoint.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnParabolaPoint.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnParabolaPoint.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnParameterScan.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParameterScan.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnParameterScan.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnParameterScan.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnPlot.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnPlot.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnPlot.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnPlot.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnPosDef.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnPosDef.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnPosDef.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnPosDef.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnPrint.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnPrint.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnPrint.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnPrint.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnScan.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnScan.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnSeedGenerator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnSimplex.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnSimplex.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnStrategy.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnStrategy.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnStrategy.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnStrategy.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnUserCovariance.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserCovariance.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnUserCovariance.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnUserCovariance.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnUserFcn.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserFcn.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnUserFcn.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnUserFcn.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnUserParameterState.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnUserParameterState.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnUserParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnUserParameters.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnUserTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnUserTransformation.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/MnUtils.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUtils.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/MnUtils.kt rename to kmath-optimization/src/commonMain/tmp/minuit/MnUtils.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt rename to kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt b/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt rename to kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/ScanBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/ScanBuilder.kt rename to kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/ScanMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/ScanMinimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/ScanMinimizer.kt rename to kmath-optimization/src/commonMain/tmp/minuit/ScanMinimizer.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/SimplexBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/SimplexBuilder.kt rename to kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/SimplexMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexMinimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/SimplexMinimizer.kt rename to kmath-optimization/src/commonMain/tmp/minuit/SimplexMinimizer.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/SimplexParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexParameters.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/SimplexParameters.kt rename to kmath-optimization/src/commonMain/tmp/minuit/SimplexParameters.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/SinParameterTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/SinParameterTransformation.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/SinParameterTransformation.kt rename to kmath-optimization/src/commonMain/tmp/minuit/SinParameterTransformation.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt rename to kmath-optimization/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt rename to kmath-optimization/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/VariableMetricBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/VariableMetricBuilder.kt rename to kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt rename to kmath-optimization/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt rename to kmath-optimization/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt diff --git a/kmath-stat/src/commonMain/tmp/minuit/package-info.kt b/kmath-optimization/src/commonMain/tmp/minuit/package-info.kt similarity index 100% rename from kmath-stat/src/commonMain/tmp/minuit/package-info.kt rename to kmath-optimization/src/commonMain/tmp/minuit/package-info.kt -- 2.34.1 From a68884142fd65e42e9cb02d308beb8294ae11512 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Mon, 27 Sep 2021 12:36:48 +0200 Subject: [PATCH 022/102] Added gradle wrapper validation See https://github.com/marketplace/actions/gradle-wrapper-validation --- .github/workflows/build.yml | 2 ++ .github/workflows/publish.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a9f04621..4ea3428c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,5 +35,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- + - name: Gradle Wrapper Validation + uses: gradle/wrapper-validation-action@v1.0.4 - name: Build run: ./gradlew build --no-daemon --stacktrace diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c5c110e89..2e51e72d8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -40,6 +40,8 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- + - name: Gradle Wrapper Validation + uses: gradle/wrapper-validation-action@v1.0.4 - name: Publish Windows Artifacts if: matrix.os == 'windows-latest' run: > -- 2.34.1 From 01bbb4bb1313f91cc584a6c9b6fdf904e34cddb7 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 2 Oct 2021 09:55:52 +0300 Subject: [PATCH 023/102] API cleanup --- build.gradle.kts | 2 +- .../space/kscience/kmath/tensors/PCA.kt | 10 +- ...rmalization.kt => dataSetNormalization.kt} | 6 +- ...thLUP.kt => linearSystemSolvingWithLUP.kt} | 6 +- .../{NeuralNetwork.kt => neuralNetwork.kt} | 0 .../kmath/linear/BufferedLinearSpace.kt | 19 ++- .../kmath/linear/DoubleLinearSpace.kt | 109 ++++++++++++++++++ .../space/kscience/kmath/nd/Structure1D.kt | 2 +- .../space/kscience/kmath/nd/Structure2D.kt | 4 +- .../space/kscience/kmath/operations/BigInt.kt | 4 +- .../kscience/kmath/structures/DoubleBuffer.kt | 6 + .../kmath/linear/DoubleLUSolverTest.kt | 35 +++--- .../space/kscience/kmath/linear/MatrixTest.kt | 30 ++--- .../kmath/structures/NumberNDFieldTest.kt | 10 +- .../kscience/kmath/dimensions/Wrappers.kt | 8 +- .../kscience/kmath/real/DoubleMatrixTest.kt | 12 +- .../kscience/kmath/real/DoubleVectorTest.kt | 8 +- .../kmath/optimization/QowOptimizer.kt | 3 +- .../core/BroadcastDoubleTensorAlgebra.kt | 11 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 2 + settings.gradle.kts | 7 +- 21 files changed, 211 insertions(+), 83 deletions(-) rename examples/src/main/kotlin/space/kscience/kmath/tensors/{DataSetNormalization.kt => dataSetNormalization.kt} (84%) rename examples/src/main/kotlin/space/kscience/kmath/tensors/{LinearSystemSolvingWithLUP.kt => linearSystemSolvingWithLUP.kt} (92%) rename examples/src/main/kotlin/space/kscience/kmath/tensors/{NeuralNetwork.kt => neuralNetwork.kt} (100%) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt diff --git a/build.gradle.kts b/build.gradle.kts index 6bb19cd35..68b894d06 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,7 +19,7 @@ allprojects { } group = "space.kscience" - version = "0.3.0-dev-14" + version = "0.3.0-dev-15" } subprojects { diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt index 3302b49a8..d83d47805 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -5,19 +5,19 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra +import space.kscience.kmath.tensors.core.tensorAlgebra +import space.kscience.kmath.tensors.core.withBroadcast // simple PCA -fun main(): Unit = BroadcastDoubleTensorAlgebra { // work in context with broadcast methods +fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with broadcast methods val seed = 100500L // assume x is range from 0 until 10 val x = fromArray( intArrayOf(10), - (0 until 10).toList().map { it.toDouble() }.toDoubleArray() + DoubleArray(10) { it.toDouble() } ) // take y dependent on x with noise @@ -62,7 +62,7 @@ fun main(): Unit = BroadcastDoubleTensorAlgebra { // work in context with broad println("Eigenvector:\n$v") // reduce dimension of dataset - val datasetReduced = v dot stack(listOf(xScaled, yScaled)) + val datasetReduced = v dot stack(listOf(xScaled, yScaled)) println("Reduced data:\n$datasetReduced") // we can restore original data from reduced data; diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt similarity index 84% rename from examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt rename to examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt index 3ef745da3..9d5b8c2a5 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt @@ -5,13 +5,13 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra +import space.kscience.kmath.tensors.core.tensorAlgebra +import space.kscience.kmath.tensors.core.withBroadcast // Dataset normalization -fun main() = BroadcastDoubleTensorAlgebra { // work in context with broadcast methods +fun main() = Double.tensorAlgebra.withBroadcast { // work in context with broadcast methods // take dataset of 5-element vectors from normal distribution val dataset = randomNormal(intArrayOf(100, 5)) * 1.5 // all elements from N(0, 1.5) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt similarity index 92% rename from examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt rename to examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt index 27886413f..846e338da 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt @@ -5,13 +5,13 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.tensorAlgebra +import space.kscience.kmath.tensors.core.withBroadcast // solving linear system with LUP decomposition -fun main() = BroadcastDoubleTensorAlgebra {// work in context with linear operations +fun main() = Double.tensorAlgebra.withBroadcast {// work in context with linear operations // set true value of x val trueX = fromArray( diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt similarity index 100% rename from examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt rename to examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt 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 5f17de607..3d562f26f 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 @@ -8,12 +8,14 @@ package space.kscience.kmath.linear import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.BufferedRingND import space.kscience.kmath.nd.as2D +import space.kscience.kmath.nd.asND import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.unwrap -import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferFactory +import space.kscience.kmath.structures.VirtualBuffer +import space.kscience.kmath.structures.indices public class BufferedLinearSpace>( @@ -33,17 +35,17 @@ public class BufferedLinearSpace>( bufferFactory(size) { elementAlgebra.initializer(it) } override fun Matrix.unaryMinus(): Matrix = ndRing(rowNum, colNum).run { - unwrap().map { -it }.as2D() + asND().map { -it }.as2D() } override fun Matrix.plus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } - unwrap().plus(other.unwrap()).as2D() + asND().plus(other.asND()).as2D() } override fun Matrix.minus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } - unwrap().minus(other.unwrap()).as2D() + asND().minus(other.asND()).as2D() } private fun Buffer.linearize() = if (this is VirtualBuffer) { @@ -87,13 +89,10 @@ public class BufferedLinearSpace>( } override fun Matrix.times(value: T): Matrix = ndRing(rowNum, colNum).run { - unwrap().map { it * value }.as2D() + asND().map { it * value }.as2D() } } public fun > A.linearSpace(bufferFactory: BufferFactory): BufferedLinearSpace = BufferedLinearSpace(this, bufferFactory) - -public val DoubleField.linearSpace: BufferedLinearSpace - get() = BufferedLinearSpace(this, ::DoubleBuffer) \ No newline at end of file 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 new file mode 100644 index 000000000..a3e031902 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt @@ -0,0 +1,109 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.linear + +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.nd.DoubleFieldND +import space.kscience.kmath.nd.as2D +import space.kscience.kmath.nd.asND +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.indices + +public object DoubleLinearSpace : LinearSpace { + + override val elementAlgebra: DoubleField get() = DoubleField + + private fun ndRing( + rows: Int, + cols: Int, + ): DoubleFieldND = DoubleFieldND(intArrayOf(rows, cols)) + + override fun buildMatrix( + rows: Int, + columns: Int, + initializer: DoubleField.(i: Int, j: Int) -> Double + ): Matrix = ndRing(rows, columns).produce { (i, j) -> DoubleField.initializer(i, j) }.as2D() + + + override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): DoubleBuffer = + DoubleBuffer(size) { DoubleField.initializer(it) } + + override fun Matrix.unaryMinus(): Matrix = ndRing(rowNum, colNum).run { + asND().map { -it }.as2D() + } + + override fun Matrix.plus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { + require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } + asND().plus(other.asND()).as2D() + } + + override fun Matrix.minus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { + require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } + asND().minus(other.asND()).as2D() + } + + // Create a continuous in-memory representation of this vector for better memory layout handling + private fun Buffer.linearize() = if (this is DoubleBuffer) { + this + } else { + DoubleBuffer(size) { get(it) } + } + + @OptIn(PerformancePitfall::class) + override fun Matrix.dot(other: Matrix): Matrix { + require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } + val rows = this@dot.rows.map { it.linearize() } + val columns = other.columns.map { it.linearize() } + return buildMatrix(rowNum, other.colNum) { i, j -> + val r = rows[i] + val c = columns[j] + var res = 0.0 + for (l in r.indices) { + res += r[l] * c[l] + } + res + } + } + + @OptIn(PerformancePitfall::class) + override fun Matrix.dot(vector: Point): DoubleBuffer { + require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } + val rows = this@dot.rows.map { it.linearize() } + return DoubleBuffer(rowNum) { i -> + val r = rows[i] + var res = 0.0 + for (j in r.indices) { + res += r[j] * vector[j] + } + res + } + + } + + override fun Matrix.times(value: Double): Matrix = ndRing(rowNum, colNum).run { + asND().map { it * value }.as2D() + } + + public override fun Point.plus(other: Point): DoubleBuffer = DoubleBuffer(size) { + get(it) + other[it] + } + + public override fun Point.minus(other: Point): DoubleBuffer = DoubleBuffer(size) { + get(it) - other[it] + } + + public override fun Point.times(value: Double): DoubleBuffer = DoubleBuffer(size) { i -> get(i) * value } + + public operator fun Point.div(value: Double): DoubleBuffer = DoubleBuffer(size) { i -> get(i) / value } + + public override fun Double.times(v: Point): DoubleBuffer = v * this + + +} + +public val DoubleField.linearSpace: DoubleLinearSpace get() = DoubleLinearSpace 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 91cd5abe9..f2a4336eb 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 @@ -136,7 +136,7 @@ public fun Buffer.asND(): Structure1D = Buffer1DWrapper(this) /** * Expose inner buffer of this [Structure1D] if possible */ -internal fun Structure1D.unwrap(): Buffer = when { +internal fun Structure1D.asND(): Buffer = when { this is Buffer1DWrapper -> buffer this is Structure1DWrapper && structure is BufferND -> structure.buffer else -> this diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index 57836a9ef..8d3cc3a3f 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 @@ -160,10 +160,10 @@ public fun MutableStructureND.as2D(): MutableStructure2D = this as? Mu /** * Expose inner [StructureND] if possible */ -internal fun Structure2D.unwrap(): StructureND = +internal fun Structure2D.asND(): StructureND = if (this is Structure2DWrapper) structure else this -internal fun MutableStructure2D.unwrap(): MutableStructureND = +internal fun MutableStructure2D.asND(): MutableStructureND = if (this is MutableStructure2DWrapper) structure else this 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 9797027c7..82754e43d 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 @@ -532,7 +532,7 @@ public val BigInt.algebra: BigIntField get() = BigIntField public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer = boxing(size, initializer) -public inline fun BigInt.buffer(size: Int, initializer: (Int) -> BigInt): Buffer = +public inline fun BigInt.Companion.buffer(size: Int, initializer: (Int) -> BigInt): Buffer = Buffer.boxing(size, initializer) @Deprecated("Use BigInt::mutableBuffer") @@ -543,4 +543,4 @@ public inline fun BigInt.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer.boxing(size, initializer) public fun BigIntField.nd(vararg shape: Int): BufferedRingND = - BufferedRingND(shape, BigIntField, Buffer.Companion::bigInt) + BufferedRingND(shape, BigIntField, BigInt::buffer) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt index b94a36bab..3b554ab07 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt @@ -25,6 +25,12 @@ public value class DoubleBuffer(public val array: DoubleArray) : MutableBuffer assertMatrixEquals(expected: StructureND, actual: StructureND = VirtualMatrix(6, 6) { row, col -> when { col == 0 -> .50 @@ -49,7 +50,7 @@ class MatrixTest { infix fun Matrix.pow(power: Int): Matrix { var res = this repeat(power - 1) { - res = LinearSpace.double.run { res dot this@pow } + res = res dot this@pow } return res } @@ -58,19 +59,18 @@ class MatrixTest { } @Test - fun test2DDot() { + fun test2DDot() = Double.algebra.linearSpace.run { val firstMatrix = StructureND.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D() val secondMatrix = StructureND.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D() - LinearSpace.double.run { // val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() } // val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() } - val result = firstMatrix dot secondMatrix - assertEquals(2, result.rowNum) - assertEquals(2, result.colNum) - assertEquals(8.0, result[0, 1]) - assertEquals(8.0, result[1, 0]) - assertEquals(14.0, result[1, 1]) - } + val result = firstMatrix dot secondMatrix + assertEquals(2, result.rowNum) + assertEquals(2, result.colNum) + assertEquals(8.0, result[0, 1]) + assertEquals(8.0, result[1, 0]) + assertEquals(14.0, result[1, 1]) + } } 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 b2982b335..e58976f4a 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,7 +5,7 @@ package space.kscience.kmath.structures -import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.combine @@ -13,6 +13,7 @@ import space.kscience.kmath.nd.get import space.kscience.kmath.nd.ndAlgebra 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.math.abs import kotlin.math.pow @@ -42,17 +43,18 @@ class NumberNDFieldTest { } @Test - fun testGeneration() { + fun testGeneration() = Double.algebra.linearSpace.run { - val array = LinearSpace.double.buildMatrix(3, 3) { i, j -> + val array = buildMatrix(3, 3) { i, j -> (i * 10 + j).toDouble() } - for (i in 0..2) + for (i in 0..2) { for (j in 0..2) { val expected = (i * 10 + j).toDouble() assertEquals(expected, array[i, j], "Error at index [$i, $j]") } + } } @Test diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt index f6c4415dc..c47f43723 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt @@ -5,13 +5,11 @@ package space.kscience.kmath.dimensions -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.linear.Point -import space.kscience.kmath.linear.transpose +import space.kscience.kmath.linear.* import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.algebra import kotlin.jvm.JvmInline /** @@ -151,7 +149,7 @@ public value class DMatrixContext>(public val context: context.run { (this@transpose as Matrix).transpose() }.coerce() public companion object { - public val real: DMatrixContext = DMatrixContext(LinearSpace.double) + public val real: DMatrixContext = DMatrixContext(Double.algebra.linearSpace) } } 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 79f05daa5..3277410c0 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,12 +5,12 @@ package space.kscience.kmath.real -import space.kscience.kmath.linear.LinearSpace +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.real.* +import space.kscience.kmath.operations.algebra import space.kscience.kmath.structures.contentEquals import kotlin.test.Test import kotlin.test.assertEquals @@ -59,13 +59,13 @@ internal class DoubleMatrixTest { } @Test - fun testMatrixAndDouble() { + fun testMatrixAndDouble() = Double.algebra.linearSpace.run { val matrix1 = realMatrix(2, 3)( 1.0, 0.0, 3.0, 4.0, 6.0, 2.0 ) val matrix2 = (matrix1 * 2.5 + 1.0 - 2.0) / 2.0 - val expectedResult = LinearSpace.double.matrix(2, 3)( + val expectedResult = matrix(2, 3)( 0.75, -0.5, 3.25, 4.5, 7.0, 2.0 ) @@ -159,8 +159,8 @@ internal class DoubleMatrixTest { } @Test - fun testAllElementOperations() { - val matrix1 = LinearSpace.double.matrix(2, 4)( + fun testAllElementOperations() = Double.algebra.linearSpace.run { + val matrix1 = matrix(2, 4)( -1.0, 0.0, 3.0, 15.0, 4.0, -6.0, 7.0, -11.0 ) diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt index 7bb936658..771981772 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt @@ -5,10 +5,10 @@ package space.kscience.kmath.real -import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.asMatrix +import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.transpose -import space.kscience.kmath.real.plus +import space.kscience.kmath.operations.algebra import space.kscience.kmath.structures.DoubleBuffer import kotlin.test.Test import kotlin.test.assertEquals @@ -30,12 +30,12 @@ internal class DoubleVectorTest { } @Test - fun testDot() { + fun testDot() = Double.algebra.linearSpace.run { val vector1 = DoubleBuffer(5) { it.toDouble() } val vector2 = DoubleBuffer(5) { 5 - it.toDouble() } val matrix1 = vector1.asMatrix() val matrix2 = vector2.asMatrix().transpose() - val product = LinearSpace.double.run { matrix1 dot matrix2 } + val product = matrix1 dot matrix2 assertEquals(5.0, product[1, 0]) assertEquals(6.0, product[2, 2]) } 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 00df0944f..68941304f 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 @@ -13,6 +13,7 @@ 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.algebra import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.DoubleL2Norm @@ -32,7 +33,7 @@ public class QowRuns(public val runs: Int) : OptimizationFeature { @UnstableKMathAPI public object QowOptimizer : Optimizer { - private val linearSpace: LinearSpace = LinearSpace.double + private val linearSpace: LinearSpace = Double.algebra.linearSpace private val solver: LinearSolver = linearSpace.lupSolver() @OptIn(UnstableKMathAPI::class) 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 3eb8e5636..3d73fd53b 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,6 +5,7 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.broadcastTensors @@ -90,4 +91,12 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { newOther.mutableBuffer.array()[tensor.bufferStart + i] } } -} \ No newline at end of file +} + + +/** + * Compute a value using broadcast double tensor algebra + */ +@UnstableKMathAPI +public fun DoubleTensorAlgebra.withBroadcast(block: BroadcastDoubleTensorAlgebra.() -> R): R = + BroadcastDoubleTensorAlgebra.block() \ No newline at end of file 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 db18220cd..8e39e6cdd 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 @@ -949,4 +949,6 @@ public open class DoubleTensorAlgebra : override fun Tensor.lu(): Triple = lu(1e-9) } +public val Double.Companion.tensorAlgebra: DoubleTensorAlgebra.Companion get() = DoubleTensorAlgebra + diff --git a/settings.gradle.kts b/settings.gradle.kts index 0fc77b38e..8cfa62133 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,11 +5,11 @@ pluginManagement { gradlePluginPortal() } - val kotlinVersion = "1.5.30" + val kotlinVersion = "1.6.0-M1" plugins { id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - id("ru.mipt.npm.gradle.project") version "0.10.3" + id("ru.mipt.npm.gradle.project") version "0.10.4" kotlin("multiplatform") version kotlinVersion kotlin("plugin.allopen") version kotlinVersion } @@ -17,6 +17,9 @@ pluginManagement { rootProject.name = "kmath" +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") +enableFeaturePreview("VERSION_CATALOGS") + include( ":kmath-memory", ":kmath-complex", -- 2.34.1 From 0f634688cc4ed5cba39596a4c72b58e30fec4d2f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 2 Oct 2021 15:56:57 +0300 Subject: [PATCH 024/102] API cleanup --- gradle.properties | 6 ++- .../DoubleBufferOperations.kt} | 48 +++++++++---------- .../kmath/operations/OptionalOperations.kt | 4 +- .../kscience/kmath/ejml/EjmlLinearSpace.kt | 4 +- .../space/kscience/kmath/real/RealVector.kt | 7 +-- 5 files changed, 37 insertions(+), 32 deletions(-) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/{structures/DoubleBufferField.kt => operations/DoubleBufferOperations.kt} (89%) diff --git a/gradle.properties b/gradle.properties index 49bbf36dd..959511c68 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,9 +4,11 @@ # kotlin.code.style=official -kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.mpp.stability.nowarn=true -kotlin.native.enableDependencyPropagation=false + +#kotlin.mpp.enableGranularSourceSetsMetadata=true +#kotlin.native.enableDependencyPropagation=false + kotlin.jupyter.add.scanner=false org.gradle.configureondemand=true diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt similarity index 89% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt index 2bf6de3cb..a95bd2541 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt @@ -3,18 +3,18 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ -package space.kscience.kmath.structures +package space.kscience.kmath.operations import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.fold import kotlin.math.* /** * [ExtendedFieldOperations] over [DoubleBuffer]. */ -@Deprecated("To be replaced by generic BufferAlgebra") -public object DoubleBufferFieldOperations : ExtendedFieldOperations> { +public object DoubleBufferOperations : ExtendedFieldOperations> { override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { DoubleBuffer(size) { -array[it] } } else { @@ -179,13 +179,13 @@ public class DoubleBufferField(public val size: Int) : ExtendedField = DoubleBuffer(size) { value.toDouble() } - override fun Buffer.unaryMinus(): Buffer = DoubleBufferFieldOperations.run { + override fun Buffer.unaryMinus(): Buffer = DoubleBufferOperations.run { -this@unaryMinus } override fun add(a: Buffer, b: Buffer): DoubleBuffer { require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - return DoubleBufferFieldOperations.add(a, b) + return DoubleBufferOperations.add(a, b) } override fun scale(a: Buffer, value: Double): DoubleBuffer { @@ -199,87 +199,87 @@ public class DoubleBufferField(public val size: Int) : ExtendedField, b: Buffer): DoubleBuffer { require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - return DoubleBufferFieldOperations.multiply(a, b) + return DoubleBufferOperations.multiply(a, b) } override fun divide(a: Buffer, b: Buffer): DoubleBuffer { require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - return DoubleBufferFieldOperations.divide(a, b) + return DoubleBufferOperations.divide(a, b) } override fun sin(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.sin(arg) + return DoubleBufferOperations.sin(arg) } override fun cos(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.cos(arg) + return DoubleBufferOperations.cos(arg) } override fun tan(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.tan(arg) + return DoubleBufferOperations.tan(arg) } override fun asin(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.asin(arg) + return DoubleBufferOperations.asin(arg) } override fun acos(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.acos(arg) + return DoubleBufferOperations.acos(arg) } override fun atan(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.atan(arg) + return DoubleBufferOperations.atan(arg) } override fun sinh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.sinh(arg) + return DoubleBufferOperations.sinh(arg) } override fun cosh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.cosh(arg) + return DoubleBufferOperations.cosh(arg) } override fun tanh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.tanh(arg) + return DoubleBufferOperations.tanh(arg) } override fun asinh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.asinh(arg) + return DoubleBufferOperations.asinh(arg) } override fun acosh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.acosh(arg) + return DoubleBufferOperations.acosh(arg) } override fun atanh(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.atanh(arg) + return DoubleBufferOperations.atanh(arg) } override fun power(arg: Buffer, pow: Number): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.power(arg, pow) + return DoubleBufferOperations.power(arg, pow) } override fun exp(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.exp(arg) + return DoubleBufferOperations.exp(arg) } override fun ln(arg: Buffer): DoubleBuffer { require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.ln(arg) + return DoubleBufferOperations.ln(arg) } override fun norm(arg: Buffer): Double = DoubleL2Norm.norm(arg) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt index 7f44eda49..3a2703c54 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt @@ -306,14 +306,14 @@ public fun >> tanh(arg: T): T */ @UnstableKMathAPI @Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> asinh(arg: T): T = arg.context.asinh(arg) +public fun >> asinh(arg: T): T = arg.context.asinh(arg) /** * Computes the inverse hyperbolic cosine of [arg]. */ @UnstableKMathAPI @Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> acosh(arg: T): T = arg.context.acosh(arg) +public fun >> acosh(arg: T): T = arg.context.acosh(arg) /** * Computes the inverse hyperbolic tangent of [arg]. 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 4a53af60d..25333157a 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 @@ -40,6 +40,8 @@ public abstract class EjmlLinearSpace, out M : org.ejml public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector + @Suppress("UNCHECKED_CAST") @UnstableKMathAPI - public fun EjmlMatrix.inverse(): Structure2D = computeFeature(this, InverseMatrixFeature::class)?.inverse as Structure2D + public fun EjmlMatrix.inverse(): Structure2D = + computeFeature(this, InverseMatrixFeature::class)?.inverse as Structure2D } diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt index b707ebfc5..cca1c3551 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt @@ -7,11 +7,12 @@ package space.kscience.kmath.real import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Norm -import space.kscience.kmath.structures.* +import space.kscience.kmath.operations.DoubleL2Norm +import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer.Companion.double +import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.indices import kotlin.math.pow -import kotlin.math.sqrt public typealias DoubleVector = Point -- 2.34.1 From 85aefb538096e96f9e50d68896c20378f3d9ba49 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 2 Oct 2021 16:14:38 +0300 Subject: [PATCH 025/102] Completely remove AlgebraElements.kt --- CHANGELOG.md | 1 + .../kmath/ejml/codegen/ejmlCodegen.kt | 20 +-- .../kscience/kmath/linear/dotPerformance.kt | 2 +- .../kmath/operations/AlgebraElements.kt | 128 ----------------- .../kmath/operations/OptionalOperations.kt | 130 ------------------ .../kmath/optimization/QowOptimizer.kt | 3 +- 6 files changed, 14 insertions(+), 270 deletions(-) delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index c27dafeb4..6cb9f57f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ - Expression algebra builders - Complex and Quaternion no longer are elements. - Second generic from DifferentiableExpression +- Algebra elements are completely removed. Use algebra contexts instead. ### Fixed - Ring inherits RingOperations, not GroupOperations 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 a533e98a5..cfebf61e7 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 @@ -240,10 +240,10 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } override val q: Matrix<${type}> by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) } - override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix() + UFeature } + override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> { @@ -251,7 +251,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, val cholesky = DecompositionFactory_${ops}.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - cholesky.getT(null).wrapMatrix() + LFeature + cholesky.getT(null).wrapMatrix().withFeature(LFeature) } } @@ -261,11 +261,11 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } override val l: Matrix<${type}> by lazy { - lup.getLower(null).wrapMatrix() + LFeature + lup.getLower(null).wrapMatrix().withFeature(LFeature) } override val u: Matrix<${type}> by lazy { - lup.getUpper(null).wrapMatrix() + UFeature + lup.getUpper(null).wrapMatrix().withFeature(UFeature) } override val p: Matrix<${type}> by lazy { lup.getRowPivot(null).wrapMatrix() } @@ -275,10 +275,10 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } override val q: Matrix<${type}> by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) } - override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix() + UFeature } + override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> { @@ -286,7 +286,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, val cholesky = DecompositionFactory_${ops}.cholesky().apply { decompose(origin.copy()) } - (cholesky.getT(null) as ${ejmlMatrixParentTypeMatrix}).wrapMatrix() + LFeature + (cholesky.getT(null) as ${ejmlMatrixParentTypeMatrix}).wrapMatrix().withFeature(LFeature) } } @@ -297,11 +297,11 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } override val l: Matrix<${type}> by lazy { - lu.getLower(null).wrapMatrix() + LFeature + lu.getLower(null).wrapMatrix().withFeature(LFeature) } override val u: Matrix<${type}> by lazy { - lu.getUpper(null).wrapMatrix() + UFeature + lu.getUpper(null).wrapMatrix().withFeature(UFeature) } override val inverse: Matrix<${type}> by lazy { 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 31762b6d8..6e8767a5b 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt @@ -24,7 +24,7 @@ fun main() { val time = measureTimeMillis { with(Double.algebra.linearSpace) { repeat(10) { - val res = matrix1 dot matrix2 + matrix1 dot matrix2 } } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt deleted file mode 100644 index 7669e073a..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * The generic mathematics elements that is able to store its context - * - * @param C the type of mathematical context for this element. - * @param T the type wrapped by this wrapper. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public interface AlgebraElement> { - /** - * The context this element belongs to. - */ - public val context: C -} -// -///** -// * Divides this element by number. -// * -// * @param k the divisor. -// * @return the quotient. -// */ -//public operator fun , S : Space> T.div(k: Number): T = -// context.multiply(this, 1.0 / k.toDouble()) -// -///** -// * Multiplies this element by number. -// * -// * @param k the multiplicand. -// * @return the product. -// */ -//public operator fun , S : Space> T.times(k: Number): T = -// context.multiply(this, k.toDouble()) - -/** - * Subtracts element from this one. - * - * @param b the subtrahend. - * @return the difference. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public operator fun , S : NumbersAddOperations> T.minus(b: T): T = - context.add(this, context.run { -b }) - -/** - * Adds element to this one. - * - * @receiver the augend. - * @param b the addend. - * @return the sum. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public operator fun , S : Ring> T.plus(b: T): T = - context.add(this, b) - -///** -// * Number times element -// */ -//public operator fun , S : Space> Number.times(element: T): T = -// element.times(this) - -/** - * Multiplies this element by another one. - * - * @receiver the multiplicand. - * @param b the multiplier. - * @return the product. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public operator fun , R : Ring> T.times(b: T): T = - context.multiply(this, b) - - -/** - * Divides this element by another one. - * - * @param b the divisor. - * @return the quotient. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public operator fun , F : Field> T.div(b: T): T = - context.divide(this, b) - - -/** - * The element of [Group]. - * - * @param T the type of space operation results. - * @param I self type of the element. Needed for static type checking. - * @param S the type of space. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public interface GroupElement, S : Group> : AlgebraElement - -/** - * The element of [Ring]. - * - * @param T the type of ring operation results. - * @param I self type of the element. Needed for static type checking. - * @param R the type of ring. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public interface RingElement, R : Ring> : GroupElement - -/** - * The element of [Field]. - * - * @param T the type of field operation results. - * @param I self type of the element. Needed for static type checking. - * @param F the type of field. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public interface FieldElement, F : Field> : RingElement diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt index 3a2703c54..d32e03533 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt @@ -5,8 +5,6 @@ package space.kscience.kmath.operations -import space.kscience.kmath.misc.UnstableKMathAPI - /** * A container for trigonometric operations for specific type. * @@ -76,48 +74,6 @@ public interface TrigonometricOperations : Algebra { } } -/** - * Computes the sine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> sin(arg: T): T = arg.context.sin(arg) - -/** - * Computes the cosine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> cos(arg: T): T = arg.context.cos(arg) - -/** - * Computes the tangent of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> tan(arg: T): T = arg.context.tan(arg) - -/** - * Computes the inverse sine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> asin(arg: T): T = arg.context.asin(arg) - -/** - * Computes the inverse cosine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> acos(arg: T): T = arg.context.acos(arg) - -/** - * Computes the inverse tangent of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> atan(arg: T): T = arg.context.atan(arg) - /** * A context extension to include power operations based on exponentiation. * @@ -152,31 +108,6 @@ public interface PowerOperations : Algebra { } } -/** - * Raises this element to the power [power]. - * - * @receiver the base. - * @param power the exponent. - * @return the base raised to the power. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public infix fun >> T.pow(power: Double): T = context.power(this, power) - -/** - * Computes the square root of the value [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> sqrt(arg: T): T = arg pow 0.5 - -/** - * Computes the square of the value [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> sqr(arg: T): T = arg pow 2.0 - /** * A container for operations related to `exp` and `ln` functions. * @@ -266,62 +197,6 @@ public interface ExponentialOperations : Algebra { } } -/** - * The identifier of exponential function. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> exp(arg: T): T = arg.context.exp(arg) - -/** - * The identifier of natural logarithm. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> ln(arg: T): T = arg.context.ln(arg) - - -/** - * Computes the hyperbolic sine of [arg]. - */ -@UnstableKMathAPI -public fun >> sinh(arg: T): T = arg.context.sinh(arg) - -/** - * Computes the hyperbolic cosine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> cosh(arg: T): T = arg.context.cosh(arg) - -/** - * Computes the hyperbolic tangent of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> tanh(arg: T): T = arg.context.tanh(arg) - -/** - * Computes the inverse hyperbolic sine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> asinh(arg: T): T = arg.context.asinh(arg) - -/** - * Computes the inverse hyperbolic cosine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> acosh(arg: T): T = arg.context.acosh(arg) - -/** - * Computes the inverse hyperbolic tangent of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> atanh(arg: T): T = arg.context.atanh(arg) - /** * A container for norm functional on element. * @@ -335,8 +210,3 @@ public interface Norm { public fun norm(arg: T): R } -/** - * Computes the norm of [arg] (i.e., absolute value or vector length). - */ -@UnstableKMathAPI -public fun >, R> norm(arg: T): R = arg.context.norm(arg) diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt index 68941304f..babbaf6cd 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 @@ -13,9 +13,10 @@ 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 import space.kscience.kmath.operations.algebra import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.DoubleL2Norm + public class QowRuns(public val runs: Int) : OptimizationFeature { init { -- 2.34.1 From abae29bbede98231c17ebe00708443ac39fbb854 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 2 Oct 2021 18:54:45 +0300 Subject: [PATCH 026/102] DoubleBuffer algebra refactoring --- .../space/kscience/kmath/fit/chiSquared.kt | 11 +- .../kotlin/space/kscience/kmath/fit/qowFit.kt | 4 +- .../kmath/functions/interpolateSquare.kt | 2 +- .../commons/transform/Transformations.kt | 7 +- .../commons/optimization/OptimizeTest.kt | 2 +- .../kmath/expressions/specialExpressions.kt | 2 +- .../kmath/linear/DoubleLinearSpace.kt | 17 +- .../space/kscience/kmath/nd/Structure1D.kt | 2 +- .../kmath/operations/DoubleBufferField.kt | 130 +++ .../operations/DoubleBufferOperations.kt | 150 +-- .../bufferOperation.kt | 3 +- .../kscience/kmath/operations/numbers.kt | 5 +- .../space/kscience/kmath/structures/Buffer.kt | 4 +- .../kmath/streaming/RingBufferTest.kt | 2 +- .../space/kscience/kmath/ejml/_generated.kt | 995 ++++++++++++++++++ .../space/kscience/kmath/real/RealMatrix.kt | 2 +- .../integration/GaussIntegratorRuleFactory.kt | 2 +- .../kmath/integration/SplineIntegrator.kt | 6 +- .../kscience/kmath/geometry/Vector2DTest.kt | 5 +- .../kscience/kmath/geometry/Vector3DTest.kt | 2 +- .../kmath/histogram/UnivariateHistogram.kt | 4 +- .../kscience/kmath/jupyter/KMathJupyter.kt | 2 +- .../space/kscience/kmath/stat/Median.kt | 2 +- .../kmath/tensors/core/internal/linUtils.kt | 2 +- .../kmath/tensors/core/internal/utils.kt | 1 + 25 files changed, 1203 insertions(+), 161 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/{structures => operations}/bufferOperation.kt (97%) create mode 100644 kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt 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 8db97d672..dbe0b8454 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt @@ -10,20 +10,21 @@ 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.binding import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.optimization.* +import space.kscience.kmath.operations.asIterable +import space.kscience.kmath.operations.toList +import space.kscience.kmath.optimization.FunctionOptimizationTarget +import space.kscience.kmath.optimization.optimizeWith +import space.kscience.kmath.optimization.resultPoint +import space.kscience.kmath.optimization.resultValue import space.kscience.kmath.real.DoubleVector import space.kscience.kmath.real.map import space.kscience.kmath.real.step import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.structures.asIterable -import space.kscience.kmath.structures.toList import space.kscience.plotly.* import space.kscience.plotly.models.ScatterMode import space.kscience.plotly.models.TraceValues -import kotlin.math.abs import kotlin.math.pow import kotlin.math.sqrt 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 04764d763..d52976671 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt @@ -13,6 +13,8 @@ import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.expressions.Symbol 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 @@ -20,8 +22,6 @@ import space.kscience.kmath.optimization.resultPoint import space.kscience.kmath.real.map import space.kscience.kmath.real.step import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.structures.asIterable -import space.kscience.kmath.structures.toList import space.kscience.plotly.* import space.kscience.plotly.models.ScatterMode import kotlin.math.abs diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt index 76422d658..3f958b3b0 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt @@ -8,8 +8,8 @@ package space.kscience.kmath.functions import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.real.map import space.kscience.kmath.real.step -import space.kscience.kmath.structures.map import space.kscience.plotly.Plotly import space.kscience.plotly.UnstablePlotlyAPI import space.kscience.plotly.makeFile diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt index 1a99e9fc6..73ab91542 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt @@ -10,10 +10,13 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import org.apache.commons.math3.transform.* import space.kscience.kmath.complex.Complex +import space.kscience.kmath.operations.SuspendBufferTransform import space.kscience.kmath.streaming.chunked import space.kscience.kmath.streaming.spread -import space.kscience.kmath.structures.* - +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.VirtualBuffer +import space.kscience.kmath.structures.asBuffer /** 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 681ec9ebc..c670ceead 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 @@ -13,11 +13,11 @@ import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.Symbol.Companion.y import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.operations.map import space.kscience.kmath.optimization.* import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.map import kotlin.math.pow import kotlin.test.Test diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt index 6b17dfca5..907ce4004 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt @@ -6,8 +6,8 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.asIterable import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asIterable import space.kscience.kmath.structures.indices import kotlin.jvm.JvmName 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 a3e031902..4a1311b54 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 @@ -9,6 +9,7 @@ import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.DoubleFieldND import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.asND +import space.kscience.kmath.operations.DoubleBufferOperations import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer @@ -89,17 +90,21 @@ public object DoubleLinearSpace : LinearSpace { asND().map { it * value }.as2D() } - public override fun Point.plus(other: Point): DoubleBuffer = DoubleBuffer(size) { - get(it) + other[it] + public override fun Point.plus(other: Point): DoubleBuffer = DoubleBufferOperations.run { + this@plus + other } - public override fun Point.minus(other: Point): DoubleBuffer = DoubleBuffer(size) { - get(it) - other[it] + public override fun Point.minus(other: Point): DoubleBuffer = DoubleBufferOperations.run { + this@minus - other } - public override fun Point.times(value: Double): DoubleBuffer = DoubleBuffer(size) { i -> get(i) * value } + public override fun Point.times(value: Double): DoubleBuffer = DoubleBufferOperations.run { + scale(this@times, value) + } - public operator fun Point.div(value: Double): DoubleBuffer = DoubleBuffer(size) { i -> get(i) / value } + public operator fun Point.div(value: Double): DoubleBuffer = DoubleBufferOperations.run { + scale(this@div, 1.0 / value) + } public override fun Double.times(v: Point): DoubleBuffer = v * this 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 f2a4336eb..3dcc77334 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 @@ -6,10 +6,10 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.asMutableBuffer -import space.kscience.kmath.structures.asSequence import kotlin.jvm.JvmInline /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt new file mode 100644 index 000000000..acc2c2dc0 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt @@ -0,0 +1,130 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.operations + +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.DoubleBuffer + +/** + * [ExtendedField] over [DoubleBuffer]. + * + * @property size the size of buffers to operate on. + */ +public class DoubleBufferField(public val size: Int) : ExtendedField>, DoubleBufferOperations() { + override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } + override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } + + override fun sinh(arg: Buffer): DoubleBuffer = super.sinh(arg) + + override fun cosh(arg: Buffer): DoubleBuffer = super.cosh(arg) + + override fun tanh(arg: Buffer): DoubleBuffer = super.tanh(arg) + + override fun asinh(arg: Buffer): DoubleBuffer = super.asinh(arg) + + override fun acosh(arg: Buffer): DoubleBuffer = super.acosh(arg) + + override fun atanh(arg: Buffer): DoubleBuffer= super.atanh(arg) + + // override fun number(value: Number): Buffer = DoubleBuffer(size) { value.toDouble() } +// +// override fun Buffer.unaryMinus(): Buffer = DoubleBufferOperations.run { +// -this@unaryMinus +// } +// +// override fun add(a: Buffer, b: Buffer): DoubleBuffer { +// require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } +// return DoubleBufferOperations.add(a, b) +// } +// + +// +// override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { +// require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } +// return DoubleBufferOperations.multiply(a, b) +// } +// +// override fun divide(a: Buffer, b: Buffer): DoubleBuffer { +// require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } +// return DoubleBufferOperations.divide(a, b) +// } +// +// override fun sin(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.sin(arg) +// } +// +// override fun cos(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.cos(arg) +// } +// +// override fun tan(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.tan(arg) +// } +// +// override fun asin(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.asin(arg) +// } +// +// override fun acos(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.acos(arg) +// } +// +// override fun atan(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.atan(arg) +// } +// +// override fun sinh(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.sinh(arg) +// } +// +// override fun cosh(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.cosh(arg) +// } +// +// override fun tanh(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.tanh(arg) +// } +// +// override fun asinh(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.asinh(arg) +// } +// +// override fun acosh(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.acosh(arg) +// } +// +// override fun atanh(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.atanh(arg) +// } +// +// override fun power(arg: Buffer, pow: Number): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.power(arg, pow) +// } +// +// override fun exp(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.exp(arg) +// } +// +// override fun ln(arg: Buffer): DoubleBuffer { +// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } +// return DoubleBufferOperations.ln(arg) +// } + +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt index a95bd2541..50b821962 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt @@ -8,13 +8,13 @@ package space.kscience.kmath.operations import space.kscience.kmath.linear.Point import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.fold + import kotlin.math.* /** * [ExtendedFieldOperations] over [DoubleBuffer]. */ -public object DoubleBufferOperations : ExtendedFieldOperations> { +public abstract class DoubleBufferOperations : ExtendedFieldOperations>, Norm, Double> { override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { DoubleBuffer(size) { -array[it] } } else { @@ -32,7 +32,22 @@ public object DoubleBufferOperations : ExtendedFieldOperations> { DoubleBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] }) } else DoubleBuffer(DoubleArray(a.size) { a[it] + b[it] }) } -// + + override fun Buffer.plus(b: Buffer): DoubleBuffer = add(this, b) + + override fun Buffer.minus(b: Buffer): DoubleBuffer { + require(b.size == this.size) { + "The size of the first buffer ${this.size} should be the same as for second one: ${b.size} " + } + + return if (this is DoubleBuffer && b is DoubleBuffer) { + val aArray = this.array + val bArray = b.array + DoubleBuffer(DoubleArray(this.size) { aArray[it] - bArray[it] }) + } else DoubleBuffer(DoubleArray(this.size) { this[it] - b[it] }) + } + + // // override fun multiply(a: Buffer, k: Number): RealBuffer { // val kValue = k.toDouble() // @@ -159,128 +174,21 @@ public object DoubleBufferOperations : ExtendedFieldOperations> { override fun ln(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) }) - } else + } else { DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) }) + } + + override fun norm(arg: Buffer): Double = DoubleL2Norm.norm(arg) + + override fun scale(a: Buffer, value: Double): DoubleBuffer = if (a is DoubleBuffer) { + val aArray = a.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] * value }) + } else DoubleBuffer(DoubleArray(a.size) { a[it] * value }) + + public companion object : DoubleBufferOperations() } public object DoubleL2Norm : Norm, Double> { override fun norm(arg: Point): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) } -/** - * [ExtendedField] over [DoubleBuffer]. - * - * @property size the size of buffers to operate on. - */ -@Deprecated("To be replaced by generic BufferAlgebra") -public class DoubleBufferField(public val size: Int) : ExtendedField>, Norm, Double> { - override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } - override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } - - override fun number(value: Number): Buffer = DoubleBuffer(size) { value.toDouble() } - - override fun Buffer.unaryMinus(): Buffer = DoubleBufferOperations.run { - -this@unaryMinus - } - - override fun add(a: Buffer, b: Buffer): DoubleBuffer { - require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - return DoubleBufferOperations.add(a, b) - } - - override fun scale(a: Buffer, value: Double): DoubleBuffer { - require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - - return if (a is DoubleBuffer) { - val aArray = a.array - DoubleBuffer(DoubleArray(a.size) { aArray[it] * value }) - } else DoubleBuffer(DoubleArray(a.size) { a[it] * value }) - } - - override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { - require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - return DoubleBufferOperations.multiply(a, b) - } - - override fun divide(a: Buffer, b: Buffer): DoubleBuffer { - require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - return DoubleBufferOperations.divide(a, b) - } - - override fun sin(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.sin(arg) - } - - override fun cos(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.cos(arg) - } - - override fun tan(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.tan(arg) - } - - override fun asin(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.asin(arg) - } - - override fun acos(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.acos(arg) - } - - override fun atan(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.atan(arg) - } - - override fun sinh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.sinh(arg) - } - - override fun cosh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.cosh(arg) - } - - override fun tanh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.tanh(arg) - } - - override fun asinh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.asinh(arg) - } - - override fun acosh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.acosh(arg) - } - - override fun atanh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.atanh(arg) - } - - override fun power(arg: Buffer, pow: Number): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.power(arg, pow) - } - - override fun exp(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.exp(arg) - } - - override fun ln(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferOperations.ln(arg) - } - - override fun norm(arg: Buffer): Double = DoubleL2Norm.norm(arg) -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt similarity index 97% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt index bc3f5b64b..6bf3266e3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt @@ -3,9 +3,10 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ -package space.kscience.kmath.structures +package space.kscience.kmath.operations import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.structures.* /** * Typealias for buffer transformations. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index c90553aaa..4c0010bf9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -14,7 +14,8 @@ public interface ExtendedFieldOperations : FieldOperations, TrigonometricOperations, PowerOperations, - ExponentialOperations { + ExponentialOperations, + ScaleOperations { override fun tan(arg: T): T = sin(arg) / cos(arg) override fun tanh(arg: T): T = sinh(arg) / cosh(arg) @@ -41,7 +42,7 @@ public interface ExtendedFieldOperations : /** * Advanced Number-like field that implements basic operations. */ -public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra, ScaleOperations { +public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra{ override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index fc23169ca..c68bca2d9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.structures +import space.kscience.kmath.operations.asSequence import kotlin.jvm.JvmInline import kotlin.reflect.KClass @@ -49,7 +50,8 @@ public interface Buffer { public companion object { - public fun toString(buffer: Buffer<*>): String = buffer.asSequence().joinToString(prefix = "[", separator = ", ", postfix = "]") + public fun toString(buffer: Buffer<*>): String = + buffer.asSequence().joinToString(prefix = "[", separator = ", ", postfix = "]") /** * Check the element-by-element match of content of two buffers. diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt index 14081b0f5..a3143a1ac 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.streaming import kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking -import space.kscience.kmath.structures.asSequence +import space.kscience.kmath.operations.asSequence import kotlin.test.Test import kotlin.test.assertEquals 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 new file mode 100644 index 000000000..dce739dc2 --- /dev/null +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt @@ -0,0 +1,995 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */ + +package space.kscience.kmath.ejml + +import org.ejml.data.* +import org.ejml.dense.row.CommonOps_DDRM +import org.ejml.dense.row.CommonOps_FDRM +import org.ejml.dense.row.factory.DecompositionFactory_DDRM +import org.ejml.dense.row.factory.DecompositionFactory_FDRM +import org.ejml.sparse.FillReducing +import org.ejml.sparse.csc.CommonOps_DSCC +import org.ejml.sparse.csc.CommonOps_FSCC +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.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 +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.FloatBuffer +import kotlin.reflect.KClass +import kotlin.reflect.cast + +/** + * [EjmlVector] specialization for [Double]. + */ +public class EjmlDoubleVector(override val origin: M) : EjmlVector(origin) { + init { + require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } + } + + override operator fun get(index: Int): Double = origin[0, index] +} + +/** + * [EjmlVector] specialization for [Float]. + */ +public class EjmlFloatVector(override val origin: M) : EjmlVector(origin) { + init { + require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } + } + + override operator fun get(index: Int): Float = origin[0, index] +} + +/** + * [EjmlMatrix] specialization for [Double]. + */ +public class EjmlDoubleMatrix(override val origin: M) : EjmlMatrix(origin) { + override operator fun get(i: Int, j: Int): Double = origin[i, j] +} + +/** + * [EjmlMatrix] specialization for [Float]. + */ +public class EjmlFloatMatrix(override val origin: M) : EjmlMatrix(origin) { + override operator fun get(i: Int, j: Int): Float = origin[i, j] +} + +/** + * [EjmlLinearSpace] implementation based on [CommonOps_DDRM], [DecompositionFactory_DDRM] operations and + * [DMatrixRMaj] matrices. + */ +public object EjmlLinearSpaceDDRM : EjmlLinearSpace() { + /** + * The [DoubleField] reference. + */ + override val elementAlgebra: DoubleField get() = DoubleField + + @Suppress("UNCHECKED_CAST") + override fun Matrix.toEjml(): EjmlDoubleMatrix = when { + this is EjmlDoubleMatrix<*> && origin is DMatrixRMaj -> this as EjmlDoubleMatrix + else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } + } + + @Suppress("UNCHECKED_CAST") + override fun Point.toEjml(): EjmlDoubleVector = when { + this is EjmlDoubleVector<*> && origin is DMatrixRMaj -> this as EjmlDoubleVector + else -> EjmlDoubleVector(DMatrixRMaj(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } + }) + } + + override fun buildMatrix( + rows: Int, + columns: Int, + initializer: DoubleField.(i: Int, j: Int) -> Double, + ): EjmlDoubleMatrix = DMatrixRMaj(rows, columns).also { + (0 until rows).forEach { row -> + (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } + } + }.wrapMatrix() + + override fun buildVector( + size: Int, + initializer: DoubleField.(Int) -> Double, + ): EjmlDoubleVector = EjmlDoubleVector(DMatrixRMaj(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } + }) + + private fun T.wrapMatrix() = EjmlDoubleMatrix(this) + private fun T.wrapVector() = EjmlDoubleVector(this) + + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + + override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixRMaj(1, 1) + CommonOps_DDRM.mult(toEjml().origin, other.toEjml().origin, out) + return out.wrapMatrix() + } + + override fun Matrix.dot(vector: Point): EjmlDoubleVector { + val out = DMatrixRMaj(1, 1) + CommonOps_DDRM.mult(toEjml().origin, vector.toEjml().origin, out) + return out.wrapVector() + } + + override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixRMaj(1, 1) + + CommonOps_DDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + ) + + return out.wrapMatrix() + } + + override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.scale(value, toEjml().origin, res) + return res.wrapMatrix() + } + + override fun Point.unaryMinus(): EjmlDoubleVector { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.changeSign(toEjml().origin, res) + return res.wrapVector() + } + + override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixRMaj(1, 1) + + CommonOps_DDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + ) + + return out.wrapMatrix() + } + + override fun Point.plus(other: Point): EjmlDoubleVector { + val out = DMatrixRMaj(1, 1) + + CommonOps_DDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + ) + + return out.wrapVector() + } + + override fun Point.minus(other: Point): EjmlDoubleVector { + val out = DMatrixRMaj(1, 1) + + CommonOps_DDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + ) + + return out.wrapVector() + } + + override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this + + override fun Point.times(value: Double): EjmlDoubleVector { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.scale(value, toEjml().origin, res) + return res.wrapVector() + } + + override fun Double.times(v: Point): EjmlDoubleVector = v * this + + @UnstableKMathAPI + override fun computeFeature(structure: Matrix, type: KClass): F? { + structure.getFeature(type)?.let { return it } + val origin = structure.toEjml().origin + + return when (type) { + InverseMatrixFeature::class -> object : InverseMatrixFeature { + override val inverse: Matrix by lazy { + val res = origin.copy() + CommonOps_DDRM.invert(res) + res.wrapMatrix() + } + } + + DeterminantFeature::class -> object : DeterminantFeature { + override val determinant: Double by lazy { CommonOps_DDRM.det(origin) } + } + + SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { + private val svd by lazy { + DecompositionFactory_DDRM.svd(origin.numRows, origin.numCols, true, true, false) + .apply { decompose(origin.copy()) } + } + + override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } + override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } + override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } + override val singularValues: Point by lazy { DoubleBuffer(svd.singularValues) } + } + + QRDecompositionFeature::class -> object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } + } + + override val q: Matrix by lazy { + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + } + + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + } + + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { + val cholesky = + DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } + + cholesky.getT(null).wrapMatrix().withFeature(LFeature) + } + } + + LupDecompositionFeature::class -> object : LupDecompositionFeature { + private val lup by lazy { + DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } + } + + override val l: Matrix by lazy { + lup.getLower(null).wrapMatrix().withFeature(LFeature) + } + + override val u: Matrix by lazy { + lup.getUpper(null).wrapMatrix().withFeature(UFeature) + } + + override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } + } + + else -> null + }?.let(type::cast) + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p matrix. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) + return res.wrapMatrix() + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p vector. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Point): EjmlDoubleVector { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) + return EjmlDoubleVector(res) + } +} + +/** + * [EjmlLinearSpace] implementation based on [CommonOps_FDRM], [DecompositionFactory_FDRM] operations and + * [FMatrixRMaj] matrices. + */ +public object EjmlLinearSpaceFDRM : EjmlLinearSpace() { + /** + * The [FloatField] reference. + */ + override val elementAlgebra: FloatField get() = FloatField + + @Suppress("UNCHECKED_CAST") + override fun Matrix.toEjml(): EjmlFloatMatrix = when { + this is EjmlFloatMatrix<*> && origin is FMatrixRMaj -> this as EjmlFloatMatrix + else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } + } + + @Suppress("UNCHECKED_CAST") + override fun Point.toEjml(): EjmlFloatVector = when { + this is EjmlFloatVector<*> && origin is FMatrixRMaj -> this as EjmlFloatVector + else -> EjmlFloatVector(FMatrixRMaj(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } + }) + } + + override fun buildMatrix( + rows: Int, + columns: Int, + initializer: FloatField.(i: Int, j: Int) -> Float, + ): EjmlFloatMatrix = FMatrixRMaj(rows, columns).also { + (0 until rows).forEach { row -> + (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } + } + }.wrapMatrix() + + override fun buildVector( + size: Int, + initializer: FloatField.(Int) -> Float, + ): EjmlFloatVector = EjmlFloatVector(FMatrixRMaj(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } + }) + + private fun T.wrapMatrix() = EjmlFloatMatrix(this) + private fun T.wrapVector() = EjmlFloatVector(this) + + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + + override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { + val out = FMatrixRMaj(1, 1) + CommonOps_FDRM.mult(toEjml().origin, other.toEjml().origin, out) + return out.wrapMatrix() + } + + override fun Matrix.dot(vector: Point): EjmlFloatVector { + val out = FMatrixRMaj(1, 1) + CommonOps_FDRM.mult(toEjml().origin, vector.toEjml().origin, out) + return out.wrapVector() + } + + override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { + val out = FMatrixRMaj(1, 1) + + CommonOps_FDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + ) + + return out.wrapMatrix() + } + + override operator fun Matrix.times(value: Float): EjmlFloatMatrix { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.scale(value, toEjml().origin, res) + return res.wrapMatrix() + } + + override fun Point.unaryMinus(): EjmlFloatVector { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.changeSign(toEjml().origin, res) + return res.wrapVector() + } + + override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { + val out = FMatrixRMaj(1, 1) + + CommonOps_FDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + ) + + return out.wrapMatrix() + } + + override fun Point.plus(other: Point): EjmlFloatVector { + val out = FMatrixRMaj(1, 1) + + CommonOps_FDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + ) + + return out.wrapVector() + } + + override fun Point.minus(other: Point): EjmlFloatVector { + val out = FMatrixRMaj(1, 1) + + CommonOps_FDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + ) + + return out.wrapVector() + } + + override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this + + override fun Point.times(value: Float): EjmlFloatVector { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.scale(value, toEjml().origin, res) + return res.wrapVector() + } + + override fun Float.times(v: Point): EjmlFloatVector = v * this + + @UnstableKMathAPI + override fun computeFeature(structure: Matrix, type: KClass): F? { + structure.getFeature(type)?.let { return it } + val origin = structure.toEjml().origin + + return when (type) { + InverseMatrixFeature::class -> object : InverseMatrixFeature { + override val inverse: Matrix by lazy { + val res = origin.copy() + CommonOps_FDRM.invert(res) + res.wrapMatrix() + } + } + + DeterminantFeature::class -> object : DeterminantFeature { + override val determinant: Float by lazy { CommonOps_FDRM.det(origin) } + } + + SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { + private val svd by lazy { + DecompositionFactory_FDRM.svd(origin.numRows, origin.numCols, true, true, false) + .apply { decompose(origin.copy()) } + } + + override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } + override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } + override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } + override val singularValues: Point by lazy { FloatBuffer(svd.singularValues) } + } + + QRDecompositionFeature::class -> object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) } + } + + override val q: Matrix by lazy { + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + } + + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + } + + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { + val cholesky = + DecompositionFactory_FDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } + + cholesky.getT(null).wrapMatrix().withFeature(LFeature) + } + } + + LupDecompositionFeature::class -> object : LupDecompositionFeature { + private val lup by lazy { + DecompositionFactory_FDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } + } + + override val l: Matrix by lazy { + lup.getLower(null).wrapMatrix().withFeature(LFeature) + } + + override val u: Matrix by lazy { + lup.getUpper(null).wrapMatrix().withFeature(UFeature) + } + + override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } + } + + else -> null + }?.let(type::cast) + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p matrix. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) + return res.wrapMatrix() + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p vector. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Point): EjmlFloatVector { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) + return EjmlFloatVector(res) + } +} + +/** + * [EjmlLinearSpace] implementation based on [CommonOps_DSCC], [DecompositionFactory_DSCC] operations and + * [DMatrixSparseCSC] matrices. + */ +public object EjmlLinearSpaceDSCC : EjmlLinearSpace() { + /** + * The [DoubleField] reference. + */ + override val elementAlgebra: DoubleField get() = DoubleField + + @Suppress("UNCHECKED_CAST") + override fun Matrix.toEjml(): EjmlDoubleMatrix = when { + this is EjmlDoubleMatrix<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleMatrix + else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } + } + + @Suppress("UNCHECKED_CAST") + override fun Point.toEjml(): EjmlDoubleVector = when { + this is EjmlDoubleVector<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleVector + else -> EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } + }) + } + + override fun buildMatrix( + rows: Int, + columns: Int, + initializer: DoubleField.(i: Int, j: Int) -> Double, + ): EjmlDoubleMatrix = DMatrixSparseCSC(rows, columns).also { + (0 until rows).forEach { row -> + (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } + } + }.wrapMatrix() + + override fun buildVector( + size: Int, + initializer: DoubleField.(Int) -> Double, + ): EjmlDoubleVector = EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } + }) + + private fun T.wrapMatrix() = EjmlDoubleMatrix(this) + private fun T.wrapVector() = EjmlDoubleVector(this) + + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + + override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.mult(toEjml().origin, other.toEjml().origin, out) + return out.wrapMatrix() + } + + override fun Matrix.dot(vector: Point): EjmlDoubleVector { + val out = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.mult(toEjml().origin, vector.toEjml().origin, out) + return out.wrapVector() + } + + override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixSparseCSC(1, 1) + + CommonOps_DSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapMatrix() + } + + override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.scale(value, toEjml().origin, res) + return res.wrapMatrix() + } + + override fun Point.unaryMinus(): EjmlDoubleVector { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.changeSign(toEjml().origin, res) + return res.wrapVector() + } + + override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixSparseCSC(1, 1) + + CommonOps_DSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapMatrix() + } + + override fun Point.plus(other: Point): EjmlDoubleVector { + val out = DMatrixSparseCSC(1, 1) + + CommonOps_DSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapVector() + } + + override fun Point.minus(other: Point): EjmlDoubleVector { + val out = DMatrixSparseCSC(1, 1) + + CommonOps_DSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapVector() + } + + override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this + + override fun Point.times(value: Double): EjmlDoubleVector { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.scale(value, toEjml().origin, res) + return res.wrapVector() + } + + override fun Double.times(v: Point): EjmlDoubleVector = v * this + + @UnstableKMathAPI + override fun computeFeature(structure: Matrix, type: KClass): F? { + structure.getFeature(type)?.let { return it } + val origin = structure.toEjml().origin + + return when (type) { + QRDecompositionFeature::class -> object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } + } + + override val q: Matrix by lazy { + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + } + + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + } + + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { + val cholesky = + DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) } + + (cholesky.getT(null) as DMatrix).wrapMatrix().withFeature(LFeature) + } + } + + LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : + LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { + private val lu by lazy { + DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } + } + + override val l: Matrix by lazy { + lu.getLower(null).wrapMatrix().withFeature(LFeature) + } + + override val u: Matrix by lazy { + lu.getUpper(null).wrapMatrix().withFeature(UFeature) + } + + override val inverse: Matrix by lazy { + var a = origin + val inverse = DMatrixRMaj(1, 1) + val solver = LinearSolverFactory_DSCC.lu(FillReducing.NONE) + if (solver.modifiesA()) a = a.copy() + val i = CommonOps_DDRM.identity(a.numRows) + solver.solve(i, inverse) + inverse.wrapMatrix() + } + + override val determinant: Double by lazy { elementAlgebra.number(lu.computeDeterminant().real) } + } + + else -> null + }?.let(type::cast) + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p matrix. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) + return res.wrapMatrix() + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p vector. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Point): EjmlDoubleVector { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) + return EjmlDoubleVector(res) + } +} + +/** + * [EjmlLinearSpace] implementation based on [CommonOps_FSCC], [DecompositionFactory_FSCC] operations and + * [FMatrixSparseCSC] matrices. + */ +public object EjmlLinearSpaceFSCC : EjmlLinearSpace() { + /** + * The [FloatField] reference. + */ + override val elementAlgebra: FloatField get() = FloatField + + @Suppress("UNCHECKED_CAST") + override fun Matrix.toEjml(): EjmlFloatMatrix = when { + this is EjmlFloatMatrix<*> && origin is FMatrixSparseCSC -> this as EjmlFloatMatrix + else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } + } + + @Suppress("UNCHECKED_CAST") + override fun Point.toEjml(): EjmlFloatVector = when { + this is EjmlFloatVector<*> && origin is FMatrixSparseCSC -> this as EjmlFloatVector + else -> EjmlFloatVector(FMatrixSparseCSC(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } + }) + } + + override fun buildMatrix( + rows: Int, + columns: Int, + initializer: FloatField.(i: Int, j: Int) -> Float, + ): EjmlFloatMatrix = FMatrixSparseCSC(rows, columns).also { + (0 until rows).forEach { row -> + (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } + } + }.wrapMatrix() + + override fun buildVector( + size: Int, + initializer: FloatField.(Int) -> Float, + ): EjmlFloatVector = EjmlFloatVector(FMatrixSparseCSC(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } + }) + + private fun T.wrapMatrix() = EjmlFloatMatrix(this) + private fun T.wrapVector() = EjmlFloatVector(this) + + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + + override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { + val out = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.mult(toEjml().origin, other.toEjml().origin, out) + return out.wrapMatrix() + } + + override fun Matrix.dot(vector: Point): EjmlFloatVector { + val out = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.mult(toEjml().origin, vector.toEjml().origin, out) + return out.wrapVector() + } + + override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { + val out = FMatrixSparseCSC(1, 1) + + CommonOps_FSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapMatrix() + } + + override operator fun Matrix.times(value: Float): EjmlFloatMatrix { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.scale(value, toEjml().origin, res) + return res.wrapMatrix() + } + + override fun Point.unaryMinus(): EjmlFloatVector { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.changeSign(toEjml().origin, res) + return res.wrapVector() + } + + override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { + val out = FMatrixSparseCSC(1, 1) + + CommonOps_FSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapMatrix() + } + + override fun Point.plus(other: Point): EjmlFloatVector { + val out = FMatrixSparseCSC(1, 1) + + CommonOps_FSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapVector() + } + + override fun Point.minus(other: Point): EjmlFloatVector { + val out = FMatrixSparseCSC(1, 1) + + CommonOps_FSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapVector() + } + + override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this + + override fun Point.times(value: Float): EjmlFloatVector { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.scale(value, toEjml().origin, res) + return res.wrapVector() + } + + override fun Float.times(v: Point): EjmlFloatVector = v * this + + @UnstableKMathAPI + override fun computeFeature(structure: Matrix, type: KClass): F? { + structure.getFeature(type)?.let { return it } + val origin = structure.toEjml().origin + + return when (type) { + QRDecompositionFeature::class -> object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } + } + + override val q: Matrix by lazy { + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + } + + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + } + + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { + val cholesky = + DecompositionFactory_FSCC.cholesky().apply { decompose(origin.copy()) } + + (cholesky.getT(null) as FMatrix).wrapMatrix().withFeature(LFeature) + } + } + + LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : + LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { + private val lu by lazy { + DecompositionFactory_FSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } + } + + override val l: Matrix by lazy { + lu.getLower(null).wrapMatrix().withFeature(LFeature) + } + + override val u: Matrix by lazy { + lu.getUpper(null).wrapMatrix().withFeature(UFeature) + } + + override val inverse: Matrix by lazy { + var a = origin + val inverse = FMatrixRMaj(1, 1) + val solver = LinearSolverFactory_FSCC.lu(FillReducing.NONE) + if (solver.modifiesA()) a = a.copy() + val i = CommonOps_FDRM.identity(a.numRows) + solver.solve(i, inverse) + inverse.wrapMatrix() + } + + override val determinant: Float by lazy { elementAlgebra.number(lu.computeDeterminant().real) } + } + + else -> null + }?.let(type::cast) + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p matrix. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) + return res.wrapMatrix() + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p vector. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Point): EjmlFloatVector { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) + return EjmlFloatVector(res) + } +} + 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 88932d59b..c1ee8b48f 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 @@ -13,9 +13,9 @@ 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 import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.asIterable import kotlin.math.pow /* 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 b09129626..94c73832b 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 @@ -5,10 +5,10 @@ package space.kscience.kmath.integration +import space.kscience.kmath.operations.map import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.map import kotlin.jvm.Synchronized import kotlin.math.ulp import kotlin.native.concurrent.ThreadLocal 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 662cdf3d7..6abe89aad 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 @@ -12,14 +12,10 @@ 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.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.sum +import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.MutableBufferFactory -import space.kscience.kmath.structures.map /** * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt index 84b1f4fd6..89ee23354 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt @@ -1,9 +1,8 @@ package space.kscience.kmath.geometry -import space.kscience.kmath.structures.asSequence -import space.kscience.kmath.structures.toList -import kotlin.test.assertEquals +import space.kscience.kmath.operations.toList import kotlin.test.Test +import kotlin.test.assertEquals internal class Vector2DTest { private val vector = Vector2D(1.0, -7.999) diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt index 717e78871..70f8f4ebd 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.geometry -import space.kscience.kmath.structures.toList +import space.kscience.kmath.operations.toList import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt index 0841fcb4c..d5b74fb9b 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt @@ -7,8 +7,8 @@ package space.kscience.kmath.histogram import space.kscience.kmath.domains.UnivariateDomain import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asSequence @UnstableKMathAPI @@ -34,7 +34,7 @@ public class UnivariateBin( } @OptIn(UnstableKMathAPI::class) -public interface UnivariateHistogram : Histogram{ +public interface UnivariateHistogram : Histogram { public operator fun get(value: Double): UnivariateBin? override operator fun get(point: Buffer): UnivariateBin? = get(point[0]) 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 e646d2bd0..9731908b3 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 @@ -21,9 +21,9 @@ 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 import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asSequence /** * A function for conversion of number to MST for pretty print diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt index 54b2e42b3..664e4e8e7 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.stat +import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asSequence /** * Non-composable median diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index a0f5d8080..d31e02677 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -9,9 +9,9 @@ import space.kscience.kmath.nd.MutableStructure1D import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.operations.asSequence import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.VirtualBuffer -import space.kscience.kmath.structures.asSequence import space.kscience.kmath.tensors.core.BufferedTensor import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensorAlgebra 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 6088c32e4..8428dae5c 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 @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.as1D +import space.kscience.kmath.operations.toMutableList import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.* -- 2.34.1 From fd8a61c852b2514324647b39c8c4fc6c085035d2 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 4 Oct 2021 12:40:30 +0300 Subject: [PATCH 027/102] Fix Mean bug --- .../kscience/kmath/benchmarks/DotBenchmark.kt | 11 +++---- .../ExpressionsInterpretersBenchmark.kt | 5 +-- .../FunctionalExpressionAlgebra.kt | 4 +++ .../kmath/linear/DoubleLinearSpace.kt | 6 ++-- .../kotlin/space/kscience/kmath/stat/Mean.kt | 23 ++++++++++--- .../space/kscience/kmath/stat/Statistic.kt | 20 +++++++---- .../kscience/kmath/stat/StatisticTest.kt | 33 ++++++++++++++----- 7 files changed, 72 insertions(+), 30 deletions(-) diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 33cb57c6f..64f9b5dff 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -14,7 +14,6 @@ import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.algebra import space.kscience.kmath.structures.Buffer import kotlin.random.Random @@ -25,11 +24,11 @@ internal class DotBenchmark { const val dim = 1000 //creating invertible matrix - val matrix1 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> - if (i <= j) random.nextDouble() else 0.0 + val matrix1 = DoubleField.linearSpace.buildMatrix(dim, dim) { _, _ -> + random.nextDouble() } - val matrix2 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> - if (i <= j) random.nextDouble() else 0.0 + val matrix2 = DoubleField.linearSpace.buildMatrix(dim, dim) { _, _ -> + random.nextDouble() } val cmMatrix1 = CMLinearSpace { matrix1.toCM() } @@ -65,7 +64,7 @@ internal class DotBenchmark { } @Benchmark - fun doubleDot(blackhole: Blackhole) = with(Double.algebra.linearSpace) { + fun doubleDot(blackhole: Blackhole) = with(DoubleField.linearSpace) { blackhole.consume(matrix1 dot matrix2) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index 8c3c8ec2b..63e1511bd 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -75,8 +75,9 @@ internal class ExpressionsInterpretersBenchmark { private val algebra = DoubleField private const val times = 1_000_000 - private val functional = DoubleField.expressionInExtendedField { - bindSymbol(x) * number(2.0) + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x)) + private val functional = DoubleField.expression { + val x = bindSymbol(Symbol.x) + x * number(2.0) + 2.0 / x - 16.0 / sin(x) } private val node = MstExtendedField { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index bb7f36fc5..36ccb96f7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -192,3 +192,7 @@ public inline fun > A.expressionInField( public inline fun > A.expressionInExtendedField( block: FunctionalExpressionExtendedField.() -> Expression, ): Expression = FunctionalExpressionExtendedField(this).block() + +public inline fun DoubleField.expression( + block: FunctionalExpressionExtendedField.() -> Expression, +): Expression = FunctionalExpressionExtendedField(this).block() 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 4a1311b54..c2f53939f 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 @@ -13,7 +13,6 @@ import space.kscience.kmath.operations.DoubleBufferOperations import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.indices public object DoubleLinearSpace : LinearSpace { @@ -30,7 +29,6 @@ public object DoubleLinearSpace : LinearSpace { initializer: DoubleField.(i: Int, j: Int) -> Double ): Matrix = ndRing(rows, columns).produce { (i, j) -> DoubleField.initializer(i, j) }.as2D() - override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): DoubleBuffer = DoubleBuffer(size) { DoubleField.initializer(it) } @@ -50,9 +48,9 @@ public object DoubleLinearSpace : LinearSpace { // Create a continuous in-memory representation of this vector for better memory layout handling private fun Buffer.linearize() = if (this is DoubleBuffer) { - this + this.array } else { - DoubleBuffer(size) { get(it) } + DoubleArray(size) { get(it) } } @OptIn(PerformancePitfall::class) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt index 7daed5798..1d09fffd1 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt @@ -27,8 +27,13 @@ public class Mean( override suspend fun evaluate(data: Buffer): T = super.evaluate(data) - override suspend fun computeIntermediate(data: Buffer): Pair = - evaluateBlocking(data) to data.size + override suspend fun computeIntermediate(data: Buffer): Pair = group { + var res = zero + for (i in data.indices) { + res += data[i] + } + res to data.size + } override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = group { first.first + second.first } to (first.second + second.second) @@ -38,13 +43,23 @@ public class Mean( } public companion object { - //TODO replace with optimized version which respects overflow + @Deprecated("Use Double.mean instead") public val double: Mean = Mean(DoubleField) { sum, count -> sum / count } + @Deprecated("Use Int.mean instead") public val int: Mean = Mean(IntRing) { sum, count -> sum / count } + @Deprecated("Use Long.mean instead") public val long: Mean = Mean(LongRing) { sum, count -> sum / count } public fun evaluate(buffer: Buffer): Double = double.evaluateBlocking(buffer) public fun evaluate(buffer: Buffer): Int = int.evaluateBlocking(buffer) public fun evaluate(buffer: Buffer): Long = long.evaluateBlocking(buffer) } -} \ No newline at end of file +} + + +//TODO replace with optimized version which respects overflow +public val Double.Companion.mean: Mean get() = Mean(DoubleField) { sum, count -> sum / count } +public val Int.Companion.mean: Mean get() = Mean(IntRing) { sum, count -> sum / count } +public val Long.Companion.mean: Mean get() = Mean(LongRing) { sum, count -> sum / count } + + diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt index ab80fbe1c..107161514 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt @@ -8,7 +8,6 @@ package space.kscience.kmath.stat import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.runningReduce @@ -18,16 +17,23 @@ import space.kscience.kmath.structures.Buffer /** * A function, that transforms a buffer of random quantities to some resulting value */ -public interface Statistic { +public fun interface Statistic { public suspend fun evaluate(data: Buffer): R } -public interface BlockingStatistic : Statistic { +public suspend operator fun Statistic.invoke(data: Buffer): R = evaluate(data) + +/** + * A statistic that is computed in a synchronous blocking mode + */ +public fun interface BlockingStatistic : Statistic { public fun evaluateBlocking(data: Buffer): R override suspend fun evaluate(data: Buffer): R = evaluateBlocking(data) } +public operator fun BlockingStatistic.invoke(data: Buffer): R = evaluateBlocking(data) + /** * A statistic tha could be computed separately on different blocks of data and then composed * @@ -48,8 +54,10 @@ public interface ComposableStatistic : Statistic { override suspend fun evaluate(data: Buffer): R = toResult(computeIntermediate(data)) } -@FlowPreview -@ExperimentalCoroutinesApi +/** + * Flow intermediate state of the [ComposableStatistic] + */ +@OptIn(ExperimentalCoroutinesApi::class) private fun ComposableStatistic.flowIntermediate( flow: Flow>, dispatcher: CoroutineDispatcher = Dispatchers.Default, @@ -64,7 +72,7 @@ private fun ComposableStatistic.flowIntermediate( * * The resulting flow contains values that include the whole previous statistics, not only the last chunk. */ -@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) +@OptIn(ExperimentalCoroutinesApi::class) public fun ComposableStatistic.flow( flow: Flow>, dispatcher: CoroutineDispatcher = Dispatchers.Default, diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt index c64bcc78c..2a3147869 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt @@ -5,11 +5,13 @@ package space.kscience.kmath.stat -import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.last +import kotlinx.coroutines.flow.take import kotlinx.coroutines.runBlocking import space.kscience.kmath.streaming.chunked import kotlin.test.Test +import kotlin.test.assertEquals internal class StatisticTest { //create a random number generator. @@ -22,12 +24,27 @@ internal class StatisticTest { val chunked = data.chunked(1000) @Test - fun testParallelMean() = runBlocking { - val average = Mean.double - .flow(chunked) //create a flow with results - .drop(99) // Skip first 99 values and use one with total data - .first() //get 1e5 data samples average - - println(average) + fun singleBlockingMean() { + val first = runBlocking { chunked.first()} + val res = Double.mean(first) + assertEquals(0.5,res, 1e-1) } + + @Test + fun singleSuspendMean() = runBlocking { + val first = runBlocking { chunked.first()} + val res = Double.mean(first) + assertEquals(0.5,res, 1e-1) + } + + @Test + fun parallelMean() = runBlocking { + val average = Double.mean + .flow(chunked) //create a flow from evaluated results + .take(100) // Take 100 data chunks from the source and accumulate them + .last() //get 1e5 data samples average + + assertEquals(0.5,average, 1e-3) + } + } -- 2.34.1 From d9f36365d9caac00f70b2dfb9b0c352260e1ded9 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 4 Oct 2021 22:31:06 +0300 Subject: [PATCH 028/102] Fix Mean bug --- .../src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt | 6 +++--- .../kotlin/space/kscience/kmath/stat/StatisticTest.kt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt index 1d09fffd1..2a9bd3cd4 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt @@ -50,9 +50,9 @@ public class Mean( @Deprecated("Use Long.mean instead") public val long: Mean = Mean(LongRing) { sum, count -> sum / count } - public fun evaluate(buffer: Buffer): Double = double.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Int = int.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Long = long.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Double = Double.mean.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Int = Int.mean.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Long = Long.mean.evaluateBlocking(buffer) } } diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt index 2a3147869..777b93c29 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt @@ -44,7 +44,7 @@ internal class StatisticTest { .take(100) // Take 100 data chunks from the source and accumulate them .last() //get 1e5 data samples average - assertEquals(0.5,average, 1e-3) + assertEquals(0.5,average, 1e-2) } } -- 2.34.1 From 30e3e8039724bf84645f3efd28c4bf8fe7195a9f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 6 Oct 2021 12:25:32 +0300 Subject: [PATCH 029/102] Add nd add benchmarks --- benchmarks/build.gradle.kts | 6 ++ .../kmath/benchmarks/NDFieldBenchmark.kt | 57 ++++++++++++------- kmath-nd4j/build.gradle.kts | 2 +- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 3 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 1 - .../tensors/core/tensorAlgebraExtensions.kt | 8 +++ 6 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index fa72dc8ee..686c491b9 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -36,6 +36,7 @@ kotlin { implementation(project(":kmath-dimensions")) implementation(project(":kmath-for-real")) implementation(project(":kmath-jafama")) + implementation(project(":kmath-tensors")) implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.1") } } @@ -81,6 +82,11 @@ benchmark { include("BufferBenchmark") } + configurations.register("nd") { + commonConfiguration() + include("NDFieldBenchmark") + } + configurations.register("dot") { commonConfiguration() include("DotBenchmark") 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 f72bc3ba0..76fec05d3 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -12,44 +12,63 @@ import kotlinx.benchmark.State import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.autoNdAlgebra import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.nd4j.nd4j import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.ones +import space.kscience.kmath.tensors.core.tensorAlgebra @State(Scope.Benchmark) internal class NDFieldBenchmark { @Benchmark - fun autoFieldAdd(blackhole: Blackhole) { - with(autoField) { - var res: StructureND = one - repeat(n) { res += one } - blackhole.consume(res) - } + fun autoFieldAdd(blackhole: Blackhole) = with(autoField) { + var res: StructureND = one + repeat(n) { res += one } + blackhole.consume(res) } @Benchmark - fun specializedFieldAdd(blackhole: Blackhole) { - with(specializedField) { - var res: StructureND = one - repeat(n) { res += 1.0 } - blackhole.consume(res) - } + fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) { + var res: StructureND = one + repeat(n) { res += 1.0 } + blackhole.consume(res) } - @Benchmark - fun boxingFieldAdd(blackhole: Blackhole) { - with(genericField) { - var res: StructureND = one - repeat(n) { res += 1.0 } - blackhole.consume(res) - } + fun boxingFieldAdd(blackhole: Blackhole) = with(genericField) { + var res: StructureND = one + repeat(n) { res += 1.0 } + blackhole.consume(res) } + @Benchmark + fun tensorAdd(blackhole: Blackhole) = with(Double.tensorAlgebra) { + var res: DoubleTensor = ones(dim, dim) + repeat(n) { res = res + 1.0 } + blackhole.consume(res) + } + + @Benchmark + fun tensorInPlaceAdd(blackhole: Blackhole) = with(Double.tensorAlgebra) { + val res: DoubleTensor = ones(dim, dim) + repeat(n) { res += 1.0 } + blackhole.consume(res) + } + +// @Benchmark +// fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) { +// var res: StructureND = one +// repeat(n) { res += 1.0 } +// blackhole.consume(res) +// } + private companion object { private const val dim = 1000 private const val n = 100 private val autoField = DoubleField.autoNdAlgebra(dim, dim) private val specializedField = DoubleField.ndAlgebra(dim, dim) private val genericField = DoubleField.ndAlgebra(Buffer.Companion::boxing, dim, dim) + private val nd4jField = DoubleField.nd4j(dim, dim) } } diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts index dcb6f1b4a..09264501f 100644 --- a/kmath-nd4j/build.gradle.kts +++ b/kmath-nd4j/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { api(project(":kmath-tensors")) api("org.nd4j:nd4j-api:1.0.0-M1") testImplementation("org.nd4j:nd4j-native-platform:1.0.0-M1") - testImplementation("org.slf4j:slf4j-simple:1.7.31") + testImplementation("org.slf4j:slf4j-simple:1.7.32") } readme { 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 54df31556..b604bf5f2 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 @@ -45,7 +45,6 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND.map(transform: C.(T) -> T): Nd4jArrayStructure { val newStruct = ndArray.dup().wrap() newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) } @@ -265,6 +264,8 @@ public class DoubleNd4jArrayField(override val shape: IntArray) : Nd4jArrayExten } } +public fun DoubleField.nd4j(vararg shape: Int): DoubleNd4jArrayField = DoubleNd4jArrayField(intArrayOf(*shape)) + /** * Represents [FieldND] over [Nd4jArrayStructure] of [Float]. */ 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 0ac37e19b..ee9251dd1 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 @@ -158,7 +158,6 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { if (shape contentEquals intArrayOf(1)) ndArray.getDouble(0) else null // TODO rewrite - @PerformancePitfall override fun diagonalEmbedding( diagonalEntries: Tensor, offset: Int, 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 new file mode 100644 index 000000000..b73f95054 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt @@ -0,0 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.tensors.core + +public fun DoubleTensorAlgebra.ones(vararg shape: Int): DoubleTensor = ones(intArrayOf(*shape)) \ No newline at end of file -- 2.34.1 From 09a9df5213b273c6848183355736729f58b39ba3 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 9 Oct 2021 20:19:36 +0300 Subject: [PATCH 030/102] Add complex power --- CHANGELOG.md | 1 + .../space/kscience/kmath/complex/Complex.kt | 29 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cb9f57f4..05376d425 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Unified architecture for Integration and Optimization using features. - `BigInt` operation performance improvement and fixes by @zhelenskiy (#328) - Integration between `MST` and Symja `IExpr` +- Complex power ### Changed - Exponential operations merged with hyperbolic functions 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 793587492..7d948cb61 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 @@ -9,10 +9,7 @@ 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.ExtendedField -import space.kscience.kmath.operations.Norm -import space.kscience.kmath.operations.NumbersAddOperations -import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MemoryBuffer import space.kscience.kmath.structures.MutableBuffer @@ -52,11 +49,23 @@ private val PI_DIV_2 = Complex(PI / 2, 0) * A field of [Complex]. */ @OptIn(UnstableKMathAPI::class) -public object ComplexField : ExtendedField, Norm, NumbersAddOperations, +public object ComplexField : + ExtendedField, + Norm, + NumbersAddOperations, ScaleOperations { + override val zero: Complex = 0.0.toComplex() override val one: Complex = 1.0.toComplex() + override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null + + override fun binaryOperationFunction(operation: String): (left: Complex, right: Complex) -> Complex = + when (operation) { + PowerOperations.POW_OPERATION -> ComplexField::power + else -> super.binaryOperationFunction(operation) + } + /** * The imaginary unit. */ @@ -117,10 +126,14 @@ public object ComplexField : ExtendedField, Norm, Num return i * (ln(1 - iArg) - ln(1 + iArg)) / 2 } - override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) + override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) { arg.re.pow(pow.toDouble()).toComplex() - else + } else { exp(pow * ln(arg)) + } + + public fun power(arg: Complex, pow: Complex): Complex = exp(pow * ln(arg)) + override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) @@ -172,8 +185,6 @@ public object ComplexField : ExtendedField, Norm, Num public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this) override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) - - override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null } /** -- 2.34.1 From 8d2770c275e931e0e3788539f0d5067dc4c4f333 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 13 Oct 2021 09:06:54 +0300 Subject: [PATCH 031/102] Build tools to 0.10.5 --- build.gradle.kts | 2 +- settings.gradle.kts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 68b894d06..665c057e9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,7 +19,7 @@ allprojects { } group = "space.kscience" - version = "0.3.0-dev-15" + version = "0.3.0-dev-16" } subprojects { diff --git a/settings.gradle.kts b/settings.gradle.kts index 8cfa62133..528adb336 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,6 @@ pluginManagement { repositories { + mavenLocal() maven("https://repo.kotlin.link") mavenCentral() gradlePluginPortal() @@ -9,7 +10,7 @@ pluginManagement { plugins { id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - id("ru.mipt.npm.gradle.project") version "0.10.4" + id("ru.mipt.npm.gradle.project") version "0.10.5" kotlin("multiplatform") version kotlinVersion kotlin("plugin.allopen") version kotlinVersion } -- 2.34.1 From 0ac5363acf7c6717275989ec6c3376a05002b953 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 16 Oct 2021 11:10:34 +0300 Subject: [PATCH 032/102] Multik wrapper prototype --- examples/build.gradle.kts | 14 +- .../space/kscience/kmath/tensors/multik.kt | 21 ++ kmath-multik/build.gradle.kts | 14 ++ .../kmath/multik/MultikTensorAlgebra.kt | 199 ++++++++++++++++++ 4 files changed, 244 insertions(+), 4 deletions(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt create mode 100644 kmath-multik/build.gradle.kts create mode 100644 kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index d06005321..7b1bce26a 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -29,6 +29,11 @@ dependencies { implementation(project(":kmath-tensors")) implementation(project(":kmath-symja")) implementation(project(":kmath-for-real")) + //jafama + implementation(project(":kmath-jafama")) + //multik + implementation(projects.kmathMultik) + implementation("org.nd4j:nd4j-native:1.0.0-beta7") @@ -42,11 +47,12 @@ dependencies { // } else implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - implementation("org.slf4j:slf4j-simple:1.7.31") + // 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.4.2") - //jafama - implementation(project(":kmath-jafama")) + implementation("space.kscience:plotlykt-server:0.5.0") } kotlin.sourceSets.all { diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt new file mode 100644 index 000000000..820a793ac --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.tensors + +import org.jetbrains.kotlinx.multik.api.Multik +import org.jetbrains.kotlinx.multik.api.linalg.dot +import org.jetbrains.kotlinx.multik.api.ndarray +import org.jetbrains.kotlinx.multik.ndarray.operations.minus +import org.jetbrains.kotlinx.multik.ndarray.operations.plus +import org.jetbrains.kotlinx.multik.ndarray.operations.unaryMinus + +fun main() { + val a = Multik.ndarray(intArrayOf(1, 2, 3)) + val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)) + 2 + (-a) - 2 + + a dot a +} \ No newline at end of file diff --git a/kmath-multik/build.gradle.kts b/kmath-multik/build.gradle.kts new file mode 100644 index 000000000..16a7ab652 --- /dev/null +++ b/kmath-multik/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("ru.mipt.npm.gradle.jvm") +} + +description = "JetBrains Multik connector" + +dependencies { + api(project(":kmath-tensors")) + api("org.jetbrains.kotlinx:multik-api:0.1.0") +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE +} \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt new file mode 100644 index 000000000..b25d3ef56 --- /dev/null +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -0,0 +1,199 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.multik + +import org.jetbrains.kotlinx.multik.ndarray.data.* +import org.jetbrains.kotlinx.multik.ndarray.operations.* +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.nd.mapInPlace +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.tensors.api.Tensor +import space.kscience.kmath.tensors.api.TensorAlgebra + +@JvmInline +public value class MultikTensor(public val array: MutableMultiArray) : Tensor { + override val shape: IntArray get() = array.shape + + override fun get(index: IntArray): T = array[index] + + @PerformancePitfall + override fun elements(): Sequence> = + array.multiIndices.iterator().asSequence().map { it to get(it) } + + override fun set(index: IntArray, value: T) { + array[index] = value + } +} + + +public abstract class MultikTensorAlgebra( + public val elementAlgebra: Ring, + public val comparator: Comparator +) : TensorAlgebra { + + /** + * Convert a tensor to [MultikTensor] if necessary. If tensor is converted, changes on the resulting tensor + * are not reflected back onto the source + */ + public fun Tensor.asMultik(): MultikTensor { + return if (this is MultikTensor) { + this + } else { + TODO() + } + } + + public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) + + override fun Tensor.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) { + get(intArrayOf(0)) + } else null + + override fun T.plus(other: Tensor): MultikTensor = + other.plus(this) + + override fun Tensor.plus(value: T): MultikTensor = + asMultik().array.deepCopy().apply { plusAssign(value) }.wrap() + + override fun Tensor.plus(other: Tensor): MultikTensor = + asMultik().array.plus(other.asMultik().array).wrap() + + override fun Tensor.plusAssign(value: T) { + if (this is MultikTensor) { + array.plusAssign(value) + } else { + mapInPlace { _, t -> elementAlgebra.add(t, value) } + } + } + + override fun Tensor.plusAssign(other: Tensor) { + if (this is MultikTensor) { + array.plusAssign(other.asMultik().array) + } else { + mapInPlace { index, t -> elementAlgebra.add(t, other[index]) } + } + } + + //TODO avoid additional copy + override fun T.minus(other: Tensor): MultikTensor = -(other - this) + + override fun Tensor.minus(value: T): MultikTensor = + asMultik().array.deepCopy().apply { minusAssign(value) }.wrap() + + override fun Tensor.minus(other: Tensor): MultikTensor = + asMultik().array.minus(other.asMultik().array).wrap() + + override fun Tensor.minusAssign(value: T) { + if (this is MultikTensor) { + array.minusAssign(value) + } else { + mapInPlace { _, t -> elementAlgebra.run { t - value } } + } + } + + override fun Tensor.minusAssign(other: Tensor) { + if (this is MultikTensor) { + array.minusAssign(other.asMultik().array) + } else { + mapInPlace { index, t -> elementAlgebra.run { t - other[index] } } + } + } + + override fun T.times(other: Tensor): MultikTensor = + other.asMultik().array.deepCopy().apply { timesAssign(this@times) }.wrap() + + override fun Tensor.times(value: T): Tensor = + asMultik().array.deepCopy().apply { timesAssign(value) }.wrap() + + override fun Tensor.times(other: Tensor): MultikTensor = + asMultik().array.times(other.asMultik().array).wrap() + + override fun Tensor.timesAssign(value: T) { + if (this is MultikTensor) { + array.timesAssign(value) + } else { + mapInPlace { _, t -> elementAlgebra.multiply(t, value) } + } + } + + override fun Tensor.timesAssign(other: Tensor) { + if (this is MultikTensor) { + array.timesAssign(other.asMultik().array) + } else { + mapInPlace { index, t -> elementAlgebra.multiply(t, other[index]) } + } + } + + override fun Tensor.unaryMinus(): MultikTensor = + asMultik().array.unaryMinus().wrap() + + override fun Tensor.get(i: Int): MultikTensor { + TODO("Not yet implemented") + } + + override fun Tensor.transpose(i: Int, j: Int): MultikTensor { + TODO("Not yet implemented") + } + + override fun Tensor.view(shape: IntArray): MultikTensor { + require(shape.all { it > 0 }) + require(shape.fold(1, Int::times) == this.shape.size) { + "Cannot reshape array of size ${this.shape.size} into a new shape ${ + shape.joinToString( + prefix = "(", + postfix = ")" + ) + }" + } + + val mt = asMultik().array + return if (mt.shape.contentEquals(shape)) { + @Suppress("UNCHECKED_CAST") + this as NDArray + } else { + NDArray(mt.data, mt.offset, shape, dim = DN(shape.size), base = mt.base ?: mt) + }.wrap() + } + + override fun Tensor.viewAs(other: Tensor): MultikTensor { + TODO("Not yet implemented") + } + + override fun Tensor.dot(other: Tensor): MultikTensor { + TODO("Not yet implemented") + } + + override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): MultikTensor { + TODO("Not yet implemented") + } + + override fun Tensor.sum(): T = asMultik().array.reduceMultiIndexed { _: IntArray, acc: T, t: T -> + elementAlgebra.add(acc, t) + } + + override fun Tensor.sum(dim: Int, keepDim: Boolean): MultikTensor { + TODO("Not yet implemented") + } + + override fun Tensor.min(): T = + asMultik().array.minWith(comparator) ?: error("No elements in tensor") + + override fun Tensor.min(dim: Int, keepDim: Boolean): MultikTensor { + TODO("Not yet implemented") + } + + override fun Tensor.max(): T = + asMultik().array.maxWith(comparator) ?: error("No elements in tensor") + + + override fun Tensor.max(dim: Int, keepDim: Boolean): MultikTensor { + TODO("Not yet implemented") + } + + override fun Tensor.argMax(dim: Int, keepDim: Boolean): MultikTensor { + TODO("Not yet implemented") + } +} \ No newline at end of file -- 2.34.1 From d0354da80a52e56fdb81dadd881a0ab4fa0a0d24 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 17 Oct 2021 11:12:35 +0300 Subject: [PATCH 033/102] Shapeless ND and Buffer algebras --- CHANGELOG.md | 3 + .../kmath/benchmarks/NDFieldBenchmark.kt | 32 ++- .../kmath/benchmarks/ViktorBenchmark.kt | 20 +- .../kmath/benchmarks/ViktorLogBenchmark.kt | 20 +- .../kscience/kmath/operations/complexDemo.kt | 12 +- .../kscience/kmath/structures/NDField.kt | 4 +- .../kmath/structures/StreamDoubleFieldND.kt | 10 +- .../kscience/kmath/structures/buffers.kt | 3 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../kotlin/space/kscience/kmath/ast/parser.kt | 16 +- .../kscience/kmath/ast/rendering/features.kt | 30 +- .../kscience/kmath/ast/rendering/phases.kt | 14 +- .../kscience/kmath/ast/rendering/TestLatex.kt | 4 +- .../kmath/ast/rendering/TestMathML.kt | 4 +- .../kmath/wasm/internal/WasmBuilder.kt | 22 +- .../DerivativeStructureExpression.kt | 4 +- .../space/kscience/kmath/complex/Complex.kt | 3 +- .../kscience/kmath/complex/ComplexFieldND.kt | 134 +++------ .../kscience/kmath/complex/Quaternion.kt | 2 +- .../FunctionalExpressionAlgebra.kt | 8 +- .../kscience/kmath/expressions/MstAlgebra.kt | 24 +- .../kmath/expressions/SimpleAutoDiff.kt | 2 +- .../kmath/linear/BufferedLinearSpace.kt | 29 +- .../kmath/linear/DoubleLinearSpace.kt | 30 +- .../kscience/kmath/linear/LinearSpace.kt | 3 +- .../space/kscience/kmath/nd/AlgebraND.kt | 116 +++----- .../kscience/kmath/nd/BufferAlgebraND.kt | 262 ++++++++++-------- .../space/kscience/kmath/nd/BufferND.kt | 24 +- .../space/kscience/kmath/nd/DoubleFieldND.kt | 132 +++------ .../space/kscience/kmath/nd/ShapeIndex.kt | 120 ++++++++ .../space/kscience/kmath/nd/ShortRingND.kt | 25 +- .../space/kscience/kmath/nd/StructureND.kt | 110 +------- .../kscience/kmath/nd/algebraNDExtentions.kt | 34 +++ .../kscience/kmath/operations/Algebra.kt | 14 +- .../space/kscience/kmath/operations/BigInt.kt | 8 +- .../kmath/operations/BufferAlgebra.kt | 179 +++++++----- .../kmath/operations/DoubleBufferField.kt | 14 +- ...BufferOperations.kt => DoubleBufferOps.kt} | 6 +- .../kmath/operations/NumericAlgebra.kt | 2 +- .../kscience/kmath/operations/numbers.kt | 8 +- .../kscience/kmath/structures/NDFieldTest.kt | 3 +- .../kmath/structures/NumberNDFieldTest.kt | 13 +- .../space/kscience/kmath/chains/flowExtra.kt | 4 +- .../space/kscience/kmath/real/realND.kt | 4 +- .../kmath/histogram/DoubleHistogramSpace.kt | 9 +- .../kmath/histogram/IndexedHistogramSpace.kt | 9 +- .../histogram/MultivariateHistogramTest.kt | 3 +- .../kmath/kotlingrad/scalarsAdapters.kt | 12 +- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 164 +++++------ .../kmath/nd4j/Nd4jArrayAlgebraTest.kt | 18 +- .../space/kscience/kmath/symja/adapters.kt | 12 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 8 +- .../core/internal/TensorLinearStructure.kt | 16 +- .../tensors/core/internal/tensorCastsUtils.kt | 7 +- .../kmath/viktor/ViktorStructureND.kt | 20 +- settings.gradle.kts | 8 +- 56 files changed, 893 insertions(+), 906 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/{DoubleBufferOperations.kt => DoubleBufferOps.kt} (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05376d425..bb267744e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,9 @@ - Use `Symbol` factory function instead of `StringSymbol` - New discoverability pattern: `.algebra.` - Adjusted commons-math API for linear solvers to match conventions. +- Buffer algebra does not require size anymore +- Operations -> Ops +- Default Buffer and ND algebras are now Ops and lack neutral elements (0, 1) as well as algebra-level shapes. ### Deprecated - Specialized `DoubleBufferAlgebra` 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 76fec05d3..950a10b33 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -9,9 +9,10 @@ import kotlinx.benchmark.Benchmark import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State +import space.kscience.kmath.nd.BufferedFieldOpsND import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.autoNdAlgebra import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.nd.one import space.kscience.kmath.nd4j.nd4j import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.Buffer @@ -23,21 +24,21 @@ import space.kscience.kmath.tensors.core.tensorAlgebra internal class NDFieldBenchmark { @Benchmark fun autoFieldAdd(blackhole: Blackhole) = with(autoField) { - var res: StructureND = one - repeat(n) { res += one } + var res: StructureND = one(shape) + repeat(n) { res += 1.0 } blackhole.consume(res) } @Benchmark fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) { - var res: StructureND = one + var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @Benchmark fun boxingFieldAdd(blackhole: Blackhole) = with(genericField) { - var res: StructureND = one + var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -56,19 +57,20 @@ internal class NDFieldBenchmark { blackhole.consume(res) } -// @Benchmark -// fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) { -// var res: StructureND = one -// repeat(n) { res += 1.0 } -// blackhole.consume(res) -// } + @Benchmark + fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) { + var res: StructureND = one(dim, dim) + repeat(n) { res += 1.0 } + blackhole.consume(res) + } private companion object { private const val dim = 1000 private const val n = 100 - private val autoField = DoubleField.autoNdAlgebra(dim, dim) - private val specializedField = DoubleField.ndAlgebra(dim, dim) - private val genericField = DoubleField.ndAlgebra(Buffer.Companion::boxing, dim, dim) - private val nd4jField = DoubleField.nd4j(dim, dim) + private val shape = intArrayOf(dim, dim) + private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) + private val specializedField = DoubleField.ndAlgebra + private val genericField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) + private val nd4jField = DoubleField.nd4j } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index b97a05a52..6b4d5759b 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -10,18 +10,17 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.autoNdAlgebra -import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.viktor.ViktorNDField +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.viktor.ViktorFieldND @State(Scope.Benchmark) internal class ViktorBenchmark { @Benchmark fun automaticFieldAddition(blackhole: Blackhole) { with(autoField) { - var res: StructureND = one + var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -30,7 +29,7 @@ internal class ViktorBenchmark { @Benchmark fun realFieldAddition(blackhole: Blackhole) { with(realField) { - var res: StructureND = one + var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -39,7 +38,7 @@ internal class ViktorBenchmark { @Benchmark fun viktorFieldAddition(blackhole: Blackhole) { with(viktorField) { - var res = one + var res = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -56,10 +55,11 @@ internal class ViktorBenchmark { private companion object { private const val dim = 1000 private const val n = 100 + private val shape = Shape(dim, dim) // automatically build context most suited for given type. - private val autoField = DoubleField.autoNdAlgebra(dim, dim) - private val realField = DoubleField.ndAlgebra(dim, dim) - private val viktorField = ViktorNDField(dim, dim) + private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) + private val realField = DoubleField.ndAlgebra + private val viktorField = ViktorFieldND(dim, dim) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index 91e9dcd76..ef2adaad8 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -10,18 +10,21 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.autoNdAlgebra +import space.kscience.kmath.nd.BufferedFieldOpsND +import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.nd.one import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.structures.Buffer import space.kscience.kmath.viktor.ViktorFieldND @State(Scope.Benchmark) internal class ViktorLogBenchmark { @Benchmark fun realFieldLog(blackhole: Blackhole) { - with(realNdField) { - val fortyTwo = produce { 42.0 } - var res = one + with(realField) { + val fortyTwo = produce(shape) { 42.0 } + var res = one(shape) repeat(n) { res = ln(fortyTwo) } blackhole.consume(res) } @@ -30,7 +33,7 @@ internal class ViktorLogBenchmark { @Benchmark fun viktorFieldLog(blackhole: Blackhole) { with(viktorField) { - val fortyTwo = produce { 42.0 } + val fortyTwo = produce(shape) { 42.0 } var res = one repeat(n) { res = ln(fortyTwo) } blackhole.consume(res) @@ -48,10 +51,11 @@ internal class ViktorLogBenchmark { private companion object { private const val dim = 1000 private const val n = 100 + private val shape = Shape(dim, dim) // automatically build context most suited for given type. - private val autoField = DoubleField.autoNdAlgebra(dim, dim) - private val realNdField = DoubleField.ndAlgebra(dim, dim) - private val viktorField = ViktorFieldND(intArrayOf(dim, dim)) + private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) + private val realField = DoubleField.ndAlgebra + private val viktorField = ViktorFieldND(dim, dim) } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt index 319221bcc..67d83d77c 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt @@ -11,27 +11,27 @@ import space.kscience.kmath.complex.bufferAlgebra import space.kscience.kmath.complex.ndAlgebra import space.kscience.kmath.nd.BufferND import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.produce fun main() = Complex.algebra { val complex = 2 + 2 * i println(complex * 8 - 5 * i) //flat buffer - val buffer = bufferAlgebra(8).run { - buffer { Complex(it, -it) }.map { Complex(it.im, it.re) } + val buffer = with(bufferAlgebra){ + buffer(8) { Complex(it, -it) }.map { Complex(it.im, it.re) } } println(buffer) - // 2d element - val element: BufferND = ndAlgebra(2, 2).produce { (i, j) -> + val element: BufferND = ndAlgebra.produce(2, 2) { (i, j) -> Complex(i - j, i + j) } println(element) // 1d element operation - val result: StructureND = ndAlgebra(8).run { - val a = produce { (it) -> i * it - it.toDouble() } + val result: StructureND = ndAlgebra{ + val a = produce(8) { (it) -> i * it - it.toDouble() } val b = 3 val c = Complex(1.0, 1.0) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt index 5b0e2eb30..7359f3bf6 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -14,7 +14,7 @@ import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd4j.Nd4jArrayField import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke -import space.kscience.kmath.viktor.ViktorNDField +import space.kscience.kmath.viktor.ViktorFieldND import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.system.measureTimeMillis @@ -41,7 +41,7 @@ fun main() { // Nd4j specialized field. val nd4jField = Nd4jArrayField.real(dim, dim) //viktor field - val viktorField = ViktorNDField(dim, dim) + val viktorField = ViktorFieldND(dim, dim) //parallel processing based on Java Streams val parallelField = DoubleField.ndStreaming(dim, dim) 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 b1248bd0f..f1f5f2e84 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.structures import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.NumbersAddOps import java.util.* import java.util.stream.IntStream @@ -17,11 +17,11 @@ import java.util.stream.IntStream * execution. */ class StreamDoubleFieldND(override val shape: IntArray) : FieldND, - NumbersAddOperations>, + NumbersAddOps>, ExtendedField> { private val strides = DefaultStrides(shape) - override val elementContext: DoubleField get() = DoubleField + override val elementAlgebra: DoubleField get() = DoubleField override val zero: BufferND by lazy { produce { zero } } override val one: BufferND by lazy { produce { one } } @@ -36,7 +36,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND this.buffer as DoubleBuffer + this is BufferND && this.indexes == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } } @@ -69,7 +69,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND, b: StructureND, transform: DoubleField.(Double, Double) -> Double, diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt index d78141507..889ea99bd 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.structures import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.buffer import space.kscience.kmath.operations.bufferAlgebra +import space.kscience.kmath.operations.withSize inline fun MutableBuffer.Companion.same( n: Int, @@ -16,7 +17,7 @@ inline fun MutableBuffer.Companion.same( fun main() { - with(DoubleField.bufferAlgebra(5)) { + with(DoubleField.bufferAlgebra.withSize(5)) { println(number(2.0) + buffer(1, 2, 3, 4, 5)) } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 05679dc3c..ffed3a254 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.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt index ef6d51c7b..7f2780548 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt @@ -18,10 +18,10 @@ import com.github.h0tk3y.betterParse.parser.ParseResult import com.github.h0tk3y.betterParse.parser.Parser import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.FieldOperations -import space.kscience.kmath.operations.GroupOperations +import space.kscience.kmath.operations.FieldOps +import space.kscience.kmath.operations.GroupOps import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.RingOperations +import space.kscience.kmath.operations.RingOps /** * better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4. @@ -60,7 +60,7 @@ public object ArithmeticsEvaluator : Grammar() { .or(binaryFunction) .or(unaryFunction) .or(singular) - .or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(GroupOperations.MINUS_OPERATION, it) }) + .or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(GroupOps.MINUS_OPERATION, it) }) .or(-lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) private val powChain: Parser by leftAssociative(term = term, operator = pow) { a, _, b -> @@ -72,9 +72,9 @@ public object ArithmeticsEvaluator : Grammar() { operator = div or mul use TokenMatch::type ) { a, op, b -> if (op == div) - MST.Binary(FieldOperations.DIV_OPERATION, a, b) + MST.Binary(FieldOps.DIV_OPERATION, a, b) else - MST.Binary(RingOperations.TIMES_OPERATION, a, b) + MST.Binary(RingOps.TIMES_OPERATION, a, b) } private val subSumChain: Parser by leftAssociative( @@ -82,9 +82,9 @@ public object ArithmeticsEvaluator : Grammar() { operator = plus or minus use TokenMatch::type ) { a, op, b -> if (op == plus) - MST.Binary(GroupOperations.PLUS_OPERATION, a, b) + MST.Binary(GroupOps.PLUS_OPERATION, a, b) else - MST.Binary(GroupOperations.MINUS_OPERATION, a, b) + MST.Binary(GroupOps.MINUS_OPERATION, a, b) } override val rootParser: Parser by subSumChain 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 a7a28d87f..8b76b6f19 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 @@ -39,7 +39,7 @@ public val PrintNumeric: RenderFeature = RenderFeature { _, node -> @UnstableKMathAPI private fun printSignedNumberString(s: String): MathSyntax = if (s.startsWith('-')) UnaryMinusSyntax( - operation = GroupOperations.MINUS_OPERATION, + operation = GroupOps.MINUS_OPERATION, operand = OperandSyntax( operand = NumberSyntax(string = s.removePrefix("-")), parentheses = true, @@ -72,7 +72,7 @@ public class PrettyPrintFloats(public val types: Set>) : Rend val exponent = afterE.toDouble().toString().removeSuffix(".0") return MultiplicationSyntax( - operation = RingOperations.TIMES_OPERATION, + operation = RingOps.TIMES_OPERATION, left = OperandSyntax(operand = NumberSyntax(significand), parentheses = true), right = OperandSyntax( operand = SuperscriptSyntax( @@ -91,7 +91,7 @@ public class PrettyPrintFloats(public val types: Set>) : Rend if (toString.startsWith('-')) return UnaryMinusSyntax( - operation = GroupOperations.MINUS_OPERATION, + operation = GroupOps.MINUS_OPERATION, operand = OperandSyntax(operand = infty, parentheses = true), ) @@ -211,9 +211,9 @@ public class BinaryPlus(operations: Collection?) : Binary(operations) { public companion object { /** - * The default instance configured with [GroupOperations.PLUS_OPERATION]. + * The default instance configured with [GroupOps.PLUS_OPERATION]. */ - public val Default: BinaryPlus = BinaryPlus(setOf(GroupOperations.PLUS_OPERATION)) + public val Default: BinaryPlus = BinaryPlus(setOf(GroupOps.PLUS_OPERATION)) } } @@ -233,9 +233,9 @@ public class BinaryMinus(operations: Collection?) : Binary(operations) { public companion object { /** - * The default instance configured with [GroupOperations.MINUS_OPERATION]. + * The default instance configured with [GroupOps.MINUS_OPERATION]. */ - public val Default: BinaryMinus = BinaryMinus(setOf(GroupOperations.MINUS_OPERATION)) + public val Default: BinaryMinus = BinaryMinus(setOf(GroupOps.MINUS_OPERATION)) } } @@ -253,9 +253,9 @@ public class UnaryPlus(operations: Collection?) : Unary(operations) { public companion object { /** - * The default instance configured with [GroupOperations.PLUS_OPERATION]. + * The default instance configured with [GroupOps.PLUS_OPERATION]. */ - public val Default: UnaryPlus = UnaryPlus(setOf(GroupOperations.PLUS_OPERATION)) + public val Default: UnaryPlus = UnaryPlus(setOf(GroupOps.PLUS_OPERATION)) } } @@ -273,9 +273,9 @@ public class UnaryMinus(operations: Collection?) : Unary(operations) { public companion object { /** - * The default instance configured with [GroupOperations.MINUS_OPERATION]. + * The default instance configured with [GroupOps.MINUS_OPERATION]. */ - public val Default: UnaryMinus = UnaryMinus(setOf(GroupOperations.MINUS_OPERATION)) + public val Default: UnaryMinus = UnaryMinus(setOf(GroupOps.MINUS_OPERATION)) } } @@ -295,9 +295,9 @@ public class Fraction(operations: Collection?) : Binary(operations) { public companion object { /** - * The default instance configured with [FieldOperations.DIV_OPERATION]. + * The default instance configured with [FieldOps.DIV_OPERATION]. */ - public val Default: Fraction = Fraction(setOf(FieldOperations.DIV_OPERATION)) + public val Default: Fraction = Fraction(setOf(FieldOps.DIV_OPERATION)) } } @@ -422,9 +422,9 @@ public class Multiplication(operations: Collection?) : Binary(operations public companion object { /** - * The default instance configured with [RingOperations.TIMES_OPERATION]. + * The default instance configured with [RingOps.TIMES_OPERATION]. */ - public val Default: Multiplication = Multiplication(setOf(RingOperations.TIMES_OPERATION)) + public val Default: Multiplication = Multiplication(setOf(RingOps.TIMES_OPERATION)) } } 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 3d05e03d6..ecea2d104 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 @@ -7,10 +7,10 @@ package space.kscience.kmath.ast.rendering import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess.PostProcessPhase import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.FieldOperations -import space.kscience.kmath.operations.GroupOperations +import space.kscience.kmath.operations.FieldOps +import space.kscience.kmath.operations.GroupOps import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.RingOperations +import space.kscience.kmath.operations.RingOps /** * Removes unnecessary times (×) symbols from [MultiplicationSyntax]. @@ -306,10 +306,10 @@ public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> is BinarySyntax -> when (it.operation) { PowerOperations.POW_OPERATION -> 1 - RingOperations.TIMES_OPERATION -> 3 - FieldOperations.DIV_OPERATION -> 3 - GroupOperations.MINUS_OPERATION -> 4 - GroupOperations.PLUS_OPERATION -> 4 + RingOps.TIMES_OPERATION -> 3 + FieldOps.DIV_OPERATION -> 3 + GroupOps.MINUS_OPERATION -> 4 + GroupOps.PLUS_OPERATION -> 4 else -> 0 } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt index d8e432230..aba713c43 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.ast.rendering import space.kscience.kmath.ast.rendering.TestUtils.testLatex import space.kscience.kmath.expressions.MST -import space.kscience.kmath.operations.GroupOperations +import space.kscience.kmath.operations.GroupOps import kotlin.test.Test internal class TestLatex { @@ -36,7 +36,7 @@ internal class TestLatex { fun unaryOperator() = testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)") @Test - fun unaryPlus() = testLatex(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1") + fun unaryPlus() = testLatex(MST.Unary(GroupOps.PLUS_OPERATION, MST.Numeric(1)), "+1") @Test fun unaryMinus() = testLatex("-x", "-x") diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt index a7fcbc75b..658ecd47a 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.ast.rendering import space.kscience.kmath.ast.rendering.TestUtils.testMathML import space.kscience.kmath.expressions.MST -import space.kscience.kmath.operations.GroupOperations +import space.kscience.kmath.operations.GroupOps import kotlin.test.Test internal class TestMathML { @@ -47,7 +47,7 @@ internal class TestMathML { @Test fun unaryPlus() = - testMathML(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1") + testMathML(MST.Unary(GroupOps.PLUS_OPERATION, MST.Numeric(1)), "+1") @Test fun unaryMinus() = testMathML("-x", "-x") 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 5b6cf65db..b04c4d48f 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 @@ -108,8 +108,8 @@ internal class DoubleWasmBuilder(target: MST) : WasmBuilder(f64, DoubleF override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.f64.const(mst.value) override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) { - GroupOperations.MINUS_OPERATION -> ctx.f64.neg(visit(mst.value)) - GroupOperations.PLUS_OPERATION -> visit(mst.value) + GroupOps.MINUS_OPERATION -> ctx.f64.neg(visit(mst.value)) + GroupOps.PLUS_OPERATION -> visit(mst.value) PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(mst.value)) TrigonometricOperations.SIN_OPERATION -> ctx.call("sin", arrayOf(visit(mst.value)), f64) TrigonometricOperations.COS_OPERATION -> ctx.call("cos", arrayOf(visit(mst.value)), f64) @@ -129,10 +129,10 @@ internal class DoubleWasmBuilder(target: MST) : WasmBuilder(f64, DoubleF } override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { - GroupOperations.PLUS_OPERATION -> ctx.f64.add(visit(mst.left), visit(mst.right)) - GroupOperations.MINUS_OPERATION -> ctx.f64.sub(visit(mst.left), visit(mst.right)) - RingOperations.TIMES_OPERATION -> ctx.f64.mul(visit(mst.left), visit(mst.right)) - FieldOperations.DIV_OPERATION -> ctx.f64.div(visit(mst.left), visit(mst.right)) + GroupOps.PLUS_OPERATION -> ctx.f64.add(visit(mst.left), visit(mst.right)) + GroupOps.MINUS_OPERATION -> ctx.f64.sub(visit(mst.left), visit(mst.right)) + RingOps.TIMES_OPERATION -> ctx.f64.mul(visit(mst.left), visit(mst.right)) + FieldOps.DIV_OPERATION -> ctx.f64.div(visit(mst.left), visit(mst.right)) PowerOperations.POW_OPERATION -> ctx.call("pow", arrayOf(visit(mst.left), visit(mst.right)), f64) else -> super.visitBinary(mst) } @@ -142,15 +142,15 @@ internal class IntWasmBuilder(target: MST) : WasmBuilder(i32, IntRing, targ override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.i32.const(mst.value) override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) { - GroupOperations.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(mst.value)) - GroupOperations.PLUS_OPERATION -> visit(mst.value) + GroupOps.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(mst.value)) + GroupOps.PLUS_OPERATION -> visit(mst.value) else -> super.visitUnary(mst) } override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { - GroupOperations.PLUS_OPERATION -> ctx.i32.add(visit(mst.left), visit(mst.right)) - GroupOperations.MINUS_OPERATION -> ctx.i32.sub(visit(mst.left), visit(mst.right)) - RingOperations.TIMES_OPERATION -> ctx.i32.mul(visit(mst.left), visit(mst.right)) + GroupOps.PLUS_OPERATION -> ctx.i32.add(visit(mst.left), visit(mst.right)) + GroupOps.MINUS_OPERATION -> ctx.i32.sub(visit(mst.left), visit(mst.right)) + RingOps.TIMES_OPERATION -> ctx.i32.mul(visit(mst.left), visit(mst.right)) else -> super.visitBinary(mst) } } diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index bc0119ca2..a178e8dd7 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -9,7 +9,7 @@ import org.apache.commons.math3.analysis.differentiation.DerivativeStructure import space.kscience.kmath.expressions.* import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.NumbersAddOps /** * A field over commons-math [DerivativeStructure]. @@ -22,7 +22,7 @@ public class DerivativeStructureField( public val order: Int, bindings: Map, ) : ExtendedField, ExpressionAlgebra, - NumbersAddOperations { + NumbersAddOps { public val numberOfVariables: Int = bindings.size override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } 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 7d948cb61..e61a7bccc 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 @@ -52,7 +52,7 @@ private val PI_DIV_2 = Complex(PI / 2, 0) public object ComplexField : ExtendedField, Norm, - NumbersAddOperations, + NumbersAddOps, ScaleOperations { override val zero: Complex = 0.0.toComplex() @@ -216,7 +216,6 @@ public data class Complex(val re: Double, val im: Double) { public val Complex.Companion.algebra: ComplexField get() = ComplexField - /** * Creates a complex number with real part equal to this real. * 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 29e790d16..3951b5de0 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 @@ -6,13 +6,8 @@ package space.kscience.kmath.complex import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.BufferND -import space.kscience.kmath.nd.BufferedFieldND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.BufferField -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations -import space.kscience.kmath.operations.bufferAlgebra +import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -22,100 +17,61 @@ import kotlin.contracts.contract * An optimized nd-field for complex numbers */ @OptIn(UnstableKMathAPI::class) -public class ComplexFieldND( - shape: IntArray, -) : BufferedFieldND(shape, ComplexField, Buffer.Companion::complex), - NumbersAddOperations>, - ExtendedField> { +public sealed class ComplexFieldOpsND : BufferedFieldOpsND(ComplexField.bufferAlgebra), + ScaleOperations>, ExtendedFieldOps> { - override val zero: BufferND by lazy { produce { zero } } - override val one: BufferND by lazy { produce { one } } - - override fun number(value: Number): BufferND { - val d = value.toComplex() // minimize conversions - return produce { d } + override fun StructureND.toBufferND(): BufferND = when (this) { + is BufferND -> this + else -> { + val indexer = indexerBuilder(shape) + BufferND(indexer, Buffer.complex(indexer.linearSize) { offset -> get(indexer.index(offset)) }) + } } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun map( -// arg: AbstractNDBuffer, -// transform: DoubleField.(Double) -> Double, -// ): RealNDElement { -// check(arg) -// val array = RealBuffer(arg.strides.linearSize) { offset -> DoubleField.transform(arg.buffer[offset]) } -// return BufferedNDFieldElement(this, array) -// } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun produce(initializer: DoubleField.(IntArray) -> Double): RealNDElement { -// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } -// return BufferedNDFieldElement(this, array) -// } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun mapIndexed( -// arg: AbstractNDBuffer, -// transform: DoubleField.(index: IntArray, Double) -> Double, -// ): RealNDElement { -// check(arg) -// return BufferedNDFieldElement( -// this, -// RealBuffer(arg.strides.linearSize) { offset -> -// elementContext.transform( -// arg.strides.index(offset), -// arg.buffer[offset] -// ) -// }) -// } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun combine( -// a: AbstractNDBuffer, -// b: AbstractNDBuffer, -// transform: DoubleField.(Double, Double) -> Double, -// ): RealNDElement { -// check(a, b) -// val buffer = RealBuffer(strides.linearSize) { offset -> -// elementContext.transform(a.buffer[offset], b.buffer[offset]) -// } -// return BufferedNDFieldElement(this, buffer) -// } + //TODO do specialization - override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } + override fun scale(a: StructureND, value: Double): BufferND = + mapInline(a.toBufferND()) { it * value } - override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } + override fun power(arg: StructureND, pow: Number): BufferND = + mapInline(arg.toBufferND()) { power(it, pow) } - override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } + override fun exp(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { exp(it) } + override fun ln(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { ln(it) } - override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } + override fun sin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sin(it) } + override fun cos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cos(it) } + override fun tan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tan(it) } + override fun asin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asin(it) } + override fun acos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acos(it) } + override fun atan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atan(it) } - override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } -} + override fun sinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sinh(it) } + override fun cosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cosh(it) } + override fun tanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tanh(it) } + override fun asinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asinh(it) } + override fun acosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acosh(it) } + override fun atanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atanh(it) } - -/** - * Fast element production using function inlining - */ -public inline fun BufferedFieldND.produceInline(initializer: ComplexField.(Int) -> Complex): BufferND { - contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) } - val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) } - return BufferND(strides, buffer) + public companion object : ComplexFieldOpsND() } @UnstableKMathAPI -public fun ComplexField.bufferAlgebra(size: Int): BufferField = - bufferAlgebra(Buffer.Companion::complex, size) +public val ComplexField.bufferAlgebra: BufferFieldOps + get() = bufferAlgebra(Buffer.Companion::complex) + + +@OptIn(UnstableKMathAPI::class) +public class ComplexFieldND(override val shape: Shape) : + ComplexFieldOpsND(), FieldND, NumbersAddOps> { + + override fun number(value: Number): BufferND { + val d = value.toDouble() // minimize conversions + return produce(shape) { d.toComplex() } + } +} + +public val ComplexField.ndAlgebra: ComplexFieldOpsND get() = ComplexFieldOpsND public fun ComplexField.ndAlgebra(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape) 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 e5d7ebd1e..b0ec10c35 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 @@ -44,7 +44,7 @@ public val Quaternion.r: Double */ @OptIn(UnstableKMathAPI::class) public object QuaternionField : Field, Norm, PowerOperations, - ExponentialOperations, NumbersAddOperations, ScaleOperations { + ExponentialOperations, NumbersAddOps, ScaleOperations { override val zero: Quaternion = 0.toQuaternion() override val one: Quaternion = 1.toQuaternion() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 36ccb96f7..1baca0f55 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -52,13 +52,13 @@ public open class FunctionalExpressionGroup>( override val zero: Expression get() = const(algebra.zero) override fun Expression.unaryMinus(): Expression = - unaryOperation(GroupOperations.MINUS_OPERATION, this) + unaryOperation(GroupOps.MINUS_OPERATION, this) /** * Builds an Expression of addition of two another expressions. */ override fun add(a: Expression, b: Expression): Expression = - binaryOperation(GroupOperations.PLUS_OPERATION, a, b) + binaryOperation(GroupOps.PLUS_OPERATION, a, b) // /** // * Builds an Expression of multiplication of expression by number. @@ -89,7 +89,7 @@ public open class FunctionalExpressionRing>( * Builds an Expression of multiplication of two expressions. */ override fun multiply(a: Expression, b: Expression): Expression = - binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) + binaryOperationFunction(RingOps.TIMES_OPERATION)(a, b) public operator fun Expression.times(arg: T): Expression = this * const(arg) public operator fun T.times(arg: Expression): Expression = arg * this @@ -108,7 +108,7 @@ public open class FunctionalExpressionField>( * Builds an Expression of division an expression by another one. */ override fun divide(a: Expression, b: Expression): Expression = - binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) + binaryOperationFunction(FieldOps.DIV_OPERATION)(a, b) public operator fun Expression.div(arg: T): Expression = this / const(arg) public operator fun T.div(arg: Expression): Expression = arg / this 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 bbc74005c..360715408 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 @@ -31,18 +31,18 @@ public object MstGroup : Group, NumericAlgebra, ScaleOperations { override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value) override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOperations.PLUS_OPERATION)(a, b) + override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOps.PLUS_OPERATION)(a, b) override operator fun MST.unaryPlus(): MST.Unary = - unaryOperationFunction(GroupOperations.PLUS_OPERATION)(this) + unaryOperationFunction(GroupOps.PLUS_OPERATION)(this) override operator fun MST.unaryMinus(): MST.Unary = - unaryOperationFunction(GroupOperations.MINUS_OPERATION)(this) + unaryOperationFunction(GroupOps.MINUS_OPERATION)(this) override operator fun MST.minus(b: MST): MST.Binary = - binaryOperationFunction(GroupOperations.MINUS_OPERATION)(this, b) + binaryOperationFunction(GroupOps.MINUS_OPERATION)(this, b) override fun scale(a: MST, value: Double): MST.Binary = - binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(value)) + binaryOperationFunction(RingOps.TIMES_OPERATION)(a, number(value)) override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstNumericAlgebra.binaryOperationFunction(operation) @@ -56,7 +56,7 @@ public object MstGroup : Group, NumericAlgebra, ScaleOperations { */ @Suppress("OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -public object MstRing : Ring, NumbersAddOperations, ScaleOperations { +public object MstRing : Ring, NumbersAddOps, ScaleOperations { override inline val zero: MST.Numeric get() = MstGroup.zero override val one: MST.Numeric = number(1.0) @@ -65,10 +65,10 @@ public object MstRing : Ring, NumbersAddOperations, ScaleOperations, NumbersAddOperations, ScaleOperations, NumbersAddOperations, ScaleOperations { +public object MstField : Field, NumbersAddOps, ScaleOperations { override inline val zero: MST.Numeric get() = MstRing.zero override inline val one: MST.Numeric get() = MstRing.one @@ -95,11 +95,11 @@ public object MstField : Field, NumbersAddOperations, ScaleOperations< override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) override fun scale(a: MST, value: Double): MST.Binary = - MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) + MstGroup.binaryOperationFunction(RingOps.TIMES_OPERATION)(a, MstGroup.number(value)) override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) override fun divide(a: MST, b: MST): MST.Binary = - binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) + binaryOperationFunction(FieldOps.DIV_OPERATION)(a, b) override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } @@ -138,7 +138,7 @@ public object MstExtendedField : ExtendedField, NumericAlgebra { override fun sqrt(arg: MST): MST = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) override fun scale(a: MST, value: Double): MST = - binaryOperation(GroupOperations.PLUS_OPERATION, a, number(value)) + binaryOperation(GroupOps.PLUS_OPERATION, a, number(value)) override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) 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 d5b80da2c..089503dc8 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 @@ -59,7 +59,7 @@ public fun DerivationResult.grad(vararg variables: Symbol): Point>( public val context: F, bindings: Map, -) : Field>, ExpressionAlgebra>, NumbersAddOperations> { +) : Field>, ExpressionAlgebra>, NumbersAddOps> { override val zero: AutoDiffValue get() = const(context.zero) override val one: AutoDiffValue get() = const(context.one) 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 3d562f26f..39dbe3a81 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 @@ -6,12 +6,10 @@ package space.kscience.kmath.linear import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.BufferedRingND +import space.kscience.kmath.nd.BufferedRingOpsND import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.asND -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.VirtualBuffer @@ -19,31 +17,28 @@ import space.kscience.kmath.structures.indices public class BufferedLinearSpace>( - override val elementAlgebra: A, - private val bufferFactory: BufferFactory, + private val bufferAlgebra: BufferAlgebra ) : LinearSpace { + override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra - private fun ndRing( - rows: Int, - cols: Int, - ): BufferedRingND = elementAlgebra.ndAlgebra(bufferFactory, rows, cols) + private val ndAlgebra = BufferedRingOpsND(bufferAlgebra) override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix = - ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() + ndAlgebra.produce(intArrayOf(rows, columns)) { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() override fun buildVector(size: Int, initializer: A.(Int) -> T): Point = - bufferFactory(size) { elementAlgebra.initializer(it) } + bufferAlgebra.buffer(size) { elementAlgebra.initializer(it) } - override fun Matrix.unaryMinus(): Matrix = ndRing(rowNum, colNum).run { + override fun Matrix.unaryMinus(): Matrix = ndAlgebra { asND().map { -it }.as2D() } - override fun Matrix.plus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { + override fun Matrix.plus(other: Matrix): Matrix = ndAlgebra { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } asND().plus(other.asND()).as2D() } - override fun Matrix.minus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { + override fun Matrix.minus(other: Matrix): Matrix = ndAlgebra { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } asND().minus(other.asND()).as2D() } @@ -88,11 +83,11 @@ public class BufferedLinearSpace>( } } - override fun Matrix.times(value: T): Matrix = ndRing(rowNum, colNum).run { + override fun Matrix.times(value: T): Matrix = ndAlgebra { asND().map { it * value }.as2D() } } public fun > A.linearSpace(bufferFactory: BufferFactory): BufferedLinearSpace = - BufferedLinearSpace(this, bufferFactory) + BufferedLinearSpace(BufferRingOps(this, bufferFactory)) 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 c2f53939f..ec6040af0 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 @@ -6,11 +6,12 @@ package space.kscience.kmath.linear import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DoubleFieldND +import space.kscience.kmath.nd.DoubleFieldOpsND import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.asND -import space.kscience.kmath.operations.DoubleBufferOperations +import space.kscience.kmath.operations.DoubleBufferOps import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer @@ -18,30 +19,27 @@ public object DoubleLinearSpace : LinearSpace { override val elementAlgebra: DoubleField get() = DoubleField - private fun ndRing( - rows: Int, - cols: Int, - ): DoubleFieldND = DoubleFieldND(intArrayOf(rows, cols)) - override fun buildMatrix( rows: Int, columns: Int, initializer: DoubleField.(i: Int, j: Int) -> Double - ): Matrix = ndRing(rows, columns).produce { (i, j) -> DoubleField.initializer(i, j) }.as2D() + ): Matrix = DoubleFieldOpsND.produce(intArrayOf(rows, columns)) { (i, j) -> + DoubleField.initializer(i, j) + }.as2D() override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): DoubleBuffer = DoubleBuffer(size) { DoubleField.initializer(it) } - override fun Matrix.unaryMinus(): Matrix = ndRing(rowNum, colNum).run { + override fun Matrix.unaryMinus(): Matrix = DoubleFieldOpsND { asND().map { -it }.as2D() } - override fun Matrix.plus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { + override fun Matrix.plus(other: Matrix): Matrix = DoubleFieldOpsND { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } asND().plus(other.asND()).as2D() } - override fun Matrix.minus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { + override fun Matrix.minus(other: Matrix): Matrix = DoubleFieldOpsND { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } asND().minus(other.asND()).as2D() } @@ -84,23 +82,23 @@ public object DoubleLinearSpace : LinearSpace { } - override fun Matrix.times(value: Double): Matrix = ndRing(rowNum, colNum).run { + override fun Matrix.times(value: Double): Matrix = DoubleFieldOpsND { asND().map { it * value }.as2D() } - public override fun Point.plus(other: Point): DoubleBuffer = DoubleBufferOperations.run { + public override fun Point.plus(other: Point): DoubleBuffer = DoubleBufferOps.run { this@plus + other } - public override fun Point.minus(other: Point): DoubleBuffer = DoubleBufferOperations.run { + public override fun Point.minus(other: Point): DoubleBuffer = DoubleBufferOps.run { this@minus - other } - public override fun Point.times(value: Double): DoubleBuffer = DoubleBufferOperations.run { + public override fun Point.times(value: Double): DoubleBuffer = DoubleBufferOps.run { scale(this@times, value) } - public operator fun Point.div(value: Double): DoubleBuffer = DoubleBufferOperations.run { + public operator fun Point.div(value: Double): DoubleBuffer = DoubleBufferOps.run { scale(this@div, 1.0 / value) } 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 1d8985b59..5349ad864 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 @@ -10,6 +10,7 @@ import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.nd.as1D +import space.kscience.kmath.operations.BufferRingOps import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke @@ -188,7 +189,7 @@ public interface LinearSpace> { public fun > buffered( algebra: A, bufferFactory: BufferFactory = Buffer.Companion::boxing, - ): LinearSpace = BufferedLinearSpace(algebra, bufferFactory) + ): LinearSpace = BufferedLinearSpace(BufferRingOps(algebra, bufferFactory)) @Deprecated("use DoubleField.linearSpace") public val double: LinearSpace = buffered(DoubleField, ::DoubleBuffer) 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 b925c2642..dde04a97a 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 @@ -7,7 +7,6 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.* import kotlin.reflect.KClass /** @@ -19,6 +18,14 @@ import kotlin.reflect.KClass public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) : RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.") +public typealias Shape = IntArray + +public fun Shape(shapeFirst: Int, vararg shapeRest: Int): Shape = intArrayOf(shapeFirst, *shapeRest) + +public interface WithShape { + public val shape: Shape +} + /** * The base interface for all ND-algebra implementations. * @@ -26,20 +33,15 @@ public class ShapeMismatchException(public val expected: IntArray, public val ac * @param C the type of the element context. */ public interface AlgebraND> { - /** - * The shape of ND-structures this algebra operates on. - */ - public val shape: IntArray - /** * The algebra over elements of ND structure. */ - public val elementContext: C + public val elementAlgebra: C /** * Produces a new NDStructure using given initializer function. */ - public fun produce(initializer: C.(IntArray) -> T): StructureND + public fun produce(shape: Shape, initializer: C.(IntArray) -> T): StructureND /** * Maps elements from one structure to another one by applying [transform] to them. @@ -54,7 +56,7 @@ public interface AlgebraND> { /** * Combines two structures into one. */ - public fun combine(a: StructureND, b: StructureND, transform: C.(T, T) -> T): StructureND + public fun zip(left: StructureND, right: StructureND, transform: C.(T, T) -> T): StructureND /** * Element-wise invocation of function working on [T] on a [StructureND]. @@ -77,7 +79,6 @@ public interface AlgebraND> { public companion object } - /** * Get a feature of the structure in this scope. Structure features take precedence other context features. * @@ -89,37 +90,13 @@ public interface AlgebraND> { public inline fun AlgebraND.getFeature(structure: StructureND): F? = getFeature(structure, F::class) -/** - * Checks if given elements are consistent with this context. - * - * @param structures the structures to check. - * @return the array of valid structures. - */ -internal fun > AlgebraND.checkShape(vararg structures: StructureND): Array> = - structures - .map(StructureND::shape) - .singleOrNull { !shape.contentEquals(it) } - ?.let>> { throw ShapeMismatchException(shape, it) } - ?: structures - -/** - * Checks if given element is consistent with this context. - * - * @param element the structure to check. - * @return the valid structure. - */ -internal fun > AlgebraND.checkShape(element: StructureND): StructureND { - if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape) - return element -} - /** * Space of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param S the type of group over structure elements. + * @param A the type of group over structure elements. */ -public interface GroupND> : Group>, AlgebraND { +public interface GroupOpsND> : GroupOps>, AlgebraND { /** * Element-wise addition. * @@ -128,7 +105,7 @@ public interface GroupND> : Group>, AlgebraND * @return the sum. */ override fun add(a: StructureND, b: StructureND): StructureND = - combine(a, b) { aValue, bValue -> add(aValue, bValue) } + zip(a, b) { aValue, bValue -> add(aValue, bValue) } // TODO move to extensions after KEEP-176 @@ -171,13 +148,17 @@ public interface GroupND> : Group>, AlgebraND public companion object } +public interface GroupND> : Group>, GroupOpsND, WithShape { + override val zero: StructureND get() = produce(shape) { elementAlgebra.zero } +} + /** * Ring of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param R the type of ring over structure elements. + * @param A the type of ring over structure elements. */ -public interface RingND> : Ring>, GroupND { +public interface RingOpsND> : RingOps>, GroupOpsND { /** * Element-wise multiplication. * @@ -186,7 +167,7 @@ public interface RingND> : Ring>, GroupND, b: StructureND): StructureND = - combine(a, b) { aValue, bValue -> multiply(aValue, bValue) } + zip(a, b) { aValue, bValue -> multiply(aValue, bValue) } //TODO move to extensions after KEEP-176 @@ -211,13 +192,19 @@ public interface RingND> : Ring>, GroupND> : Ring>, RingOpsND, GroupND, WithShape { + override val one: StructureND get() = produce(shape) { elementAlgebra.one } +} + + /** * Field of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param F the type field over structure elements. + * @param A the type field over structure elements. */ -public interface FieldND> : Field>, RingND { +public interface FieldOpsND> : FieldOps>, RingOpsND, + ScaleOperations> { /** * Element-wise division. * @@ -226,9 +213,9 @@ public interface FieldND> : Field>, RingND, b: StructureND): StructureND = - combine(a, b) { aValue, bValue -> divide(aValue, bValue) } + zip(a, b) { aValue, bValue -> divide(aValue, bValue) } - //TODO move to extensions after KEEP-176 + //TODO move to extensions after https://github.com/Kotlin/KEEP/blob/master/proposals/context-receivers.md /** * Divides an ND structure by an element of it. * @@ -247,42 +234,9 @@ public interface FieldND> : Field>, RingND): StructureND = arg.map { divide(it, this@div) } - /** - * Element-wise scaling. - * - * @param a the multiplicand. - * @param value the multiplier. - * @return the product. - */ override fun scale(a: StructureND, value: Double): StructureND = a.map { scale(it, value) } - -// @ThreadLocal -// public companion object { -// private val realNDFieldCache: MutableMap = hashMapOf() -// -// /** -// * Create a nd-field for [Double] values or pull it from cache if it was created previously. -// */ -// public fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) } -// -// /** -// * Create an ND field with boxing generic buffer. -// */ -// public fun > boxing( -// field: F, -// vararg shape: Int, -// bufferFactory: BufferFactory = Buffer.Companion::boxing, -// ): BufferedNDField = BufferedNDField(shape, field, bufferFactory) -// -// /** -// * Create a most suitable implementation for nd-field using reified class. -// */ -// @Suppress("UNCHECKED_CAST") -// public inline fun > auto(field: F, vararg shape: Int): NDField = -// when { -// T::class == Double::class -> real(*shape) as NDField -// T::class == Complex::class -> complex(*shape) as BufferedNDField -// else -> BoxingNDField(shape, field, Buffer.Companion::auto) -// } -// } } + +public interface FieldND> : Field>, FieldOpsND, RingND, WithShape { + override val one: StructureND get() = produce(shape) { elementAlgebra.one } +} \ No newline at end of file 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 ae72f3689..06534c5e5 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 @@ -3,145 +3,173 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ +@file:OptIn(UnstableKMathAPI::class) + package space.kscience.kmath.nd import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.jvm.JvmName public interface BufferAlgebraND> : AlgebraND { - public val strides: Strides - public val bufferFactory: BufferFactory + public val indexerBuilder: (IntArray) -> ShapeIndex + public val bufferAlgebra: BufferAlgebra + override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra - override fun produce(initializer: A.(IntArray) -> T): BufferND = BufferND( - strides, - bufferFactory(strides.linearSize) { offset -> - elementContext.initializer(strides.index(offset)) + override fun produce(shape: Shape, initializer: A.(IntArray) -> T): BufferND { + val indexer = indexerBuilder(shape) + return BufferND( + indexer, + bufferAlgebra.buffer(indexer.linearSize) { offset -> + elementAlgebra.initializer(indexer.index(offset)) + } + ) + } + + public fun StructureND.toBufferND(): BufferND = when (this) { + is BufferND -> this + else -> { + val indexer = indexerBuilder(shape) + BufferND(indexer, bufferAlgebra.buffer(indexer.linearSize) { offset -> get(indexer.index(offset)) }) + } + } + + override fun StructureND.map(transform: A.(T) -> T): BufferND = mapInline(toBufferND(), transform) + + override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): BufferND = + mapIndexedInline(toBufferND(), transform) + + override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): BufferND = + zipInline(left.toBufferND(), right.toBufferND(), transform) + + public companion object { + public val defaultIndexerBuilder: (IntArray) -> ShapeIndex = DefaultStrides.Companion::invoke + } +} + +public inline fun > BufferAlgebraND.mapInline( + arg: BufferND, + crossinline transform: A.(T) -> T +): BufferND { + val indexes = arg.indexes + return BufferND(indexes, bufferAlgebra.mapInline(arg.buffer, transform)) +} + +internal inline fun > BufferAlgebraND.mapIndexedInline( + arg: BufferND, + crossinline transform: A.(index: IntArray, arg: T) -> T +): BufferND { + val indexes = arg.indexes + return BufferND( + indexes, + bufferAlgebra.mapIndexedInline(arg.buffer) { offset, value -> + transform(indexes.index(offset), value) } ) - - public val StructureND.buffer: Buffer - get() = when { - !shape.contentEquals(this@BufferAlgebraND.shape) -> throw ShapeMismatchException( - this@BufferAlgebraND.shape, - shape - ) - this is BufferND && this.strides == this@BufferAlgebraND.strides -> this.buffer - else -> bufferFactory(strides.linearSize) { offset -> get(strides.index(offset)) } - } - - override fun StructureND.map(transform: A.(T) -> T): BufferND { - val buffer = bufferFactory(strides.linearSize) { offset -> - elementContext.transform(buffer[offset]) - } - return BufferND(strides, buffer) - } - - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): BufferND { - val buffer = bufferFactory(strides.linearSize) { offset -> - elementContext.transform( - strides.index(offset), - buffer[offset] - ) - } - return BufferND(strides, buffer) - } - - override fun combine(a: StructureND, b: StructureND, transform: A.(T, T) -> T): BufferND { - val buffer = bufferFactory(strides.linearSize) { offset -> - elementContext.transform(a.buffer[offset], b.buffer[offset]) - } - return BufferND(strides, buffer) - } } -public open class BufferedGroupND>( - final override val shape: IntArray, - final override val elementContext: A, - final override val bufferFactory: BufferFactory, -) : GroupND, BufferAlgebraND { - override val strides: Strides = DefaultStrides(shape) - override val zero: BufferND by lazy { produce { zero } } - override fun StructureND.unaryMinus(): StructureND = produce { -get(it) } +internal inline fun > BufferAlgebraND.zipInline( + l: BufferND, + r: BufferND, + crossinline block: A.(l: T, r: T) -> T +): BufferND { + require(l.indexes == r.indexes) + val indexes = l.indexes + return BufferND(indexes, bufferAlgebra.zipInline(l.buffer, r.buffer, block)) } -public open class BufferedRingND>( - shape: IntArray, - elementContext: R, - bufferFactory: BufferFactory, -) : BufferedGroupND(shape, elementContext, bufferFactory), RingND { - override val one: BufferND by lazy { produce { one } } +public open class BufferedGroupNDOps>( + override val bufferAlgebra: BufferAlgebra, + override val indexerBuilder: (IntArray) -> ShapeIndex = BufferAlgebraND.defaultIndexerBuilder +) : GroupOpsND, BufferAlgebraND { + override fun StructureND.unaryMinus(): StructureND = map { -it } } -public open class BufferedFieldND>( - shape: IntArray, - elementContext: R, - bufferFactory: BufferFactory, -) : BufferedRingND(shape, elementContext, bufferFactory), FieldND { +public open class BufferedRingOpsND>( + bufferAlgebra: BufferAlgebra, + indexerBuilder: (IntArray) -> ShapeIndex = BufferAlgebraND.defaultIndexerBuilder +) : BufferedGroupNDOps(bufferAlgebra, indexerBuilder), RingOpsND + +public open class BufferedFieldOpsND>( + bufferAlgebra: BufferAlgebra, + indexerBuilder: (IntArray) -> ShapeIndex = BufferAlgebraND.defaultIndexerBuilder +) : BufferedRingOpsND(bufferAlgebra, indexerBuilder), FieldOpsND { + + public constructor( + elementAlgebra: A, + bufferFactory: BufferFactory, + indexerBuilder: (IntArray) -> ShapeIndex = BufferAlgebraND.defaultIndexerBuilder + ) : this(BufferFieldOps(elementAlgebra, bufferFactory), indexerBuilder) override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } } -// group factories -public fun > A.ndAlgebra( - bufferFactory: BufferFactory, - vararg shape: Int, -): BufferedGroupND = BufferedGroupND(shape, this, bufferFactory) +public val > BufferAlgebra.nd: BufferedGroupNDOps get() = BufferedGroupNDOps(this) +public val > BufferAlgebra.nd: BufferedRingOpsND get() = BufferedRingOpsND(this) +public val > BufferAlgebra.nd: BufferedFieldOpsND get() = BufferedFieldOpsND(this) -@JvmName("withNdGroup") -public inline fun , R> A.withNdAlgebra( - noinline bufferFactory: BufferFactory, - vararg shape: Int, - action: BufferedGroupND.() -> R, -): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return ndAlgebra(bufferFactory, *shape).run(action) -} -//ring factories -public fun > A.ndAlgebra( - bufferFactory: BufferFactory, +public fun > BufferAlgebraND.produce( vararg shape: Int, -): BufferedRingND = BufferedRingND(shape, this, bufferFactory) + initializer: A.(IntArray) -> T +): BufferND = produce(shape, initializer) -@JvmName("withNdRing") -public inline fun , R> A.withNdAlgebra( - noinline bufferFactory: BufferFactory, - vararg shape: Int, - action: BufferedRingND.() -> R, -): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return ndAlgebra(bufferFactory, *shape).run(action) -} +//// group factories +//public fun > A.ndAlgebra( +// bufferAlgebra: BufferAlgebra, +// vararg shape: Int, +//): BufferedGroupNDOps = BufferedGroupNDOps(bufferAlgebra) +// +//@JvmName("withNdGroup") +//public inline fun , R> A.withNdAlgebra( +// noinline bufferFactory: BufferFactory, +// vararg shape: Int, +// action: BufferedGroupNDOps.() -> R, +//): R { +// contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } +// return ndAlgebra(bufferFactory, *shape).run(action) +//} -//field factories -public fun > A.ndAlgebra( - bufferFactory: BufferFactory, - vararg shape: Int, -): BufferedFieldND = BufferedFieldND(shape, this, bufferFactory) - -/** - * Create a [FieldND] for this [Field] inferring proper buffer factory from the type - */ -@UnstableKMathAPI -@Suppress("UNCHECKED_CAST") -public inline fun > A.autoNdAlgebra( - vararg shape: Int, -): FieldND = when (this) { - DoubleField -> DoubleFieldND(shape) as FieldND - else -> BufferedFieldND(shape, this, Buffer.Companion::auto) -} - -@JvmName("withNdField") -public inline fun , R> A.withNdAlgebra( - noinline bufferFactory: BufferFactory, - vararg shape: Int, - action: BufferedFieldND.() -> R, -): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return ndAlgebra(bufferFactory, *shape).run(action) -} \ No newline at end of file +////ring factories +//public fun > A.ndAlgebra( +// bufferFactory: BufferFactory, +// vararg shape: Int, +//): BufferedRingNDOps = BufferedRingNDOps(shape, this, bufferFactory) +// +//@JvmName("withNdRing") +//public inline fun , R> A.withNdAlgebra( +// noinline bufferFactory: BufferFactory, +// vararg shape: Int, +// action: BufferedRingNDOps.() -> R, +//): R { +// contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } +// return ndAlgebra(bufferFactory, *shape).run(action) +//} +// +////field factories +//public fun > A.ndAlgebra( +// bufferFactory: BufferFactory, +// vararg shape: Int, +//): BufferedFieldNDOps = BufferedFieldNDOps(shape, this, bufferFactory) +// +///** +// * Create a [FieldND] for this [Field] inferring proper buffer factory from the type +// */ +//@UnstableKMathAPI +//@Suppress("UNCHECKED_CAST") +//public inline fun > A.autoNdAlgebra( +// vararg shape: Int, +//): FieldND = when (this) { +// DoubleField -> DoubleFieldND(shape) as FieldND +// else -> BufferedFieldNDOps(shape, this, Buffer.Companion::auto) +//} +// +//@JvmName("withNdField") +//public inline fun , R> A.withNdAlgebra( +// noinline bufferFactory: BufferFactory, +// vararg shape: Int, +// action: BufferedFieldNDOps.() -> R, +//): R { +// contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } +// return ndAlgebra(bufferFactory, *shape).run(action) +//} \ No newline at end of file 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 694e0ceae..9eba401ab 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 @@ -15,26 +15,20 @@ import space.kscience.kmath.structures.MutableBufferFactory * Represents [StructureND] over [Buffer]. * * @param T the type of items. - * @param strides The strides to access elements of [Buffer] by linear indices. + * @param indexes The strides to access elements of [Buffer] by linear indices. * @param buffer The underlying buffer. */ public open class BufferND( - public val strides: Strides, + public val indexes: ShapeIndex, public val buffer: Buffer, ) : StructureND { - init { - if (strides.linearSize != buffer.size) { - error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}") - } - } + override operator fun get(index: IntArray): T = buffer[indexes.offset(index)] - override operator fun get(index: IntArray): T = buffer[strides.offset(index)] - - override val shape: IntArray get() = strides.shape + override val shape: IntArray get() = indexes.shape @PerformancePitfall - override fun elements(): Sequence> = strides.indices().map { + override fun elements(): Sequence> = indexes.indices().map { it to this[it] } @@ -49,7 +43,7 @@ public inline fun StructureND.mapToBuffer( crossinline transform: (T) -> R, ): BufferND { return if (this is BufferND) - BufferND(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) }) + BufferND(this.indexes, factory.invoke(indexes.linearSize) { transform(buffer[it]) }) else { val strides = DefaultStrides(shape) BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) @@ -64,11 +58,11 @@ public inline fun StructureND.mapToBuffer( * @param mutableBuffer The underlying buffer. */ public class MutableBufferND( - strides: Strides, + strides: ShapeIndex, public val mutableBuffer: MutableBuffer, ) : MutableStructureND, BufferND(strides, mutableBuffer) { override fun set(index: IntArray, value: T) { - mutableBuffer[strides.offset(index)] = value + mutableBuffer[indexes.offset(index)] = value } } @@ -80,7 +74,7 @@ public inline fun MutableStructureND.mapToMutableBuffer( crossinline transform: (T) -> R, ): MutableBufferND { return if (this is MutableBufferND) - MutableBufferND(this.strides, factory.invoke(strides.linearSize) { transform(mutableBuffer[it]) }) + MutableBufferND(this.indexes, factory.invoke(indexes.linearSize) { transform(mutableBuffer[it]) }) else { val strides = DefaultStrides(shape) MutableBufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) 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 0c7d4d5d1..294c44ec4 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 @@ -6,108 +6,68 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations -import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.operations.* import space.kscience.kmath.structures.DoubleBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract -@OptIn(UnstableKMathAPI::class) -public class DoubleFieldND( - shape: IntArray, -) : BufferedFieldND(shape, DoubleField, ::DoubleBuffer), - NumbersAddOperations>, - ScaleOperations>, - ExtendedField> { +public sealed class DoubleFieldOpsND : BufferedFieldOpsND(DoubleField.bufferAlgebra), + ScaleOperations>, ExtendedFieldOps> { - override val zero: BufferND by lazy { produce { zero } } - override val one: BufferND by lazy { produce { one } } + override fun StructureND.toBufferND(): BufferND = when (this) { + is BufferND -> this + else -> { + val indexer = indexerBuilder(shape) + BufferND(indexer, DoubleBuffer(indexer.linearSize) { offset -> get(indexer.index(offset)) }) + } + } + + //TODO do specialization + + override fun scale(a: StructureND, value: Double): BufferND = + mapInline(a.toBufferND()) { it * value } + + override fun power(arg: StructureND, pow: Number): BufferND = + mapInline(arg.toBufferND()) { power(it, pow) } + + override fun exp(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { exp(it) } + override fun ln(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { ln(it) } + + override fun sin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sin(it) } + override fun cos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cos(it) } + override fun tan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tan(it) } + override fun asin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asin(it) } + override fun acos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acos(it) } + override fun atan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atan(it) } + + override fun sinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sinh(it) } + override fun cosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cosh(it) } + override fun tanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tanh(it) } + override fun asinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asinh(it) } + override fun acosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acosh(it) } + override fun atanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atanh(it) } + + public companion object : DoubleFieldOpsND() +} + +@OptIn(UnstableKMathAPI::class) +public class DoubleFieldND(override val shape: Shape) : + DoubleFieldOpsND(), FieldND, NumbersAddOps> { override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions - return produce { d } + return produce(shape) { d } } - - override val StructureND.buffer: DoubleBuffer - get() = when { - !shape.contentEquals(this@DoubleFieldND.shape) -> throw ShapeMismatchException( - this@DoubleFieldND.shape, - shape - ) - this is BufferND && this.strides == this@DoubleFieldND.strides -> this.buffer as DoubleBuffer - else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } - } - - @Suppress("OVERRIDE_BY_INLINE") - override inline fun StructureND.map( - transform: DoubleField.(Double) -> Double, - ): BufferND { - val buffer = DoubleBuffer(strides.linearSize) { offset -> DoubleField.transform(buffer.array[offset]) } - return BufferND(strides, buffer) - } - - @Suppress("OVERRIDE_BY_INLINE") - override inline fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { - val array = DoubleArray(strides.linearSize) { offset -> - val index = strides.index(offset) - DoubleField.initializer(index) - } - return BufferND(strides, DoubleBuffer(array)) - } - - @Suppress("OVERRIDE_BY_INLINE") - override inline fun StructureND.mapIndexed( - transform: DoubleField.(index: IntArray, Double) -> Double, - ): BufferND = BufferND( - strides, - buffer = DoubleBuffer(strides.linearSize) { offset -> - DoubleField.transform( - strides.index(offset), - buffer.array[offset] - ) - }) - - @Suppress("OVERRIDE_BY_INLINE") - override inline fun combine( - a: StructureND, - b: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): BufferND { - val buffer = DoubleBuffer(strides.linearSize) { offset -> - DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset]) - } - return BufferND(strides, buffer) - } - - override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } - - override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } - - override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - - override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } - - override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } } +public val DoubleField.ndAlgebra: DoubleFieldOpsND get() = DoubleFieldOpsND + public fun DoubleField.ndAlgebra(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) /** * Produce a context for n-dimensional operations inside this real field */ +@UnstableKMathAPI public inline fun DoubleField.withNdAlgebra(vararg shape: Int, action: DoubleFieldND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return DoubleFieldND(shape).run(action) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt new file mode 100644 index 000000000..bdbae70c2 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt @@ -0,0 +1,120 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.nd + +import kotlin.native.concurrent.ThreadLocal + +/** + * A converter from linear index to multivariate index + */ +public interface ShapeIndex{ + public val shape: Shape + + /** + * Get linear index from multidimensional index + */ + public fun offset(index: IntArray): Int + + /** + * Get multidimensional from linear + */ + public fun index(offset: Int): IntArray + + /** + * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides + */ + public val linearSize: Int + + // TODO introduce a fast way to calculate index of the next element? + + /** + * Iterate over ND indices in a natural order + */ + public fun indices(): Sequence + + override fun equals(other: Any?): Boolean + override fun hashCode(): Int +} + +/** + * Linear transformation of indexes + */ +public abstract class Strides: ShapeIndex { + /** + * Array strides + */ + public abstract val strides: IntArray + + public override fun offset(index: IntArray): Int = index.mapIndexed { i, value -> + if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${this.shape[i]})") + value * strides[i] + }.sum() + + // TODO introduce a fast way to calculate index of the next element? + + /** + * Iterate over ND indices in a natural order + */ + public override fun indices(): Sequence = (0 until linearSize).asSequence().map(::index) +} + +/** + * Simple implementation of [Strides]. + */ +public class DefaultStrides private constructor(override val shape: IntArray) : Strides() { + override val linearSize: Int get() = strides[shape.size] + + /** + * Strides for memory access + */ + override val strides: IntArray by lazy { + sequence { + var current = 1 + yield(1) + + shape.forEach { + current *= it + yield(current) + } + }.toList().toIntArray() + } + + override fun index(offset: Int): IntArray { + val res = IntArray(shape.size) + var current = offset + var strideIndex = strides.size - 2 + + while (strideIndex >= 0) { + res[strideIndex] = (current / strides[strideIndex]) + current %= strides[strideIndex] + strideIndex-- + } + + return res + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is DefaultStrides) return false + if (!shape.contentEquals(other.shape)) return false + return true + } + + override fun hashCode(): Int = shape.contentHashCode() + + @ThreadLocal + public companion object { + //private val defaultStridesCache = HashMap() + + /** + * Cached builder for default strides + */ + public operator fun invoke(shape: IntArray): Strides = DefaultStrides(shape) + //defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } + + //TODO fix cache + } +} \ No newline at end of file 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 b56bef230..65c1f71b4 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 @@ -6,34 +6,27 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.ShortRing -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.ShortBuffer +import space.kscience.kmath.operations.bufferAlgebra import kotlin.contracts.InvocationKind import kotlin.contracts.contract +public sealed class ShortRingOpsND : BufferedRingOpsND(ShortRing.bufferAlgebra) { + public companion object : ShortRingOpsND() +} + @OptIn(UnstableKMathAPI::class) public class ShortRingND( - shape: IntArray, -) : BufferedRingND(shape, ShortRing, Buffer.Companion::auto), - NumbersAddOperations> { - - override val zero: BufferND by lazy { produce { zero } } - override val one: BufferND by lazy { produce { one } } + override val shape: Shape +) : ShortRingOpsND(), RingND, NumbersAddOps> { override fun number(value: Number): BufferND { val d = value.toShort() // minimize conversions - return produce { d } + return produce(shape) { d } } } -/** - * Fast element production using function inlining. - */ -public inline fun BufferedRingND.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND = - BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) - public inline fun ShortRing.withNdAlgebra(vararg shape: Int, action: ShortRingND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return ShortRingND(shape).run(action) 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 6123336ba..611d2724f 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 @@ -15,7 +15,6 @@ import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import kotlin.jvm.JvmName import kotlin.math.abs -import kotlin.native.concurrent.ThreadLocal import kotlin.reflect.KClass public interface StructureFeature : Feature @@ -72,7 +71,7 @@ public interface StructureND : Featured { if (st1 === st2) return true // fast comparison of buffers if possible - if (st1 is BufferND && st2 is BufferND && st1.strides == st2.strides) + if (st1 is BufferND && st2 is BufferND && st1.indexes == st2.indexes) return Buffer.contentEquals(st1.buffer, st2.buffer) //element by element comparison if it could not be avoided @@ -88,7 +87,7 @@ public interface StructureND : Featured { if (st1 === st2) return true // fast comparison of buffers if possible - if (st1 is BufferND && st2 is BufferND && st1.strides == st2.strides) + if (st1 is BufferND && st2 is BufferND && st1.indexes == st2.indexes) return Buffer.contentEquals(st1.buffer, st2.buffer) //element by element comparison if it could not be avoided @@ -187,11 +186,11 @@ public fun > LinearSpace>.contentEquals( * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. */ @PerformancePitfall -public fun > GroupND>.contentEquals( +public fun > GroupOpsND>.contentEquals( st1: StructureND, st2: StructureND, absoluteTolerance: T, -): Boolean = st1.elements().all { (index, value) -> elementContext { (value - st2[index]) } < absoluteTolerance } +): Boolean = st1.elements().all { (index, value) -> elementAlgebra { (value - st2[index]) } < absoluteTolerance } /** * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. @@ -231,107 +230,10 @@ public interface MutableStructureND : StructureND { * Transform a structure element-by element in place. */ @OptIn(PerformancePitfall::class) -public inline fun MutableStructureND.mapInPlace(action: (IntArray, T) -> T): Unit = +public inline fun MutableStructureND.mapInPlace(action: (index: IntArray, t: T) -> T): Unit = elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } -/** - * A way to convert ND indices to linear one and back. - */ -public interface Strides { - /** - * Shape of NDStructure - */ - public val shape: IntArray - - /** - * Array strides - */ - public val strides: IntArray - - /** - * Get linear index from multidimensional index - */ - public fun offset(index: IntArray): Int = index.mapIndexed { i, value -> - if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${this.shape[i]})") - value * strides[i] - }.sum() - - /** - * Get multidimensional from linear - */ - public fun index(offset: Int): IntArray - - /** - * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides - */ - public val linearSize: Int - - // TODO introduce a fast way to calculate index of the next element? - - /** - * Iterate over ND indices in a natural order - */ - public fun indices(): Sequence = (0 until linearSize).asSequence().map(::index) -} - -/** - * Simple implementation of [Strides]. - */ -public class DefaultStrides private constructor(override val shape: IntArray) : Strides { - override val linearSize: Int - get() = strides[shape.size] - - /** - * Strides for memory access - */ - override val strides: IntArray by lazy { - sequence { - var current = 1 - yield(1) - - shape.forEach { - current *= it - yield(current) - } - }.toList().toIntArray() - } - - override fun index(offset: Int): IntArray { - val res = IntArray(shape.size) - var current = offset - var strideIndex = strides.size - 2 - - while (strideIndex >= 0) { - res[strideIndex] = (current / strides[strideIndex]) - current %= strides[strideIndex] - strideIndex-- - } - - return res - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is DefaultStrides) return false - if (!shape.contentEquals(other.shape)) return false - return true - } - - override fun hashCode(): Int = shape.contentHashCode() - - @ThreadLocal - public companion object { - private val defaultStridesCache = HashMap() - - /** - * Cached builder for default strides - */ - public operator fun invoke(shape: IntArray): Strides = - defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } - } -} - -public inline fun StructureND.combine( +public inline fun StructureND.zip( struct: StructureND, crossinline block: (T, T) -> T, ): StructureND { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt new file mode 100644 index 000000000..7bc18a4dd --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.nd + +import space.kscience.kmath.operations.Algebra +import space.kscience.kmath.operations.Group +import space.kscience.kmath.operations.Ring +import kotlin.jvm.JvmName + + +public fun > AlgebraND.produce( + shapeFirst: Int, + vararg shapeRest: Int, + initializer: A.(IntArray) -> T +): StructureND = produce(Shape(shapeFirst, *shapeRest), initializer) + +public fun > AlgebraND.zero(shape: Shape): StructureND = produce(shape) { zero } + +@JvmName("zeroVarArg") +public fun > AlgebraND.zero( + shapeFirst: Int, + vararg shapeRest: Int, +): StructureND = produce(shapeFirst, *shapeRest) { zero } + +public fun > AlgebraND.one(shape: Shape): StructureND = produce(shape) { one } + +@JvmName("oneVarArg") +public fun > AlgebraND.one( + shapeFirst: Int, + vararg shapeRest: Int, +): StructureND = produce(shapeFirst, *shapeRest) { one } \ No newline at end of file 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 daff58d9a..d731ee4ee 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 @@ -117,7 +117,7 @@ public inline operator fun , R> A.invoke(block: A.() -> R): R = r * * @param T the type of element of this semispace. */ -public interface GroupOperations : Algebra { +public interface GroupOps : Algebra { /** * Addition of two elements. * @@ -162,7 +162,7 @@ public interface GroupOperations : Algebra { * @return the difference. */ public operator fun T.minus(b: T): T = add(this, -b) - + // Dynamic dispatch of operations override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> +arg } MINUS_OPERATION -> { arg -> -arg } @@ -193,7 +193,7 @@ public interface GroupOperations : Algebra { * * @param T the type of element of this semispace. */ -public interface Group : GroupOperations { +public interface Group : GroupOps { /** * The neutral element of addition. */ @@ -206,7 +206,7 @@ public interface Group : GroupOperations { * * @param T the type of element of this semiring. */ -public interface RingOperations : GroupOperations { +public interface RingOps : GroupOps { /** * Multiplies two elements. * @@ -242,7 +242,7 @@ public interface RingOperations : GroupOperations { * * @param T the type of element of this ring. */ -public interface Ring : Group, RingOperations { +public interface Ring : Group, RingOps { /** * The neutral element of multiplication */ @@ -256,7 +256,7 @@ public interface Ring : Group, RingOperations { * * @param T the type of element of this semifield. */ -public interface FieldOperations : RingOperations { +public interface FieldOps : RingOps { /** * Division of two elements. * @@ -295,6 +295,6 @@ public interface FieldOperations : RingOperations { * * @param T the type of element of this field. */ -public interface Field : Ring, FieldOperations, ScaleOperations, NumericAlgebra { +public interface Field : Ring, FieldOps, ScaleOperations, NumericAlgebra { override fun number(value: Number): T = scale(one, value.toDouble()) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt index 82754e43d..97e35e4b0 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 @@ -6,7 +6,7 @@ package space.kscience.kmath.operations import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.BufferedRingND +import space.kscience.kmath.nd.BufferedRingOpsND import space.kscience.kmath.operations.BigInt.Companion.BASE import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE import space.kscience.kmath.structures.Buffer @@ -26,7 +26,7 @@ private typealias TBase = ULong * @author Peter Klimai */ @OptIn(UnstableKMathAPI::class) -public object BigIntField : Field, NumbersAddOperations, ScaleOperations { +public object BigIntField : Field, NumbersAddOps, ScaleOperations { override val zero: BigInt = BigInt.ZERO override val one: BigInt = BigInt.ONE @@ -542,5 +542,5 @@ public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) - public inline fun BigInt.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer = Buffer.boxing(size, initializer) -public fun BigIntField.nd(vararg shape: Int): BufferedRingND = - BufferedRingND(shape, BigIntField, BigInt::buffer) +public val BigIntField.nd: BufferedRingOpsND + get() = BufferedRingOpsND(BufferRingOps(BigIntField, BigInt::buffer)) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt index e82b62c1b..5a14e7734 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -5,32 +5,34 @@ package space.kscience.kmath.operations -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.ShortBuffer + +public interface WithSize { + public val size: Int +} /** * An algebra over [Buffer] */ -@UnstableKMathAPI -public interface BufferAlgebra> : Algebra> { - public val bufferFactory: BufferFactory +public interface BufferAlgebra> : Algebra> { public val elementAlgebra: A - public val size: Int + public val bufferFactory: BufferFactory - public fun buffer(vararg elements: T): Buffer { + public fun buffer(size: Int, vararg elements: T): Buffer { require(elements.size == size) { "Expected $size elements but found ${elements.size}" } return bufferFactory(size) { elements[it] } } //TODO move to multi-receiver inline extension - public fun Buffer.map(block: (T) -> T): Buffer = bufferFactory(size) { block(get(it)) } + public fun Buffer.map(block: A.(T) -> T): Buffer = mapInline(this, block) - public fun Buffer.zip(other: Buffer, block: (left: T, right: T) -> T): Buffer { - require(size == other.size) { "Incompatible buffer sizes. left: $size, right: ${other.size}" } - return bufferFactory(size) { block(this[it], other[it]) } - } + public fun Buffer.mapIndexed(block: A.(index: Int, arg: T) -> T): Buffer = mapIndexedInline(this, block) + + public fun Buffer.zip(other: Buffer, block: A.(left: T, right: T) -> T): Buffer = + zipInline(this, other, block) override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { val operationFunction = elementAlgebra.unaryOperationFunction(operation) @@ -45,112 +47,149 @@ public interface BufferAlgebra> : Algebra> { } } -@UnstableKMathAPI -public fun BufferField.buffer(initializer: (Int) -> T): Buffer { +/** + * Inline map + */ +public inline fun > BufferAlgebra.mapInline( + buffer: Buffer, + crossinline block: A.(T) -> T +): Buffer = bufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) } + +/** + * Inline map + */ +public inline fun > BufferAlgebra.mapIndexedInline( + buffer: Buffer, + crossinline block: A.(index: Int, arg: T) -> T +): Buffer = bufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) } + +/** + * Inline zip + */ +public inline fun > BufferAlgebra.zipInline( + l: Buffer, + r: Buffer, + crossinline block: A.(l: T, r: T) -> T +): Buffer { + require(l.size == r.size) { "Incompatible buffer sizes. left: ${l.size}, right: ${r.size}" } + return bufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) } +} + +public fun BufferAlgebra.buffer(size: Int, initializer: (Int) -> T): Buffer { + return bufferFactory(size, initializer) +} + +public fun A.buffer(initializer: (Int) -> T): Buffer where A : BufferAlgebra, A : WithSize { return bufferFactory(size, initializer) } -@UnstableKMathAPI public fun > BufferAlgebra.sin(arg: Buffer): Buffer = - arg.map(elementAlgebra::sin) + mapInline(arg) { sin(it) } -@UnstableKMathAPI public fun > BufferAlgebra.cos(arg: Buffer): Buffer = - arg.map(elementAlgebra::cos) + mapInline(arg) { cos(it) } -@UnstableKMathAPI public fun > BufferAlgebra.tan(arg: Buffer): Buffer = - arg.map(elementAlgebra::tan) + mapInline(arg) { tan(it) } -@UnstableKMathAPI public fun > BufferAlgebra.asin(arg: Buffer): Buffer = - arg.map(elementAlgebra::asin) + mapInline(arg) { asin(it) } -@UnstableKMathAPI public fun > BufferAlgebra.acos(arg: Buffer): Buffer = - arg.map(elementAlgebra::acos) + mapInline(arg) { acos(it) } -@UnstableKMathAPI public fun > BufferAlgebra.atan(arg: Buffer): Buffer = - arg.map(elementAlgebra::atan) + mapInline(arg) { atan(it) } -@UnstableKMathAPI public fun > BufferAlgebra.exp(arg: Buffer): Buffer = - arg.map(elementAlgebra::exp) + mapInline(arg) { exp(it) } -@UnstableKMathAPI public fun > BufferAlgebra.ln(arg: Buffer): Buffer = - arg.map(elementAlgebra::ln) + mapInline(arg) { ln(it) } -@UnstableKMathAPI public fun > BufferAlgebra.sinh(arg: Buffer): Buffer = - arg.map(elementAlgebra::sinh) + mapInline(arg) { sinh(it) } -@UnstableKMathAPI public fun > BufferAlgebra.cosh(arg: Buffer): Buffer = - arg.map(elementAlgebra::cosh) + mapInline(arg) { cosh(it) } -@UnstableKMathAPI public fun > BufferAlgebra.tanh(arg: Buffer): Buffer = - arg.map(elementAlgebra::tanh) + mapInline(arg) { tanh(it) } -@UnstableKMathAPI public fun > BufferAlgebra.asinh(arg: Buffer): Buffer = - arg.map(elementAlgebra::asinh) + mapInline(arg) { asinh(it) } -@UnstableKMathAPI public fun > BufferAlgebra.acosh(arg: Buffer): Buffer = - arg.map(elementAlgebra::acosh) + mapInline(arg) { acosh(it) } -@UnstableKMathAPI public fun > BufferAlgebra.atanh(arg: Buffer): Buffer = - arg.map(elementAlgebra::atanh) + mapInline(arg) { atanh(it) } -@UnstableKMathAPI public fun > BufferAlgebra.pow(arg: Buffer, pow: Number): Buffer = - with(elementAlgebra) { arg.map { power(it, pow) } } + mapInline(arg) { power(it, pow) } -@UnstableKMathAPI -public class BufferField>( - override val bufferFactory: BufferFactory, +public open class BufferRingOps>( override val elementAlgebra: A, + override val bufferFactory: BufferFactory, +) : BufferAlgebra, RingOps>{ + + override fun add(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l + r } + override fun multiply(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l * r } + override fun Buffer.unaryMinus(): Buffer = map { -it } + + override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = + super.unaryOperationFunction(operation) + + override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = + super.binaryOperationFunction(operation) +} + +public val ShortRing.bufferAlgebra: BufferRingOps + get() = BufferRingOps(ShortRing, ::ShortBuffer) + +public open class BufferFieldOps>( + elementAlgebra: A, + bufferFactory: BufferFactory, +) : BufferRingOps(elementAlgebra, bufferFactory), BufferAlgebra, FieldOps>, ScaleOperations> { + + override fun add(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l + r } + override fun multiply(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l * r } + override fun divide(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l / r } + + override fun scale(a: Buffer, value: Double): Buffer = a.map { scale(it, value) } + override fun Buffer.unaryMinus(): Buffer = map { -it } + + override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = + super.binaryOperationFunction(operation) +} + +public class BufferField>( + elementAlgebra: A, + bufferFactory: BufferFactory, override val size: Int -) : BufferAlgebra, Field> { +) : BufferFieldOps(elementAlgebra, bufferFactory), Field>, WithSize { override val zero: Buffer = bufferFactory(size) { elementAlgebra.zero } override val one: Buffer = bufferFactory(size) { elementAlgebra.one } - - - override fun add(a: Buffer, b: Buffer): Buffer = a.zip(b, elementAlgebra::add) - override fun multiply(a: Buffer, b: Buffer): Buffer = a.zip(b, elementAlgebra::multiply) - override fun divide(a: Buffer, b: Buffer): Buffer = a.zip(b, elementAlgebra::divide) - - override fun scale(a: Buffer, value: Double): Buffer = with(elementAlgebra) { a.map { scale(it, value) } } - override fun Buffer.unaryMinus(): Buffer = with(elementAlgebra) { map { -it } } - - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { - return super.unaryOperationFunction(operation) - } - - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { - return super.binaryOperationFunction(operation) - } } +/** + * Generate full buffer field from given buffer operations + */ +public fun > BufferFieldOps.withSize(size: Int): BufferField = + BufferField(elementAlgebra, bufferFactory, size) + //Double buffer specialization -@UnstableKMathAPI public fun BufferField.buffer(vararg elements: Number): Buffer { require(elements.size == size) { "Expected $size elements but found ${elements.size}" } return bufferFactory(size) { elements[it].toDouble() } } -@UnstableKMathAPI -public fun > A.bufferAlgebra(bufferFactory: BufferFactory, size: Int): BufferField = - BufferField(bufferFactory, this, size) +public fun > A.bufferAlgebra(bufferFactory: BufferFactory): BufferFieldOps = + BufferFieldOps(this, bufferFactory) -@UnstableKMathAPI -public fun DoubleField.bufferAlgebra(size: Int): BufferField = - BufferField(::DoubleBuffer, DoubleField, size) +public val DoubleField.bufferAlgebra: BufferFieldOps + get() = BufferFieldOps(DoubleField, ::DoubleBuffer) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt index acc2c2dc0..060ea5a7e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt @@ -13,21 +13,21 @@ import space.kscience.kmath.structures.DoubleBuffer * * @property size the size of buffers to operate on. */ -public class DoubleBufferField(public val size: Int) : ExtendedField>, DoubleBufferOperations() { +public class DoubleBufferField(public val size: Int) : ExtendedField>, DoubleBufferOps() { override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } - override fun sinh(arg: Buffer): DoubleBuffer = super.sinh(arg) + override fun sinh(arg: Buffer): DoubleBuffer = super.sinh(arg) - override fun cosh(arg: Buffer): DoubleBuffer = super.cosh(arg) + override fun cosh(arg: Buffer): DoubleBuffer = super.cosh(arg) - override fun tanh(arg: Buffer): DoubleBuffer = super.tanh(arg) + override fun tanh(arg: Buffer): DoubleBuffer = super.tanh(arg) - override fun asinh(arg: Buffer): DoubleBuffer = super.asinh(arg) + override fun asinh(arg: Buffer): DoubleBuffer = super.asinh(arg) - override fun acosh(arg: Buffer): DoubleBuffer = super.acosh(arg) + override fun acosh(arg: Buffer): DoubleBuffer = super.acosh(arg) - override fun atanh(arg: Buffer): DoubleBuffer= super.atanh(arg) + override fun atanh(arg: Buffer): DoubleBuffer= super.atanh(arg) // override fun number(value: Number): Buffer = DoubleBuffer(size) { value.toDouble() } // diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt similarity index 97% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt index 50b821962..2580cd6f8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt @@ -12,9 +12,9 @@ import space.kscience.kmath.structures.DoubleBuffer import kotlin.math.* /** - * [ExtendedFieldOperations] over [DoubleBuffer]. + * [ExtendedFieldOps] over [DoubleBuffer]. */ -public abstract class DoubleBufferOperations : ExtendedFieldOperations>, Norm, Double> { +public abstract class DoubleBufferOps : ExtendedFieldOps>, Norm, Double> { override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { DoubleBuffer(size) { -array[it] } } else { @@ -185,7 +185,7 @@ public abstract class DoubleBufferOperations : ExtendedFieldOperations, Double> { 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 a3d8f5ffe..ca88ad42d 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 @@ -150,7 +150,7 @@ public interface ScaleOperations : Algebra { * TODO to be removed and replaced by extensions after multiple receivers are there */ @UnstableKMathAPI -public interface NumbersAddOperations : Ring, NumericAlgebra { +public interface NumbersAddOps : Ring, NumericAlgebra { /** * Addition of element and scalar. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 4c0010bf9..c1775296c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -10,8 +10,8 @@ import kotlin.math.pow as kpow /** * Advanced Number-like semifield that implements basic operations. */ -public interface ExtendedFieldOperations : - FieldOperations, +public interface ExtendedFieldOps : + FieldOps, TrigonometricOperations, PowerOperations, ExponentialOperations, @@ -35,14 +35,14 @@ public interface ExtendedFieldOperations : ExponentialOperations.ACOSH_OPERATION -> ::acosh ExponentialOperations.ASINH_OPERATION -> ::asinh ExponentialOperations.ATANH_OPERATION -> ::atanh - else -> super.unaryOperationFunction(operation) + else -> super.unaryOperationFunction(operation) } } /** * Advanced Number-like field that implements basic operations. */ -public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra{ +public interface ExtendedField : ExtendedFieldOps, Field, NumericAlgebra{ override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt index 05a67ab09..2009eb64f 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.structures import space.kscience.kmath.nd.get import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.nd.produce import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import space.kscience.kmath.testutils.FieldVerifier @@ -21,7 +22,7 @@ internal class NDFieldTest { @Test fun testStrides() { - val ndArray = DoubleField.ndAlgebra(10, 10).produce { (it[0] + it[1]).toDouble() } + val ndArray = DoubleField.ndAlgebra.produce(10, 10) { (it[0] + it[1]).toDouble() } assertEquals(ndArray[5, 5], 10.0) } } 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 e58976f4a..907301a53 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 @@ -7,10 +7,7 @@ package space.kscience.kmath.structures import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.combine -import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.algebra @@ -22,9 +19,9 @@ import kotlin.test.assertEquals @Suppress("UNUSED_VARIABLE") class NumberNDFieldTest { - val algebra = DoubleField.ndAlgebra(3, 3) - val array1 = algebra.produce { (i, j) -> (i + j).toDouble() } - val array2 = algebra.produce { (i, j) -> (i - j).toDouble() } + val algebra = DoubleField.ndAlgebra + val array1 = algebra.produce(3, 3) { (i, j) -> (i + j).toDouble() } + val array2 = algebra.produce(3, 3) { (i, j) -> (i - j).toDouble() } @Test fun testSum() { @@ -77,7 +74,7 @@ class NumberNDFieldTest { @Test fun combineTest() { - val division = array1.combine(array2, Double::div) + val division = array1.zip(array2, Double::div) } object L2Norm : Norm, Double> { diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt index 1821daac9..1620f029c 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt @@ -10,12 +10,12 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.runningReduce import kotlinx.coroutines.flow.scan -import space.kscience.kmath.operations.GroupOperations +import space.kscience.kmath.operations.GroupOps import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -public fun Flow.cumulativeSum(group: GroupOperations): Flow = +public fun Flow.cumulativeSum(group: GroupOps): Flow = group { runningReduce { sum, element -> sum + element } } @ExperimentalCoroutinesApi diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt index b2c3209c2..0edd51be2 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt @@ -13,8 +13,8 @@ import space.kscience.kmath.structures.DoubleBuffer * Map one [BufferND] using function without indices. */ public inline fun BufferND.mapInline(crossinline transform: DoubleField.(Double) -> Double): BufferND { - val array = DoubleArray(strides.linearSize) { offset -> DoubleField.transform(buffer[offset]) } - return BufferND(strides, DoubleBuffer(array)) + val array = DoubleArray(indexes.linearSize) { offset -> DoubleField.transform(buffer[offset]) } + return BufferND(indexes, DoubleBuffer(array)) } /** diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt index 5446f05f8..c452edc9c 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt @@ -28,10 +28,9 @@ public class DoubleHistogramSpace( public val dimension: Int get() = lower.size - private val shape = IntArray(binNums.size) { binNums[it] + 2 } + override val shape: IntArray = IntArray(binNums.size) { binNums[it] + 2 } override val histogramValueSpace: DoubleFieldND = DoubleField.ndAlgebra(*shape) - override val strides: Strides get() = histogramValueSpace.strides private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] } /** @@ -52,7 +51,7 @@ public class DoubleHistogramSpace( val lowerBoundary = index.mapIndexed { axis, i -> when (i) { 0 -> Double.NEGATIVE_INFINITY - strides.shape[axis] - 1 -> upper[axis] + shape[axis] - 1 -> upper[axis] else -> lower[axis] + (i.toDouble()) * binSize[axis] } }.asBuffer() @@ -60,7 +59,7 @@ public class DoubleHistogramSpace( val upperBoundary = index.mapIndexed { axis, i -> when (i) { 0 -> lower[axis] - strides.shape[axis] - 1 -> Double.POSITIVE_INFINITY + shape[axis] - 1 -> Double.POSITIVE_INFINITY else -> lower[axis] + (i.toDouble() + 1) * binSize[axis] } }.asBuffer() @@ -75,7 +74,7 @@ public class DoubleHistogramSpace( } override fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram { - val ndCounter = StructureND.auto(strides) { Counter.real() } + val ndCounter = StructureND.auto(shape) { Counter.real() } val hBuilder = HistogramBuilder { point, value -> val index = getIndex(point) ndCounter[index].add(value.toDouble()) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt index 44f3072d2..7c719ccd7 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt @@ -8,8 +8,9 @@ package space.kscience.kmath.histogram import space.kscience.kmath.domains.Domain import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.FieldND -import space.kscience.kmath.nd.Strides +import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Group import space.kscience.kmath.operations.ScaleOperations @@ -34,10 +35,10 @@ public class IndexedHistogram, V : Any>( return context.produceBin(index, values[index]) } - override val dimension: Int get() = context.strides.shape.size + override val dimension: Int get() = context.shape.size override val bins: Iterable> - get() = context.strides.indices().map { + get() = DefaultStrides(context.shape).indices().map { context.produceBin(it, values[it]) }.asIterable() @@ -49,7 +50,7 @@ public class IndexedHistogram, V : Any>( public interface IndexedHistogramSpace, V : Any> : Group>, ScaleOperations> { //public val valueSpace: Space - public val strides: Strides + public val shape: Shape public val histogramValueSpace: FieldND //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape), /** 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 c797eb65a..23dd076e1 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 @@ -5,6 +5,7 @@ package space.kscience.kmath.histogram +import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.operations.invoke import space.kscience.kmath.real.DoubleVector import kotlin.random.Random @@ -69,7 +70,7 @@ internal class MultivariateHistogramTest { } val res = histogram1 - histogram2 assertTrue { - strides.indices().all { index -> + DefaultStrides(shape).indices().all { index -> res.values[index] <= histogram1.values[index] } } diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt index 857824275..11e5853a8 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt @@ -106,8 +106,8 @@ public fun > MST.toSFun(): SFun = when (this) { is Symbol -> toSVar() is MST.Unary -> when (operation) { - GroupOperations.PLUS_OPERATION -> +value.toSFun() - GroupOperations.MINUS_OPERATION -> -value.toSFun() + GroupOps.PLUS_OPERATION -> +value.toSFun() + GroupOps.MINUS_OPERATION -> -value.toSFun() TrigonometricOperations.SIN_OPERATION -> sin(value.toSFun()) TrigonometricOperations.COS_OPERATION -> cos(value.toSFun()) TrigonometricOperations.TAN_OPERATION -> tan(value.toSFun()) @@ -124,10 +124,10 @@ public fun > MST.toSFun(): SFun = when (this) { } is MST.Binary -> when (operation) { - GroupOperations.PLUS_OPERATION -> left.toSFun() + right.toSFun() - GroupOperations.MINUS_OPERATION -> left.toSFun() - right.toSFun() - RingOperations.TIMES_OPERATION -> left.toSFun() * right.toSFun() - FieldOperations.DIV_OPERATION -> left.toSFun() / right.toSFun() + GroupOps.PLUS_OPERATION -> left.toSFun() + right.toSFun() + GroupOps.MINUS_OPERATION -> left.toSFun() - right.toSFun() + RingOps.TIMES_OPERATION -> left.toSFun() * right.toSFun() + FieldOps.DIV_OPERATION -> left.toSFun() / right.toSFun() PowerOperations.POW_OPERATION -> left.toSFun() pow (right as MST.Numeric).toSConst() else -> error("Binary operation $operation not defined in $this") } 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 b604bf5f2..d65ad0dc9 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt @@ -15,13 +15,6 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.* -internal fun AlgebraND<*, *>.checkShape(array: INDArray): INDArray { - val arrayShape = array.shape().toIntArray() - if (!shape.contentEquals(arrayShape)) throw ShapeMismatchException(shape, arrayShape) - return array -} - - /** * Represents [AlgebraND] over [Nd4jArrayAlgebra]. * @@ -39,33 +32,34 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND.ndArray: INDArray - override fun produce(initializer: C.(IntArray) -> T): Nd4jArrayStructure { + override fun produce(shape: Shape, initializer: C.(IntArray) -> T): Nd4jArrayStructure { val struct = Nd4j.create(*shape)!!.wrap() - struct.indicesIterator().forEach { struct[it] = elementContext.initializer(it) } + struct.indicesIterator().forEach { struct[it] = elementAlgebra.initializer(it) } return struct } override fun StructureND.map(transform: C.(T) -> T): Nd4jArrayStructure { val newStruct = ndArray.dup().wrap() - newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) } + newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementAlgebra.transform(value) } return newStruct } override fun StructureND.mapIndexed( transform: C.(index: IntArray, T) -> T, ): Nd4jArrayStructure { - val new = Nd4j.create(*this@Nd4jArrayAlgebra.shape).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(idx, this[idx]) } + val new = Nd4j.create(*shape).wrap() + new.indicesIterator().forEach { idx -> new[idx] = elementAlgebra.transform(idx, this[idx]) } return new } - override fun combine( - a: StructureND, - b: StructureND, + override fun zip( + left: StructureND, + right: StructureND, transform: C.(T, T) -> T, ): Nd4jArrayStructure { - val new = Nd4j.create(*shape).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(a[idx], b[idx]) } + require(left.shape.contentEquals(right.shape)) { "Can't zip tow structures of shape ${left.shape} and ${right.shape}" } + val new = Nd4j.create(*left.shape).wrap() + new.indicesIterator().forEach { idx -> new[idx] = elementAlgebra.transform(left[idx], right[idx]) } return new } } @@ -76,10 +70,7 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND> : GroupND, Nd4jArrayAlgebra { - - override val zero: Nd4jArrayStructure - get() = Nd4j.zeros(*shape).wrap() +public sealed interface Nd4jArrayGroupOps> : GroupOpsND, Nd4jArrayAlgebra { override fun add(a: StructureND, b: StructureND): Nd4jArrayStructure = a.ndArray.add(b.ndArray).wrap() @@ -101,10 +92,7 @@ public sealed interface Nd4jArrayGroup> : GroupND, Nd4j * @param R the type of ring of structure elements. */ @OptIn(UnstableKMathAPI::class) -public sealed interface Nd4jArrayRing> : RingND, Nd4jArrayGroup { - - override val one: Nd4jArrayStructure - get() = Nd4j.ones(*shape).wrap() +public sealed interface Nd4jArrayRingOps> : RingOpsND, Nd4jArrayGroupOps { override fun multiply(a: StructureND, b: StructureND): Nd4jArrayStructure = a.ndArray.mul(b.ndArray).wrap() @@ -125,21 +113,12 @@ public sealed interface Nd4jArrayRing> : RingND, Nd4jAr // } public companion object { - private val intNd4jArrayRingCache: ThreadLocal> = - ThreadLocal.withInitial(::HashMap) - - /** - * Creates an [RingND] for [Int] values or pull it from cache if it was created previously. - */ - public fun int(vararg shape: Int): Nd4jArrayRing = - intNd4jArrayRingCache.get().getOrPut(shape) { IntNd4jArrayRing(shape) } - /** * Creates a most suitable implementation of [RingND] using reified class. */ @Suppress("UNCHECKED_CAST") - public inline fun auto(vararg shape: Int): Nd4jArrayRing> = when { - T::class == Int::class -> int(*shape) as Nd4jArrayRing> + public inline fun auto(vararg shape: Int): Nd4jArrayRingOps> = when { + T::class == Int::class -> IntRing.nd4j as Nd4jArrayRingOps> else -> throw UnsupportedOperationException("This factory method only supports Long type.") } } @@ -151,38 +130,21 @@ public sealed interface Nd4jArrayRing> : RingND, Nd4jAr * @param T the type of the element contained in ND structure. * @param F the type field of structure elements. */ -public sealed interface Nd4jArrayField> : FieldND, Nd4jArrayRing { +public sealed interface Nd4jArrayField> : FieldOpsND, Nd4jArrayRingOps { + override fun divide(a: StructureND, b: StructureND): Nd4jArrayStructure = a.ndArray.div(b.ndArray).wrap() public operator fun Number.div(b: StructureND): Nd4jArrayStructure = b.ndArray.rdiv(this).wrap() public companion object { - private val floatNd4jArrayFieldCache: ThreadLocal> = - ThreadLocal.withInitial(::HashMap) - - private val doubleNd4JArrayFieldCache: ThreadLocal> = - ThreadLocal.withInitial(::HashMap) - - /** - * Creates an [FieldND] for [Float] values or pull it from cache if it was created previously. - */ - public fun float(vararg shape: Int): Nd4jArrayRing = - floatNd4jArrayFieldCache.get().getOrPut(shape) { FloatNd4jArrayField(shape) } - - /** - * Creates an [FieldND] for [Double] values or pull it from cache if it was created previously. - */ - public fun real(vararg shape: Int): Nd4jArrayRing = - doubleNd4JArrayFieldCache.get().getOrPut(shape) { DoubleNd4jArrayField(shape) } - /** * Creates a most suitable implementation of [FieldND] using reified class. */ @Suppress("UNCHECKED_CAST") public inline fun auto(vararg shape: Int): Nd4jArrayField> = when { - T::class == Float::class -> float(*shape) as Nd4jArrayField> - T::class == Double::class -> real(*shape) as Nd4jArrayField> + T::class == Float::class -> FloatField.nd4j as Nd4jArrayField> + T::class == Double::class -> DoubleField.nd4j as Nd4jArrayField> else -> throw UnsupportedOperationException("This factory method only supports Float and Double types.") } } @@ -191,8 +153,9 @@ public sealed interface Nd4jArrayField> : FieldND, Nd4 /** * Represents intersection of [ExtendedField] and [Field] over [Nd4jArrayStructure]. */ -public sealed interface Nd4jArrayExtendedField> : ExtendedField>, - Nd4jArrayField { +public sealed interface Nd4jArrayExtendedFieldOps> : + ExtendedFieldOps>, Nd4jArrayField { + override fun sin(arg: StructureND): StructureND = Transforms.sin(arg.ndArray).wrap() override fun cos(arg: StructureND): StructureND = Transforms.cos(arg.ndArray).wrap() override fun asin(arg: StructureND): StructureND = Transforms.asin(arg.ndArray).wrap() @@ -221,63 +184,59 @@ public sealed interface Nd4jArrayExtendedField> : Ex /** * Represents [FieldND] over [Nd4jArrayDoubleStructure]. */ -public class DoubleNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { - override val elementContext: DoubleField get() = DoubleField +public open class DoubleNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps { + override val elementAlgebra: DoubleField get() = DoubleField - override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asDoubleStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray get() = when (this) { - is Nd4jArrayStructure -> checkShape(ndArray) + is Nd4jArrayStructure -> ndArray else -> Nd4j.zeros(*shape).also { elements().forEach { (idx, value) -> it.putScalar(idx, value) } } } - override fun scale(a: StructureND, value: Double): Nd4jArrayStructure { - return a.ndArray.mul(value).wrap() - } + override fun scale(a: StructureND, value: Double): Nd4jArrayStructure = a.ndArray.mul(value).wrap() - override operator fun StructureND.div(arg: Double): Nd4jArrayStructure { - return ndArray.div(arg).wrap() - } + override operator fun StructureND.div(arg: Double): Nd4jArrayStructure = ndArray.div(arg).wrap() - override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure { - return ndArray.add(arg).wrap() - } + override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure = ndArray.add(arg).wrap() - override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure { - return ndArray.sub(arg).wrap() - } + override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure = ndArray.sub(arg).wrap() - override operator fun StructureND.times(arg: Double): Nd4jArrayStructure { - return ndArray.mul(arg).wrap() - } + override operator fun StructureND.times(arg: Double): Nd4jArrayStructure = ndArray.mul(arg).wrap() - override operator fun Double.div(arg: StructureND): Nd4jArrayStructure { - return arg.ndArray.rdiv(this).wrap() - } + override operator fun Double.div(arg: StructureND): Nd4jArrayStructure = + arg.ndArray.rdiv(this).wrap() - override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure { - return arg.ndArray.rsub(this).wrap() - } + override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure = + arg.ndArray.rsub(this).wrap() + + public companion object : DoubleNd4jArrayFieldOps() } -public fun DoubleField.nd4j(vararg shape: Int): DoubleNd4jArrayField = DoubleNd4jArrayField(intArrayOf(*shape)) +public val DoubleField.nd4j: DoubleNd4jArrayFieldOps get() = DoubleNd4jArrayFieldOps + +public class DoubleNd4jArrayField(override val shape: Shape) : DoubleNd4jArrayFieldOps(), FieldND + +public fun DoubleField.nd4j(shapeFirst: Int, vararg shapeRest: Int): DoubleNd4jArrayField = + DoubleNd4jArrayField(intArrayOf(shapeFirst, * shapeRest)) + /** * Represents [FieldND] over [Nd4jArrayStructure] of [Float]. */ -public class FloatNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { - override val elementContext: FloatField get() = FloatField +public open class FloatNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps { + override val elementAlgebra: FloatField get() = FloatField - override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asFloatStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = asFloatStructure() @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray get() = when (this) { - is Nd4jArrayStructure -> checkShape(ndArray) + is Nd4jArrayStructure -> ndArray else -> Nd4j.zeros(*shape).also { elements().forEach { (idx, value) -> it.putScalar(idx, value) } } @@ -303,21 +262,29 @@ public class FloatNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtend override operator fun Float.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() + + public companion object : FloatNd4jArrayFieldOps() } +public class FloatNd4jArrayField(override val shape: Shape) : FloatNd4jArrayFieldOps(), RingND + +public val FloatField.nd4j: FloatNd4jArrayFieldOps get() = FloatNd4jArrayFieldOps + +public fun FloatField.nd4j(shapeFirst: Int, vararg shapeRest: Int): FloatNd4jArrayField = + FloatNd4jArrayField(intArrayOf(shapeFirst, * shapeRest)) + /** * Represents [RingND] over [Nd4jArrayIntStructure]. */ -public class IntNd4jArrayRing(override val shape: IntArray) : Nd4jArrayRing { - override val elementContext: IntRing - get() = IntRing +public open class IntNd4jArrayRingOps : Nd4jArrayRingOps { + override val elementAlgebra: IntRing get() = IntRing - override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asIntStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = asIntStructure() @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray get() = when (this) { - is Nd4jArrayStructure -> checkShape(ndArray) + is Nd4jArrayStructure -> ndArray else -> Nd4j.zeros(*shape).also { elements().forEach { (idx, value) -> it.putScalar(idx, value) } } @@ -334,4 +301,13 @@ public class IntNd4jArrayRing(override val shape: IntArray) : Nd4jArrayRing): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() + + public companion object : IntNd4jArrayRingOps() } + +public val IntRing.nd4j: IntNd4jArrayRingOps get() = IntNd4jArrayRingOps + +public class IntNd4jArrayRing(override val shape: Shape) : IntNd4jArrayRingOps(), RingND + +public fun IntRing.nd4j(shapeFirst: Int, vararg shapeRest: Int): IntNd4jArrayRing = + IntNd4jArrayRing(intArrayOf(shapeFirst, * shapeRest)) \ No newline at end of file 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 a03a7269e..465937fa9 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 @@ -8,6 +8,10 @@ package space.kscience.kmath.nd4j import org.nd4j.linalg.factory.Nd4j import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.one +import space.kscience.kmath.nd.produce +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.IntRing import space.kscience.kmath.operations.invoke import kotlin.math.PI import kotlin.test.Test @@ -19,7 +23,7 @@ import kotlin.test.fail internal class Nd4jArrayAlgebraTest { @Test fun testProduce() { - val res = with(DoubleNd4jArrayField(intArrayOf(2, 2))) { produce { it.sum().toDouble() } } + val res = DoubleField.nd4j.produce(2, 2) { it.sum().toDouble() } val expected = (Nd4j.create(2, 2) ?: fail()).asDoubleStructure() expected[intArrayOf(0, 0)] = 0.0 expected[intArrayOf(0, 1)] = 1.0 @@ -30,7 +34,9 @@ internal class Nd4jArrayAlgebraTest { @Test fun testMap() { - val res = with(IntNd4jArrayRing(intArrayOf(2, 2))) { one.map { it + it * 2 } } + val res = IntRing.nd4j { + one(2, 2).map { it + it * 2 } + } val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() expected[intArrayOf(0, 0)] = 3 expected[intArrayOf(0, 1)] = 3 @@ -41,7 +47,7 @@ internal class Nd4jArrayAlgebraTest { @Test fun testAdd() { - val res = with(IntNd4jArrayRing(intArrayOf(2, 2))) { one + 25 } + val res = IntRing.nd4j { one(2, 2) + 25 } val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() expected[intArrayOf(0, 0)] = 26 expected[intArrayOf(0, 1)] = 26 @@ -51,10 +57,10 @@ internal class Nd4jArrayAlgebraTest { } @Test - fun testSin() = DoubleNd4jArrayField(intArrayOf(2, 2)).invoke { - val initial = produce { (i, j) -> if (i == j) PI / 2 else 0.0 } + fun testSin() = DoubleField.nd4j{ + val initial = produce(2, 2) { (i, j) -> if (i == j) PI / 2 else 0.0 } val transformed = sin(initial) - val expected = produce { (i, j) -> if (i == j) 1.0 else 0.0 } + val expected = produce(2, 2) { (i, j) -> if (i == j) 1.0 else 0.0 } println(transformed) assertTrue { StructureND.contentEquals(transformed, expected) } diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt index 8def1ae83..a7ca298a9 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt @@ -64,8 +64,8 @@ public fun MST.toIExpr(): IExpr = when (this) { } is MST.Unary -> when (operation) { - GroupOperations.PLUS_OPERATION -> value.toIExpr() - GroupOperations.MINUS_OPERATION -> F.Negate(value.toIExpr()) + GroupOps.PLUS_OPERATION -> value.toIExpr() + GroupOps.MINUS_OPERATION -> F.Negate(value.toIExpr()) TrigonometricOperations.SIN_OPERATION -> F.Sin(value.toIExpr()) TrigonometricOperations.COS_OPERATION -> F.Cos(value.toIExpr()) TrigonometricOperations.TAN_OPERATION -> F.Tan(value.toIExpr()) @@ -85,10 +85,10 @@ public fun MST.toIExpr(): IExpr = when (this) { } is MST.Binary -> when (operation) { - GroupOperations.PLUS_OPERATION -> left.toIExpr() + right.toIExpr() - GroupOperations.MINUS_OPERATION -> left.toIExpr() - right.toIExpr() - RingOperations.TIMES_OPERATION -> left.toIExpr() * right.toIExpr() - FieldOperations.DIV_OPERATION -> F.Divide(left.toIExpr(), right.toIExpr()) + GroupOps.PLUS_OPERATION -> left.toIExpr() + right.toIExpr() + GroupOps.MINUS_OPERATION -> left.toIExpr() - right.toIExpr() + RingOps.TIMES_OPERATION -> left.toIExpr() * right.toIExpr() + FieldOps.DIV_OPERATION -> F.Divide(left.toIExpr(), right.toIExpr()) PowerOperations.POW_OPERATION -> F.Power(left.toIExpr(), F.symjify((right as MST.Numeric).value)) else -> error("Binary operation $operation not defined in $this") } diff --git a/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 8e39e6cdd..594070cd2 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 @@ -373,8 +373,12 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): - DoubleTensor { + override fun diagonalEmbedding( + diagonalEntries: Tensor, + offset: Int, + dim1: Int, + dim2: Int + ): DoubleTensor { val n = diagonalEntries.shape.size val d1 = minusIndexFrom(n + 1, dim1) val d2 = minusIndexFrom(n + 1, dim2) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt index 817ed60d8..57668722a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt @@ -44,7 +44,7 @@ internal fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArra * * @param shape the shape of the tensor. */ -internal class TensorLinearStructure(override val shape: IntArray) : Strides { +internal class TensorLinearStructure(override val shape: IntArray) : Strides() { override val strides: IntArray get() = stridesFromShape(shape) @@ -54,4 +54,18 @@ internal class TensorLinearStructure(override val shape: IntArray) : Strides { override val linearSize: Int get() = shape.reduce(Int::times) + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as TensorLinearStructure + + if (!shape.contentEquals(other.shape)) return false + + return true + } + + override fun hashCode(): Int { + return shape.contentHashCode() + } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index 29aa02931..e0451c2eb 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -26,8 +26,11 @@ internal fun Tensor.copyToBufferedTensor(): BufferedTensor = internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { is BufferedTensor -> this - is MutableBufferND -> if (this.strides.strides contentEquals TensorLinearStructure(this.shape).strides) - BufferedTensor(this.shape, this.mutableBuffer, 0) else this.copyToBufferedTensor() + is MutableBufferND -> if (this.indexes == TensorLinearStructure(this.shape)) { + BufferedTensor(this.shape, this.mutableBuffer, 0) + } else { + this.copyToBufferedTensor() + } else -> this.copyToBufferedTensor() } 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 682123ddd..fca23bc16 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 @@ -11,7 +11,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.ScaleOperations @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @@ -34,7 +34,7 @@ public fun F64Array.asStructure(): ViktorStructureND = ViktorStructureND(this) @OptIn(UnstableKMathAPI::class) @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public class ViktorFieldND(override val shape: IntArray) : FieldND, - NumbersAddOperations>, ExtendedField>, + NumbersAddOps>, ExtendedField>, ScaleOperations> { public val StructureND.f64Buffer: F64Array @@ -44,7 +44,7 @@ public class ViktorFieldND(override val shape: IntArray) : FieldND this.f64Buffer - else -> produce { this@f64Buffer[it] }.f64Buffer + else -> produce(shape) { this@f64Buffer[it] }.f64Buffer } override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } @@ -52,9 +52,9 @@ public class ViktorFieldND(override val shape: IntArray) : FieldND Double): ViktorStructureND = + override fun produce(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = F64Array(*shape).apply { this@ViktorFieldND.strides.indices().forEach { index -> set(value = DoubleField.initializer(index), indices = index) @@ -78,13 +78,13 @@ public class ViktorFieldND(override val shape: IntArray) : FieldND, - b: StructureND, + override fun zip( + left: StructureND, + right: StructureND, transform: DoubleField.(Double, Double) -> Double, ): ViktorStructureND = F64Array(*shape).apply { this@ViktorFieldND.strides.indices().forEach { index -> - set(value = DoubleField.transform(a[index], b[index]), indices = index) + set(value = DoubleField.transform(left[index], right[index]), indices = index) } }.asStructure() @@ -123,4 +123,4 @@ public class ViktorFieldND(override val shape: IntArray) : FieldND): ViktorStructureND = arg.f64Buffer.log().asStructure() } -public fun ViktorNDField(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) +public fun ViktorFieldND(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) diff --git a/settings.gradle.kts b/settings.gradle.kts index 528adb336..dc70cbb9e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,16 +1,18 @@ pluginManagement { repositories { - mavenLocal() maven("https://repo.kotlin.link") mavenCentral() gradlePluginPortal() } - val kotlinVersion = "1.6.0-M1" + val kotlinVersion = "1.6.0-RC" + val toolsVersion = "0.10.5" plugins { id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - id("ru.mipt.npm.gradle.project") version "0.10.5" + id("ru.mipt.npm.gradle.project") version toolsVersion + id("ru.mipt.npm.gradle.jvm") version toolsVersion + id("ru.mipt.npm.gradle.mpp") version toolsVersion kotlin("multiplatform") version kotlinVersion kotlin("plugin.allopen") version kotlinVersion } -- 2.34.1 From 688382eed6e514cf61d00047b75a8669c7599ce8 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 17 Oct 2021 12:42:35 +0300 Subject: [PATCH 034/102] Shapeless ND and Buffer algebras --- .../kmath/benchmarks/NDFieldBenchmark.kt | 12 +- .../kmath/functions/matrixIntegration.kt | 3 +- .../kscience/kmath/structures/ComplexND.kt | 1 + .../kscience/kmath/structures/NDField.kt | 26 ++-- .../kmath/structures/StreamDoubleFieldND.kt | 14 +- .../DerivativeStructureExpression.kt | 6 +- .../space/kscience/kmath/complex/Complex.kt | 24 ++-- .../kscience/kmath/complex/Quaternion.kt | 26 ++-- .../FunctionalExpressionAlgebra.kt | 12 +- .../kscience/kmath/expressions/MstAlgebra.kt | 32 ++--- .../kmath/expressions/SimpleAutoDiff.kt | 24 ++-- .../space/kscience/kmath/nd/AlgebraND.kt | 26 ++-- .../kscience/kmath/nd/BufferAlgebraND.kt | 6 +- .../space/kscience/kmath/nd/BufferND.kt | 12 +- .../space/kscience/kmath/nd/DoubleFieldND.kt | 134 +++++++++++++++--- .../kscience/kmath/operations/Algebra.kt | 34 ++--- .../space/kscience/kmath/operations/BigInt.kt | 6 +- .../kmath/operations/BufferAlgebra.kt | 10 +- .../kmath/operations/DoubleBufferOps.kt | 63 ++++---- .../kscience/kmath/operations/numbers.kt | 68 ++++----- .../kscience/kmath/operations/BigNumbers.kt | 14 +- .../kscience/kmath/functions/Polynomial.kt | 6 +- .../kmath/geometry/Euclidean2DSpace.kt | 2 +- .../kmath/geometry/Euclidean3DSpace.kt | 4 +- .../kmath/histogram/IndexedHistogramSpace.kt | 8 +- .../kmath/histogram/TreeHistogramSpace.kt | 12 +- .../kscience/kmath/jafama/KMathJafama.kt | 28 ++-- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 16 +-- .../kscience/kmath/stat/SamplerAlgebra.kt | 4 +- .../kmath/tensors/api/TensorAlgebra.kt | 16 ++- .../tensors/core/internal/tensorCastsUtils.kt | 2 +- .../kmath/viktor/ViktorStructureND.kt | 12 +- 32 files changed, 382 insertions(+), 281 deletions(-) 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 950a10b33..7f7c03412 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -57,12 +57,12 @@ internal class NDFieldBenchmark { blackhole.consume(res) } - @Benchmark - fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) { - var res: StructureND = one(dim, dim) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } +// @Benchmark +// fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) { +// var res: StructureND = one(dim, dim) +// repeat(n) { res += 1.0 } +// blackhole.consume(res) +// } private companion object { private const val dim = 1000 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 93b5671fe..609afb47e 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -9,6 +9,7 @@ import space.kscience.kmath.integration.gaussIntegrator import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.produce import space.kscience.kmath.nd.withNdAlgebra import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.invoke @@ -17,7 +18,7 @@ fun main(): Unit = Double.algebra { withNdAlgebra(2, 2) { //Produce a diagonal StructureND - fun diagonal(v: Double) = produce { (i, j) -> + fun diagonal(v: Double) = produce { (i, j) -> if (i == j) v else 0.0 } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt index d4554b3ba..42636fafb 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.linear.transpose import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.nd.produce import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import kotlin.system.measureTimeMillis diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt index 7359f3bf6..cf0721ce7 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -8,10 +8,8 @@ package space.kscience.kmath.structures import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import org.nd4j.linalg.factory.Nd4j -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.autoNdAlgebra -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd4j.Nd4jArrayField +import space.kscience.kmath.nd.* +import space.kscience.kmath.nd4j.nd4j import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import space.kscience.kmath.viktor.ViktorFieldND @@ -31,15 +29,17 @@ fun main() { Nd4j.zeros(0) val dim = 1000 val n = 1000 + val shape = Shape(dim, dim) + // automatically build context most suited for given type. - val autoField = DoubleField.autoNdAlgebra(dim, dim) + val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) // specialized nd-field for Double. It works as generic Double field as well. - val realField = DoubleField.ndAlgebra(dim, dim) + val realField = DoubleField.ndAlgebra //A generic boxing field. It should be used for objects, not primitives. - val boxingField = DoubleField.ndAlgebra(Buffer.Companion::boxing, dim, dim) + val boxingField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) // Nd4j specialized field. - val nd4jField = Nd4jArrayField.real(dim, dim) + val nd4jField = DoubleField.nd4j //viktor field val viktorField = ViktorFieldND(dim, dim) //parallel processing based on Java Streams @@ -47,21 +47,21 @@ fun main() { measureAndPrint("Boxing addition") { boxingField { - var res: StructureND = one + var res: StructureND = one(shape) repeat(n) { res += 1.0 } } } measureAndPrint("Specialized addition") { realField { - var res: StructureND = one + var res: StructureND = one(shape) repeat(n) { res += 1.0 } } } measureAndPrint("Nd4j specialized addition") { nd4jField { - var res: StructureND = one + var res: StructureND = one(shape) repeat(n) { res += 1.0 } } } @@ -82,13 +82,13 @@ fun main() { measureAndPrint("Automatic field addition") { autoField { - var res: StructureND = one + var res: StructureND = one(shape) repeat(n) { res += 1.0 } } } measureAndPrint("Lazy addition") { - val res = realField.one.mapAsync(GlobalScope) { + val res = realField.one(shape).mapAsync(GlobalScope) { var c = 0.0 repeat(n) { c += 1.0 diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt index f1f5f2e84..dfd06973e 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -22,12 +22,12 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND by lazy { produce { zero } } - override val one: BufferND by lazy { produce { one } } + override val zero: BufferND by lazy { produce(shape) { zero } } + override val one: BufferND by lazy { produce(shape) { one } } override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions - return produce { d } + return produce(shape) { d } } private val StructureND.buffer: DoubleBuffer @@ -40,7 +40,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } } - override fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { + override fun produce(shape: Shape, initializer: DoubleField.(IntArray) -> Double): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> val index = strides.index(offset) DoubleField.initializer(index) @@ -70,12 +70,12 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND, - b: StructureND, + left: StructureND, + right: StructureND, transform: DoubleField.(Double, Double) -> Double, ): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> - DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset]) + DoubleField.transform(left.buffer.array[offset], right.buffer.array[offset]) }.toArray() return BufferND(strides, array.asBuffer()) } diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index a178e8dd7..d42e40d1e 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -70,12 +70,12 @@ public class DerivativeStructureField( override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() - override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) + override fun add(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.add(right) override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value) - override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b) - override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b) + override fun multiply(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.multiply(right) + override fun divide(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.divide(right) override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin() override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos() override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.tan() 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 e61a7bccc..879cfe94e 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 @@ -77,33 +77,33 @@ public object ComplexField : override fun scale(a: Complex, value: Double): Complex = Complex(a.re * value, a.im * value) - override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im) + 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 multiply(a: Complex, b: Complex): Complex = - Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re) + 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) - override fun divide(a: Complex, b: Complex): Complex = when { - abs(b.im) < abs(b.re) -> { - val wr = b.im / b.re - val wd = b.re + wr * b.im + override fun divide(left: Complex, right: Complex): Complex = when { + abs(right.im) < abs(right.re) -> { + val wr = right.im / right.re + val wd = right.re + wr * right.im if (wd.isNaN() || wd == 0.0) throw ArithmeticException("Division by zero or infinity") else - Complex((a.re + a.im * wr) / wd, (a.im - a.re * wr) / wd) + Complex((left.re + left.im * wr) / wd, (left.im - left.re * wr) / wd) } - b.im == 0.0 -> throw ArithmeticException("Division by zero") + right.im == 0.0 -> throw ArithmeticException("Division by zero") else -> { - val wr = b.re / b.im - val wd = b.im + wr * b.re + val wr = right.re / right.im + val wd = right.im + wr * right.re if (wd.isNaN() || wd == 0.0) throw ArithmeticException("Division by zero or infinity") else - Complex((a.re * wr + a.im) / wd, (a.im * wr - a.re) / wd) + Complex((left.re * wr + left.im) / wd, (left.im * wr - left.re) / wd) } } 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 b0ec10c35..9fdd60e1f 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -63,27 +63,27 @@ public object QuaternionField : Field, Norm, */ public val k: Quaternion = Quaternion(0, 0, 0, 1) - override fun add(a: Quaternion, b: Quaternion): Quaternion = - Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z) + override fun add(left: Quaternion, right: Quaternion): Quaternion = + Quaternion(left.w + right.w, left.x + right.x, left.y + right.y, left.z + right.z) override fun scale(a: Quaternion, value: Double): Quaternion = Quaternion(a.w * value, a.x * value, a.y * value, a.z * value) - override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion( - a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, - a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, - a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x, - a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w, + override fun multiply(left: Quaternion, right: Quaternion): Quaternion = Quaternion( + left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z, + left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y, + left.w * right.y - left.x * right.z + left.y * right.w + left.z * right.x, + left.w * right.z + left.x * right.y - left.y * right.x + left.z * right.w, ) - override fun divide(a: Quaternion, b: Quaternion): Quaternion { - val s = b.w * b.w + b.x * b.x + b.y * b.y + b.z * b.z + override fun divide(left: Quaternion, right: Quaternion): Quaternion { + val s = right.w * right.w + right.x * right.x + right.y * right.y + right.z * right.z return Quaternion( - (b.w * a.w + b.x * a.x + b.y * a.y + b.z * a.z) / s, - (b.w * a.x - b.x * a.w - b.y * a.z + b.z * a.y) / s, - (b.w * a.y + b.x * a.z - b.y * a.w - b.z * a.x) / s, - (b.w * a.z - b.x * a.y + b.y * a.x - b.z * a.w) / s, + (right.w * left.w + right.x * left.x + right.y * left.y + right.z * left.z) / s, + (right.w * left.x - right.x * left.w - right.y * left.z + right.z * left.y) / s, + (right.w * left.y + right.x * left.z - right.y * left.w - right.z * left.x) / s, + (right.w * left.z - right.x * left.y + right.y * left.x - right.z * left.w) / s, ) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 1baca0f55..661680565 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -57,8 +57,8 @@ public open class FunctionalExpressionGroup>( /** * Builds an Expression of addition of two another expressions. */ - override fun add(a: Expression, b: Expression): Expression = - binaryOperation(GroupOps.PLUS_OPERATION, a, b) + override fun add(left: Expression, right: Expression): Expression = + binaryOperation(GroupOps.PLUS_OPERATION, left, right) // /** // * Builds an Expression of multiplication of expression by number. @@ -88,8 +88,8 @@ public open class FunctionalExpressionRing>( /** * Builds an Expression of multiplication of two expressions. */ - override fun multiply(a: Expression, b: Expression): Expression = - binaryOperationFunction(RingOps.TIMES_OPERATION)(a, b) + override fun multiply(left: Expression, right: Expression): Expression = + binaryOperationFunction(RingOps.TIMES_OPERATION)(left, right) public operator fun Expression.times(arg: T): Expression = this * const(arg) public operator fun T.times(arg: Expression): Expression = arg * this @@ -107,8 +107,8 @@ public open class FunctionalExpressionField>( /** * Builds an Expression of division an expression by another one. */ - override fun divide(a: Expression, b: Expression): Expression = - binaryOperationFunction(FieldOps.DIV_OPERATION)(a, b) + override fun divide(left: Expression, right: Expression): Expression = + binaryOperationFunction(FieldOps.DIV_OPERATION)(left, right) public operator fun Expression.div(arg: T): Expression = this / const(arg) public operator fun T.div(arg: Expression): Expression = arg / this 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 360715408..dd3c46207 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 @@ -31,15 +31,15 @@ public object MstGroup : Group, NumericAlgebra, ScaleOperations { override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value) override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOps.PLUS_OPERATION)(a, b) + override fun add(left: MST, right: MST): MST.Binary = binaryOperationFunction(GroupOps.PLUS_OPERATION)(left, right) override operator fun MST.unaryPlus(): MST.Unary = unaryOperationFunction(GroupOps.PLUS_OPERATION)(this) override operator fun MST.unaryMinus(): MST.Unary = unaryOperationFunction(GroupOps.MINUS_OPERATION)(this) - override operator fun MST.minus(b: MST): MST.Binary = - binaryOperationFunction(GroupOps.MINUS_OPERATION)(this, b) + override operator fun MST.minus(other: MST): MST.Binary = + binaryOperationFunction(GroupOps.MINUS_OPERATION)(this, other) override fun scale(a: MST, value: Double): MST.Binary = binaryOperationFunction(RingOps.TIMES_OPERATION)(a, number(value)) @@ -62,17 +62,17 @@ public object MstRing : Ring, NumbersAddOps, ScaleOperations { override fun number(value: Number): MST.Numeric = MstGroup.number(value) override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b) + override fun add(left: MST, right: MST): MST.Binary = MstGroup.add(left, right) override fun scale(a: MST, value: Double): MST.Binary = MstGroup.binaryOperationFunction(RingOps.TIMES_OPERATION)(a, MstGroup.number(value)) - override fun multiply(a: MST, b: MST): MST.Binary = - binaryOperationFunction(RingOps.TIMES_OPERATION)(a, b) + override fun multiply(left: MST, right: MST): MST.Binary = + binaryOperationFunction(RingOps.TIMES_OPERATION)(left, right) override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus } - override operator fun MST.minus(b: MST): MST.Binary = MstGroup { this@minus - b } + override operator fun MST.minus(other: MST): MST.Binary = MstGroup { this@minus - other } override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstGroup.binaryOperationFunction(operation) @@ -92,18 +92,18 @@ public object MstField : Field, NumbersAddOps, ScaleOperations { override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) override fun number(value: Number): MST.Numeric = MstRing.number(value) - override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) + override fun add(left: MST, right: MST): MST.Binary = MstRing.add(left, right) override fun scale(a: MST, value: Double): MST.Binary = MstGroup.binaryOperationFunction(RingOps.TIMES_OPERATION)(a, MstGroup.number(value)) - override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) - override fun divide(a: MST, b: MST): MST.Binary = - binaryOperationFunction(FieldOps.DIV_OPERATION)(a, b) + override fun multiply(left: MST, right: MST): MST.Binary = MstRing.multiply(left, right) + override fun divide(left: MST, right: MST): MST.Binary = + binaryOperationFunction(FieldOps.DIV_OPERATION)(left, right) override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } - override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b } + override operator fun MST.minus(other: MST): MST.Binary = MstRing { this@minus - other } override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperationFunction(operation) @@ -134,17 +134,17 @@ public object MstExtendedField : ExtendedField, NumericAlgebra { override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ASINH_OPERATION)(arg) override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg) override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg) - override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b) + override fun add(left: MST, right: MST): MST.Binary = MstField.add(left, right) override fun sqrt(arg: MST): MST = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) override fun scale(a: MST, value: Double): MST = binaryOperation(GroupOps.PLUS_OPERATION, a, number(value)) - override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) - override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) + override fun multiply(left: MST, right: MST): MST.Binary = MstField.multiply(left, right) + override fun divide(left: MST, right: MST): MST.Binary = MstField.divide(left, right) override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus } - override operator fun MST.minus(b: MST): MST.Binary = MstField { this@minus - b } + override operator fun MST.minus(other: MST): MST.Binary = MstField { this@minus - other } override fun power(arg: MST, pow: Number): MST.Binary = binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) 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 089503dc8..704c4edd8 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 @@ -168,22 +168,22 @@ public open class SimpleAutoDiffField>( // Basic math (+, -, *, /) - override fun add(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = - derive(const { a.value + b.value }) { z -> - a.d += z.d - b.d += z.d + override fun add(left: AutoDiffValue, right: AutoDiffValue): AutoDiffValue = + derive(const { left.value + right.value }) { z -> + left.d += z.d + right.d += z.d } - override fun multiply(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = - derive(const { a.value * b.value }) { z -> - a.d += z.d * b.value - b.d += z.d * a.value + override fun multiply(left: AutoDiffValue, right: AutoDiffValue): AutoDiffValue = + derive(const { left.value * right.value }) { z -> + left.d += z.d * right.value + right.d += z.d * left.value } - override fun divide(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = - derive(const { a.value / b.value }) { z -> - a.d += z.d / b.value - b.d -= z.d * a.value / (b.value * b.value) + override fun divide(left: AutoDiffValue, right: AutoDiffValue): AutoDiffValue = + derive(const { left.value / right.value }) { z -> + left.d += z.d / right.value + right.d -= z.d * left.value / (right.value * right.value) } override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = 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 dde04a97a..3f9b43f03 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 @@ -100,12 +100,12 @@ public interface GroupOpsND> : GroupOps>, /** * Element-wise addition. * - * @param a the augend. - * @param b the addend. + * @param left the augend. + * @param right the addend. * @return the sum. */ - override fun add(a: StructureND, b: StructureND): StructureND = - zip(a, b) { aValue, bValue -> add(aValue, bValue) } + override fun add(left: StructureND, right: StructureND): StructureND = + zip(left, right) { aValue, bValue -> add(aValue, bValue) } // TODO move to extensions after KEEP-176 @@ -134,7 +134,7 @@ public interface GroupOpsND> : GroupOps>, * @param arg the addend. * @return the sum. */ - public operator fun T.plus(arg: StructureND): StructureND = arg.map { value -> add(this@plus, value) } + public operator fun T.plus(arg: StructureND): StructureND = arg + this /** * Subtracts an ND structure from an element of it. @@ -162,12 +162,12 @@ public interface RingOpsND> : RingOps>, Gro /** * Element-wise multiplication. * - * @param a the multiplicand. - * @param b the multiplier. + * @param left the multiplicand. + * @param right the multiplier. * @return the product. */ - override fun multiply(a: StructureND, b: StructureND): StructureND = - zip(a, b) { aValue, bValue -> multiply(aValue, bValue) } + override fun multiply(left: StructureND, right: StructureND): StructureND = + zip(left, right) { aValue, bValue -> multiply(aValue, bValue) } //TODO move to extensions after KEEP-176 @@ -208,12 +208,12 @@ public interface FieldOpsND> : FieldOps>, Rin /** * Element-wise division. * - * @param a the dividend. - * @param b the divisor. + * @param left the dividend. + * @param right the divisor. * @return the quotient. */ - override fun divide(a: StructureND, b: StructureND): StructureND = - zip(a, b) { aValue, bValue -> divide(aValue, bValue) } + override fun divide(left: StructureND, right: StructureND): StructureND = + zip(left, right) { aValue, bValue -> divide(aValue, bValue) } //TODO move to extensions after https://github.com/Kotlin/KEEP/blob/master/proposals/context-receivers.md /** 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 06534c5e5..c94988eef 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 @@ -73,7 +73,7 @@ internal inline fun > BufferAlgebraND.zipInline( r: BufferND, crossinline block: A.(l: T, r: T) -> T ): BufferND { - require(l.indexes == r.indexes) + require(l.indexes == r.indexes) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } val indexes = l.indexes return BufferND(indexes, bufferAlgebra.zipInline(l.buffer, r.buffer, block)) } @@ -114,6 +114,10 @@ public fun > BufferAlgebraND.produce( initializer: A.(IntArray) -> T ): BufferND = produce(shape, initializer) +public fun , A> A.produce( + initializer: EA.(IntArray) -> T +): BufferND where A : BufferAlgebraND, A : WithShape = produce(shape, initializer) + //// group factories //public fun > A.ndAlgebra( // bufferAlgebra: BufferAlgebra, 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 9eba401ab..c17632101 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 @@ -20,7 +20,7 @@ import space.kscience.kmath.structures.MutableBufferFactory */ public open class BufferND( public val indexes: ShapeIndex, - public val buffer: Buffer, + public open val buffer: Buffer, ) : StructureND { override operator fun get(index: IntArray): T = buffer[indexes.offset(index)] @@ -55,14 +55,14 @@ public inline fun StructureND.mapToBuffer( * * @param T the type of items. * @param strides The strides to access elements of [MutableBuffer] by linear indices. - * @param mutableBuffer The underlying buffer. + * @param buffer The underlying buffer. */ public class MutableBufferND( strides: ShapeIndex, - public val mutableBuffer: MutableBuffer, -) : MutableStructureND, BufferND(strides, mutableBuffer) { + override val buffer: MutableBuffer, +) : MutableStructureND, BufferND(strides, buffer) { override fun set(index: IntArray, value: T) { - mutableBuffer[indexes.offset(index)] = value + buffer[indexes.offset(index)] = value } } @@ -74,7 +74,7 @@ public inline fun MutableStructureND.mapToMutableBuffer( crossinline transform: (T) -> R, ): MutableBufferND { return if (this is MutableBufferND) - MutableBufferND(this.indexes, factory.invoke(indexes.linearSize) { transform(mutableBuffer[it]) }) + MutableBufferND(this.indexes, factory.invoke(indexes.linearSize) { transform(buffer[it]) }) else { val strides = DefaultStrides(shape) MutableBufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) 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 294c44ec4..1502a6fd0 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 @@ -10,42 +10,132 @@ import space.kscience.kmath.operations.* import space.kscience.kmath.structures.DoubleBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract +import kotlin.math.pow + +public class DoubleBufferND( + indexes: ShapeIndex, + override val buffer: DoubleBuffer, +) : BufferND(indexes, buffer) + public sealed class DoubleFieldOpsND : BufferedFieldOpsND(DoubleField.bufferAlgebra), ScaleOperations>, ExtendedFieldOps> { - override fun StructureND.toBufferND(): BufferND = when (this) { - is BufferND -> this + override fun StructureND.toBufferND(): DoubleBufferND = when (this) { + is DoubleBufferND -> this else -> { val indexer = indexerBuilder(shape) - BufferND(indexer, DoubleBuffer(indexer.linearSize) { offset -> get(indexer.index(offset)) }) + DoubleBufferND(indexer, DoubleBuffer(indexer.linearSize) { offset -> get(indexer.index(offset)) }) } } - //TODO do specialization + private inline fun mapInline( + arg: DoubleBufferND, + transform: (Double) -> Double + ): DoubleBufferND { + val indexes = arg.indexes + val array = arg.buffer.array + return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { transform(array[it]) }) + } - override fun scale(a: StructureND, value: Double): BufferND = + private inline fun zipInline( + l: DoubleBufferND, + r: DoubleBufferND, + block: (l: Double, r: Double) -> Double + ): DoubleBufferND { + require(l.indexes == r.indexes) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } + val indexes = l.indexes + val lArray = l.buffer.array + val rArray = r.buffer.array + return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { block(lArray[it], rArray[it]) }) + } + + override fun StructureND.map(transform: DoubleField.(Double) -> Double): BufferND = + mapInline(toBufferND()) { DoubleField.transform(it) } + + + override fun zip( + left: StructureND, + right: StructureND, + transform: DoubleField.(Double, Double) -> Double + ): BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> DoubleField.transform(l, r) } + + override fun produce(shape: Shape, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND { + val indexer = indexerBuilder(shape) + return DoubleBufferND( + indexer, + DoubleBuffer(indexer.linearSize) { offset -> + elementAlgebra.initializer(indexer.index(offset)) + } + ) + } + + override fun add(left: StructureND, right: StructureND): DoubleBufferND = + zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l + r } + + override fun multiply(left: StructureND, right: StructureND): DoubleBufferND = + zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l * r } + + override fun StructureND.unaryMinus(): DoubleBufferND = mapInline(toBufferND()) { -it } + + override fun StructureND.div(other: StructureND): DoubleBufferND = + zipInline(toBufferND(), other.toBufferND()) { l, r -> l / r } + + override fun StructureND.plus(arg: Double): DoubleBufferND = mapInline(toBufferND()) { it + arg } + + override fun StructureND.minus(arg: Double): StructureND = mapInline(toBufferND()) { it - arg } + + override fun Double.plus(arg: StructureND): StructureND = arg + this + + override fun Double.minus(arg: StructureND): StructureND = mapInline(arg.toBufferND()) { this - it } + + override fun scale(a: StructureND, value: Double): DoubleBufferND = mapInline(a.toBufferND()) { it * value } - override fun power(arg: StructureND, pow: Number): BufferND = - mapInline(arg.toBufferND()) { power(it, pow) } + override fun power(arg: StructureND, pow: Number): DoubleBufferND = + mapInline(arg.toBufferND()) { it.pow(pow.toDouble()) } - override fun exp(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { exp(it) } - override fun ln(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { ln(it) } + override fun exp(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.exp(it) } - override fun sin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sin(it) } - override fun cos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cos(it) } - override fun tan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tan(it) } - override fun asin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asin(it) } - override fun acos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acos(it) } - override fun atan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atan(it) } + override fun ln(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.ln(it) } - override fun sinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sinh(it) } - override fun cosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cosh(it) } - override fun tanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tanh(it) } - override fun asinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asinh(it) } - override fun acosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acosh(it) } - override fun atanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atanh(it) } + override fun sin(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.sin(it) } + + override fun cos(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.cos(it) } + + override fun tan(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.tan(it) } + + override fun asin(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.asin(it) } + + override fun acos(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.acos(it) } + + override fun atan(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.atan(it) } + + override fun sinh(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.sinh(it) } + + override fun cosh(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.cosh(it) } + + override fun tanh(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.tanh(it) } + + override fun asinh(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.asinh(it) } + + override fun acosh(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.acosh(it) } + + override fun atanh(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { kotlin.math.atanh(it) } public companion object : DoubleFieldOpsND() } @@ -54,7 +144,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D public class DoubleFieldND(override val shape: Shape) : DoubleFieldOpsND(), FieldND, NumbersAddOps> { - override fun number(value: Number): BufferND { + override fun number(value: Number): DoubleBufferND { val d = value.toDouble() // minimize conversions return produce(shape) { d } } 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 d731ee4ee..d0b0c0b73 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 @@ -121,11 +121,11 @@ public interface GroupOps : Algebra { /** * Addition of two elements. * - * @param a the augend. - * @param b the addend. + * @param left the augend. + * @param right the addend. * @return the sum. */ - public fun add(a: T, b: T): T + public fun add(left: T, right: T): T // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176. @@ -149,19 +149,19 @@ public interface GroupOps : Algebra { * Addition of two elements. * * @receiver the augend. - * @param b the addend. + * @param other the addend. * @return the sum. */ - public operator fun T.plus(b: T): T = add(this, b) + public operator fun T.plus(other: T): T = add(this, other) /** * Subtraction of two elements. * * @receiver the minuend. - * @param b the subtrahend. + * @param other the subtrahend. * @return the difference. */ - public operator fun T.minus(b: T): T = add(this, -b) + public operator fun T.minus(other: T): T = add(this, -other) // Dynamic dispatch of operations override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> +arg } @@ -210,18 +210,18 @@ public interface RingOps : GroupOps { /** * Multiplies two elements. * - * @param a the multiplier. - * @param b the multiplicand. + * @param left the multiplier. + * @param right the multiplicand. */ - public fun multiply(a: T, b: T): T + public fun multiply(left: T, right: T): T /** * Multiplies this element by scalar. * * @receiver the multiplier. - * @param b the multiplicand. + * @param other the multiplicand. */ - public operator fun T.times(b: T): T = multiply(this, b) + public operator fun T.times(other: T): T = multiply(this, other) override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { TIMES_OPERATION -> ::multiply @@ -260,20 +260,20 @@ public interface FieldOps : RingOps { /** * Division of two elements. * - * @param a the dividend. - * @param b the divisor. + * @param left the dividend. + * @param right the divisor. * @return the quotient. */ - public fun divide(a: T, b: T): T + public fun divide(left: T, right: T): T /** * Division of two elements. * * @receiver the dividend. - * @param b the divisor. + * @param other the divisor. * @return the quotient. */ - public operator fun T.div(b: T): T = divide(this, b) + public operator fun T.div(other: T): T = divide(this, other) override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { DIV_OPERATION -> ::divide 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 97e35e4b0..5a713049e 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 @@ -34,10 +34,10 @@ public object BigIntField : Field, NumbersAddOps, ScaleOperation @Suppress("EXTENSION_SHADOWED_BY_MEMBER") override fun BigInt.unaryMinus(): BigInt = -this - override fun add(a: BigInt, b: BigInt): BigInt = a.plus(b) + override fun add(left: BigInt, right: BigInt): BigInt = left.plus(right) override fun scale(a: BigInt, value: Double): BigInt = a.times(number(value)) - override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b) - override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b) + override fun multiply(left: BigInt, right: BigInt): BigInt = left.times(right) + override fun divide(left: BigInt, right: BigInt): BigInt = left.div(right) public operator fun String.unaryPlus(): BigInt = this.parseBigInteger() ?: error("Can't parse $this as big integer") public operator fun String.unaryMinus(): BigInt = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt index 5a14e7734..bc05f3904 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -134,8 +134,8 @@ public open class BufferRingOps>( override val bufferFactory: BufferFactory, ) : BufferAlgebra, RingOps>{ - override fun add(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l + r } - override fun multiply(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l * r } + override fun add(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l + r } + override fun multiply(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l * r } override fun Buffer.unaryMinus(): Buffer = map { -it } override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = @@ -153,9 +153,9 @@ public open class BufferFieldOps>( bufferFactory: BufferFactory, ) : BufferRingOps(elementAlgebra, bufferFactory), BufferAlgebra, FieldOps>, ScaleOperations> { - override fun add(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l + r } - override fun multiply(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l * r } - override fun divide(a: Buffer, b: Buffer): Buffer = zipInline(a, b) { l, r -> l / r } + override fun add(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l + r } + override fun multiply(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l * r } + override fun divide(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l / r } override fun scale(a: Buffer, value: Double): Buffer = a.map { scale(it, value) } override fun Buffer.unaryMinus(): Buffer = map { -it } 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 2580cd6f8..29b25aae8 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 @@ -15,36 +15,37 @@ import kotlin.math.* * [ExtendedFieldOps] over [DoubleBuffer]. */ public abstract class DoubleBufferOps : ExtendedFieldOps>, Norm, Double> { + override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { DoubleBuffer(size) { -array[it] } } else { DoubleBuffer(size) { -get(it) } } - override fun add(a: Buffer, b: Buffer): DoubleBuffer { - require(b.size == a.size) { - "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " + override fun add(left: Buffer, right: Buffer): DoubleBuffer { + require(right.size == left.size) { + "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " } - return if (a is DoubleBuffer && b is DoubleBuffer) { - val aArray = a.array - val bArray = b.array - DoubleBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] }) - } else DoubleBuffer(DoubleArray(a.size) { a[it] + b[it] }) + return if (left is DoubleBuffer && right is DoubleBuffer) { + val aArray = left.array + val bArray = right.array + DoubleBuffer(DoubleArray(left.size) { aArray[it] + bArray[it] }) + } else DoubleBuffer(DoubleArray(left.size) { left[it] + right[it] }) } - override fun Buffer.plus(b: Buffer): DoubleBuffer = add(this, b) + override fun Buffer.plus(other: Buffer): DoubleBuffer = add(this, other) - override fun Buffer.minus(b: Buffer): DoubleBuffer { - require(b.size == this.size) { - "The size of the first buffer ${this.size} should be the same as for second one: ${b.size} " + override fun Buffer.minus(other: Buffer): DoubleBuffer { + require(other.size == this.size) { + "The size of the first buffer ${this.size} should be the same as for second one: ${other.size} " } - return if (this is DoubleBuffer && b is DoubleBuffer) { + return if (this is DoubleBuffer && other is DoubleBuffer) { val aArray = this.array - val bArray = b.array + val bArray = other.array DoubleBuffer(DoubleArray(this.size) { aArray[it] - bArray[it] }) - } else DoubleBuffer(DoubleArray(this.size) { this[it] - b[it] }) + } else DoubleBuffer(DoubleArray(this.size) { this[it] - other[it] }) } // @@ -66,29 +67,29 @@ public abstract class DoubleBufferOps : ExtendedFieldOps>, Norm, b: Buffer): DoubleBuffer { - require(b.size == a.size) { - "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " + override fun multiply(left: Buffer, right: Buffer): DoubleBuffer { + require(right.size == left.size) { + "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " } - return if (a is DoubleBuffer && b is DoubleBuffer) { - val aArray = a.array - val bArray = b.array - DoubleBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] }) + return if (left is DoubleBuffer && right is DoubleBuffer) { + val aArray = left.array + val bArray = right.array + DoubleBuffer(DoubleArray(left.size) { aArray[it] * bArray[it] }) } else - DoubleBuffer(DoubleArray(a.size) { a[it] * b[it] }) + DoubleBuffer(DoubleArray(left.size) { left[it] * right[it] }) } - override fun divide(a: Buffer, b: Buffer): DoubleBuffer { - require(b.size == a.size) { - "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " + override fun divide(left: Buffer, right: Buffer): DoubleBuffer { + require(right.size == left.size) { + "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " } - return if (a is DoubleBuffer && b is DoubleBuffer) { - val aArray = a.array - val bArray = b.array - DoubleBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] }) - } else DoubleBuffer(DoubleArray(a.size) { a[it] / b[it] }) + return if (left is DoubleBuffer && right is DoubleBuffer) { + val aArray = left.array + val bArray = right.array + DoubleBuffer(DoubleArray(left.size) { aArray[it] / bArray[it] }) + } else DoubleBuffer(DoubleArray(left.size) { left[it] / right[it] }) } override fun sin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index c1775296c..1168dc6ba 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -73,10 +73,10 @@ public object DoubleField : ExtendedField, Norm, ScaleOp else -> super.binaryOperationFunction(operation) } - override inline fun add(a: Double, b: Double): Double = a + b + override inline fun add(left: Double, right: Double): Double = left + right - override inline fun multiply(a: Double, b: Double): Double = a * b - override inline fun divide(a: Double, b: Double): Double = a / b + override inline fun multiply(left: Double, right: Double): Double = left * right + override inline fun divide(left: Double, right: Double): Double = left / right override inline fun scale(a: Double, value: Double): Double = a * value @@ -102,10 +102,10 @@ public object DoubleField : ExtendedField, Norm, ScaleOp override inline fun norm(arg: Double): Double = abs(arg) override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(b: Double): Double = this + b - override inline fun Double.minus(b: Double): Double = this - b - override inline fun Double.times(b: Double): Double = this * b - override inline fun Double.div(b: Double): Double = this / b + override inline fun Double.plus(other: Double): Double = this + other + override inline fun Double.minus(other: Double): Double = this - other + override inline fun Double.times(other: Double): Double = this * other + override inline fun Double.div(other: Double): Double = this / other } public val Double.Companion.algebra: DoubleField get() = DoubleField @@ -126,12 +126,12 @@ public object FloatField : ExtendedField, Norm { else -> super.binaryOperationFunction(operation) } - override inline fun add(a: Float, b: Float): Float = a + b + override inline fun add(left: Float, right: Float): Float = left + right override fun scale(a: Float, value: Double): Float = a * value.toFloat() - override inline fun multiply(a: Float, b: Float): Float = a * b + override inline fun multiply(left: Float, right: Float): Float = left * right - override inline fun divide(a: Float, b: Float): Float = a / b + override inline fun divide(left: Float, right: Float): Float = left / right override inline fun sin(arg: Float): Float = kotlin.math.sin(arg) override inline fun cos(arg: Float): Float = kotlin.math.cos(arg) @@ -155,10 +155,10 @@ public object FloatField : ExtendedField, Norm { override inline fun norm(arg: Float): Float = abs(arg) override inline fun Float.unaryMinus(): Float = -this - override inline fun Float.plus(b: Float): Float = this + b - override inline fun Float.minus(b: Float): Float = this - b - override inline fun Float.times(b: Float): Float = this * b - override inline fun Float.div(b: Float): Float = this / b + override inline fun Float.plus(other: Float): Float = this + other + override inline fun Float.minus(other: Float): Float = this - other + override inline fun Float.times(other: Float): Float = this * other + override inline fun Float.div(other: Float): Float = this / other } public val Float.Companion.algebra: FloatField get() = FloatField @@ -175,14 +175,14 @@ public object IntRing : Ring, Norm, NumericAlgebra { get() = 1 override fun number(value: Number): Int = value.toInt() - override inline fun add(a: Int, b: Int): Int = a + b - override inline fun multiply(a: Int, b: Int): Int = a * b + override inline fun add(left: Int, right: Int): Int = left + right + override inline fun multiply(left: Int, right: Int): Int = left * right override inline fun norm(arg: Int): Int = abs(arg) override inline fun Int.unaryMinus(): Int = -this - override inline fun Int.plus(b: Int): Int = this + b - override inline fun Int.minus(b: Int): Int = this - b - override inline fun Int.times(b: Int): Int = this * b + override inline fun Int.plus(other: Int): Int = this + other + override inline fun Int.minus(other: Int): Int = this - other + override inline fun Int.times(other: Int): Int = this * other } public val Int.Companion.algebra: IntRing get() = IntRing @@ -199,14 +199,14 @@ public object ShortRing : Ring, Norm, NumericAlgebra get() = 1 override fun number(value: Number): Short = value.toShort() - override inline fun add(a: Short, b: Short): Short = (a + b).toShort() - override inline fun multiply(a: Short, b: Short): Short = (a * b).toShort() + override inline fun add(left: Short, right: Short): Short = (left + right).toShort() + override inline fun multiply(left: Short, right: Short): Short = (left * right).toShort() override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort() override inline fun Short.unaryMinus(): Short = (-this).toShort() - override inline fun Short.plus(b: Short): Short = (this + b).toShort() - override inline fun Short.minus(b: Short): Short = (this - b).toShort() - override inline fun Short.times(b: Short): Short = (this * b).toShort() + override inline fun Short.plus(other: Short): Short = (this + other).toShort() + override inline fun Short.minus(other: Short): Short = (this - other).toShort() + override inline fun Short.times(other: Short): Short = (this * other).toShort() } public val Short.Companion.algebra: ShortRing get() = ShortRing @@ -223,14 +223,14 @@ public object ByteRing : Ring, Norm, NumericAlgebra { get() = 1 override fun number(value: Number): Byte = value.toByte() - override inline fun add(a: Byte, b: Byte): Byte = (a + b).toByte() - override inline fun multiply(a: Byte, b: Byte): Byte = (a * b).toByte() + override inline fun add(left: Byte, right: Byte): Byte = (left + right).toByte() + override inline fun multiply(left: Byte, right: Byte): Byte = (left * right).toByte() override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte() override inline fun Byte.unaryMinus(): Byte = (-this).toByte() - override inline fun Byte.plus(b: Byte): Byte = (this + b).toByte() - override inline fun Byte.minus(b: Byte): Byte = (this - b).toByte() - override inline fun Byte.times(b: Byte): Byte = (this * b).toByte() + override inline fun Byte.plus(other: Byte): Byte = (this + other).toByte() + override inline fun Byte.minus(other: Byte): Byte = (this - other).toByte() + override inline fun Byte.times(other: Byte): Byte = (this * other).toByte() } public val Byte.Companion.algebra: ByteRing get() = ByteRing @@ -247,14 +247,14 @@ public object LongRing : Ring, Norm, NumericAlgebra { get() = 1L override fun number(value: Number): Long = value.toLong() - override inline fun add(a: Long, b: Long): Long = a + b - override inline fun multiply(a: Long, b: Long): Long = a * b + override inline fun add(left: Long, right: Long): Long = left + right + override inline fun multiply(left: Long, right: Long): Long = left * right override fun norm(arg: Long): Long = abs(arg) override inline fun Long.unaryMinus(): Long = (-this) - override inline fun Long.plus(b: Long): Long = (this + b) - override inline fun Long.minus(b: Long): Long = (this - b) - override inline fun Long.times(b: Long): Long = (this * b) + override inline fun Long.plus(other: Long): Long = (this + other) + override inline fun Long.minus(other: Long): Long = (this - other) + override inline fun Long.times(other: Long): Long = (this * other) } public val Long.Companion.algebra: LongRing get() = LongRing diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt index 69dd858c4..3a9c242fc 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt @@ -18,9 +18,9 @@ public object JBigIntegerField : Ring, NumericAlgebra { override val one: BigInteger get() = BigInteger.ONE override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong()) - override fun add(a: BigInteger, b: BigInteger): BigInteger = a.add(b) - override operator fun BigInteger.minus(b: BigInteger): BigInteger = subtract(b) - override fun multiply(a: BigInteger, b: BigInteger): BigInteger = a.multiply(b) + override fun add(left: BigInteger, right: BigInteger): BigInteger = left.add(right) + override operator fun BigInteger.minus(other: BigInteger): BigInteger = subtract(other) + override fun multiply(left: BigInteger, right: BigInteger): BigInteger = left.multiply(right) override operator fun BigInteger.unaryMinus(): BigInteger = negate() } @@ -39,15 +39,15 @@ public abstract class JBigDecimalFieldBase internal constructor( override val one: BigDecimal get() = BigDecimal.ONE - override fun add(a: BigDecimal, b: BigDecimal): BigDecimal = a.add(b) - override operator fun BigDecimal.minus(b: BigDecimal): BigDecimal = subtract(b) + override fun add(left: BigDecimal, right: BigDecimal): BigDecimal = left.add(right) + override operator fun BigDecimal.minus(other: BigDecimal): BigDecimal = subtract(other) override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble()) override fun scale(a: BigDecimal, value: Double): BigDecimal = a.multiply(value.toBigDecimal(mathContext), mathContext) - override fun multiply(a: BigDecimal, b: BigDecimal): BigDecimal = a.multiply(b, mathContext) - override fun divide(a: BigDecimal, b: BigDecimal): BigDecimal = a.divide(b, mathContext) + override fun multiply(left: BigDecimal, right: BigDecimal): BigDecimal = left.multiply(right, mathContext) + override fun divide(left: BigDecimal, right: BigDecimal): BigDecimal = left.divide(right, mathContext) override fun power(arg: BigDecimal, pow: Number): BigDecimal = arg.pow(pow.toInt(), mathContext) override fun sqrt(arg: BigDecimal): BigDecimal = arg.sqrt(mathContext) override operator fun BigDecimal.unaryMinus(): BigDecimal = negate(mathContext) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index 54b285a70..e862c0b9d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -104,12 +104,12 @@ public class PolynomialSpace( Polynomial(coefficients.map { -it }) } - override fun add(a: Polynomial, b: Polynomial): Polynomial { - val dim = max(a.coefficients.size, b.coefficients.size) + override fun add(left: Polynomial, right: Polynomial): Polynomial { + val dim = max(left.coefficients.size, right.coefficients.size) return ring { Polynomial(List(dim) { index -> - a.coefficients.getOrElse(index) { zero } + b.coefficients.getOrElse(index) { zero } + left.coefficients.getOrElse(index) { zero } + right.coefficients.getOrElse(index) { zero } }) } } 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 e8b1ce95b..5e3cbff83 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 @@ -47,7 +47,7 @@ public object Euclidean2DSpace : GeometrySpace, ScaleOperations, ScaleOperations, V : Any> public fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram - override fun add(a: IndexedHistogram, b: IndexedHistogram): IndexedHistogram { - require(a.context == this) { "Can't operate on a histogram produced by external space" } - require(b.context == this) { "Can't operate on a histogram produced by external space" } - return IndexedHistogram(this, histogramValueSpace { a.values + b.values }) + override fun add(left: IndexedHistogram, right: IndexedHistogram): IndexedHistogram { + require(left.context == this) { "Can't operate on a histogram produced by external space" } + require(right.context == this) { "Can't operate on a histogram produced by external space" } + return IndexedHistogram(this, histogramValueSpace { left.values + right.values }) } override fun scale(a: IndexedHistogram, value: Double): IndexedHistogram { diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt index 96f945f6a..cc54d7e1a 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt @@ -88,20 +88,20 @@ public class TreeHistogramSpace( TreeHistogramBuilder(binFactory).apply(block).build() override fun add( - a: UnivariateHistogram, - b: UnivariateHistogram, + left: UnivariateHistogram, + right: UnivariateHistogram, ): UnivariateHistogram { // require(a.context == this) { "Histogram $a does not belong to this context" } // require(b.context == this) { "Histogram $b does not belong to this context" } val bins = TreeMap().apply { - (a.bins.map { it.domain } union b.bins.map { it.domain }).forEach { def -> + (left.bins.map { it.domain } union right.bins.map { it.domain }).forEach { def -> put( def.center, UnivariateBin( def, - value = (a[def.center]?.value ?: 0.0) + (b[def.center]?.value ?: 0.0), - standardDeviation = (a[def.center]?.standardDeviation - ?: 0.0) + (b[def.center]?.standardDeviation ?: 0.0) + value = (left[def.center]?.value ?: 0.0) + (right[def.center]?.value ?: 0.0), + standardDeviation = (left[def.center]?.standardDeviation + ?: 0.0) + (right[def.center]?.standardDeviation ?: 0.0) ) ) } diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt index 1a6e3325b..645a14e30 100644 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt @@ -28,10 +28,10 @@ public object JafamaDoubleField : ExtendedField, Norm, S else -> super.binaryOperationFunction(operation) } - override inline fun add(a: Double, b: Double): Double = a + b + override inline fun add(left: Double, right: Double): Double = left + right - override inline fun multiply(a: Double, b: Double): Double = a * b - override inline fun divide(a: Double, b: Double): Double = a / b + override inline fun multiply(left: Double, right: Double): Double = left * right + override inline fun divide(left: Double, right: Double): Double = left / right override inline fun scale(a: Double, value: Double): Double = a * value @@ -57,10 +57,10 @@ public object JafamaDoubleField : ExtendedField, Norm, S override inline fun norm(arg: Double): Double = FastMath.abs(arg) override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(b: Double): Double = this + b - override inline fun Double.minus(b: Double): Double = this - b - override inline fun Double.times(b: Double): Double = this * b - override inline fun Double.div(b: Double): Double = this / b + override inline fun Double.plus(other: Double): Double = this + other + override inline fun Double.minus(other: Double): Double = this - other + override inline fun Double.times(other: Double): Double = this * other + override inline fun Double.div(other: Double): Double = this / other } /** @@ -79,10 +79,10 @@ public object StrictJafamaDoubleField : ExtendedField, Norm super.binaryOperationFunction(operation) } - override inline fun add(a: Double, b: Double): Double = a + b + override inline fun add(left: Double, right: Double): Double = left + right - override inline fun multiply(a: Double, b: Double): Double = a * b - override inline fun divide(a: Double, b: Double): Double = a / b + override inline fun multiply(left: Double, right: Double): Double = left * right + override inline fun divide(left: Double, right: Double): Double = left / right override inline fun scale(a: Double, value: Double): Double = a * value @@ -108,8 +108,8 @@ public object StrictJafamaDoubleField : ExtendedField, Norm> : AlgebraND> : GroupOpsND, Nd4jArrayAlgebra { - override fun add(a: StructureND, b: StructureND): Nd4jArrayStructure = - a.ndArray.add(b.ndArray).wrap() + override fun add(left: StructureND, right: StructureND): Nd4jArrayStructure = + left.ndArray.add(right.ndArray).wrap() - override operator fun StructureND.minus(b: StructureND): Nd4jArrayStructure = - ndArray.sub(b.ndArray).wrap() + override operator fun StructureND.minus(other: StructureND): Nd4jArrayStructure = + ndArray.sub(other.ndArray).wrap() override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() @@ -94,8 +94,8 @@ public sealed interface Nd4jArrayGroupOps> : GroupOpsND @OptIn(UnstableKMathAPI::class) public sealed interface Nd4jArrayRingOps> : RingOpsND, Nd4jArrayGroupOps { - override fun multiply(a: StructureND, b: StructureND): Nd4jArrayStructure = - a.ndArray.mul(b.ndArray).wrap() + override fun multiply(left: StructureND, right: StructureND): Nd4jArrayStructure = + left.ndArray.mul(right.ndArray).wrap() // // override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { // check(this) @@ -132,8 +132,8 @@ public sealed interface Nd4jArrayRingOps> : RingOpsND, */ public sealed interface Nd4jArrayField> : FieldOpsND, Nd4jArrayRingOps { - override fun divide(a: StructureND, b: StructureND): Nd4jArrayStructure = - a.ndArray.div(b.ndArray).wrap() + override fun divide(left: StructureND, right: StructureND): Nd4jArrayStructure = + left.ndArray.div(right.ndArray).wrap() public operator fun Number.div(b: StructureND): Nd4jArrayStructure = b.ndArray.rdiv(this).wrap() diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt index c1bbace86..e0be72d4b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt @@ -41,8 +41,8 @@ public class SamplerSpace(public val algebra: S) : Group = ConstantSampler(algebra.zero) - override fun add(a: Sampler, b: Sampler): Sampler = BasicSampler { generator -> - a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } } + override fun add(left: Sampler, right: Sampler): Sampler = BasicSampler { generator -> + left.sample(generator).zip(right.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } } } override fun scale(a: Sampler, value: Double): Sampler = BasicSampler { generator -> diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 6076748d9..810ebe777 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.api -import space.kscience.kmath.operations.Algebra +import space.kscience.kmath.operations.RingOps /** * Algebra over a ring on [Tensor]. @@ -13,7 +13,7 @@ import space.kscience.kmath.operations.Algebra * * @param T the type of items in the tensors. */ -public interface TensorAlgebra : Algebra> { +public interface TensorAlgebra : RingOps> { /** * Returns a single tensor value of unit dimension if tensor shape equals to [1]. * @@ -53,7 +53,7 @@ public interface TensorAlgebra : Algebra> { * @param other tensor to be added. * @return the sum of this tensor and [other]. */ - public operator fun Tensor.plus(other: Tensor): Tensor + override fun Tensor.plus(other: Tensor): Tensor /** * Adds the scalar [value] to each element of this tensor. @@ -93,7 +93,7 @@ public interface TensorAlgebra : Algebra> { * @param other tensor to be subtracted. * @return the difference between this tensor and [other]. */ - public operator fun Tensor.minus(other: Tensor): Tensor + override fun Tensor.minus(other: Tensor): Tensor /** * Subtracts the scalar [value] from each element of this tensor. @@ -134,7 +134,7 @@ public interface TensorAlgebra : Algebra> { * @param other tensor to be multiplied. * @return the product of this tensor and [other]. */ - public operator fun Tensor.times(other: Tensor): Tensor + override fun Tensor.times(other: Tensor): Tensor /** * Multiplies the scalar [value] by each element of this tensor. @@ -155,7 +155,7 @@ public interface TensorAlgebra : Algebra> { * * @return tensor negation of the original tensor. */ - public operator fun Tensor.unaryMinus(): Tensor + override fun Tensor.unaryMinus(): Tensor /** * Returns the tensor at index i @@ -323,4 +323,8 @@ public interface TensorAlgebra : Algebra> { * @return the index of maximum value of each row of the input tensor in the given dimension [dim]. */ public fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor + + override fun add(left: Tensor, right: Tensor): Tensor = left + right + + override fun multiply(left: Tensor, right: Tensor): Tensor = left * right } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index e0451c2eb..1f5778d5e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -27,7 +27,7 @@ internal fun Tensor.copyToBufferedTensor(): BufferedTensor = internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { is BufferedTensor -> this is MutableBufferND -> if (this.indexes == TensorLinearStructure(this.shape)) { - BufferedTensor(this.shape, this.mutableBuffer, 0) + BufferedTensor(this.shape, this.buffer, 0) } else { this.copyToBufferedTensor() } 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 fca23bc16..a914542bc 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 @@ -88,17 +88,17 @@ public class ViktorFieldND(override val shape: IntArray) : FieldND, b: StructureND): ViktorStructureND = - (a.f64Buffer + b.f64Buffer).asStructure() + override fun add(left: StructureND, right: StructureND): ViktorStructureND = + (left.f64Buffer + right.f64Buffer).asStructure() override fun scale(a: StructureND, value: Double): ViktorStructureND = (a.f64Buffer * value).asStructure() - override inline fun StructureND.plus(b: StructureND): ViktorStructureND = - (f64Buffer + b.f64Buffer).asStructure() + override inline fun StructureND.plus(other: StructureND): ViktorStructureND = + (f64Buffer + other.f64Buffer).asStructure() - override inline fun StructureND.minus(b: StructureND): ViktorStructureND = - (f64Buffer - b.f64Buffer).asStructure() + override inline fun StructureND.minus(other: StructureND): ViktorStructureND = + (f64Buffer - other.f64Buffer).asStructure() override inline fun StructureND.times(k: Number): ViktorStructureND = (f64Buffer * k.toDouble()).asStructure() -- 2.34.1 From 4513b06e87d4bb2a16266eb5cba5e96167c0e0cd Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 17 Oct 2021 13:09:21 +0300 Subject: [PATCH 035/102] Shapeless ND and Buffer algebras --- .idea/copyright/kmath.xml | 6 - .idea/copyright/profiles_settings.xml | 21 --- .idea/scopes/Apply_copyright.xml | 4 - .../space/kscience/kmath/nd/AlgebraND.kt | 4 +- .../kmath/operations/NumericAlgebra.kt | 2 +- .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 124 ++++++++++++++++++ .../kmath/viktor/ViktorStructureND.kt | 100 +------------- 7 files changed, 130 insertions(+), 131 deletions(-) delete mode 100644 .idea/copyright/kmath.xml delete mode 100644 .idea/copyright/profiles_settings.xml delete mode 100644 .idea/scopes/Apply_copyright.xml create mode 100644 kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt diff --git a/.idea/copyright/kmath.xml b/.idea/copyright/kmath.xml deleted file mode 100644 index 1070e5d33..000000000 --- a/.idea/copyright/kmath.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index b538bdf41..000000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/scopes/Apply_copyright.xml b/.idea/scopes/Apply_copyright.xml deleted file mode 100644 index 0eb589133..000000000 --- a/.idea/scopes/Apply_copyright.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 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 3f9b43f03..b4e8b7487 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 @@ -203,7 +203,9 @@ public interface RingND> : Ring>, RingOpsND> : FieldOps>, RingOpsND, +public interface FieldOpsND> : + FieldOps>, + RingOpsND, ScaleOperations> { /** * Element-wise division. 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 ca88ad42d..5f6848211 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 @@ -150,7 +150,7 @@ public interface ScaleOperations : Algebra { * TODO to be removed and replaced by extensions after multiple receivers are there */ @UnstableKMathAPI -public interface NumbersAddOps : Ring, NumericAlgebra { +public interface NumbersAddOps : RingOps, NumericAlgebra { /** * Addition of element and scalar. * 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 new file mode 100644 index 000000000..c72553a64 --- /dev/null +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt @@ -0,0 +1,124 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.viktor + +import org.jetbrains.bio.viktor.F64Array +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.ExtendedFieldOps +import space.kscience.kmath.operations.NumbersAddOps + +@OptIn(UnstableKMathAPI::class) +@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public open class ViktorFieldOpsND : + FieldOpsND, + ExtendedFieldOps> { + + public val StructureND.f64Buffer: F64Array + get() = when (this) { + is ViktorStructureND -> this.f64Buffer + else -> produce(shape) { this@f64Buffer[it] }.f64Buffer + } + + override val elementAlgebra: DoubleField get() = DoubleField + + override fun produce(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = + F64Array(*shape).apply { + DefaultStrides(shape).indices().forEach { index -> + set(value = DoubleField.initializer(index), indices = index) + } + }.asStructure() + + override fun StructureND.unaryMinus(): StructureND = -1 * this + + override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = + F64Array(*shape).apply { + DefaultStrides(shape).indices().forEach { index -> + set(value = DoubleField.transform(this@map[index]), indices = index) + } + }.asStructure() + + override fun StructureND.mapIndexed( + transform: DoubleField.(index: IntArray, Double) -> Double, + ): ViktorStructureND = F64Array(*shape).apply { + DefaultStrides(shape).indices().forEach { index -> + set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index) + } + }.asStructure() + + override fun zip( + left: StructureND, + right: StructureND, + transform: DoubleField.(Double, Double) -> Double, + ): ViktorStructureND { + require(left.shape.contentEquals(right.shape)) + return F64Array(*left.shape).apply { + DefaultStrides(left.shape).indices().forEach { index -> + set(value = DoubleField.transform(left[index], right[index]), indices = index) + } + }.asStructure() + } + + override fun add(left: StructureND, right: StructureND): ViktorStructureND = + (left.f64Buffer + right.f64Buffer).asStructure() + + override fun scale(a: StructureND, value: Double): ViktorStructureND = + (a.f64Buffer * value).asStructure() + + override fun StructureND.plus(other: StructureND): ViktorStructureND = + (f64Buffer + other.f64Buffer).asStructure() + + override fun StructureND.minus(other: StructureND): ViktorStructureND = + (f64Buffer - other.f64Buffer).asStructure() + + override fun StructureND.times(k: Number): ViktorStructureND = + (f64Buffer * k.toDouble()).asStructure() + + override fun StructureND.plus(arg: Double): ViktorStructureND = + (f64Buffer.plus(arg)).asStructure() + + override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } + override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } + override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } + override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } + override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } + override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } + + override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } + + override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() + + override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() + + override fun sinh(arg: StructureND): ViktorStructureND = arg.map { sinh(it) } + + override fun cosh(arg: StructureND): ViktorStructureND = arg.map { cosh(it) } + + override fun asinh(arg: StructureND): ViktorStructureND = arg.map { asinh(it) } + + override fun acosh(arg: StructureND): ViktorStructureND = arg.map { acosh(it) } + + override fun atanh(arg: StructureND): ViktorStructureND = arg.map { atanh(it) } + + public companion object : ViktorFieldOpsND() +} + +public val DoubleField.viktorAlgebra: ViktorFieldOpsND get() = ViktorFieldOpsND + +public open class ViktorFieldND( + override val shape: Shape +) : ViktorFieldOpsND(), FieldND, NumbersAddOps> { + override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } + override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } + + override fun number(value: Number): ViktorStructureND = + F64Array.full(init = value.toDouble(), shape = shape).asStructure() +} + +public fun DoubleField.viktorAlgebra(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) + +public fun ViktorFieldND(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) \ No newline at end of file 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 a914542bc..0d29983f9 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 @@ -7,12 +7,8 @@ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64Array import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOps -import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.nd.DefaultStrides +import space.kscience.kmath.nd.MutableStructureND @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructureND { @@ -31,96 +27,4 @@ public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructur public fun F64Array.asStructure(): ViktorStructureND = ViktorStructureND(this) -@OptIn(UnstableKMathAPI::class) -@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public class ViktorFieldND(override val shape: IntArray) : FieldND, - NumbersAddOps>, ExtendedField>, - ScaleOperations> { - public val StructureND.f64Buffer: F64Array - get() = when { - !shape.contentEquals(this@ViktorFieldND.shape) -> throw ShapeMismatchException( - this@ViktorFieldND.shape, - shape - ) - this is ViktorStructureND && this.f64Buffer.shape.contentEquals(this@ViktorFieldND.shape) -> this.f64Buffer - else -> produce(shape) { this@f64Buffer[it] }.f64Buffer - } - - override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } - override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } - - private val strides: Strides = DefaultStrides(shape) - - override val elementAlgebra: DoubleField get() = DoubleField - - override fun produce(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = - F64Array(*shape).apply { - this@ViktorFieldND.strides.indices().forEach { index -> - set(value = DoubleField.initializer(index), indices = index) - } - }.asStructure() - - override fun StructureND.unaryMinus(): StructureND = -1 * this - - override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = - F64Array(*this@ViktorFieldND.shape).apply { - this@ViktorFieldND.strides.indices().forEach { index -> - set(value = DoubleField.transform(this@map[index]), indices = index) - } - }.asStructure() - - override fun StructureND.mapIndexed( - transform: DoubleField.(index: IntArray, Double) -> Double, - ): ViktorStructureND = F64Array(*this@ViktorFieldND.shape).apply { - this@ViktorFieldND.strides.indices().forEach { index -> - set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index) - } - }.asStructure() - - override fun zip( - left: StructureND, - right: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): ViktorStructureND = F64Array(*shape).apply { - this@ViktorFieldND.strides.indices().forEach { index -> - set(value = DoubleField.transform(left[index], right[index]), indices = index) - } - }.asStructure() - - override fun add(left: StructureND, right: StructureND): ViktorStructureND = - (left.f64Buffer + right.f64Buffer).asStructure() - - override fun scale(a: StructureND, value: Double): ViktorStructureND = - (a.f64Buffer * value).asStructure() - - override inline fun StructureND.plus(other: StructureND): ViktorStructureND = - (f64Buffer + other.f64Buffer).asStructure() - - override inline fun StructureND.minus(other: StructureND): ViktorStructureND = - (f64Buffer - other.f64Buffer).asStructure() - - override inline fun StructureND.times(k: Number): ViktorStructureND = - (f64Buffer * k.toDouble()).asStructure() - - override inline fun StructureND.plus(arg: Double): ViktorStructureND = - (f64Buffer.plus(arg)).asStructure() - - override fun number(value: Number): ViktorStructureND = - F64Array.full(init = value.toDouble(), shape = shape).asStructure() - - override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } - override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } - override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } - override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } - override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } - override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } - - override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } - - override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() - - override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() -} - -public fun ViktorFieldND(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) -- 2.34.1 From 6de43ee4bae0f224c44b798e82e00a60921d9b74 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 17 Oct 2021 13:52:40 +0300 Subject: [PATCH 036/102] update multik module --- .../src/main/kotlin/space/kscience/kmath/tensors/multik.kt | 3 +++ settings.gradle.kts | 1 + 2 files changed, 4 insertions(+) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt index 820a793ac..fc6d7dd56 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.tensors import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.linalg.dot +import org.jetbrains.kotlinx.multik.api.math.exp import org.jetbrains.kotlinx.multik.api.ndarray import org.jetbrains.kotlinx.multik.ndarray.operations.minus import org.jetbrains.kotlinx.multik.ndarray.operations.plus @@ -18,4 +19,6 @@ fun main() { 2 + (-a) - 2 a dot a + + a.exp() } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index dc70cbb9e..e73381bf2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -32,6 +32,7 @@ include( ":kmath-histograms", ":kmath-commons", ":kmath-viktor", + ":kmath-multik", ":kmath-optimization", ":kmath-stat", ":kmath-nd4j", -- 2.34.1 From 9b9fe07044ff25b8ebc8bb25b57d951bae02dd36 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 17 Oct 2021 16:42:46 +0300 Subject: [PATCH 037/102] Specialized operations for ND algebra --- .../kmath/operations/mixedNDOperations.kt | 24 ++++++++++++++++ .../DerivativeStructureExpression.kt | 8 +++--- .../kscience/kmath/complex/Quaternion.kt | 14 +++++----- .../space/kscience/kmath/nd/DoubleFieldND.kt | 28 +++++++++++++++++++ .../kmath/operations/NumericAlgebra.kt | 20 ++++++------- 5 files changed, 73 insertions(+), 21 deletions(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt new file mode 100644 index 000000000..628344ceb --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt @@ -0,0 +1,24 @@ +package space.kscience.kmath.operations + +import space.kscience.kmath.commons.linear.CMLinearSpace +import space.kscience.kmath.linear.matrix +import space.kscience.kmath.nd.DoubleBufferND +import space.kscience.kmath.nd.Shape +import space.kscience.kmath.nd.Structure2D +import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.viktor.ViktorStructureND +import space.kscience.kmath.viktor.viktorAlgebra + +fun main() { + val viktorStructure: ViktorStructureND = DoubleField.viktorAlgebra.produce(Shape(2, 2)) { (i, j) -> + if (i == j) 2.0 else 0.0 + } + + val cmMatrix: Structure2D = CMLinearSpace.matrix(2, 2)(0.0, 1.0, 0.0, 3.0) + + val res: DoubleBufferND = DoubleField.ndAlgebra { + exp(viktorStructure) + 2.0 * cmMatrix + } + + println(res) +} \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index d42e40d1e..4d2bd6237 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -99,10 +99,10 @@ public class DerivativeStructureField( override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() - override operator fun DerivativeStructure.plus(b: Number): DerivativeStructure = add(b.toDouble()) - override operator fun DerivativeStructure.minus(b: Number): DerivativeStructure = subtract(b.toDouble()) - override operator fun Number.plus(b: DerivativeStructure): DerivativeStructure = b + this - override operator fun Number.minus(b: DerivativeStructure): DerivativeStructure = b - this + override operator fun DerivativeStructure.plus(other: Number): DerivativeStructure = add(other.toDouble()) + override operator fun DerivativeStructure.minus(other: Number): DerivativeStructure = subtract(other.toDouble()) + override operator fun Number.plus(other: DerivativeStructure): DerivativeStructure = other + this + override operator fun Number.minus(other: DerivativeStructure): DerivativeStructure = other - this } /** 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 9fdd60e1f..47cc61313 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 @@ -158,16 +158,16 @@ public object QuaternionField : Field, Norm, return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z) } - override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z) + override operator fun Number.plus(other: Quaternion): Quaternion = Quaternion(toDouble() + other.w, other.x, other.y, other.z) - override operator fun Number.minus(b: Quaternion): Quaternion = - Quaternion(toDouble() - b.w, -b.x, -b.y, -b.z) + override operator fun Number.minus(other: Quaternion): Quaternion = + Quaternion(toDouble() - other.w, -other.x, -other.y, -other.z) - override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z) - override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.toDouble(), x, y, z) + override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z) + override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z) - override operator fun Number.times(b: Quaternion): Quaternion = - Quaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z) + override operator fun Number.times(other: Quaternion): Quaternion = + Quaternion(toDouble() * other.w, toDouble() * other.x, toDouble() * other.y, toDouble() * other.z) override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) 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 1502a6fd0..6235971a2 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 @@ -81,6 +81,34 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D override fun StructureND.div(other: StructureND): DoubleBufferND = zipInline(toBufferND(), other.toBufferND()) { l, r -> l / r } + override fun divide(left: StructureND, right: StructureND): DoubleBufferND = + zipInline(left.toBufferND(), right.toBufferND()) { l: Double, r: Double -> l / r } + + override fun StructureND.div(arg: Double): DoubleBufferND = + mapInline(toBufferND()) { it / arg } + + override fun Double.div(arg: StructureND): DoubleBufferND = + mapInline(arg.toBufferND()) { this / it } + + override fun StructureND.unaryPlus(): DoubleBufferND = toBufferND() + + override fun StructureND.plus(other: StructureND): DoubleBufferND = + zipInline(toBufferND(), other.toBufferND()) { l: Double, r: Double -> l + r } + + override fun StructureND.minus(other: StructureND): DoubleBufferND = + zipInline(toBufferND(), other.toBufferND()) { l: Double, r: Double -> l - r } + + override fun StructureND.times(other: StructureND): DoubleBufferND = + zipInline(toBufferND(), other.toBufferND()) { l: Double, r: Double -> l * r } + + override fun StructureND.times(k: Number): DoubleBufferND = + mapInline(toBufferND()) { it * k.toDouble() } + + override fun StructureND.div(k: Number): DoubleBufferND = + mapInline(toBufferND()) { it / k.toDouble() } + + override fun Number.times(other: StructureND): DoubleBufferND = other * this + override fun StructureND.plus(arg: Double): DoubleBufferND = mapInline(toBufferND()) { it + arg } override fun StructureND.minus(arg: Double): StructureND = mapInline(toBufferND()) { it - arg } 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 5f6848211..6be3449f9 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 @@ -139,10 +139,10 @@ public interface ScaleOperations : Algebra { * Multiplication of this number by element. * * @receiver the multiplier. - * @param b the multiplicand. + * @param other the multiplicand. * @return the product. */ - public operator fun Number.times(b: T): T = b * this + public operator fun Number.times(other: T): T = other * this } /** @@ -155,33 +155,33 @@ public interface NumbersAddOps : RingOps, NumericAlgebra { * Addition of element and scalar. * * @receiver the augend. - * @param b the addend. + * @param other the addend. */ - public operator fun T.plus(b: Number): T = this + number(b) + public operator fun T.plus(other: Number): T = this + number(other) /** * Addition of scalar and element. * * @receiver the augend. - * @param b the addend. + * @param other the addend. */ - public operator fun Number.plus(b: T): T = b + this + public operator fun Number.plus(other: T): T = other + this /** * Subtraction of element from number. * * @receiver the minuend. - * @param b the subtrahend. + * @param other the subtrahend. * @receiver the difference. */ - public operator fun T.minus(b: Number): T = this - number(b) + public operator fun T.minus(other: Number): T = this - number(other) /** * Subtraction of number from element. * * @receiver the minuend. - * @param b the subtrahend. + * @param other the subtrahend. * @receiver the difference. */ - public operator fun Number.minus(b: T): T = -b + this + public operator fun Number.minus(other: T): T = -other + this } \ No newline at end of file -- 2.34.1 From 827f115a9257235e8e36ee43af06937e2488eb75 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 17 Oct 2021 21:12:14 +0300 Subject: [PATCH 038/102] Multik wrapper --- benchmarks/build.gradle.kts | 1 + .../kmath/benchmarks/NDFieldBenchmark.kt | 24 +++- .../space/kscience/kmath/nd/ShapeIndex.kt | 15 +- .../kscience/kmath/multik/MultikOpsND.kt | 135 ++++++++++++++++++ .../kmath/multik/MultikTensorAlgebra.kt | 30 ++-- .../kscience/kmath/multik/MultikNDTest.kt | 13 ++ .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 5 +- .../tensors/core/tensorAlgebraExtensions.kt | 10 +- 8 files changed, 204 insertions(+), 29 deletions(-) create mode 100644 kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt create mode 100644 kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 686c491b9..cca3d312d 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -48,6 +48,7 @@ kotlin { implementation(project(":kmath-nd4j")) implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-viktor")) + implementation(projects.kmathMultik) implementation("org.nd4j:nd4j-native:1.0.0-M1") // uncomment if your system supports AVX2 // val os = System.getProperty("os.name") 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 7f7c03412..672aa4307 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -9,6 +9,7 @@ import kotlinx.benchmark.Benchmark import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State +import space.kscience.kmath.multik.multikND import space.kscience.kmath.nd.BufferedFieldOpsND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.ndAlgebra @@ -17,8 +18,9 @@ import space.kscience.kmath.nd4j.nd4j import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.Buffer import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.ones +import space.kscience.kmath.tensors.core.one import space.kscience.kmath.tensors.core.tensorAlgebra +import space.kscience.kmath.viktor.viktorAlgebra @State(Scope.Benchmark) internal class NDFieldBenchmark { @@ -43,16 +45,30 @@ internal class NDFieldBenchmark { blackhole.consume(res) } + @Benchmark + fun multikAdd(blackhole: Blackhole) = with(multikField) { + var res: StructureND = one(shape) + repeat(n) { res += 1.0 } + blackhole.consume(res) + } + + @Benchmark + fun viktorAdd(blackhole: Blackhole) = with(viktorField) { + var res: StructureND = one(shape) + repeat(n) { res += 1.0 } + blackhole.consume(res) + } + @Benchmark fun tensorAdd(blackhole: Blackhole) = with(Double.tensorAlgebra) { - var res: DoubleTensor = ones(dim, dim) + var res: DoubleTensor = one(shape) repeat(n) { res = res + 1.0 } blackhole.consume(res) } @Benchmark fun tensorInPlaceAdd(blackhole: Blackhole) = with(Double.tensorAlgebra) { - val res: DoubleTensor = ones(dim, dim) + val res: DoubleTensor = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -72,5 +88,7 @@ internal class NDFieldBenchmark { private val specializedField = DoubleField.ndAlgebra private val genericField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) private val nd4jField = DoubleField.nd4j + private val multikField = DoubleField.multikND + private val viktorField = DoubleField.viktorAlgebra } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt index bdbae70c2..a78bcfa70 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt @@ -105,16 +105,15 @@ public class DefaultStrides private constructor(override val shape: IntArray) : override fun hashCode(): Int = shape.contentHashCode() - @ThreadLocal - public companion object { - //private val defaultStridesCache = HashMap() + public companion object { /** * Cached builder for default strides */ - public operator fun invoke(shape: IntArray): Strides = DefaultStrides(shape) - //defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } - - //TODO fix cache + public operator fun invoke(shape: IntArray): Strides = + defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } } -} \ No newline at end of file +} + +@ThreadLocal +private val defaultStridesCache = HashMap() \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt new file mode 100644 index 000000000..d6996d427 --- /dev/null +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt @@ -0,0 +1,135 @@ +package space.kscience.kmath.multik + +import org.jetbrains.kotlinx.multik.api.mk +import org.jetbrains.kotlinx.multik.api.zeros +import org.jetbrains.kotlinx.multik.ndarray.data.* +import org.jetbrains.kotlinx.multik.ndarray.operations.* +import space.kscience.kmath.nd.FieldOpsND +import space.kscience.kmath.nd.RingOpsND +import space.kscience.kmath.nd.Shape +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.* + +/** + * A ring algebra for Multik operations + */ +public open class MultikRingOpsND> internal constructor( + public val type: DataType, + override val elementAlgebra: A +) : RingOpsND { + + protected fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) + + override fun produce(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { + val res = mk.zeros(shape, type).asDNArray() + for (index in res.multiIndices) { + res[index] = elementAlgebra.initializer(index) + } + return res.wrap() + } + + protected fun StructureND.asMultik(): MultikTensor = if (this is MultikTensor) { + this + } else { + produce(shape) { get(it) } + } + + override fun StructureND.map(transform: A.(T) -> T): MultikTensor { + //taken directly from Multik sources + val array = asMultik().array + val data = initMemoryView(array.size, type) + var count = 0 + for (el in array) data[count++] = elementAlgebra.transform(el) + return NDArray(data, shape = array.shape, dim = array.dim).wrap() + } + + override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): MultikTensor { + //taken directly from Multik sources + val array = asMultik().array + val data = initMemoryView(array.size, type) + val indexIter = array.multiIndices.iterator() + var index = 0 + for (item in array) { + if (indexIter.hasNext()) { + data[index++] = elementAlgebra.transform(indexIter.next(), item) + } else { + throw ArithmeticException("Index overflow has happened.") + } + } + return NDArray(data, shape = array.shape, dim = array.dim).wrap() + } + + override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): MultikTensor { + require(left.shape.contentEquals(right.shape)) { "ND array shape mismatch" } //TODO replace by ShapeMismatchException + val leftArray = left.asMultik().array + val rightArray = right.asMultik().array + val data = initMemoryView(leftArray.size, type) + var counter = 0 + val leftIterator = leftArray.iterator() + val rightIterator = rightArray.iterator() + //iterating them together + while (leftIterator.hasNext()) { + data[counter++] = elementAlgebra.transform(leftIterator.next(), rightIterator.next()) + } + return NDArray(data, shape = leftArray.shape, dim = leftArray.dim).wrap() + } + + override fun StructureND.unaryMinus(): MultikTensor = asMultik().array.unaryMinus().wrap() + + override fun add(left: StructureND, right: StructureND): MultikTensor = + (left.asMultik().array + right.asMultik().array).wrap() + + override fun StructureND.plus(arg: T): MultikTensor = + asMultik().array.plus(arg).wrap() + + override fun StructureND.minus(arg: T): MultikTensor = asMultik().array.minus(arg).wrap() + + override fun T.plus(arg: StructureND): MultikTensor = arg + this + + override fun T.minus(arg: StructureND): MultikTensor = arg.map { this@minus - it } + + override fun multiply(left: StructureND, right: StructureND): MultikTensor = + left.asMultik().array.times(right.asMultik().array).wrap() + + override fun StructureND.times(arg: T): MultikTensor = + asMultik().array.times(arg).wrap() + + override fun T.times(arg: StructureND): MultikTensor = arg * this + + override fun StructureND.unaryPlus(): MultikTensor = asMultik() + + override fun StructureND.plus(other: StructureND): MultikTensor = + asMultik().array.plus(other.asMultik().array).wrap() + + override fun StructureND.minus(other: StructureND): MultikTensor = + asMultik().array.minus(other.asMultik().array).wrap() + + override fun StructureND.times(other: StructureND): MultikTensor = + asMultik().array.times(other.asMultik().array).wrap() +} + +/** + * A field algebra for multik operations + */ +public class MultikFieldOpsND> internal constructor( + type: DataType, + elementAlgebra: A +) : MultikRingOpsND(type, elementAlgebra), FieldOpsND { + override fun StructureND.div(other: StructureND): StructureND = + asMultik().array.div(other.asMultik().array).wrap() +} + +public val DoubleField.multikND: MultikFieldOpsND + get() = MultikFieldOpsND(DataType.DoubleDataType, DoubleField) + +public val FloatField.multikND: MultikFieldOpsND + get() = MultikFieldOpsND(DataType.FloatDataType, FloatField) + +public val ShortRing.multikND: MultikRingOpsND + get() = MultikRingOpsND(DataType.ShortDataType, ShortRing) + +public val IntRing.multikND: MultikRingOpsND + get() = MultikRingOpsND(DataType.IntDataType, IntRing) + +public val LongRing.multikND: MultikRingOpsND + get() = MultikRingOpsND(DataType.LongDataType, LongRing) \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index b25d3ef56..e9e56e06e 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -5,6 +5,8 @@ package space.kscience.kmath.multik +import org.jetbrains.kotlinx.multik.api.mk +import org.jetbrains.kotlinx.multik.api.zeros import org.jetbrains.kotlinx.multik.ndarray.data.* import org.jetbrains.kotlinx.multik.ndarray.operations.* import space.kscience.kmath.misc.PerformancePitfall @@ -30,6 +32,7 @@ public value class MultikTensor(public val array: MutableMultiArray) : public abstract class MultikTensorAlgebra( + public val type: DataType, public val elementAlgebra: Ring, public val comparator: Comparator ) : TensorAlgebra { @@ -38,15 +41,19 @@ public abstract class MultikTensorAlgebra( * Convert a tensor to [MultikTensor] if necessary. If tensor is converted, changes on the resulting tensor * are not reflected back onto the source */ - public fun Tensor.asMultik(): MultikTensor { + private fun Tensor.asMultik(): MultikTensor { return if (this is MultikTensor) { this } else { - TODO() + val res = mk.zeros(shape, type).asDNArray() + for (index in res.multiIndices) { + res[index] = this[index] + } + res.wrap() } } - public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) + private fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) override fun Tensor.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) { get(intArrayOf(0)) @@ -77,8 +84,7 @@ public abstract class MultikTensorAlgebra( } } - //TODO avoid additional copy - override fun T.minus(other: Tensor): MultikTensor = -(other - this) + override fun T.minus(other: Tensor): MultikTensor = (-(other.asMultik().array - this)).wrap() override fun Tensor.minus(value: T): MultikTensor = asMultik().array.deepCopy().apply { minusAssign(value) }.wrap() @@ -130,13 +136,9 @@ public abstract class MultikTensorAlgebra( override fun Tensor.unaryMinus(): MultikTensor = asMultik().array.unaryMinus().wrap() - override fun Tensor.get(i: Int): MultikTensor { - TODO("Not yet implemented") - } + override fun Tensor.get(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() - override fun Tensor.transpose(i: Int, j: Int): MultikTensor { - TODO("Not yet implemented") - } + override fun Tensor.transpose(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() override fun Tensor.view(shape: IntArray): MultikTensor { require(shape.all { it > 0 }) @@ -158,16 +160,14 @@ public abstract class MultikTensorAlgebra( }.wrap() } - override fun Tensor.viewAs(other: Tensor): MultikTensor { - TODO("Not yet implemented") - } + override fun Tensor.viewAs(other: Tensor): MultikTensor = view(other.shape) override fun Tensor.dot(other: Tensor): MultikTensor { TODO("Not yet implemented") } override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): MultikTensor { - TODO("Not yet implemented") + TODO("Diagonal embedding not implemented") } override fun Tensor.sum(): T = asMultik().array.reduceMultiIndexed { _: IntArray, acc: T, t: T -> diff --git a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt new file mode 100644 index 000000000..9dd9854c7 --- /dev/null +++ b/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt @@ -0,0 +1,13 @@ +package space.kscience.kmath.multik + +import org.junit.jupiter.api.Test +import space.kscience.kmath.nd.one +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke + +internal class MultikNDTest { + @Test + fun basicAlgebra(): Unit = DoubleField.multikND{ + one(2,2) + 1.0 + } +} \ No newline at end of file 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 792890a2d..259b1a934 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 @@ -38,6 +38,7 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND.map(transform: C.(T) -> T): Nd4jArrayStructure { val newStruct = ndArray.dup().wrap() newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementAlgebra.transform(value) } @@ -117,7 +118,7 @@ public sealed interface Nd4jArrayRingOps> : RingOpsND, * Creates a most suitable implementation of [RingND] using reified class. */ @Suppress("UNCHECKED_CAST") - public inline fun auto(vararg shape: Int): Nd4jArrayRingOps> = when { + public inline fun auto(): Nd4jArrayRingOps> = when { T::class == Int::class -> IntRing.nd4j as Nd4jArrayRingOps> else -> throw UnsupportedOperationException("This factory method only supports Long type.") } @@ -142,7 +143,7 @@ public sealed interface Nd4jArrayField> : FieldOpsND, * Creates a most suitable implementation of [FieldND] using reified class. */ @Suppress("UNCHECKED_CAST") - public inline fun auto(vararg shape: Int): Nd4jArrayField> = when { + public inline fun auto(): Nd4jArrayField> = when { T::class == Float::class -> FloatField.nd4j as Nd4jArrayField> T::class == Double::class -> DoubleField.nd4j as Nd4jArrayField> else -> throw UnsupportedOperationException("This factory method only supports Float and Double types.") 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 b73f95054..916388ba9 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 @@ -5,4 +5,12 @@ package space.kscience.kmath.tensors.core -public fun DoubleTensorAlgebra.ones(vararg shape: Int): DoubleTensor = ones(intArrayOf(*shape)) \ No newline at end of file +import space.kscience.kmath.nd.Shape +import kotlin.jvm.JvmName + +@JvmName("varArgOne") +public fun DoubleTensorAlgebra.one(vararg shape: Int): DoubleTensor = ones(intArrayOf(*shape)) +public fun DoubleTensorAlgebra.one(shape: Shape): DoubleTensor = ones(shape) +@JvmName("varArgZero") +public fun DoubleTensorAlgebra.zero(vararg shape: Int): DoubleTensor = zeros(intArrayOf(*shape)) +public fun DoubleTensorAlgebra.zero(shape: Shape): DoubleTensor = zeros(shape) \ No newline at end of file -- 2.34.1 From a81ab474f73c2a6ce1ef3819d3c39df34c139065 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 18 Oct 2021 11:35:09 +0300 Subject: [PATCH 039/102] Add multik tensor factories and benchmarks --- .../kmath/benchmarks/NDFieldBenchmark.kt | 12 +++++++++ .../kmath/benchmarks/ViktorLogBenchmark.kt | 4 +-- .../kmath/functions/matrixIntegration.kt | 4 +-- .../kscience/kmath/operations/complexDemo.kt | 6 ++--- .../kmath/operations/mixedNDOperations.kt | 2 +- .../kscience/kmath/structures/ComplexND.kt | 4 +-- .../kmath/structures/StreamDoubleFieldND.kt | 8 +++--- .../kscience/kmath/complex/ComplexFieldND.kt | 2 +- .../kmath/linear/BufferedLinearSpace.kt | 2 +- .../kmath/linear/DoubleLinearSpace.kt | 2 +- .../space/kscience/kmath/nd/AlgebraND.kt | 10 ++++---- .../kscience/kmath/nd/BufferAlgebraND.kt | 10 ++++---- .../space/kscience/kmath/nd/DoubleFieldND.kt | 4 +-- .../space/kscience/kmath/nd/ShortRingND.kt | 2 +- .../kscience/kmath/nd/algebraNDExtentions.kt | 12 ++++----- .../kscience/kmath/structures/NDFieldTest.kt | 4 +-- .../kmath/structures/NumberNDFieldTest.kt | 4 +-- .../kscience/kmath/multik/MultikOpsND.kt | 8 +++--- .../kmath/multik/MultikTensorAlgebra.kt | 25 +++++++++++++++---- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 2 +- .../kmath/nd4j/Nd4jArrayAlgebraTest.kt | 8 +++--- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 2 +- .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 4 +-- 23 files changed, 84 insertions(+), 57 deletions(-) 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 672aa4307..8f9a3e2b8 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -9,7 +9,12 @@ import kotlinx.benchmark.Benchmark import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State +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.multik.multikND +import space.kscience.kmath.multik.multikTensorAlgebra import space.kscience.kmath.nd.BufferedFieldOpsND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.ndAlgebra @@ -73,6 +78,13 @@ internal class NDFieldBenchmark { blackhole.consume(res) } + @Benchmark + fun multikInPlaceAdd(blackhole: Blackhole) = with(DoubleField.multikTensorAlgebra) { + val res = Multik.ones(shape, DataType.DoubleDataType).wrap() + repeat(n) { res += 1.0 } + blackhole.consume(res) + } + // @Benchmark // fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) { // var res: StructureND = one(dim, dim) diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index ef2adaad8..a9d1e68fc 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -23,7 +23,7 @@ internal class ViktorLogBenchmark { @Benchmark fun realFieldLog(blackhole: Blackhole) { with(realField) { - val fortyTwo = produce(shape) { 42.0 } + val fortyTwo = structureND(shape) { 42.0 } var res = one(shape) repeat(n) { res = ln(fortyTwo) } blackhole.consume(res) @@ -33,7 +33,7 @@ internal class ViktorLogBenchmark { @Benchmark fun viktorFieldLog(blackhole: Blackhole) { with(viktorField) { - val fortyTwo = produce(shape) { 42.0 } + val fortyTwo = structureND(shape) { 42.0 } var res = one repeat(n) { res = ln(fortyTwo) } blackhole.consume(res) 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 609afb47e..4b6ac475c 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.integration.gaussIntegrator import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.produce +import space.kscience.kmath.nd.structureND import space.kscience.kmath.nd.withNdAlgebra import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.invoke @@ -18,7 +18,7 @@ fun main(): Unit = Double.algebra { withNdAlgebra(2, 2) { //Produce a diagonal StructureND - fun diagonal(v: Double) = produce { (i, j) -> + fun diagonal(v: Double) = structureND { (i, j) -> if (i == j) v else 0.0 } diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt index 67d83d77c..3b9c32f4b 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt @@ -11,7 +11,7 @@ import space.kscience.kmath.complex.bufferAlgebra import space.kscience.kmath.complex.ndAlgebra import space.kscience.kmath.nd.BufferND import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.produce +import space.kscience.kmath.nd.structureND fun main() = Complex.algebra { val complex = 2 + 2 * i @@ -24,14 +24,14 @@ fun main() = Complex.algebra { println(buffer) // 2d element - val element: BufferND = ndAlgebra.produce(2, 2) { (i, j) -> + val element: BufferND = ndAlgebra.structureND(2, 2) { (i, j) -> Complex(i - j, i + j) } println(element) // 1d element operation val result: StructureND = ndAlgebra{ - val a = produce(8) { (it) -> i * it - it.toDouble() } + val a = structureND(8) { (it) -> i * it - it.toDouble() } val b = 3 val c = Complex(1.0, 1.0) diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt index 628344ceb..f517046ee 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt @@ -10,7 +10,7 @@ import space.kscience.kmath.viktor.ViktorStructureND import space.kscience.kmath.viktor.viktorAlgebra fun main() { - val viktorStructure: ViktorStructureND = DoubleField.viktorAlgebra.produce(Shape(2, 2)) { (i, j) -> + val viktorStructure: ViktorStructureND = DoubleField.viktorAlgebra.structureND(Shape(2, 2)) { (i, j) -> if (i == j) 2.0 else 0.0 } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt index 42636fafb..61df3d065 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt @@ -12,7 +12,7 @@ import space.kscience.kmath.linear.transpose import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.produce +import space.kscience.kmath.nd.structureND import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import kotlin.system.measureTimeMillis @@ -55,7 +55,7 @@ fun complexExample() { val x = one * 2.5 operator fun Number.plus(other: Complex) = Complex(this.toDouble() + other.re, other.im) //a structure generator specific to this context - val matrix = produce { (k, l) -> k + l * i } + val matrix = structureND { (k, l) -> k + l * i } //Perform sum val sum = matrix + x + 1.0 diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt index dfd06973e..2b3e72136 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -22,12 +22,12 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND by lazy { produce(shape) { zero } } - override val one: BufferND by lazy { produce(shape) { one } } + override val zero: BufferND by lazy { structureND(shape) { zero } } + override val one: BufferND by lazy { structureND(shape) { one } } override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions - return produce(shape) { d } + return structureND(shape) { d } } private val StructureND.buffer: DoubleBuffer @@ -40,7 +40,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } } - override fun produce(shape: Shape, initializer: DoubleField.(IntArray) -> Double): BufferND { + override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> val index = strides.index(offset) DoubleField.initializer(index) 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 3951b5de0..9d5b1cddd 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 @@ -67,7 +67,7 @@ public class ComplexFieldND(override val shape: Shape) : override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions - return produce(shape) { d.toComplex() } + return structureND(shape) { d.toComplex() } } } 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 39dbe3a81..f72b9bd81 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 @@ -24,7 +24,7 @@ public class BufferedLinearSpace>( private val ndAlgebra = BufferedRingOpsND(bufferAlgebra) override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix = - ndAlgebra.produce(intArrayOf(rows, columns)) { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() + ndAlgebra.structureND(intArrayOf(rows, columns)) { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() override fun buildVector(size: Int, initializer: A.(Int) -> T): Point = bufferAlgebra.buffer(size) { elementAlgebra.initializer(it) } 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 ec6040af0..91db33bce 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 @@ -23,7 +23,7 @@ public object DoubleLinearSpace : LinearSpace { rows: Int, columns: Int, initializer: DoubleField.(i: Int, j: Int) -> Double - ): Matrix = DoubleFieldOpsND.produce(intArrayOf(rows, columns)) { (i, j) -> + ): Matrix = DoubleFieldOpsND.structureND(intArrayOf(rows, columns)) { (i, j) -> DoubleField.initializer(i, j) }.as2D() 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 b4e8b7487..30cb01146 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 @@ -39,9 +39,9 @@ public interface AlgebraND> { public val elementAlgebra: C /** - * Produces a new NDStructure using given initializer function. + * Produces a new [StructureND] using given initializer function. */ - public fun produce(shape: Shape, initializer: C.(IntArray) -> T): StructureND + public fun structureND(shape: Shape, initializer: C.(IntArray) -> T): StructureND /** * Maps elements from one structure to another one by applying [transform] to them. @@ -149,7 +149,7 @@ public interface GroupOpsND> : GroupOps>, } public interface GroupND> : Group>, GroupOpsND, WithShape { - override val zero: StructureND get() = produce(shape) { elementAlgebra.zero } + override val zero: StructureND get() = structureND(shape) { elementAlgebra.zero } } /** @@ -193,7 +193,7 @@ public interface RingOpsND> : RingOps>, Gro } public interface RingND> : Ring>, RingOpsND, GroupND, WithShape { - override val one: StructureND get() = produce(shape) { elementAlgebra.one } + override val one: StructureND get() = structureND(shape) { elementAlgebra.one } } @@ -240,5 +240,5 @@ public interface FieldOpsND> : } public interface FieldND> : Field>, FieldOpsND, RingND, WithShape { - override val one: StructureND get() = produce(shape) { elementAlgebra.one } + override val one: StructureND get() = structureND(shape) { elementAlgebra.one } } \ No newline at end of file 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 c94988eef..1f231ce9f 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 @@ -16,7 +16,7 @@ public interface BufferAlgebraND> : AlgebraND { public val bufferAlgebra: BufferAlgebra override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra - override fun produce(shape: Shape, initializer: A.(IntArray) -> T): BufferND { + override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): BufferND { val indexer = indexerBuilder(shape) return BufferND( indexer, @@ -109,14 +109,14 @@ public val > BufferAlgebra.nd: BufferedRingOpsND get( public val > BufferAlgebra.nd: BufferedFieldOpsND get() = BufferedFieldOpsND(this) -public fun > BufferAlgebraND.produce( +public fun > BufferAlgebraND.structureND( vararg shape: Int, initializer: A.(IntArray) -> T -): BufferND = produce(shape, initializer) +): BufferND = structureND(shape, initializer) -public fun , A> A.produce( +public fun , A> A.structureND( initializer: EA.(IntArray) -> T -): BufferND where A : BufferAlgebraND, A : WithShape = produce(shape, initializer) +): BufferND where A : BufferAlgebraND, A : WithShape = structureND(shape, initializer) //// group factories //public fun > A.ndAlgebra( 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 6235971a2..961f5869a 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 @@ -60,7 +60,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D transform: DoubleField.(Double, Double) -> Double ): BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> DoubleField.transform(l, r) } - override fun produce(shape: Shape, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND { + override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND { val indexer = indexerBuilder(shape) return DoubleBufferND( indexer, @@ -174,7 +174,7 @@ public class DoubleFieldND(override val shape: Shape) : override fun number(value: Number): DoubleBufferND { val d = value.toDouble() // minimize conversions - return produce(shape) { d } + return structureND(shape) { d } } } 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 65c1f71b4..827f0e21e 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 @@ -23,7 +23,7 @@ public class ShortRingND( override fun number(value: Number): BufferND { val d = value.toShort() // minimize conversions - return produce(shape) { d } + return structureND(shape) { d } } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt index 7bc18a4dd..0e694bcb3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt @@ -11,24 +11,24 @@ import space.kscience.kmath.operations.Ring import kotlin.jvm.JvmName -public fun > AlgebraND.produce( +public fun > AlgebraND.structureND( shapeFirst: Int, vararg shapeRest: Int, initializer: A.(IntArray) -> T -): StructureND = produce(Shape(shapeFirst, *shapeRest), initializer) +): StructureND = structureND(Shape(shapeFirst, *shapeRest), initializer) -public fun > AlgebraND.zero(shape: Shape): StructureND = produce(shape) { zero } +public fun > AlgebraND.zero(shape: Shape): StructureND = structureND(shape) { zero } @JvmName("zeroVarArg") public fun > AlgebraND.zero( shapeFirst: Int, vararg shapeRest: Int, -): StructureND = produce(shapeFirst, *shapeRest) { zero } +): StructureND = structureND(shapeFirst, *shapeRest) { zero } -public fun > AlgebraND.one(shape: Shape): StructureND = produce(shape) { one } +public fun > AlgebraND.one(shape: Shape): StructureND = structureND(shape) { one } @JvmName("oneVarArg") public fun > AlgebraND.one( shapeFirst: Int, vararg shapeRest: Int, -): StructureND = produce(shapeFirst, *shapeRest) { one } \ No newline at end of file +): StructureND = structureND(shapeFirst, *shapeRest) { one } \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt index 2009eb64f..82172af62 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.structures import space.kscience.kmath.nd.get import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.produce +import space.kscience.kmath.nd.structureND import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import space.kscience.kmath.testutils.FieldVerifier @@ -22,7 +22,7 @@ internal class NDFieldTest { @Test fun testStrides() { - val ndArray = DoubleField.ndAlgebra.produce(10, 10) { (it[0] + it[1]).toDouble() } + val ndArray = DoubleField.ndAlgebra.structureND(10, 10) { (it[0] + it[1]).toDouble() } assertEquals(ndArray[5, 5], 10.0) } } 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 907301a53..61eb6acc8 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 @@ -20,8 +20,8 @@ import kotlin.test.assertEquals @Suppress("UNUSED_VARIABLE") class NumberNDFieldTest { val algebra = DoubleField.ndAlgebra - val array1 = algebra.produce(3, 3) { (i, j) -> (i + j).toDouble() } - val array2 = algebra.produce(3, 3) { (i, j) -> (i - j).toDouble() } + val array1 = algebra.structureND(3, 3) { (i, j) -> (i + j).toDouble() } + val array2 = algebra.structureND(3, 3) { (i, j) -> (i - j).toDouble() } @Test fun testSum() { diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt index d6996d427..9ee5087e9 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt @@ -18,9 +18,9 @@ public open class MultikRingOpsND> internal constructor( override val elementAlgebra: A ) : RingOpsND { - protected fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) + public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) - override fun produce(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { + override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { val res = mk.zeros(shape, type).asDNArray() for (index in res.multiIndices) { res[index] = elementAlgebra.initializer(index) @@ -28,10 +28,10 @@ public open class MultikRingOpsND> internal constructor( return res.wrap() } - protected fun StructureND.asMultik(): MultikTensor = if (this is MultikTensor) { + public fun StructureND.asMultik(): MultikTensor = if (this is MultikTensor) { this } else { - produce(shape) { get(it) } + structureND(shape) { get(it) } } override fun StructureND.map(transform: A.(T) -> T): MultikTensor { diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index e9e56e06e..c229a44bf 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlinx.multik.ndarray.data.* import org.jetbrains.kotlinx.multik.ndarray.operations.* import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.mapInPlace -import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.* import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra @@ -31,7 +31,7 @@ public value class MultikTensor(public val array: MutableMultiArray) : } -public abstract class MultikTensorAlgebra( +public class MultikTensorAlgebra internal constructor( public val type: DataType, public val elementAlgebra: Ring, public val comparator: Comparator @@ -41,7 +41,7 @@ public abstract class MultikTensorAlgebra( * Convert a tensor to [MultikTensor] if necessary. If tensor is converted, changes on the resulting tensor * are not reflected back onto the source */ - private fun Tensor.asMultik(): MultikTensor { + public fun Tensor.asMultik(): MultikTensor { return if (this is MultikTensor) { this } else { @@ -53,7 +53,7 @@ public abstract class MultikTensorAlgebra( } } - private fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) + public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) override fun Tensor.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) { get(intArrayOf(0)) @@ -196,4 +196,19 @@ public abstract class MultikTensorAlgebra( override fun Tensor.argMax(dim: Int, keepDim: Boolean): MultikTensor { TODO("Not yet implemented") } -} \ No newline at end of file +} + +public val DoubleField.multikTensorAlgebra: MultikTensorAlgebra + get() = MultikTensorAlgebra(DataType.DoubleDataType, DoubleField) { o1, o2 -> o1.compareTo(o2) } + +public val FloatField.multikTensorAlgebra: MultikTensorAlgebra + get() = MultikTensorAlgebra(DataType.FloatDataType, FloatField) { o1, o2 -> o1.compareTo(o2) } + +public val ShortRing.multikTensorAlgebra: MultikTensorAlgebra + get() = MultikTensorAlgebra(DataType.ShortDataType, ShortRing) { o1, o2 -> o1.compareTo(o2) } + +public val IntRing.multikTensorAlgebra: MultikTensorAlgebra + get() = MultikTensorAlgebra(DataType.IntDataType, IntRing) { o1, o2 -> o1.compareTo(o2) } + +public val LongRing.multikTensorAlgebra: MultikTensorAlgebra + get() = MultikTensorAlgebra(DataType.LongDataType, LongRing) { o1, o2 -> o1.compareTo(o2) } \ No newline at end of file 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 259b1a934..1f312849a 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 @@ -32,7 +32,7 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND.ndArray: INDArray - override fun produce(shape: Shape, initializer: C.(IntArray) -> T): Nd4jArrayStructure { + override fun structureND(shape: Shape, initializer: C.(IntArray) -> T): Nd4jArrayStructure { val struct = Nd4j.create(*shape)!!.wrap() struct.indicesIterator().forEach { struct[it] = elementAlgebra.initializer(it) } return struct 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 465937fa9..103416120 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 @@ -9,7 +9,7 @@ import org.nd4j.linalg.factory.Nd4j import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.one -import space.kscience.kmath.nd.produce +import space.kscience.kmath.nd.structureND import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing import space.kscience.kmath.operations.invoke @@ -23,7 +23,7 @@ import kotlin.test.fail internal class Nd4jArrayAlgebraTest { @Test fun testProduce() { - val res = DoubleField.nd4j.produce(2, 2) { it.sum().toDouble() } + val res = DoubleField.nd4j.structureND(2, 2) { it.sum().toDouble() } val expected = (Nd4j.create(2, 2) ?: fail()).asDoubleStructure() expected[intArrayOf(0, 0)] = 0.0 expected[intArrayOf(0, 1)] = 1.0 @@ -58,9 +58,9 @@ internal class Nd4jArrayAlgebraTest { @Test fun testSin() = DoubleField.nd4j{ - val initial = produce(2, 2) { (i, j) -> if (i == j) PI / 2 else 0.0 } + val initial = structureND(2, 2) { (i, j) -> if (i == j) PI / 2 else 0.0 } val transformed = sin(initial) - val expected = produce(2, 2) { (i, j) -> if (i == j) 1.0 else 0.0 } + val expected = structureND(2, 2) { (i, j) -> if (i == j) 1.0 else 0.0 } println(transformed) assertTrue { StructureND.contentEquals(transformed, expected) } 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 594070cd2..16ed4b834 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 @@ -22,7 +22,7 @@ import kotlin.math.* public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra, AnalyticTensorAlgebra, - LinearOpsTensorAlgebra { + LinearOpsTensorAlgebra{ public companion object : DoubleTensorAlgebra() 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 c72553a64..aaa113e56 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 @@ -21,12 +21,12 @@ public open class ViktorFieldOpsND : public val StructureND.f64Buffer: F64Array get() = when (this) { is ViktorStructureND -> this.f64Buffer - else -> produce(shape) { this@f64Buffer[it] }.f64Buffer + else -> structureND(shape) { this@f64Buffer[it] }.f64Buffer } override val elementAlgebra: DoubleField get() = DoubleField - override fun produce(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = + override fun structureND(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = F64Array(*shape).apply { DefaultStrides(shape).indices().forEach { index -> set(value = DoubleField.initializer(index), indices = index) -- 2.34.1 From dccc92bf2fd9f979e70386a25d1ff1db231d368f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 18 Oct 2021 12:52:24 +0300 Subject: [PATCH 040/102] Switch to multik-default --- .../kotlin/space/kscience/kmath/tensors/multik.kt | 14 +++++++------- kmath-multik/build.gradle.kts | 2 +- .../space/kscience/kmath/multik/MultikOpsND.kt | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt index fc6d7dd56..5383b5c3e 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.tensors +import edu.mcgill.kaliningraph.power import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.linalg.dot import org.jetbrains.kotlinx.multik.api.math.exp @@ -12,13 +13,12 @@ import org.jetbrains.kotlinx.multik.api.ndarray import org.jetbrains.kotlinx.multik.ndarray.operations.minus import org.jetbrains.kotlinx.multik.ndarray.operations.plus import org.jetbrains.kotlinx.multik.ndarray.operations.unaryMinus +import space.kscience.kmath.multik.multikND +import space.kscience.kmath.nd.one +import space.kscience.kmath.operations.DoubleField -fun main() { - val a = Multik.ndarray(intArrayOf(1, 2, 3)) +fun main(): Unit = with(DoubleField.multikND) { + val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType().wrap() val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)) - 2 + (-a) - 2 - - a dot a - - a.exp() + one(a.shape) - a + power() } \ No newline at end of file diff --git a/kmath-multik/build.gradle.kts b/kmath-multik/build.gradle.kts index 16a7ab652..df2292f2e 100644 --- a/kmath-multik/build.gradle.kts +++ b/kmath-multik/build.gradle.kts @@ -6,7 +6,7 @@ description = "JetBrains Multik connector" dependencies { api(project(":kmath-tensors")) - api("org.jetbrains.kotlinx:multik-api:0.1.0") + api("org.jetbrains.kotlinx:multik-default:0.1.0") } readme { diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt index 9ee5087e9..4068ba9b9 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt @@ -1,5 +1,7 @@ package space.kscience.kmath.multik +import org.jetbrains.kotlinx.multik.api.math.cos +import org.jetbrains.kotlinx.multik.api.math.sin import org.jetbrains.kotlinx.multik.api.mk import org.jetbrains.kotlinx.multik.api.zeros import org.jetbrains.kotlinx.multik.ndarray.data.* @@ -18,7 +20,7 @@ public open class MultikRingOpsND> internal constructor( override val elementAlgebra: A ) : RingOpsND { - public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) + public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this.asDNArray()) override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { val res = mk.zeros(shape, type).asDNArray() -- 2.34.1 From bfc6cbe5d8fdda11db1ffd8dd6da73271a184eaa Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 18 Oct 2021 13:04:36 +0300 Subject: [PATCH 041/102] Update multik.kt --- .../src/main/kotlin/space/kscience/kmath/tensors/multik.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt index 5383b5c3e..b1cf435d4 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt @@ -20,5 +20,5 @@ import space.kscience.kmath.operations.DoubleField fun main(): Unit = with(DoubleField.multikND) { val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType().wrap() val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)) - one(a.shape) - a + power() -} \ No newline at end of file + one(a.shape) - a +} -- 2.34.1 From 98bbc8349c54d871bd0fffe07a704957ebdd580a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 18 Oct 2021 13:18:10 +0300 Subject: [PATCH 042/102] 0.3.0-dev-17 --- build.gradle.kts | 2 +- .../main/kotlin/space/kscience/kmath/tensors/multik.kt | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 665c057e9..c2347f7be 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,7 +19,7 @@ allprojects { } group = "space.kscience" - version = "0.3.0-dev-16" + version = "0.3.0-dev-17" } subprojects { diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt index b1cf435d4..f0b776f75 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt @@ -5,20 +5,14 @@ package space.kscience.kmath.tensors -import edu.mcgill.kaliningraph.power import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.linalg.dot -import org.jetbrains.kotlinx.multik.api.math.exp import org.jetbrains.kotlinx.multik.api.ndarray -import org.jetbrains.kotlinx.multik.ndarray.operations.minus -import org.jetbrains.kotlinx.multik.ndarray.operations.plus -import org.jetbrains.kotlinx.multik.ndarray.operations.unaryMinus import space.kscience.kmath.multik.multikND import space.kscience.kmath.nd.one import space.kscience.kmath.operations.DoubleField fun main(): Unit = with(DoubleField.multikND) { val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType().wrap() - val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)) - one(a.shape) - a + val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)).wrap() + one(a.shape) - a + b * 3 } -- 2.34.1 From 40c02f4bd719cad22fe4586471f398092c4686b0 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 19 Oct 2021 10:50:13 +0300 Subject: [PATCH 043/102] Add multik dot for tensors --- .../kmath/multik/MultikTensorAlgebra.kt | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index c229a44bf..ed5575b93 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -3,9 +3,14 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ +@file:Suppress("unused") + package space.kscience.kmath.multik +import org.jetbrains.kotlinx.multik.api.Multik +import org.jetbrains.kotlinx.multik.api.linalg.dot import org.jetbrains.kotlinx.multik.api.mk +import org.jetbrains.kotlinx.multik.api.ndarrayOf import org.jetbrains.kotlinx.multik.api.zeros import org.jetbrains.kotlinx.multik.ndarray.data.* import org.jetbrains.kotlinx.multik.ndarray.operations.* @@ -30,8 +35,20 @@ public value class MultikTensor(public val array: MutableMultiArray) : } } +private fun MultiArray.asD1Array(): D1Array { + if (this is NDArray) + return this.asD1Array() + else throw ClassCastException("Cannot cast MultiArray to NDArray.") +} -public class MultikTensorAlgebra internal constructor( + +private fun MultiArray.asD2Array(): D2Array { + if (this is NDArray) + return this.asD2Array() + else throw ClassCastException("Cannot cast MultiArray to NDArray.") +} + +public class MultikTensorAlgebra internal constructor( public val type: DataType, public val elementAlgebra: Ring, public val comparator: Comparator @@ -162,9 +179,18 @@ public class MultikTensorAlgebra internal constructor( override fun Tensor.viewAs(other: Tensor): MultikTensor = view(other.shape) - override fun Tensor.dot(other: Tensor): MultikTensor { - TODO("Not yet implemented") - } + override fun Tensor.dot(other: Tensor): MultikTensor = + if (this.shape.size == 1 && other.shape.size == 1) { + Multik.ndarrayOf( + asMultik().array.asD1Array() dot other.asMultik().array.asD1Array() + ).asDNArray().wrap() + } else if (this.shape.size == 2 && other.shape.size == 2) { + (asMultik().array.asD2Array() dot other.asMultik().array.asD2Array()).asDNArray().wrap() + } else if(this.shape.size == 2 && other.shape.size == 1) { + (asMultik().array.asD2Array() dot other.asMultik().array.asD1Array()).asDNArray().wrap() + } else { + TODO("Not implemented for broadcasting") + } override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): MultikTensor { TODO("Diagonal embedding not implemented") -- 2.34.1 From 6c4741ede6558f53e5b90e35f934ba0a83ceb13a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 20 Oct 2021 16:06:45 +0300 Subject: [PATCH 044/102] [WIP] TensorFlow --- kmath-tensorflow/build.gradle.kts | 14 ++ .../kmath/tensorflow/TensorFlowAlgebra.kt | 220 ++++++++++++++++++ settings.gradle.kts | 1 + 3 files changed, 235 insertions(+) create mode 100644 kmath-tensorflow/build.gradle.kts create mode 100644 kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt diff --git a/kmath-tensorflow/build.gradle.kts b/kmath-tensorflow/build.gradle.kts new file mode 100644 index 000000000..fa77a272a --- /dev/null +++ b/kmath-tensorflow/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("ru.mipt.npm.gradle.jvm") +} + +description = "Google tensorflow connector" + +dependencies { + api(project(":kmath-tensors")) + api("org.tensorflow:tensorflow-core-api:0.3.3") +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE +} \ No newline at end of file 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 new file mode 100644 index 000000000..849a2e909 --- /dev/null +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -0,0 +1,220 @@ +package space.kscience.kmath.tensorflow + + +import org.tensorflow.Graph +import org.tensorflow.Operand +import org.tensorflow.Output +import org.tensorflow.Session +import org.tensorflow.ndarray.NdArray +import org.tensorflow.op.Ops +import org.tensorflow.op.core.Constant +import org.tensorflow.types.family.TType +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.nd.Shape +import space.kscience.kmath.tensors.api.Tensor +import space.kscience.kmath.tensors.api.TensorAlgebra + +private fun IntArray.toLongArray() = LongArray(size) { get(it).toLong() } +private fun LongArray.toIntArray() = IntArray(size) { get(it).toInt() } + +private val NdArray.scalar: T + get() = getObject() + + +public sealed interface TensorFlowTensor : Tensor + +@JvmInline +public value class TensorFlowArray(public val tensor: NdArray) : Tensor { + override val shape: Shape get() = tensor.shape().asArray().toIntArray() + + override fun get(index: IntArray): T = tensor.getObject(*index.toLongArray()) + + @PerformancePitfall + override fun elements(): Sequence> = sequence { + tensor.scalars().forEachIndexed { index: LongArray, ndArray: NdArray -> + //yield(index.toIntArray() to ndArray.scalar) + TODO() + } + } + + override fun set(index: IntArray, value: T) { + tensor.setObject(value, *index.toLongArray()) + } +} + +public abstract class TensorFlowOutput( + private val graph: Graph, + output: Output +) : TensorFlowTensor { + + public var output: Output = output + internal set + + override val shape: Shape get() = output.shape().asArray().toIntArray() + + protected abstract fun org.tensorflow.Tensor.actualizeTensor(): NdArray + + private val actualTensor by lazy { + val session = Session(graph) + TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor()) + } + + override fun get(index: IntArray): T = actualTensor[index] + + @PerformancePitfall + override fun elements(): Sequence> = actualTensor.elements() + + override fun set(index: IntArray, value: T) { + actualTensor[index] = value + } + +} + + +public abstract class TensorFlowAlgebra internal constructor( + private val graph: Graph +) : TensorAlgebra { + + private val ops by lazy { Ops.create(graph) } + + protected fun Tensor.asTensorFlow(): TensorFlowOutput = if (this is TensorFlowOutput) this else { + TODO() + } + + protected abstract fun Output.wrap(): TensorFlowOutput + + protected abstract fun const(value: T): Constant + + override fun Tensor.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) + get(Shape(0)) else null + + private inline fun Tensor.biOp( + other: Tensor, + operation: (left: Operand, right: Operand) -> Operand + ): TensorFlowOutput { + val left = asTensorFlow().output + val right = other.asTensorFlow().output + return operation(left, right).asOutput().wrap() + } + + private inline fun T.biOp( + other: Tensor, + operation: (left: Operand, right: Operand) -> Operand + ): TensorFlowOutput { + val left = const(this) + val right = other.asTensorFlow().output + return operation(left, right).asOutput().wrap() + } + + private inline fun Tensor.biOp( + value: T, + operation: (left: Operand, right: Operand) -> Operand + ): TensorFlowOutput { + val left = asTensorFlow().output + val right = const(value) + return operation(left, right).asOutput().wrap() + } + + private inline fun Tensor.inPlaceOp( + other: Tensor, + operation: (left: Operand, right: Operand) -> Operand + ): Unit { + val origin = asTensorFlow() + val left = origin.output + val right = other.asTensorFlow().output + origin.output = operation(left, right).asOutput() + } + + private inline fun Tensor.inPlaceOp( + value: T, + operation: (left: Operand, right: Operand) -> Operand + ): Unit { + val origin = asTensorFlow() + val left = origin.output + val right = const(value) + origin.output = operation(left, right).asOutput() + } + + private inline fun unOp(value: Tensor, operation: (Operand) -> Operand): TensorFlowOutput = + operation(value.asTensorFlow().output).asOutput().wrap() + + override fun T.plus(other: Tensor) = biOp(other, ops.math::add) + + override fun Tensor.plus(value: T) = biOp(value, ops.math::add) + + override fun Tensor.plus(other: Tensor) = biOp(other, ops.math::add) + + override fun Tensor.plusAssign(value: T): Unit = inPlaceOp(value, ops.math::add) + + override fun Tensor.plusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::add) + + override fun Tensor.minus(value: T) = biOp(value, ops.math::sub) + + override fun Tensor.minus(other: Tensor) = biOp(other, ops.math::sub) + + override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) + + override fun Tensor.minusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::sub) + + override fun T.times(other: Tensor) = biOp(other, ops.math::mul) + + override fun Tensor.times(value: T) = biOp(value, ops.math::mul) + + override fun Tensor.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) + + override fun Tensor.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul) + + override fun Tensor.timesAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::mul) + + override fun Tensor.unaryMinus() = unOp(this, ops.math::neg) + + override fun Tensor.get(i: Int): Tensor{ + ops. + } + + override fun Tensor.transpose(i: Int, j: Int): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.view(shape: IntArray): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.viewAs(other: Tensor): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.dot(other: Tensor) = biOp(other, ops.math.) + + override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): Tensor = ops.run { + TODO("Not yet implemented") + } + + override fun Tensor.sum(): T { + TODO("Not yet implemented") + } + + override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.min(): T { + TODO("Not yet implemented") + } + + override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.max(): T { + TODO("Not yet implemented") + } + + override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index e73381bf2..a29f33824 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,6 +33,7 @@ include( ":kmath-commons", ":kmath-viktor", ":kmath-multik", + ":kmath-tensorflow", ":kmath-optimization", ":kmath-stat", ":kmath-nd4j", -- 2.34.1 From 69e6849a129453d00f855ee60ff76432dceb8e18 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 20 Oct 2021 16:11:36 +0300 Subject: [PATCH 045/102] Name refactoring for tensors --- .../kscience/kmath/nd/BufferAlgebraND.kt | 12 +++++------ .../space/kscience/kmath/nd/BufferND.kt | 4 ++-- .../space/kscience/kmath/nd/DoubleFieldND.kt | 2 +- .../nd/{ShapeIndex.kt => ShapeIndexer.kt} | 4 ++-- .../space/kscience/kmath/nd/Structure2D.kt | 20 +++++++++---------- .../space/kscience/kmath/nd/StructureND.kt | 2 +- .../kmath/multik/MultikTensorAlgebra.kt | 3 ++- 7 files changed, 24 insertions(+), 23 deletions(-) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/{ShapeIndex.kt => ShapeIndexer.kt} (95%) 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 1f231ce9f..859edefb8 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 @@ -12,7 +12,7 @@ import space.kscience.kmath.operations.* import space.kscience.kmath.structures.BufferFactory public interface BufferAlgebraND> : AlgebraND { - public val indexerBuilder: (IntArray) -> ShapeIndex + public val indexerBuilder: (IntArray) -> ShapeIndexer public val bufferAlgebra: BufferAlgebra override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra @@ -43,7 +43,7 @@ public interface BufferAlgebraND> : AlgebraND { zipInline(left.toBufferND(), right.toBufferND(), transform) public companion object { - public val defaultIndexerBuilder: (IntArray) -> ShapeIndex = DefaultStrides.Companion::invoke + public val defaultIndexerBuilder: (IntArray) -> ShapeIndexer = DefaultStrides.Companion::invoke } } @@ -80,25 +80,25 @@ internal inline fun > BufferAlgebraND.zipInline( public open class BufferedGroupNDOps>( override val bufferAlgebra: BufferAlgebra, - override val indexerBuilder: (IntArray) -> ShapeIndex = BufferAlgebraND.defaultIndexerBuilder + override val indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder ) : GroupOpsND, BufferAlgebraND { override fun StructureND.unaryMinus(): StructureND = map { -it } } public open class BufferedRingOpsND>( bufferAlgebra: BufferAlgebra, - indexerBuilder: (IntArray) -> ShapeIndex = BufferAlgebraND.defaultIndexerBuilder + indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder ) : BufferedGroupNDOps(bufferAlgebra, indexerBuilder), RingOpsND public open class BufferedFieldOpsND>( bufferAlgebra: BufferAlgebra, - indexerBuilder: (IntArray) -> ShapeIndex = BufferAlgebraND.defaultIndexerBuilder + indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder ) : BufferedRingOpsND(bufferAlgebra, indexerBuilder), FieldOpsND { public constructor( elementAlgebra: A, bufferFactory: BufferFactory, - indexerBuilder: (IntArray) -> ShapeIndex = BufferAlgebraND.defaultIndexerBuilder + indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder ) : this(BufferFieldOps(elementAlgebra, bufferFactory), indexerBuilder) override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } 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 c17632101..afa8f8250 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 @@ -19,7 +19,7 @@ import space.kscience.kmath.structures.MutableBufferFactory * @param buffer The underlying buffer. */ public open class BufferND( - public val indexes: ShapeIndex, + public val indexes: ShapeIndexer, public open val buffer: Buffer, ) : StructureND { @@ -58,7 +58,7 @@ public inline fun StructureND.mapToBuffer( * @param buffer The underlying buffer. */ public class MutableBufferND( - strides: ShapeIndex, + strides: ShapeIndexer, override val buffer: MutableBuffer, ) : MutableStructureND, BufferND(strides, buffer) { override fun set(index: IntArray, value: T) { 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 961f5869a..853ac43b0 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 @@ -13,7 +13,7 @@ import kotlin.contracts.contract import kotlin.math.pow public class DoubleBufferND( - indexes: ShapeIndex, + indexes: ShapeIndexer, override val buffer: DoubleBuffer, ) : BufferND(indexes, buffer) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt similarity index 95% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt index a78bcfa70..1ce6b7519 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndex.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt @@ -10,7 +10,7 @@ import kotlin.native.concurrent.ThreadLocal /** * A converter from linear index to multivariate index */ -public interface ShapeIndex{ +public interface ShapeIndexer{ public val shape: Shape /** @@ -42,7 +42,7 @@ public interface ShapeIndex{ /** * Linear transformation of indexes */ -public abstract class Strides: ShapeIndex { +public abstract class Strides: ShapeIndexer { /** * Array strides */ 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 8d3cc3a3f..e3552c02e 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 @@ -85,7 +85,7 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { */ @PerformancePitfall override val rows: List> - get() = List(rowNum) { i -> MutableBuffer1DWrapper(MutableListBuffer(colNum) { j -> get(i, j) })} + get() = List(rowNum) { i -> MutableBuffer1DWrapper(MutableListBuffer(colNum) { j -> get(i, j) }) } /** * The buffer of columns of this structure. It gets elements from the structure dynamically. @@ -100,7 +100,7 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { */ @JvmInline private value class Structure2DWrapper(val structure: StructureND) : Structure2D { - override val shape: IntArray get() = structure.shape + override val shape: Shape get() = structure.shape override val rowNum: Int get() = shape[0] override val colNum: Int get() = shape[1] @@ -116,9 +116,8 @@ private value class Structure2DWrapper(val structure: StructureND) : S /** * A 2D wrapper for a mutable nd-structure */ -private class MutableStructure2DWrapper(val structure: MutableStructureND): MutableStructure2D -{ - override val shape: IntArray get() = structure.shape +private class MutableStructure2DWrapper(val structure: MutableStructureND) : MutableStructure2D { + override val shape: Shape get() = structure.shape override val rowNum: Int get() = shape[0] override val colNum: Int get() = shape[1] @@ -129,7 +128,7 @@ private class MutableStructure2DWrapper(val structure: MutableStructureND) structure[index] = value } - override operator fun set(i: Int, j: Int, value: T){ + override operator fun set(i: Int, j: Int, value: T) { structure[intArrayOf(i, j)] = value } @@ -152,10 +151,11 @@ public fun StructureND.as2D(): Structure2D = this as? Structure2D ? /** * Represents a [StructureND] as [Structure2D]. Throws runtime error in case of dimension mismatch. */ -public fun MutableStructureND.as2D(): MutableStructure2D = this as? MutableStructure2D ?: when (shape.size) { - 2 -> MutableStructure2DWrapper(this) - else -> error("Can't create 2d-structure from ${shape.size}d-structure") -} +public fun MutableStructureND.as2D(): MutableStructure2D = + this as? MutableStructure2D ?: when (shape.size) { + 2 -> MutableStructure2DWrapper(this) + else -> error("Can't create 2d-structure from ${shape.size}d-structure") + } /** * Expose inner [StructureND] if possible 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 611d2724f..b4e62366a 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 @@ -33,7 +33,7 @@ public interface StructureND : Featured { * The shape of structure i.e., non-empty sequence of non-negative integers that specify sizes of dimensions of * this structure. */ - public val shape: IntArray + public val shape: Shape /** * The count of dimensions in this structure. It should be equal to size of [shape]. diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index ed5575b93..a89e92c8e 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlinx.multik.api.zeros import org.jetbrains.kotlinx.multik.ndarray.data.* import org.jetbrains.kotlinx.multik.ndarray.operations.* import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.mapInPlace import space.kscience.kmath.operations.* import space.kscience.kmath.tensors.api.Tensor @@ -22,7 +23,7 @@ import space.kscience.kmath.tensors.api.TensorAlgebra @JvmInline public value class MultikTensor(public val array: MutableMultiArray) : Tensor { - override val shape: IntArray get() = array.shape + override val shape: Shape get() = array.shape override fun get(index: IntArray): T = array[index] -- 2.34.1 From cfd3f3b7e152cf7bb12413534cf950f6987353b2 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 20 Oct 2021 16:35:52 +0300 Subject: [PATCH 046/102] fix NDArray cast --- .../kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index a89e92c8e..04c467861 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -171,8 +171,7 @@ public class MultikTensorAlgebra internal constructor( val mt = asMultik().array return if (mt.shape.contentEquals(shape)) { - @Suppress("UNCHECKED_CAST") - this as NDArray + (this as MultikTensor).array } else { NDArray(mt.data, mt.offset, shape, dim = DN(shape.size), base = mt.base ?: mt) }.wrap() -- 2.34.1 From 47aeb36979d3501def28d920a86cf60916d5166b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 20 Oct 2021 17:04:00 +0300 Subject: [PATCH 047/102] fix NDArray cast --- .../kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index 04c467861..ed15199a6 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -171,7 +171,7 @@ public class MultikTensorAlgebra internal constructor( val mt = asMultik().array return if (mt.shape.contentEquals(shape)) { - (this as MultikTensor).array + mt } else { NDArray(mt.data, mt.offset, shape, dim = DN(shape.size), base = mt.base ?: mt) }.wrap() @@ -186,7 +186,7 @@ public class MultikTensorAlgebra internal constructor( ).asDNArray().wrap() } else if (this.shape.size == 2 && other.shape.size == 2) { (asMultik().array.asD2Array() dot other.asMultik().array.asD2Array()).asDNArray().wrap() - } else if(this.shape.size == 2 && other.shape.size == 1) { + } else if (this.shape.size == 2 && other.shape.size == 1) { (asMultik().array.asD2Array() dot other.asMultik().array.asD1Array()).asDNArray().wrap() } else { TODO("Not implemented for broadcasting") -- 2.34.1 From cc114041c4eb2c71248d8a54876d57668286cc95 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 24 Oct 2021 18:33:39 +0300 Subject: [PATCH 048/102] Initial implementation of TensorFlow connector --- .../tensorflow/DoubleTensorFlowAlgebra.kt | 40 +++++++++++++++ .../kmath/tensorflow/TensorFlowAlgebra.kt | 49 +++++++++---------- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 14 +++--- 3 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt 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 new file mode 100644 index 000000000..864205e17 --- /dev/null +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -0,0 +1,40 @@ +package space.kscience.kmath.tensorflow + +import org.tensorflow.Graph +import org.tensorflow.Output +import org.tensorflow.ndarray.NdArray +import org.tensorflow.ndarray.Shape +import org.tensorflow.op.core.Constant +import org.tensorflow.types.TFloat64 +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.tensors.api.Tensor + +public class DoubleTensorFlowOutput( + graph: Graph, + output: Output +) : TensorFlowOutput(graph, output) { + override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = output.asTensor() +} + +public class DoubleTensorFlowAlgebra internal constructor( + graph: Graph +) : TensorFlowAlgebra(graph) { + + override fun Tensor.asTensorFlow(): TensorFlowOutput = + if (this is TensorFlowOutput && output.type() == TFloat64::class.java) { + @Suppress("UNCHECKED_CAST") + this as TensorFlowOutput + } else { + val res = TFloat64.tensorOf(Shape.of(*shape.toLongArray())) { array -> + @OptIn(PerformancePitfall::class) + elements().forEach { (index, value) -> + array.setDouble(value, *index.toLongArray()) + } + } + DoubleTensorFlowOutput(graph, ops.constant(res).asOutput()) + } + + override fun Output.wrap(): TensorFlowOutput = DoubleTensorFlowOutput(graph, this) + + override fun const(value: Double): Constant = ops.constant(value) +} \ No newline at end of file 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 849a2e909..12c1211db 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 @@ -14,11 +14,10 @@ import space.kscience.kmath.nd.Shape import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra -private fun IntArray.toLongArray() = LongArray(size) { get(it).toLong() } -private fun LongArray.toIntArray() = IntArray(size) { get(it).toInt() } +internal fun IntArray.toLongArray() = LongArray(size) { get(it).toLong() } +internal fun LongArray.toIntArray() = IntArray(size) { get(it).toInt() } -private val NdArray.scalar: T - get() = getObject() +internal val NdArray.scalar: T get() = getObject() public sealed interface TensorFlowTensor : Tensor @@ -72,14 +71,12 @@ public abstract class TensorFlowOutput( public abstract class TensorFlowAlgebra internal constructor( - private val graph: Graph + protected val graph: Graph ) : TensorAlgebra { - private val ops by lazy { Ops.create(graph) } + protected val ops: Ops by lazy { Ops.create(graph) } - protected fun Tensor.asTensorFlow(): TensorFlowOutput = if (this is TensorFlowOutput) this else { - TODO() - } + protected abstract fun Tensor.asTensorFlow(): TensorFlowOutput protected abstract fun Output.wrap(): TensorFlowOutput @@ -138,27 +135,29 @@ public abstract class TensorFlowAlgebra internal constructor( private inline fun unOp(value: Tensor, operation: (Operand) -> Operand): TensorFlowOutput = operation(value.asTensorFlow().output).asOutput().wrap() - override fun T.plus(other: Tensor) = biOp(other, ops.math::add) + override fun T.plus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::add) - override fun Tensor.plus(value: T) = biOp(value, ops.math::add) + override fun Tensor.plus(value: T): TensorFlowOutput = biOp(value, ops.math::add) - override fun Tensor.plus(other: Tensor) = biOp(other, ops.math::add) + override fun Tensor.plus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::add) override fun Tensor.plusAssign(value: T): Unit = inPlaceOp(value, ops.math::add) override fun Tensor.plusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::add) - override fun Tensor.minus(value: T) = biOp(value, ops.math::sub) + override fun Tensor.minus(value: T): TensorFlowOutput = biOp(value, ops.math::sub) - override fun Tensor.minus(other: Tensor) = biOp(other, ops.math::sub) + override fun Tensor.minus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::sub) + + override fun T.minus(other: Tensor): Tensor = biOp(other, ops.math::sub) override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) override fun Tensor.minusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::sub) - override fun T.times(other: Tensor) = biOp(other, ops.math::mul) + override fun T.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) - override fun Tensor.times(value: T) = biOp(value, ops.math::mul) + override fun Tensor.times(value: T): TensorFlowOutput = biOp(value, ops.math::mul) override fun Tensor.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) @@ -166,14 +165,14 @@ public abstract class TensorFlowAlgebra internal constructor( override fun Tensor.timesAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::mul) - override fun Tensor.unaryMinus() = unOp(this, ops.math::neg) + override fun Tensor.unaryMinus(): TensorFlowOutput = unOp(this, ops.math::neg) - override fun Tensor.get(i: Int): Tensor{ - ops. + override fun Tensor.get(i: Int): Tensor { + TODO("Not yet implemented") } - override fun Tensor.transpose(i: Int, j: Int): Tensor { - TODO("Not yet implemented") + override fun Tensor.transpose(i: Int, j: Int): Tensor = unOp(this) { + ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) } override fun Tensor.view(shape: IntArray): Tensor { @@ -184,15 +183,15 @@ public abstract class TensorFlowAlgebra internal constructor( TODO("Not yet implemented") } - override fun Tensor.dot(other: Tensor) = biOp(other, ops.math.) + override fun Tensor.dot(other: Tensor): TensorFlowOutput = biOp(other) { l, r -> + ops.linalg.matMul(l, r) + } override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): Tensor = ops.run { TODO("Not yet implemented") } - override fun Tensor.sum(): T { - TODO("Not yet implemented") - } + override fun Tensor.sum(): T = TODO("Not yet implemented") override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") 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 16ed4b834..3267e4adb 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 @@ -22,7 +22,7 @@ import kotlin.math.* public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra, AnalyticTensorAlgebra, - LinearOpsTensorAlgebra{ + LinearOpsTensorAlgebra { public companion object : DoubleTensorAlgebra() @@ -361,16 +361,16 @@ public open class DoubleTensorAlgebra : dotHelper(a.as2D(), b.as2D(), res.as2D(), l, m1, n) } - if (penultimateDim) { - return resTensor.view( + return if (penultimateDim) { + resTensor.view( resTensor.shape.dropLast(2).toIntArray() + intArrayOf(resTensor.shape.last()) ) + } else if (lastDim) { + resTensor.view(resTensor.shape.dropLast(1).toIntArray()) + } else { + resTensor } - if (lastDim) { - return resTensor.view(resTensor.shape.dropLast(1).toIntArray()) - } - return resTensor } override fun diagonalEmbedding( -- 2.34.1 From 7e59ec5804370829d85b858362a5187b3cec1740 Mon Sep 17 00:00:00 2001 From: darksnake Date: Tue, 26 Oct 2021 09:16:24 +0300 Subject: [PATCH 049/102] Refactor TensorAlgebra to take StructureND and inherit AlgebraND --- .../kmath/structures/StreamDoubleFieldND.kt | 2 +- .../kscience/kmath/tensors/neuralNetwork.kt | 4 +- .../space/kscience/kmath/nd/AlgebraND.kt | 8 +- .../kscience/kmath/nd/BufferAlgebraND.kt | 8 +- .../space/kscience/kmath/nd/BufferND.kt | 16 +- .../space/kscience/kmath/nd/DoubleFieldND.kt | 6 +- .../space/kscience/kmath/nd/StructureND.kt | 4 +- .../space/kscience/kmath/real/realND.kt | 4 +- .../kmath/multik/MultikTensorAlgebra.kt | 53 +++--- .../tensors/api/AnalyticTensorAlgebra.kt | 4 +- .../tensors/api/LinearOpsTensorAlgebra.kt | 4 +- .../kmath/tensors/api/TensorAlgebra.kt | 58 +++--- .../api/TensorPartialDivisionAlgebra.kt | 26 ++- .../core/BroadcastDoubleTensorAlgebra.kt | 31 +-- .../kmath/tensors/core/BufferedTensor.kt | 10 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 180 +++++++++++------- .../tensors/core/internal/broadcastUtils.kt | 14 +- .../kmath/tensors/core/internal/checks.kt | 3 +- .../tensors/core/internal/tensorCastsUtils.kt | 9 +- .../kmath/tensors/core/internal/utils.kt | 2 +- .../kmath/tensors/core/tensorCasts.kt | 9 +- 21 files changed, 258 insertions(+), 197 deletions(-) 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 2b3e72136..05a13f5d2 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -36,7 +36,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND this.buffer as DoubleBuffer + this is BufferND && this.indices == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt index 3025ff8a3..cdfc06922 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.toDoubleArray +import space.kscience.kmath.tensors.core.copyArray import kotlin.math.sqrt const val seed = 100500L @@ -111,7 +111,7 @@ class NeuralNetwork(private val layers: List) { private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra { val onesForAnswers = yPred.zeroesLike() - yTrue.toDoubleArray().forEachIndexed { index, labelDouble -> + yTrue.copyArray().forEachIndexed { index, labelDouble -> val label = labelDouble.toInt() onesForAnswers[intArrayOf(index, label)] = 1.0 } 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 30cb01146..3d2d08fac 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 @@ -131,19 +131,19 @@ public interface GroupOpsND> : GroupOps>, * Adds an element to ND structure of it. * * @receiver the augend. - * @param arg the addend. + * @param other the addend. * @return the sum. */ - public operator fun T.plus(arg: StructureND): StructureND = arg + this + public operator fun T.plus(other: StructureND): StructureND = other.map { value -> add(this@plus, value) } /** * Subtracts an ND structure from an element of it. * * @receiver the dividend. - * @param arg the divisor. + * @param other the divisor. * @return the quotient. */ - public operator fun T.minus(arg: StructureND): StructureND = arg.map { value -> add(-this@minus, value) } + public operator fun T.minus(other: StructureND): StructureND = other.map { value -> add(-this@minus, value) } public companion object } 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 859edefb8..cf007e7c9 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 @@ -51,7 +51,7 @@ public inline fun > BufferAlgebraND.mapInline( arg: BufferND, crossinline transform: A.(T) -> T ): BufferND { - val indexes = arg.indexes + val indexes = arg.indices return BufferND(indexes, bufferAlgebra.mapInline(arg.buffer, transform)) } @@ -59,7 +59,7 @@ internal inline fun > BufferAlgebraND.mapIndexedInline( arg: BufferND, crossinline transform: A.(index: IntArray, arg: T) -> T ): BufferND { - val indexes = arg.indexes + val indexes = arg.indices return BufferND( indexes, bufferAlgebra.mapIndexedInline(arg.buffer) { offset, value -> @@ -73,8 +73,8 @@ internal inline fun > BufferAlgebraND.zipInline( r: BufferND, crossinline block: A.(l: T, r: T) -> T ): BufferND { - require(l.indexes == r.indexes) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } - val indexes = l.indexes + require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } + val indexes = l.indices return BufferND(indexes, bufferAlgebra.zipInline(l.buffer, r.buffer, block)) } 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 afa8f8250..2b6fd3693 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 @@ -15,20 +15,20 @@ import space.kscience.kmath.structures.MutableBufferFactory * Represents [StructureND] over [Buffer]. * * @param T the type of items. - * @param indexes The strides to access elements of [Buffer] by linear indices. + * @param indices The strides to access elements of [Buffer] by linear indices. * @param buffer The underlying buffer. */ public open class BufferND( - public val indexes: ShapeIndexer, + public val indices: ShapeIndexer, public open val buffer: Buffer, ) : StructureND { - override operator fun get(index: IntArray): T = buffer[indexes.offset(index)] + override operator fun get(index: IntArray): T = buffer[indices.offset(index)] - override val shape: IntArray get() = indexes.shape + override val shape: IntArray get() = indices.shape @PerformancePitfall - override fun elements(): Sequence> = indexes.indices().map { + override fun elements(): Sequence> = indices.indices().map { it to this[it] } @@ -43,7 +43,7 @@ public inline fun StructureND.mapToBuffer( crossinline transform: (T) -> R, ): BufferND { return if (this is BufferND) - BufferND(this.indexes, factory.invoke(indexes.linearSize) { transform(buffer[it]) }) + BufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) }) else { val strides = DefaultStrides(shape) BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) @@ -62,7 +62,7 @@ public class MutableBufferND( override val buffer: MutableBuffer, ) : MutableStructureND, BufferND(strides, buffer) { override fun set(index: IntArray, value: T) { - buffer[indexes.offset(index)] = value + buffer[indices.offset(index)] = value } } @@ -74,7 +74,7 @@ public inline fun MutableStructureND.mapToMutableBuffer( crossinline transform: (T) -> R, ): MutableBufferND { return if (this is MutableBufferND) - MutableBufferND(this.indexes, factory.invoke(indexes.linearSize) { transform(buffer[it]) }) + MutableBufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) }) else { val strides = DefaultStrides(shape) MutableBufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) 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 853ac43b0..abb8e46ea 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 @@ -33,7 +33,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D arg: DoubleBufferND, transform: (Double) -> Double ): DoubleBufferND { - val indexes = arg.indexes + val indexes = arg.indices val array = arg.buffer.array return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { transform(array[it]) }) } @@ -43,8 +43,8 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D r: DoubleBufferND, block: (l: Double, r: Double) -> Double ): DoubleBufferND { - require(l.indexes == r.indexes) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } - val indexes = l.indexes + require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } + val indexes = l.indices val lArray = l.buffer.array val rArray = r.buffer.array return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { block(lArray[it], rArray[it]) }) 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 b4e62366a..496abf60f 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 @@ -71,7 +71,7 @@ public interface StructureND : Featured { if (st1 === st2) return true // fast comparison of buffers if possible - if (st1 is BufferND && st2 is BufferND && st1.indexes == st2.indexes) + if (st1 is BufferND && st2 is BufferND && st1.indices == st2.indices) return Buffer.contentEquals(st1.buffer, st2.buffer) //element by element comparison if it could not be avoided @@ -87,7 +87,7 @@ public interface StructureND : Featured { if (st1 === st2) return true // fast comparison of buffers if possible - if (st1 is BufferND && st2 is BufferND && st1.indexes == st2.indexes) + if (st1 is BufferND && st2 is BufferND && st1.indices == st2.indices) return Buffer.contentEquals(st1.buffer, st2.buffer) //element by element comparison if it could not be avoided diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt index 0edd51be2..56f50acbc 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt @@ -13,8 +13,8 @@ import space.kscience.kmath.structures.DoubleBuffer * Map one [BufferND] using function without indices. */ public inline fun BufferND.mapInline(crossinline transform: DoubleField.(Double) -> Double): BufferND { - val array = DoubleArray(indexes.linearSize) { offset -> DoubleField.transform(buffer[offset]) } - return BufferND(indexes, DoubleBuffer(array)) + val array = DoubleArray(indices.linearSize) { offset -> DoubleField.transform(buffer[offset]) } + return BufferND(indices, DoubleBuffer(array)) } /** diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index ed15199a6..3bbe8e672 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlinx.multik.ndarray.data.* import org.jetbrains.kotlinx.multik.ndarray.operations.* import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.Shape +import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.mapInPlace import space.kscience.kmath.operations.* import space.kscience.kmath.tensors.api.Tensor @@ -49,17 +50,17 @@ private fun MultiArray.asD2Array(): D2Array { else throw ClassCastException("Cannot cast MultiArray to NDArray.") } -public class MultikTensorAlgebra internal constructor( +public class MultikTensorAlgebra> internal constructor( public val type: DataType, - public val elementAlgebra: Ring, + override val elementAlgebra: A, public val comparator: Comparator -) : TensorAlgebra { +) : TensorAlgebra { /** * Convert a tensor to [MultikTensor] if necessary. If tensor is converted, changes on the resulting tensor * are not reflected back onto the source */ - public fun Tensor.asMultik(): MultikTensor { + public fun StructureND.asMultik(): MultikTensor { return if (this is MultikTensor) { this } else { @@ -73,17 +74,17 @@ public class MultikTensorAlgebra internal constructor( public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) - override fun Tensor.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) { + override fun StructureND.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) { get(intArrayOf(0)) } else null - override fun T.plus(other: Tensor): MultikTensor = + override fun T.plus(other: StructureND): MultikTensor = other.plus(this) - override fun Tensor.plus(value: T): MultikTensor = + override fun StructureND.plus(value: T): MultikTensor = asMultik().array.deepCopy().apply { plusAssign(value) }.wrap() - override fun Tensor.plus(other: Tensor): MultikTensor = + override fun StructureND.plus(other: StructureND): MultikTensor = asMultik().array.plus(other.asMultik().array).wrap() override fun Tensor.plusAssign(value: T) { @@ -94,7 +95,7 @@ public class MultikTensorAlgebra internal constructor( } } - override fun Tensor.plusAssign(other: Tensor) { + override fun Tensor.plusAssign(other: StructureND) { if (this is MultikTensor) { array.plusAssign(other.asMultik().array) } else { @@ -102,12 +103,12 @@ public class MultikTensorAlgebra internal constructor( } } - override fun T.minus(other: Tensor): MultikTensor = (-(other.asMultik().array - this)).wrap() + override fun T.minus(other: StructureND): MultikTensor = (-(other.asMultik().array - this)).wrap() - override fun Tensor.minus(value: T): MultikTensor = - asMultik().array.deepCopy().apply { minusAssign(value) }.wrap() + override fun StructureND.minus(arg: T): MultikTensor = + asMultik().array.deepCopy().apply { minusAssign(arg) }.wrap() - override fun Tensor.minus(other: Tensor): MultikTensor = + override fun StructureND.minus(other: StructureND): MultikTensor = asMultik().array.minus(other.asMultik().array).wrap() override fun Tensor.minusAssign(value: T) { @@ -118,7 +119,7 @@ public class MultikTensorAlgebra internal constructor( } } - override fun Tensor.minusAssign(other: Tensor) { + override fun Tensor.minusAssign(other: StructureND) { if (this is MultikTensor) { array.minusAssign(other.asMultik().array) } else { @@ -126,13 +127,13 @@ public class MultikTensorAlgebra internal constructor( } } - override fun T.times(other: Tensor): MultikTensor = - other.asMultik().array.deepCopy().apply { timesAssign(this@times) }.wrap() + override fun T.times(arg: StructureND): MultikTensor = + arg.asMultik().array.deepCopy().apply { timesAssign(this@times) }.wrap() - override fun Tensor.times(value: T): Tensor = - asMultik().array.deepCopy().apply { timesAssign(value) }.wrap() + override fun StructureND.times(arg: T): Tensor = + asMultik().array.deepCopy().apply { timesAssign(arg) }.wrap() - override fun Tensor.times(other: Tensor): MultikTensor = + override fun StructureND.times(other: StructureND): MultikTensor = asMultik().array.times(other.asMultik().array).wrap() override fun Tensor.timesAssign(value: T) { @@ -143,7 +144,7 @@ public class MultikTensorAlgebra internal constructor( } } - override fun Tensor.timesAssign(other: Tensor) { + override fun Tensor.timesAssign(other: StructureND) { if (this is MultikTensor) { array.timesAssign(other.asMultik().array) } else { @@ -151,7 +152,7 @@ public class MultikTensorAlgebra internal constructor( } } - override fun Tensor.unaryMinus(): MultikTensor = + override fun StructureND.unaryMinus(): MultikTensor = asMultik().array.unaryMinus().wrap() override fun Tensor.get(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() @@ -224,17 +225,17 @@ public class MultikTensorAlgebra internal constructor( } } -public val DoubleField.multikTensorAlgebra: MultikTensorAlgebra +public val DoubleField.multikTensorAlgebra: MultikTensorAlgebra get() = MultikTensorAlgebra(DataType.DoubleDataType, DoubleField) { o1, o2 -> o1.compareTo(o2) } -public val FloatField.multikTensorAlgebra: MultikTensorAlgebra +public val FloatField.multikTensorAlgebra: MultikTensorAlgebra get() = MultikTensorAlgebra(DataType.FloatDataType, FloatField) { o1, o2 -> o1.compareTo(o2) } -public val ShortRing.multikTensorAlgebra: MultikTensorAlgebra +public val ShortRing.multikTensorAlgebra: MultikTensorAlgebra get() = MultikTensorAlgebra(DataType.ShortDataType, ShortRing) { o1, o2 -> o1.compareTo(o2) } -public val IntRing.multikTensorAlgebra: MultikTensorAlgebra +public val IntRing.multikTensorAlgebra: MultikTensorAlgebra get() = MultikTensorAlgebra(DataType.IntDataType, IntRing) { o1, o2 -> o1.compareTo(o2) } -public val LongRing.multikTensorAlgebra: MultikTensorAlgebra +public val LongRing.multikTensorAlgebra: MultikTensorAlgebra get() = MultikTensorAlgebra(DataType.LongDataType, LongRing) { o1, o2 -> o1.compareTo(o2) } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index 851810c8d..caafcc7c1 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -5,13 +5,15 @@ package space.kscience.kmath.tensors.api +import space.kscience.kmath.operations.Field + /** * Analytic operations on [Tensor]. * * @param T the type of items closed under analytic functions in the tensors. */ -public interface AnalyticTensorAlgebra : TensorPartialDivisionAlgebra { +public interface AnalyticTensorAlgebra> : TensorPartialDivisionAlgebra { /** * @return the mean of all elements in the input tensor. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 78aad2189..3f32eb9ca 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -5,12 +5,14 @@ package space.kscience.kmath.tensors.api +import space.kscience.kmath.operations.Field + /** * Common linear algebra operations. Operates on [Tensor]. * * @param T the type of items closed under division in the tensors. */ -public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { +public interface LinearOpsTensorAlgebra> : TensorPartialDivisionAlgebra { /** * Computes the determinant of a square matrix input, or of each square matrix in a batched input. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 810ebe777..e910c5c31 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -5,7 +5,9 @@ package space.kscience.kmath.tensors.api -import space.kscience.kmath.operations.RingOps +import space.kscience.kmath.nd.RingOpsND +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.Ring /** * Algebra over a ring on [Tensor]. @@ -13,20 +15,20 @@ import space.kscience.kmath.operations.RingOps * * @param T the type of items in the tensors. */ -public interface TensorAlgebra : RingOps> { +public interface TensorAlgebra> : RingOpsND { /** * Returns a single tensor value of unit dimension if tensor shape equals to [1]. * * @return a nullable value of a potentially scalar tensor. */ - public fun Tensor.valueOrNull(): T? + public fun StructureND.valueOrNull(): T? /** * Returns a single tensor value of unit dimension. The tensor shape must be equal to [1]. * * @return the value of a scalar tensor. */ - public fun Tensor.value(): T = + public fun StructureND.value(): T = valueOrNull() ?: throw IllegalArgumentException("Inconsistent value for tensor of with $shape shape") /** @@ -36,7 +38,7 @@ public interface TensorAlgebra : RingOps> { * @param other tensor to be added. * @return the sum of this value and tensor [other]. */ - public operator fun T.plus(other: Tensor): Tensor + override operator fun T.plus(other: StructureND): Tensor /** * Adds the scalar [value] to each element of this tensor and returns a new resulting tensor. @@ -44,7 +46,7 @@ public interface TensorAlgebra : RingOps> { * @param value the number to be added to each element of this tensor. * @return the sum of this tensor and [value]. */ - public operator fun Tensor.plus(value: T): Tensor + override operator fun StructureND.plus(value: T): Tensor /** * Each element of the tensor [other] is added to each element of this tensor. @@ -53,7 +55,7 @@ public interface TensorAlgebra : RingOps> { * @param other tensor to be added. * @return the sum of this tensor and [other]. */ - override fun Tensor.plus(other: Tensor): Tensor + override operator fun StructureND.plus(other: StructureND): Tensor /** * Adds the scalar [value] to each element of this tensor. @@ -67,7 +69,7 @@ public interface TensorAlgebra : RingOps> { * * @param other tensor to be added. */ - public operator fun Tensor.plusAssign(other: Tensor) + public operator fun Tensor.plusAssign(other: StructureND) /** * Each element of the tensor [other] is subtracted from this value. @@ -76,15 +78,15 @@ public interface TensorAlgebra : RingOps> { * @param other tensor to be subtracted. * @return the difference between this value and tensor [other]. */ - public operator fun T.minus(other: Tensor): Tensor + override operator fun T.minus(other: StructureND): Tensor /** - * Subtracts the scalar [value] from each element of this tensor and returns a new resulting tensor. + * Subtracts the scalar [arg] from each element of this tensor and returns a new resulting tensor. * - * @param value the number to be subtracted from each element of this tensor. - * @return the difference between this tensor and [value]. + * @param arg the number to be subtracted from each element of this tensor. + * @return the difference between this tensor and [arg]. */ - public operator fun Tensor.minus(value: T): Tensor + override operator fun StructureND.minus(arg: T): Tensor /** * Each element of the tensor [other] is subtracted from each element of this tensor. @@ -93,7 +95,7 @@ public interface TensorAlgebra : RingOps> { * @param other tensor to be subtracted. * @return the difference between this tensor and [other]. */ - override fun Tensor.minus(other: Tensor): Tensor + override operator fun StructureND.minus(other: StructureND): Tensor /** * Subtracts the scalar [value] from each element of this tensor. @@ -107,25 +109,25 @@ public interface TensorAlgebra : RingOps> { * * @param other tensor to be subtracted. */ - public operator fun Tensor.minusAssign(other: Tensor) + public operator fun Tensor.minusAssign(other: StructureND) /** - * Each element of the tensor [other] is multiplied by this value. + * Each element of the tensor [arg] is multiplied by this value. * The resulting tensor is returned. * - * @param other tensor to be multiplied. - * @return the product of this value and tensor [other]. + * @param arg tensor to be multiplied. + * @return the product of this value and tensor [arg]. */ - public operator fun T.times(other: Tensor): Tensor + override operator fun T.times(arg: StructureND): Tensor /** - * Multiplies the scalar [value] by each element of this tensor and returns a new resulting tensor. + * Multiplies the scalar [arg] by each element of this tensor and returns a new resulting tensor. * - * @param value the number to be multiplied by each element of this tensor. - * @return the product of this tensor and [value]. + * @param arg the number to be multiplied by each element of this tensor. + * @return the product of this tensor and [arg]. */ - public operator fun Tensor.times(value: T): Tensor + override operator fun StructureND.times(arg: T): Tensor /** * Each element of the tensor [other] is multiplied by each element of this tensor. @@ -134,7 +136,7 @@ public interface TensorAlgebra : RingOps> { * @param other tensor to be multiplied. * @return the product of this tensor and [other]. */ - override fun Tensor.times(other: Tensor): Tensor + override operator fun StructureND.times(other: StructureND): Tensor /** * Multiplies the scalar [value] by each element of this tensor. @@ -148,14 +150,14 @@ public interface TensorAlgebra : RingOps> { * * @param other tensor to be multiplied. */ - public operator fun Tensor.timesAssign(other: Tensor) + public operator fun Tensor.timesAssign(other: StructureND) /** * Numerical negative, element-wise. * * @return tensor negation of the original tensor. */ - override fun Tensor.unaryMinus(): Tensor + override operator fun StructureND.unaryMinus(): Tensor /** * Returns the tensor at index i @@ -324,7 +326,7 @@ public interface TensorAlgebra : RingOps> { */ public fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor - override fun add(left: Tensor, right: Tensor): Tensor = left + right + override fun add(left: StructureND, right: StructureND): Tensor = left + right - override fun multiply(left: Tensor, right: Tensor): Tensor = left * right + override fun multiply(left: StructureND, right: StructureND): Tensor = left * right } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index ce519288b..43c901ed5 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -5,30 +5,34 @@ package space.kscience.kmath.tensors.api +import space.kscience.kmath.nd.FieldOpsND +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.Field + /** * Algebra over a field with partial division on [Tensor]. * For more information: https://proofwiki.org/wiki/Definition:Division_Algebra * * @param T the type of items closed under division in the tensors. */ -public interface TensorPartialDivisionAlgebra : TensorAlgebra { +public interface TensorPartialDivisionAlgebra> : TensorAlgebra, FieldOpsND { /** - * Each element of the tensor [other] is divided by this value. + * Each element of the tensor [arg] is divided by this value. * The resulting tensor is returned. * - * @param other tensor to divide by. - * @return the division of this value by the tensor [other]. + * @param arg tensor to divide by. + * @return the division of this value by the tensor [arg]. */ - public operator fun T.div(other: Tensor): Tensor + override operator fun T.div(arg: StructureND): Tensor /** - * Divide by the scalar [value] each element of this tensor returns a new resulting tensor. + * Divide by the scalar [arg] each element of this tensor returns a new resulting tensor. * - * @param value the number to divide by each element of this tensor. - * @return the division of this tensor by the [value]. + * @param arg the number to divide by each element of this tensor. + * @return the division of this tensor by the [arg]. */ - public operator fun Tensor.div(value: T): Tensor + override operator fun StructureND.div(arg: T): Tensor /** * Each element of the tensor [other] is divided by each element of this tensor. @@ -37,7 +41,9 @@ public interface TensorPartialDivisionAlgebra : TensorAlgebra { * @param other tensor to be divided by. * @return the division of this tensor by [other]. */ - public operator fun Tensor.div(other: Tensor): Tensor + override operator fun StructureND.div(other: StructureND): Tensor + + override fun divide(left: StructureND, right: StructureND): StructureND = left.div(right) /** * Divides by the scalar [value] each element of this tensor. 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 3d73fd53b..f3c5d2540 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 @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.StructureND import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.broadcastTensors @@ -18,66 +19,66 @@ import space.kscience.kmath.tensors.core.internal.tensor */ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - override fun Tensor.plus(other: Tensor): DoubleTensor { + override fun StructureND.plus(other: StructureND): DoubleTensor { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> + val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> newThis.mutableBuffer.array()[i] + newOther.mutableBuffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.plusAssign(other: Tensor) { + override fun Tensor.plusAssign(other: StructureND) { val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.linearSize) { + for (i in 0 until tensor.indices.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] += newOther.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun Tensor.minus(other: Tensor): DoubleTensor { + override fun StructureND.minus(other: StructureND): DoubleTensor { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> + val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> newThis.mutableBuffer.array()[i] - newOther.mutableBuffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.minusAssign(other: Tensor) { + override fun Tensor.minusAssign(other: StructureND) { val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.linearSize) { + for (i in 0 until tensor.indices.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] -= newOther.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun Tensor.times(other: Tensor): DoubleTensor { + override fun StructureND.times(other: StructureND): DoubleTensor { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> + val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> newThis.mutableBuffer.array()[newThis.bufferStart + i] * newOther.mutableBuffer.array()[newOther.bufferStart + i] } return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.timesAssign(other: Tensor) { + override fun Tensor.timesAssign(other: StructureND) { val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.linearSize) { + for (i in 0 until tensor.indices.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] *= newOther.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun Tensor.div(other: Tensor): DoubleTensor { + override fun StructureND.div(other: StructureND): DoubleTensor { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> + val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> newThis.mutableBuffer.array()[newOther.bufferStart + i] / newOther.mutableBuffer.array()[newOther.bufferStart + i] } @@ -86,7 +87,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun Tensor.divAssign(other: Tensor) { val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.linearSize) { + for (i in 0 until tensor.indices.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= newOther.mutableBuffer.array()[tensor.bufferStart + i] } 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 bf9a9f7f7..ba3331067 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 @@ -23,23 +23,23 @@ public open class BufferedTensor internal constructor( /** * Buffer strides based on [TensorLinearStructure] implementation */ - public val linearStructure: Strides + public val indices: Strides get() = TensorLinearStructure(shape) /** * Number of elements in tensor */ public val numElements: Int - get() = linearStructure.linearSize + get() = indices.linearSize - override fun get(index: IntArray): T = mutableBuffer[bufferStart + linearStructure.offset(index)] + override fun get(index: IntArray): T = mutableBuffer[bufferStart + indices.offset(index)] override fun set(index: IntArray, value: T) { - mutableBuffer[bufferStart + linearStructure.offset(index)] = value + mutableBuffer[bufferStart + indices.offset(index)] = value } @PerformancePitfall - override fun elements(): Sequence> = linearStructure.indices().map { + override fun elements(): Sequence> = indices.indices().map { it to get(it) } } 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 16ed4b834..472db8f5f 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 @@ -6,8 +6,10 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.nd.MutableStructure2D +import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.indices import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra @@ -20,16 +22,71 @@ import kotlin.math.* * Implementation of basic operations over double tensors and basic algebra operations on them. */ public open class DoubleTensorAlgebra : - TensorPartialDivisionAlgebra, - AnalyticTensorAlgebra, - LinearOpsTensorAlgebra{ + TensorPartialDivisionAlgebra, + AnalyticTensorAlgebra, + LinearOpsTensorAlgebra { public companion object : DoubleTensorAlgebra() - override fun Tensor.valueOrNull(): Double? = if (tensor.shape contentEquals intArrayOf(1)) + override val elementAlgebra: DoubleField + get() = DoubleField + + + /** + * Applies the [transform] function to each element of the tensor and returns the resulting modified tensor. + * + * @param transform the function to be applied to each element of the tensor. + * @return the resulting tensor after applying the function. + */ + @Suppress("OVERRIDE_BY_INLINE") + final override inline fun StructureND.map(transform: DoubleField.(Double) -> Double): DoubleTensor { + val tensor = this.tensor + //TODO remove additional copy + val sourceArray = tensor.copyArray() + val array = DoubleArray(tensor.numElements) { DoubleField.transform(sourceArray[it]) } + return DoubleTensor( + tensor.shape, + array, + tensor.bufferStart + ) + } + + @Suppress("OVERRIDE_BY_INLINE") + final override inline fun StructureND.mapIndexed(transform: DoubleField.(index: IntArray, Double) -> Double): DoubleTensor { + val tensor = this.tensor + //TODO remove additional copy + val sourceArray = tensor.copyArray() + val array = DoubleArray(tensor.numElements) { DoubleField.transform(tensor.indices.index(it), sourceArray[it]) } + return DoubleTensor( + tensor.shape, + array, + tensor.bufferStart + ) + } + + override fun zip( + left: StructureND, + right: StructureND, + transform: DoubleField.(Double, Double) -> Double + ): DoubleTensor { + require(left.shape.contentEquals(right.shape)){ + "The shapes in zip are not equal: left - ${left.shape}, right - ${right.shape}" + } + val leftTensor = left.tensor + val leftArray = leftTensor.copyArray() + val rightTensor = right.tensor + val rightArray = rightTensor.copyArray() + val array = DoubleArray(leftTensor.numElements) { DoubleField.transform(leftArray[it], rightArray[it]) } + return DoubleTensor( + leftTensor.shape, + array + ) + } + + override fun StructureND.valueOrNull(): Double? = if (tensor.shape contentEquals intArrayOf(1)) tensor.mutableBuffer.array()[tensor.bufferStart] else null - override fun Tensor.value(): Double = valueOrNull() + override fun StructureND.value(): Double = valueOrNull() ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") /** @@ -53,11 +110,10 @@ public open class DoubleTensorAlgebra : * @param initializer mapping tensor indices to values. * @return tensor with the [shape] shape and data generated by the [initializer]. */ - public fun produce(shape: IntArray, initializer: (IntArray) -> Double): DoubleTensor = - fromArray( - shape, - TensorLinearStructure(shape).indices().map(initializer).toMutableList().toDoubleArray() - ) + override fun structureND(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): DoubleTensor = fromArray( + shape, + TensorLinearStructure(shape).indices().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray() + ) override operator fun Tensor.get(i: Int): DoubleTensor { val lastShape = tensor.shape.drop(1).toIntArray() @@ -146,16 +202,16 @@ public open class DoubleTensorAlgebra : return DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) } - override fun Double.plus(other: Tensor): DoubleTensor { + override fun Double.plus(other: StructureND): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] + this } return DoubleTensor(other.shape, resBuffer) } - override fun Tensor.plus(value: Double): DoubleTensor = value + tensor + override fun StructureND.plus(value: Double): DoubleTensor = value + tensor - override fun Tensor.plus(other: Tensor): DoubleTensor { + override fun StructureND.plus(other: StructureND): DoubleTensor { checkShapesCompatible(tensor, other.tensor) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[i] + other.tensor.mutableBuffer.array()[i] @@ -169,7 +225,7 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.plusAssign(other: Tensor) { + override fun Tensor.plusAssign(other: StructureND) { checkShapesCompatible(tensor, other.tensor) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] += @@ -177,21 +233,21 @@ public open class DoubleTensorAlgebra : } } - override fun Double.minus(other: Tensor): DoubleTensor { + override fun Double.minus(other: StructureND): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> this - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } - override fun Tensor.minus(value: Double): DoubleTensor { + override fun StructureND.minus(arg: Double): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] - value + tensor.mutableBuffer.array()[tensor.bufferStart + i] - arg } return DoubleTensor(tensor.shape, resBuffer) } - override fun Tensor.minus(other: Tensor): DoubleTensor { + override fun StructureND.minus(other: StructureND): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[i] - other.tensor.mutableBuffer.array()[i] @@ -205,7 +261,7 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.minusAssign(other: Tensor) { + override fun Tensor.minusAssign(other: StructureND) { checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] -= @@ -213,16 +269,16 @@ public open class DoubleTensorAlgebra : } } - override fun Double.times(other: Tensor): DoubleTensor { - val resBuffer = DoubleArray(other.tensor.numElements) { i -> - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] * this + override fun Double.times(arg: StructureND): DoubleTensor { + val resBuffer = DoubleArray(arg.tensor.numElements) { i -> + arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] * this } - return DoubleTensor(other.shape, resBuffer) + return DoubleTensor(arg.shape, resBuffer) } - override fun Tensor.times(value: Double): DoubleTensor = value * tensor + override fun StructureND.times(arg: Double): DoubleTensor = arg * tensor - override fun Tensor.times(other: Tensor): DoubleTensor { + override fun StructureND.times(other: StructureND): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[tensor.bufferStart + i] * @@ -237,7 +293,7 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.timesAssign(other: Tensor) { + override fun Tensor.timesAssign(other: StructureND) { checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] *= @@ -245,21 +301,21 @@ public open class DoubleTensorAlgebra : } } - override fun Double.div(other: Tensor): DoubleTensor { - val resBuffer = DoubleArray(other.tensor.numElements) { i -> - this / other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] + override fun Double.div(arg: StructureND): DoubleTensor { + val resBuffer = DoubleArray(arg.tensor.numElements) { i -> + this / arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] } - return DoubleTensor(other.shape, resBuffer) + return DoubleTensor(arg.shape, resBuffer) } - override fun Tensor.div(value: Double): DoubleTensor { + override fun StructureND.div(arg: Double): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] / value + tensor.mutableBuffer.array()[tensor.bufferStart + i] / arg } return DoubleTensor(shape, resBuffer) } - override fun Tensor.div(other: Tensor): DoubleTensor { + override fun StructureND.div(other: StructureND): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[other.tensor.bufferStart + i] / @@ -282,7 +338,7 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.unaryMinus(): DoubleTensor { + override fun StructureND.unaryMinus(): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[tensor.bufferStart + i].unaryMinus() } @@ -302,11 +358,11 @@ public open class DoubleTensorAlgebra : val resTensor = DoubleTensor(resShape, resBuffer) for (offset in 0 until n) { - val oldMultiIndex = tensor.linearStructure.index(offset) + val oldMultiIndex = tensor.indices.index(offset) val newMultiIndex = oldMultiIndex.copyOf() newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } - val linearIndex = resTensor.linearStructure.offset(newMultiIndex) + val linearIndex = resTensor.indices.offset(newMultiIndex) resTensor.mutableBuffer.array()[linearIndex] = tensor.mutableBuffer.array()[tensor.bufferStart + offset] } @@ -406,7 +462,7 @@ public open class DoubleTensorAlgebra : val resTensor = zeros(resShape) for (i in 0 until diagonalEntries.tensor.numElements) { - val multiIndex = diagonalEntries.tensor.linearStructure.index(i) + val multiIndex = diagonalEntries.tensor.indices.index(i) var offset1 = 0 var offset2 = abs(realOffset) @@ -425,18 +481,6 @@ public open class DoubleTensorAlgebra : return resTensor.tensor } - /** - * Applies the [transform] function to each element of the tensor and returns the resulting modified tensor. - * - * @param transform the function to be applied to each element of the tensor. - * @return the resulting tensor after applying the function. - */ - public inline fun Tensor.map(transform: (Double) -> Double): DoubleTensor = DoubleTensor( - tensor.shape, - tensor.mutableBuffer.array().map { transform(it) }.toDoubleArray(), - tensor.bufferStart - ) - /** * Compares element-wise two tensors with a specified precision. * @@ -526,7 +570,7 @@ public open class DoubleTensorAlgebra : public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) internal inline fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = - foldFunction(tensor.toDoubleArray()) + foldFunction(tensor.copyArray()) internal inline fun Tensor.foldDim( foldFunction: (DoubleArray) -> Double, @@ -541,7 +585,7 @@ public open class DoubleTensorAlgebra : } val resNumElements = resShape.reduce(Int::times) val resTensor = DoubleTensor(resShape, DoubleArray(resNumElements) { 0.0 }, 0) - for (index in resTensor.linearStructure.indices()) { + for (index in resTensor.indices.indices()) { val prefix = index.take(dim).toIntArray() val suffix = index.takeLast(dimension - dim - 1).toIntArray() resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> @@ -645,39 +689,39 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun Tensor.exp(): DoubleTensor = tensor.map(::exp) + override fun Tensor.exp(): DoubleTensor = tensor.map { exp(it) } - override fun Tensor.ln(): DoubleTensor = tensor.map(::ln) + override fun Tensor.ln(): DoubleTensor = tensor.map { ln(it) } - override fun Tensor.sqrt(): DoubleTensor = tensor.map(::sqrt) + override fun Tensor.sqrt(): DoubleTensor = tensor.map { sqrt(it) } - override fun Tensor.cos(): DoubleTensor = tensor.map(::cos) + override fun Tensor.cos(): DoubleTensor = tensor.map { cos(it) } - override fun Tensor.acos(): DoubleTensor = tensor.map(::acos) + override fun Tensor.acos(): DoubleTensor = tensor.map { acos(it) } - override fun Tensor.cosh(): DoubleTensor = tensor.map(::cosh) + override fun Tensor.cosh(): DoubleTensor = tensor.map { cosh(it) } - override fun Tensor.acosh(): DoubleTensor = tensor.map(::acosh) + override fun Tensor.acosh(): DoubleTensor = tensor.map { acosh(it) } - override fun Tensor.sin(): DoubleTensor = tensor.map(::sin) + override fun Tensor.sin(): DoubleTensor = tensor.map { sin(it) } - override fun Tensor.asin(): DoubleTensor = tensor.map(::asin) + override fun Tensor.asin(): DoubleTensor = tensor.map { asin(it) } - override fun Tensor.sinh(): DoubleTensor = tensor.map(::sinh) + override fun Tensor.sinh(): DoubleTensor = tensor.map { sinh(it) } - override fun Tensor.asinh(): DoubleTensor = tensor.map(::asinh) + override fun Tensor.asinh(): DoubleTensor = tensor.map { asinh(it) } - override fun Tensor.tan(): DoubleTensor = tensor.map(::tan) + override fun Tensor.tan(): DoubleTensor = tensor.map { tan(it) } - override fun Tensor.atan(): DoubleTensor = tensor.map(::atan) + override fun Tensor.atan(): DoubleTensor = tensor.map { atan(it) } - override fun Tensor.tanh(): DoubleTensor = tensor.map(::tanh) + override fun Tensor.tanh(): DoubleTensor = tensor.map { tanh(it) } - override fun Tensor.atanh(): DoubleTensor = tensor.map(::atanh) + override fun Tensor.atanh(): DoubleTensor = tensor.map { atanh(it) } - override fun Tensor.ceil(): DoubleTensor = tensor.map(::ceil) + override fun Tensor.ceil(): DoubleTensor = tensor.map { ceil(it) } - override fun Tensor.floor(): DoubleTensor = tensor.map(::floor) + override fun Tensor.floor(): DoubleTensor = tensor.map { floor(it) } override fun Tensor.inv(): DoubleTensor = invLU(1e-9) 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 4b9c0c382..3787c0972 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 @@ -10,7 +10,7 @@ import kotlin.math.max internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { for (linearIndex in 0 until linearSize) { - val totalMultiIndex = resTensor.linearStructure.index(linearIndex) + val totalMultiIndex = resTensor.indices.index(linearIndex) val curMultiIndex = tensor.shape.copyOf() val offset = totalMultiIndex.size - curMultiIndex.size @@ -23,7 +23,7 @@ internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTenso } } - val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) + val curLinearIndex = tensor.indices.offset(curMultiIndex) resTensor.mutableBuffer.array()[linearIndex] = tensor.mutableBuffer.array()[tensor.bufferStart + curLinearIndex] } @@ -112,7 +112,7 @@ internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List checkShapesCompatible(a: Tensor, b: Tensor) = +internal fun checkShapesCompatible(a: StructureND, b: StructureND) = check(a.shape contentEquals b.shape) { "Incompatible shapes ${a.shape.toList()} and ${b.shape.toList()} " } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index 1f5778d5e..4123ff923 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.MutableBufferND +import space.kscience.kmath.nd.StructureND import space.kscience.kmath.structures.asMutableBuffer import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.BufferedTensor @@ -18,15 +19,15 @@ internal fun BufferedTensor.asTensor(): IntTensor = internal fun BufferedTensor.asTensor(): DoubleTensor = DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) -internal fun Tensor.copyToBufferedTensor(): BufferedTensor = +internal fun StructureND.copyToBufferedTensor(): BufferedTensor = BufferedTensor( this.shape, TensorLinearStructure(this.shape).indices().map(this::get).toMutableList().asMutableBuffer(), 0 ) -internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { +internal fun StructureND.toBufferedTensor(): BufferedTensor = when (this) { is BufferedTensor -> this - is MutableBufferND -> if (this.indexes == TensorLinearStructure(this.shape)) { + is MutableBufferND -> if (this.indices == TensorLinearStructure(this.shape)) { BufferedTensor(this.shape, this.buffer, 0) } else { this.copyToBufferedTensor() @@ -35,7 +36,7 @@ internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { } @PublishedApi -internal val Tensor.tensor: DoubleTensor +internal val StructureND.tensor: DoubleTensor get() = when (this) { is DoubleTensor -> this else -> this.toBufferedTensor().asTensor() 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 8428dae5c..553ed6add 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 @@ -85,7 +85,7 @@ internal fun format(value: Double, digits: Int = 4): String = buildString { internal fun DoubleTensor.toPrettyString(): String = buildString { var offset = 0 val shape = this@toPrettyString.shape - val linearStructure = this@toPrettyString.linearStructure + val linearStructure = this@toPrettyString.indices val vectorSize = shape.last() append("DoubleTensor(\n") var charOffset = 3 diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt index 021ca539c..feade56de 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -19,18 +19,19 @@ public fun Tensor.toDoubleTensor(): DoubleTensor = this.tensor public fun Tensor.toIntTensor(): IntTensor = this.tensor /** - * Returns [DoubleArray] of tensor elements + * Returns a copy-protected [DoubleArray] of tensor elements */ -public fun DoubleTensor.toDoubleArray(): DoubleArray { +public fun DoubleTensor.copyArray(): DoubleArray { + //TODO use ArrayCopy return DoubleArray(numElements) { i -> mutableBuffer[bufferStart + i] } } /** - * Returns [IntArray] of tensor elements + * Returns a copy-protected [IntArray] of tensor elements */ -public fun IntTensor.toIntArray(): IntArray { +public fun IntTensor.copyArray(): IntArray { return IntArray(numElements) { i -> mutableBuffer[bufferStart + i] } -- 2.34.1 From 4635cd3fb3eaab8aac97936b50a08d463e7f91c6 Mon Sep 17 00:00:00 2001 From: darksnake Date: Tue, 26 Oct 2021 16:08:02 +0300 Subject: [PATCH 050/102] Refactor TensorAlgebra to take StructureND and inherit AlgebraND --- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 123 +++++++++++------- .../api/TensorPartialDivisionAlgebra.kt | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 2 +- 3 files changed, 76 insertions(+), 51 deletions(-) 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 ee9251dd1..e40ea3dbc 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 @@ -13,7 +13,10 @@ 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.nd.Shape import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.Field import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra @@ -22,7 +25,24 @@ import space.kscience.kmath.tensors.core.DoubleTensorAlgebra /** * ND4J based [TensorAlgebra] implementation. */ -public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra { +public sealed interface Nd4jTensorAlgebra> : AnalyticTensorAlgebra { + + override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): Nd4jArrayStructure { + val array = + } + + override fun StructureND.map(transform: A.(T) -> T): Nd4jArrayStructure { + TODO("Not yet implemented") + } + + override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): Nd4jArrayStructure { + TODO("Not yet implemented") + } + + override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): Nd4jArrayStructure { + TODO("Not yet implemented") + } + /** * Wraps [INDArray] to [Nd4jArrayStructure]. */ @@ -33,105 +53,107 @@ public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra */ public val StructureND.ndArray: INDArray - override fun T.plus(other: Tensor): Tensor = other.ndArray.add(this).wrap() - override fun Tensor.plus(value: T): Tensor = ndArray.add(value).wrap() + override fun T.plus(other: StructureND): Nd4jArrayStructure = other.ndArray.add(this).wrap() + override fun StructureND.plus(value: T): Nd4jArrayStructure = ndArray.add(value).wrap() - override fun Tensor.plus(other: Tensor): Tensor = ndArray.add(other.ndArray).wrap() + override fun StructureND.plus(other: StructureND): Nd4jArrayStructure = ndArray.add(other.ndArray).wrap() override fun Tensor.plusAssign(value: T) { ndArray.addi(value) } - override fun Tensor.plusAssign(other: Tensor) { + override fun Tensor.plusAssign(other: StructureND) { ndArray.addi(other.ndArray) } - override fun T.minus(other: Tensor): Tensor = other.ndArray.rsub(this).wrap() - override fun Tensor.minus(value: T): Tensor = ndArray.sub(value).wrap() - override fun Tensor.minus(other: Tensor): Tensor = ndArray.sub(other.ndArray).wrap() + override fun T.minus(other: StructureND): Nd4jArrayStructure = other.ndArray.rsub(this).wrap() + override fun StructureND.minus(arg: T): Nd4jArrayStructure = ndArray.sub(arg).wrap() + override fun StructureND.minus(other: StructureND): Nd4jArrayStructure = ndArray.sub(other.ndArray).wrap() override fun Tensor.minusAssign(value: T) { ndArray.rsubi(value) } - override fun Tensor.minusAssign(other: Tensor) { + override fun Tensor.minusAssign(other: StructureND) { ndArray.subi(other.ndArray) } - override fun T.times(other: Tensor): Tensor = other.ndArray.mul(this).wrap() + override fun T.times(arg: StructureND): Nd4jArrayStructure = arg.ndArray.mul(this).wrap() - override fun Tensor.times(value: T): Tensor = - ndArray.mul(value).wrap() + override fun StructureND.times(arg: T): Nd4jArrayStructure = + ndArray.mul(arg).wrap() - override fun Tensor.times(other: Tensor): Tensor = ndArray.mul(other.ndArray).wrap() + override fun StructureND.times(other: StructureND): Nd4jArrayStructure = ndArray.mul(other.ndArray).wrap() override fun Tensor.timesAssign(value: T) { ndArray.muli(value) } - override fun Tensor.timesAssign(other: Tensor) { + override fun Tensor.timesAssign(other: StructureND) { ndArray.mmuli(other.ndArray) } - override fun Tensor.unaryMinus(): Tensor = ndArray.neg().wrap() - override fun Tensor.get(i: Int): Tensor = ndArray.slice(i.toLong()).wrap() - override fun Tensor.transpose(i: Int, j: Int): Tensor = ndArray.swapAxes(i, j).wrap() - override fun Tensor.dot(other: Tensor): Tensor = ndArray.mmul(other.ndArray).wrap() + override fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() + override fun Tensor.get(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() + override fun Tensor.transpose(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() + override fun Tensor.dot(other: Tensor): Nd4jArrayStructure = ndArray.mmul(other.ndArray).wrap() - override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.min(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.min(keepDim, dim).wrap() - override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.sum(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.sum(keepDim, dim).wrap() - override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.max(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.max(keepDim, dim).wrap() - override fun Tensor.view(shape: IntArray): Tensor = ndArray.reshape(shape).wrap() - override fun Tensor.viewAs(other: Tensor): Tensor = view(other.shape) + override fun Tensor.view(shape: IntArray): Nd4jArrayStructure = ndArray.reshape(shape).wrap() + override fun Tensor.viewAs(other: Tensor): Nd4jArrayStructure = view(other.shape) - override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.argMax(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndBase.get().argmax(ndArray, keepDim, dim).wrap() - override fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor = ndArray.mean(keepDim, dim).wrap() + override fun Tensor.mean(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.mean(keepDim, dim).wrap() - override fun Tensor.exp(): Tensor = Transforms.exp(ndArray).wrap() - override fun Tensor.ln(): Tensor = Transforms.log(ndArray).wrap() - override fun Tensor.sqrt(): Tensor = Transforms.sqrt(ndArray).wrap() - override fun Tensor.cos(): Tensor = Transforms.cos(ndArray).wrap() - override fun Tensor.acos(): Tensor = Transforms.acos(ndArray).wrap() - override fun Tensor.cosh(): Tensor = Transforms.cosh(ndArray).wrap() + override fun Tensor.exp(): Nd4jArrayStructure = Transforms.exp(ndArray).wrap() + override fun Tensor.ln(): Nd4jArrayStructure = Transforms.log(ndArray).wrap() + override fun Tensor.sqrt(): Nd4jArrayStructure = Transforms.sqrt(ndArray).wrap() + override fun Tensor.cos(): Nd4jArrayStructure = Transforms.cos(ndArray).wrap() + override fun Tensor.acos(): Nd4jArrayStructure = Transforms.acos(ndArray).wrap() + override fun Tensor.cosh(): Nd4jArrayStructure = Transforms.cosh(ndArray).wrap() - override fun Tensor.acosh(): Tensor = + override fun Tensor.acosh(): Nd4jArrayStructure = Nd4j.getExecutioner().exec(ACosh(ndArray, ndArray.ulike())).wrap() - override fun Tensor.sin(): Tensor = Transforms.sin(ndArray).wrap() - override fun Tensor.asin(): Tensor = Transforms.asin(ndArray).wrap() + override fun Tensor.sin(): Nd4jArrayStructure = Transforms.sin(ndArray).wrap() + override fun Tensor.asin(): Nd4jArrayStructure = Transforms.asin(ndArray).wrap() override fun Tensor.sinh(): Tensor = Transforms.sinh(ndArray).wrap() - override fun Tensor.asinh(): Tensor = + override fun Tensor.asinh(): Nd4jArrayStructure = Nd4j.getExecutioner().exec(ASinh(ndArray, ndArray.ulike())).wrap() - override fun Tensor.tan(): Tensor = Transforms.tan(ndArray).wrap() - override fun Tensor.atan(): Tensor = Transforms.atan(ndArray).wrap() - override fun Tensor.tanh(): Tensor = Transforms.tanh(ndArray).wrap() - override fun Tensor.atanh(): Tensor = Transforms.atanh(ndArray).wrap() - override fun Tensor.ceil(): Tensor = Transforms.ceil(ndArray).wrap() - override fun Tensor.floor(): Tensor = Transforms.floor(ndArray).wrap() - override fun Tensor.std(dim: Int, keepDim: Boolean): Tensor = ndArray.std(true, keepDim, dim).wrap() - override fun T.div(other: Tensor): Tensor = other.ndArray.rdiv(this).wrap() - override fun Tensor.div(value: T): Tensor = ndArray.div(value).wrap() - override fun Tensor.div(other: Tensor): Tensor = ndArray.div(other.ndArray).wrap() + override fun Tensor.tan(): Nd4jArrayStructure = Transforms.tan(ndArray).wrap() + override fun Tensor.atan(): Nd4jArrayStructure = Transforms.atan(ndArray).wrap() + override fun Tensor.tanh(): Nd4jArrayStructure = Transforms.tanh(ndArray).wrap() + override fun Tensor.atanh(): Nd4jArrayStructure = Transforms.atanh(ndArray).wrap() + override fun Tensor.ceil(): Nd4jArrayStructure = Transforms.ceil(ndArray).wrap() + override fun Tensor.floor(): Nd4jArrayStructure = Transforms.floor(ndArray).wrap() + override fun Tensor.std(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + ndArray.std(true, keepDim, dim).wrap() + + override fun T.div(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rdiv(this).wrap() + override fun StructureND.div(arg: T): Nd4jArrayStructure = ndArray.div(arg).wrap() + override fun StructureND.div(other: StructureND): Nd4jArrayStructure = ndArray.div(other.ndArray).wrap() override fun Tensor.divAssign(value: T) { ndArray.divi(value) } - override fun Tensor.divAssign(other: Tensor) { + override fun Tensor.divAssign(other: StructureND) { ndArray.divi(other.ndArray) } - override fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.variance(dim: Int, keepDim: Boolean): Nd4jArrayStructure = Nd4j.getExecutioner().exec(Variance(ndArray, true, true, dim)).wrap() private companion object { @@ -142,7 +164,10 @@ public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra /** * [Double] specialization of [Nd4jTensorAlgebra]. */ -public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { +public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { + + override val elementAlgebra: DoubleField get() = DoubleField + override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() @OptIn(PerformancePitfall::class) @@ -154,7 +179,7 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { } } - override fun Tensor.valueOrNull(): Double? = + override fun StructureND.valueOrNull(): Double? = if (shape contentEquals intArrayOf(1)) ndArray.getDouble(0) else null // TODO rewrite diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index 43c901ed5..dece54834 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -57,5 +57,5 @@ public interface TensorPartialDivisionAlgebra> : TensorAlgebra.divAssign(other: Tensor) + public operator fun Tensor.divAssign(other: StructureND) } 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 472db8f5f..3d343604b 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 @@ -330,7 +330,7 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.divAssign(other: Tensor) { + override fun Tensor.divAssign(other: StructureND) { checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= -- 2.34.1 From 29a90efca5eaa3c7669cae8c6dd0f24a8f31058f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 27 Oct 2021 14:48:36 +0300 Subject: [PATCH 051/102] Tensor algebra generified --- CHANGELOG.md | 1 + .../kmath/benchmarks/NDFieldBenchmark.kt | 7 +- .../space/kscience/kmath/tensors/multik.kt | 6 +- .../kscience/kmath/multik/MultikOpsND.kt | 137 ------------- .../kmath/multik/MultikTensorAlgebra.kt | 187 ++++++++++++++---- .../kscience/kmath/multik/MultikNDTest.kt | 2 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 113 ++++++----- .../tensors/api/AnalyticTensorAlgebra.kt | 47 ++--- .../tensors/api/LinearOpsTensorAlgebra.kt | 15 +- .../kmath/tensors/api/TensorAlgebra.kt | 36 ++-- .../core/BroadcastDoubleTensorAlgebra.kt | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 117 ++++++----- 12 files changed, 323 insertions(+), 347 deletions(-) delete mode 100644 kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index bb267744e..6733c1211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ - Buffer algebra does not require size anymore - Operations -> Ops - Default Buffer and ND algebras are now Ops and lack neutral elements (0, 1) as well as algebra-level shapes. +- Tensor algebra takes read-only structures as input and inherits AlgebraND ### Deprecated - Specialized `DoubleBufferAlgebra` 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 8f9a3e2b8..b5af5aa19 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -13,8 +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.multik.multikND -import space.kscience.kmath.multik.multikTensorAlgebra +import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.nd.BufferedFieldOpsND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.ndAlgebra @@ -79,7 +78,7 @@ internal class NDFieldBenchmark { } @Benchmark - fun multikInPlaceAdd(blackhole: Blackhole) = with(DoubleField.multikTensorAlgebra) { + fun multikInPlaceAdd(blackhole: Blackhole) = with(DoubleField.multikAlgebra) { val res = Multik.ones(shape, DataType.DoubleDataType).wrap() repeat(n) { res += 1.0 } blackhole.consume(res) @@ -100,7 +99,7 @@ internal class NDFieldBenchmark { private val specializedField = DoubleField.ndAlgebra private val genericField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) private val nd4jField = DoubleField.nd4j - private val multikField = DoubleField.multikND + private val multikField = DoubleField.multikAlgebra private val viktorField = DoubleField.viktorAlgebra } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt index f0b776f75..fad68fa96 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt @@ -7,12 +7,12 @@ package space.kscience.kmath.tensors import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ndarray -import space.kscience.kmath.multik.multikND +import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.nd.one import space.kscience.kmath.operations.DoubleField -fun main(): Unit = with(DoubleField.multikND) { +fun main(): Unit = with(DoubleField.multikAlgebra) { val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType().wrap() val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)).wrap() - one(a.shape) - a + b * 3 + one(a.shape) - a + b * 3.0 } diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt deleted file mode 100644 index 4068ba9b9..000000000 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikOpsND.kt +++ /dev/null @@ -1,137 +0,0 @@ -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.api.math.cos -import org.jetbrains.kotlinx.multik.api.math.sin -import org.jetbrains.kotlinx.multik.api.mk -import org.jetbrains.kotlinx.multik.api.zeros -import org.jetbrains.kotlinx.multik.ndarray.data.* -import org.jetbrains.kotlinx.multik.ndarray.operations.* -import space.kscience.kmath.nd.FieldOpsND -import space.kscience.kmath.nd.RingOpsND -import space.kscience.kmath.nd.Shape -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.* - -/** - * A ring algebra for Multik operations - */ -public open class MultikRingOpsND> internal constructor( - public val type: DataType, - override val elementAlgebra: A -) : RingOpsND { - - public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this.asDNArray()) - - override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { - val res = mk.zeros(shape, type).asDNArray() - for (index in res.multiIndices) { - res[index] = elementAlgebra.initializer(index) - } - return res.wrap() - } - - public fun StructureND.asMultik(): MultikTensor = if (this is MultikTensor) { - this - } else { - structureND(shape) { get(it) } - } - - override fun StructureND.map(transform: A.(T) -> T): MultikTensor { - //taken directly from Multik sources - val array = asMultik().array - val data = initMemoryView(array.size, type) - var count = 0 - for (el in array) data[count++] = elementAlgebra.transform(el) - return NDArray(data, shape = array.shape, dim = array.dim).wrap() - } - - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): MultikTensor { - //taken directly from Multik sources - val array = asMultik().array - val data = initMemoryView(array.size, type) - val indexIter = array.multiIndices.iterator() - var index = 0 - for (item in array) { - if (indexIter.hasNext()) { - data[index++] = elementAlgebra.transform(indexIter.next(), item) - } else { - throw ArithmeticException("Index overflow has happened.") - } - } - return NDArray(data, shape = array.shape, dim = array.dim).wrap() - } - - override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): MultikTensor { - require(left.shape.contentEquals(right.shape)) { "ND array shape mismatch" } //TODO replace by ShapeMismatchException - val leftArray = left.asMultik().array - val rightArray = right.asMultik().array - val data = initMemoryView(leftArray.size, type) - var counter = 0 - val leftIterator = leftArray.iterator() - val rightIterator = rightArray.iterator() - //iterating them together - while (leftIterator.hasNext()) { - data[counter++] = elementAlgebra.transform(leftIterator.next(), rightIterator.next()) - } - return NDArray(data, shape = leftArray.shape, dim = leftArray.dim).wrap() - } - - override fun StructureND.unaryMinus(): MultikTensor = asMultik().array.unaryMinus().wrap() - - override fun add(left: StructureND, right: StructureND): MultikTensor = - (left.asMultik().array + right.asMultik().array).wrap() - - override fun StructureND.plus(arg: T): MultikTensor = - asMultik().array.plus(arg).wrap() - - override fun StructureND.minus(arg: T): MultikTensor = asMultik().array.minus(arg).wrap() - - override fun T.plus(arg: StructureND): MultikTensor = arg + this - - override fun T.minus(arg: StructureND): MultikTensor = arg.map { this@minus - it } - - override fun multiply(left: StructureND, right: StructureND): MultikTensor = - left.asMultik().array.times(right.asMultik().array).wrap() - - override fun StructureND.times(arg: T): MultikTensor = - asMultik().array.times(arg).wrap() - - override fun T.times(arg: StructureND): MultikTensor = arg * this - - override fun StructureND.unaryPlus(): MultikTensor = asMultik() - - override fun StructureND.plus(other: StructureND): MultikTensor = - asMultik().array.plus(other.asMultik().array).wrap() - - override fun StructureND.minus(other: StructureND): MultikTensor = - asMultik().array.minus(other.asMultik().array).wrap() - - override fun StructureND.times(other: StructureND): MultikTensor = - asMultik().array.times(other.asMultik().array).wrap() -} - -/** - * A field algebra for multik operations - */ -public class MultikFieldOpsND> internal constructor( - type: DataType, - elementAlgebra: A -) : MultikRingOpsND(type, elementAlgebra), FieldOpsND { - override fun StructureND.div(other: StructureND): StructureND = - asMultik().array.div(other.asMultik().array).wrap() -} - -public val DoubleField.multikND: MultikFieldOpsND - get() = MultikFieldOpsND(DataType.DoubleDataType, DoubleField) - -public val FloatField.multikND: MultikFieldOpsND - get() = MultikFieldOpsND(DataType.FloatDataType, FloatField) - -public val ShortRing.multikND: MultikRingOpsND - get() = MultikRingOpsND(DataType.ShortDataType, ShortRing) - -public val IntRing.multikND: MultikRingOpsND - get() = MultikRingOpsND(DataType.IntDataType, IntRing) - -public val LongRing.multikND: MultikRingOpsND - get() = MultikRingOpsND(DataType.LongDataType, LongRing) \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index 3bbe8e672..ec0d4c6d9 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -15,12 +15,14 @@ import org.jetbrains.kotlinx.multik.api.zeros import org.jetbrains.kotlinx.multik.ndarray.data.* import org.jetbrains.kotlinx.multik.ndarray.operations.* import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.mapInPlace import space.kscience.kmath.operations.* import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra +import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra @JvmInline public value class MultikTensor(public val array: MutableMultiArray) : Tensor { @@ -50,29 +52,80 @@ private fun MultiArray.asD2Array(): D2Array { else throw ClassCastException("Cannot cast MultiArray to NDArray.") } -public class MultikTensorAlgebra> internal constructor( - public val type: DataType, - override val elementAlgebra: A, - public val comparator: Comparator -) : TensorAlgebra { +public abstract class MultikTensorAlgebra> : TensorAlgebra where T : Number, T : Comparable { + + public abstract val type: DataType + + override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { + val strides = DefaultStrides(shape) + val memoryView = initMemoryView(strides.linearSize, type) + strides.indices().forEachIndexed { linearIndex, tensorIndex -> + memoryView[linearIndex] = elementAlgebra.initializer(tensorIndex) + } + return MultikTensor(NDArray(memoryView, shape = shape, dim = DN(shape.size))) + } + + override fun StructureND.map(transform: A.(T) -> T): MultikTensor = if (this is MultikTensor) { + val data = initMemoryView(array.size, type) + var count = 0 + for (el in array) data[count++] = elementAlgebra.transform(el) + NDArray(data, shape = shape, dim = array.dim).wrap() + } else { + structureND(shape) { index -> + transform(get(index)) + } + } + + override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): MultikTensor = + if (this is MultikTensor) { + val array = asMultik().array + val data = initMemoryView(array.size, type) + val indexIter = array.multiIndices.iterator() + var index = 0 + for (item in array) { + if (indexIter.hasNext()) { + data[index++] = elementAlgebra.transform(indexIter.next(), item) + } else { + throw ArithmeticException("Index overflow has happened.") + } + } + NDArray(data, shape = array.shape, dim = array.dim).wrap() + } else { + structureND(shape) { index -> + transform(index, get(index)) + } + } + + override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): MultikTensor { + require(left.shape.contentEquals(right.shape)) { "ND array shape mismatch" } //TODO replace by ShapeMismatchException + val leftArray = left.asMultik().array + val rightArray = right.asMultik().array + val data = initMemoryView(leftArray.size, type) + var counter = 0 + val leftIterator = leftArray.iterator() + val rightIterator = rightArray.iterator() + //iterating them together + while (leftIterator.hasNext()) { + data[counter++] = elementAlgebra.transform(leftIterator.next(), rightIterator.next()) + } + return NDArray(data, shape = leftArray.shape, dim = leftArray.dim).wrap() + } /** * Convert a tensor to [MultikTensor] if necessary. If tensor is converted, changes on the resulting tensor * are not reflected back onto the source */ - public fun StructureND.asMultik(): MultikTensor { - return if (this is MultikTensor) { - this - } else { - val res = mk.zeros(shape, type).asDNArray() - for (index in res.multiIndices) { - res[index] = this[index] - } - res.wrap() + public fun StructureND.asMultik(): MultikTensor = if (this is MultikTensor) { + this + } else { + val res = mk.zeros(shape, type).asDNArray() + for (index in res.multiIndices) { + res[index] = this[index] } + res.wrap() } - public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this) + public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this.asDNArray()) override fun StructureND.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) { get(intArrayOf(0)) @@ -81,8 +134,8 @@ public class MultikTensorAlgebra> internal constructor( override fun T.plus(other: StructureND): MultikTensor = other.plus(this) - override fun StructureND.plus(value: T): MultikTensor = - asMultik().array.deepCopy().apply { plusAssign(value) }.wrap() + override fun StructureND.plus(arg: T): MultikTensor = + asMultik().array.deepCopy().apply { plusAssign(arg) }.wrap() override fun StructureND.plus(other: StructureND): MultikTensor = asMultik().array.plus(other.asMultik().array).wrap() @@ -155,11 +208,11 @@ public class MultikTensorAlgebra> internal constructor( override fun StructureND.unaryMinus(): MultikTensor = asMultik().array.unaryMinus().wrap() - override fun Tensor.get(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() + override fun StructureND.get(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() - override fun Tensor.transpose(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() + override fun StructureND.transpose(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() - override fun Tensor.view(shape: IntArray): MultikTensor { + override fun StructureND.view(shape: IntArray): MultikTensor { require(shape.all { it > 0 }) require(shape.fold(1, Int::times) == this.shape.size) { "Cannot reshape array of size ${this.shape.size} into a new shape ${ @@ -178,9 +231,9 @@ public class MultikTensorAlgebra> internal constructor( }.wrap() } - override fun Tensor.viewAs(other: Tensor): MultikTensor = view(other.shape) + override fun StructureND.viewAs(other: StructureND): MultikTensor = view(other.shape) - override fun Tensor.dot(other: Tensor): MultikTensor = + override fun StructureND.dot(other: StructureND): MultikTensor = if (this.shape.size == 1 && other.shape.size == 1) { Multik.ndarrayOf( asMultik().array.asD1Array() dot other.asMultik().array.asD1Array() @@ -197,45 +250,95 @@ public class MultikTensorAlgebra> internal constructor( TODO("Diagonal embedding not implemented") } - override fun Tensor.sum(): T = asMultik().array.reduceMultiIndexed { _: IntArray, acc: T, t: T -> + override fun StructureND.sum(): T = asMultik().array.reduceMultiIndexed { _: IntArray, acc: T, t: T -> elementAlgebra.add(acc, t) } - override fun Tensor.sum(dim: Int, keepDim: Boolean): MultikTensor { + override fun StructureND.sum(dim: Int, keepDim: Boolean): MultikTensor { TODO("Not yet implemented") } - override fun Tensor.min(): T = - asMultik().array.minWith(comparator) ?: error("No elements in tensor") + override fun StructureND.min(): T? = asMultik().array.min() - override fun Tensor.min(dim: Int, keepDim: Boolean): MultikTensor { + override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } - override fun Tensor.max(): T = - asMultik().array.maxWith(comparator) ?: error("No elements in tensor") + override fun StructureND.max(): T? = asMultik().array.max() - - override fun Tensor.max(dim: Int, keepDim: Boolean): MultikTensor { + override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } - override fun Tensor.argMax(dim: Int, keepDim: Boolean): MultikTensor { + override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } } -public val DoubleField.multikTensorAlgebra: MultikTensorAlgebra - get() = MultikTensorAlgebra(DataType.DoubleDataType, DoubleField) { o1, o2 -> o1.compareTo(o2) } +public abstract class MultikDivisionTensorAlgebra> + : MultikTensorAlgebra(), TensorPartialDivisionAlgebra where T : Number, T : Comparable { -public val FloatField.multikTensorAlgebra: MultikTensorAlgebra - get() = MultikTensorAlgebra(DataType.FloatDataType, FloatField) { o1, o2 -> o1.compareTo(o2) } + override fun T.div(arg: StructureND): MultikTensor = arg.map { elementAlgebra.divide(this@div, it) } -public val ShortRing.multikTensorAlgebra: MultikTensorAlgebra - get() = MultikTensorAlgebra(DataType.ShortDataType, ShortRing) { o1, o2 -> o1.compareTo(o2) } + override fun StructureND.div(arg: T): MultikTensor = + asMultik().array.deepCopy().apply { divAssign(arg) }.wrap() -public val IntRing.multikTensorAlgebra: MultikTensorAlgebra - get() = MultikTensorAlgebra(DataType.IntDataType, IntRing) { o1, o2 -> o1.compareTo(o2) } + override fun StructureND.div(other: StructureND): MultikTensor = + asMultik().array.div(other.asMultik().array).wrap() -public val LongRing.multikTensorAlgebra: MultikTensorAlgebra - get() = MultikTensorAlgebra(DataType.LongDataType, LongRing) { o1, o2 -> o1.compareTo(o2) } \ No newline at end of file + override fun Tensor.divAssign(value: T) { + if (this is MultikTensor) { + array.divAssign(value) + } else { + mapInPlace { _, t -> elementAlgebra.divide(t, value) } + } + } + + override fun Tensor.divAssign(other: StructureND) { + if (this is MultikTensor) { + array.divAssign(other.asMultik().array) + } else { + mapInPlace { index, t -> elementAlgebra.divide(t, other[index]) } + } + } +} + +public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra() { + override val elementAlgebra: DoubleField get() = DoubleField + override val type: DataType get() = DataType.DoubleDataType +} + +public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra +public val DoubleField.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra + +public object MultikFloatAlgebra : MultikDivisionTensorAlgebra() { + override val elementAlgebra: FloatField get() = FloatField + override val type: DataType get() = DataType.FloatDataType +} + +public val Float.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra +public val FloatField.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra + +public object MultikShortAlgebra : MultikTensorAlgebra() { + override val elementAlgebra: ShortRing get() = ShortRing + override val type: DataType get() = DataType.ShortDataType +} + +public val Short.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra +public val ShortRing.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra + +public object MultikIntAlgebra : MultikTensorAlgebra() { + override val elementAlgebra: IntRing get() = IntRing + override val type: DataType get() = DataType.IntDataType +} + +public val Int.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra +public val IntRing.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra + +public object MultikLongAlgebra : MultikTensorAlgebra() { + override val elementAlgebra: LongRing get() = LongRing + override val type: DataType get() = DataType.LongDataType +} + +public val Long.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra +public val LongRing.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra \ No newline at end of file diff --git a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt index 9dd9854c7..66ba7db2d 100644 --- a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt +++ b/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt @@ -7,7 +7,7 @@ import space.kscience.kmath.operations.invoke internal class MultikNDTest { @Test - fun basicAlgebra(): Unit = DoubleField.multikND{ + fun basicAlgebra(): Unit = DoubleField.multikAlgebra{ one(2,2) + 1.0 } } \ No newline at end of file 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 e40ea3dbc..3fb03c964 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 @@ -13,6 +13,7 @@ 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.nd.DefaultStrides import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.DoubleField @@ -27,22 +28,6 @@ import space.kscience.kmath.tensors.core.DoubleTensorAlgebra */ public sealed interface Nd4jTensorAlgebra> : AnalyticTensorAlgebra { - override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): Nd4jArrayStructure { - val array = - } - - override fun StructureND.map(transform: A.(T) -> T): Nd4jArrayStructure { - TODO("Not yet implemented") - } - - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): Nd4jArrayStructure { - TODO("Not yet implemented") - } - - override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): Nd4jArrayStructure { - TODO("Not yet implemented") - } - /** * Wraps [INDArray] to [Nd4jArrayStructure]. */ @@ -53,8 +38,21 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe */ public val StructureND.ndArray: INDArray + override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): Nd4jArrayStructure + + override fun StructureND.map(transform: A.(T) -> T): Nd4jArrayStructure = + structureND(shape) { index -> elementAlgebra.transform(get(index)) } + + override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): Nd4jArrayStructure = + structureND(shape) { index -> elementAlgebra.transform(index, get(index)) } + + override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): Nd4jArrayStructure { + require(left.shape.contentEquals(right.shape)) + return structureND(left.shape) { index -> elementAlgebra.transform(left[index], right[index]) } + } + override fun T.plus(other: StructureND): Nd4jArrayStructure = other.ndArray.add(this).wrap() - override fun StructureND.plus(value: T): Nd4jArrayStructure = ndArray.add(value).wrap() + override fun StructureND.plus(arg: T): Nd4jArrayStructure = ndArray.add(arg).wrap() override fun StructureND.plus(other: StructureND): Nd4jArrayStructure = ndArray.add(other.ndArray).wrap() @@ -94,51 +92,52 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe } override fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() - override fun Tensor.get(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() - override fun Tensor.transpose(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() - override fun Tensor.dot(other: Tensor): Nd4jArrayStructure = ndArray.mmul(other.ndArray).wrap() + override fun StructureND.get(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() + override fun StructureND.transpose(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() + override fun StructureND.dot(other: StructureND): Nd4jArrayStructure = ndArray.mmul(other.ndArray).wrap() - override fun Tensor.min(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun StructureND.min(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.min(keepDim, dim).wrap() - override fun Tensor.sum(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun StructureND.sum(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.sum(keepDim, dim).wrap() - override fun Tensor.max(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun StructureND.max(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.max(keepDim, dim).wrap() - override fun Tensor.view(shape: IntArray): Nd4jArrayStructure = ndArray.reshape(shape).wrap() - override fun Tensor.viewAs(other: Tensor): Nd4jArrayStructure = view(other.shape) + override fun StructureND.view(shape: IntArray): Nd4jArrayStructure = ndArray.reshape(shape).wrap() + override fun StructureND.viewAs(other: StructureND): Nd4jArrayStructure = view(other.shape) - override fun Tensor.argMax(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun StructureND.argMax(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndBase.get().argmax(ndArray, keepDim, dim).wrap() - override fun Tensor.mean(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.mean(keepDim, dim).wrap() + override fun StructureND.mean(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + ndArray.mean(keepDim, dim).wrap() - override fun Tensor.exp(): Nd4jArrayStructure = Transforms.exp(ndArray).wrap() - override fun Tensor.ln(): Nd4jArrayStructure = Transforms.log(ndArray).wrap() - override fun Tensor.sqrt(): Nd4jArrayStructure = Transforms.sqrt(ndArray).wrap() - override fun Tensor.cos(): Nd4jArrayStructure = Transforms.cos(ndArray).wrap() - override fun Tensor.acos(): Nd4jArrayStructure = Transforms.acos(ndArray).wrap() - override fun Tensor.cosh(): Nd4jArrayStructure = Transforms.cosh(ndArray).wrap() + override fun StructureND.exp(): Nd4jArrayStructure = Transforms.exp(ndArray).wrap() + override fun StructureND.ln(): Nd4jArrayStructure = Transforms.log(ndArray).wrap() + override fun StructureND.sqrt(): Nd4jArrayStructure = Transforms.sqrt(ndArray).wrap() + override fun StructureND.cos(): Nd4jArrayStructure = Transforms.cos(ndArray).wrap() + override fun StructureND.acos(): Nd4jArrayStructure = Transforms.acos(ndArray).wrap() + override fun StructureND.cosh(): Nd4jArrayStructure = Transforms.cosh(ndArray).wrap() - override fun Tensor.acosh(): Nd4jArrayStructure = + override fun StructureND.acosh(): Nd4jArrayStructure = Nd4j.getExecutioner().exec(ACosh(ndArray, ndArray.ulike())).wrap() - override fun Tensor.sin(): Nd4jArrayStructure = Transforms.sin(ndArray).wrap() - override fun Tensor.asin(): Nd4jArrayStructure = Transforms.asin(ndArray).wrap() - override fun Tensor.sinh(): Tensor = Transforms.sinh(ndArray).wrap() + override fun StructureND.sin(): Nd4jArrayStructure = Transforms.sin(ndArray).wrap() + override fun StructureND.asin(): Nd4jArrayStructure = Transforms.asin(ndArray).wrap() + override fun StructureND.sinh(): Tensor = Transforms.sinh(ndArray).wrap() - override fun Tensor.asinh(): Nd4jArrayStructure = + override fun StructureND.asinh(): Nd4jArrayStructure = Nd4j.getExecutioner().exec(ASinh(ndArray, ndArray.ulike())).wrap() - override fun Tensor.tan(): Nd4jArrayStructure = Transforms.tan(ndArray).wrap() - override fun Tensor.atan(): Nd4jArrayStructure = Transforms.atan(ndArray).wrap() - override fun Tensor.tanh(): Nd4jArrayStructure = Transforms.tanh(ndArray).wrap() - override fun Tensor.atanh(): Nd4jArrayStructure = Transforms.atanh(ndArray).wrap() - override fun Tensor.ceil(): Nd4jArrayStructure = Transforms.ceil(ndArray).wrap() - override fun Tensor.floor(): Nd4jArrayStructure = Transforms.floor(ndArray).wrap() - override fun Tensor.std(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun StructureND.tan(): Nd4jArrayStructure = Transforms.tan(ndArray).wrap() + override fun StructureND.atan(): Nd4jArrayStructure = Transforms.atan(ndArray).wrap() + override fun StructureND.tanh(): Nd4jArrayStructure = Transforms.tanh(ndArray).wrap() + override fun StructureND.atanh(): Nd4jArrayStructure = Transforms.atanh(ndArray).wrap() + override fun StructureND.ceil(): Nd4jArrayStructure = Transforms.ceil(ndArray).wrap() + override fun StructureND.floor(): Nd4jArrayStructure = Transforms.floor(ndArray).wrap() + override fun StructureND.std(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.std(true, keepDim, dim).wrap() override fun T.div(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rdiv(this).wrap() @@ -153,7 +152,7 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe ndArray.divi(other.ndArray) } - override fun Tensor.variance(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun StructureND.variance(dim: Int, keepDim: Boolean): Nd4jArrayStructure = Nd4j.getExecutioner().exec(Variance(ndArray, true, true, dim)).wrap() private companion object { @@ -170,6 +169,16 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() + override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): Nd4jArrayStructure { + val array: INDArray = Nd4j.zeros(*shape) + val indices = DefaultStrides(shape) + indices.indices().forEach { index -> + array.putScalar(index, elementAlgebra.initializer(index)) + } + return array.wrap() + } + + @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray get() = when (this) { @@ -190,10 +199,10 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { dim2: Int, ): Tensor = DoubleTensorAlgebra.diagonalEmbedding(diagonalEntries, offset, dim1, dim2) - override fun Tensor.sum(): Double = ndArray.sumNumber().toDouble() - override fun Tensor.min(): Double = ndArray.minNumber().toDouble() - override fun Tensor.max(): Double = ndArray.maxNumber().toDouble() - override fun Tensor.mean(): Double = ndArray.meanNumber().toDouble() - override fun Tensor.std(): Double = ndArray.stdNumber().toDouble() - override fun Tensor.variance(): Double = ndArray.varNumber().toDouble() + override fun StructureND.sum(): Double = ndArray.sumNumber().toDouble() + override fun StructureND.min(): Double = ndArray.minNumber().toDouble() + override fun StructureND.max(): Double = ndArray.maxNumber().toDouble() + override fun StructureND.mean(): Double = ndArray.meanNumber().toDouble() + override fun StructureND.std(): Double = ndArray.stdNumber().toDouble() + override fun StructureND.variance(): Double = ndArray.varNumber().toDouble() } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index caafcc7c1..debfb3ef0 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.tensors.api +import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Field @@ -18,7 +19,7 @@ public interface AnalyticTensorAlgebra> : TensorPartialDivisionA /** * @return the mean of all elements in the input tensor. */ - public fun Tensor.mean(): T + public fun StructureND.mean(): T /** * Returns the mean of each row of the input tensor in the given dimension [dim]. @@ -31,12 +32,12 @@ public interface AnalyticTensorAlgebra> : TensorPartialDivisionA * @param keepDim whether the output tensor has [dim] retained or not. * @return the mean of each row of the input tensor in the given dimension [dim]. */ - public fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor + public fun StructureND.mean(dim: Int, keepDim: Boolean): Tensor /** * @return the standard deviation of all elements in the input tensor. */ - public fun Tensor.std(): T + public fun StructureND.std(): T /** * Returns the standard deviation of each row of the input tensor in the given dimension [dim]. @@ -49,12 +50,12 @@ public interface AnalyticTensorAlgebra> : TensorPartialDivisionA * @param keepDim whether the output tensor has [dim] retained or not. * @return the standard deviation of each row of the input tensor in the given dimension [dim]. */ - public fun Tensor.std(dim: Int, keepDim: Boolean): Tensor + public fun StructureND.std(dim: Int, keepDim: Boolean): Tensor /** * @return the variance of all elements in the input tensor. */ - public fun Tensor.variance(): T + public fun StructureND.variance(): T /** * Returns the variance of each row of the input tensor in the given dimension [dim]. @@ -67,57 +68,57 @@ public interface AnalyticTensorAlgebra> : TensorPartialDivisionA * @param keepDim whether the output tensor has [dim] retained or not. * @return the variance of each row of the input tensor in the given dimension [dim]. */ - public fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor + public fun StructureND.variance(dim: Int, keepDim: Boolean): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.exp.html - public fun Tensor.exp(): Tensor + public fun StructureND.exp(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.log.html - public fun Tensor.ln(): Tensor + public fun StructureND.ln(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.sqrt.html - public fun Tensor.sqrt(): Tensor + public fun StructureND.sqrt(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.cos - public fun Tensor.cos(): Tensor + public fun StructureND.cos(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.acos - public fun Tensor.acos(): Tensor + public fun StructureND.acos(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.cosh - public fun Tensor.cosh(): Tensor + public fun StructureND.cosh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.acosh - public fun Tensor.acosh(): Tensor + public fun StructureND.acosh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sin - public fun Tensor.sin(): Tensor + public fun StructureND.sin(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asin - public fun Tensor.asin(): Tensor + public fun StructureND.asin(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sinh - public fun Tensor.sinh(): Tensor + public fun StructureND.sinh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asinh - public fun Tensor.asinh(): Tensor + public fun StructureND.asinh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.atan.html#torch.tan - public fun Tensor.tan(): Tensor + public fun StructureND.tan(): Tensor //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.atan - public fun Tensor.atan(): Tensor + public fun StructureND.atan(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.tanh - public fun Tensor.tanh(): Tensor + public fun StructureND.tanh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.atanh - public fun Tensor.atanh(): Tensor + public fun StructureND.atanh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.ceil.html#torch.ceil - public fun Tensor.ceil(): Tensor + public fun StructureND.ceil(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor - public fun Tensor.floor(): Tensor + public fun StructureND.floor(): Tensor } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 3f32eb9ca..e8fa7dacd 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.tensors.api +import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Field /** @@ -20,7 +21,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * * @return the determinant. */ - public fun Tensor.det(): Tensor + public fun StructureND.det(): Tensor /** * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. @@ -30,7 +31,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * * @return the multiplicative inverse of a matrix. */ - public fun Tensor.inv(): Tensor + public fun StructureND.inv(): Tensor /** * Cholesky decomposition. @@ -46,7 +47,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return the batch of `L` matrices. */ - public fun Tensor.cholesky(): Tensor + public fun StructureND.cholesky(): Tensor /** * QR decomposition. @@ -60,7 +61,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return pair of `Q` and `R` tensors. */ - public fun Tensor.qr(): Pair, Tensor> + public fun StructureND.qr(): Pair, Tensor> /** * LUP decomposition @@ -74,7 +75,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return triple of P, L and U tensors */ - public fun Tensor.lu(): Triple, Tensor, Tensor> + public fun StructureND.lu(): Triple, Tensor, Tensor> /** * Singular Value Decomposition. @@ -90,7 +91,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return triple `Triple(U, S, V)`. */ - public fun Tensor.svd(): Triple, Tensor, Tensor> + public fun StructureND.svd(): Triple, Tensor, Tensor> /** * Returns eigenvalues and eigenvectors of a real symmetric matrix `input` or a batch of real symmetric matrices, @@ -100,6 +101,6 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return a pair `eigenvalues to eigenvectors` */ - public fun Tensor.symEig(): Pair, Tensor> + public fun StructureND.symEig(): Pair, Tensor> } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index e910c5c31..28d7c4677 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -41,12 +41,12 @@ public interface TensorAlgebra> : RingOpsND { override operator fun T.plus(other: StructureND): Tensor /** - * Adds the scalar [value] to each element of this tensor and returns a new resulting tensor. + * Adds the scalar [arg] to each element of this tensor and returns a new resulting tensor. * - * @param value the number to be added to each element of this tensor. - * @return the sum of this tensor and [value]. + * @param arg the number to be added to each element of this tensor. + * @return the sum of this tensor and [arg]. */ - override operator fun StructureND.plus(value: T): Tensor + override operator fun StructureND.plus(arg: T): Tensor /** * Each element of the tensor [other] is added to each element of this tensor. @@ -166,7 +166,7 @@ public interface TensorAlgebra> : RingOpsND { * @param i index of the extractable tensor * @return subtensor of the original tensor with index [i] */ - public operator fun Tensor.get(i: Int): Tensor + public operator fun StructureND.get(i: Int): Tensor /** * Returns a tensor that is a transposed version of this tensor. The given dimensions [i] and [j] are swapped. @@ -176,7 +176,7 @@ public interface TensorAlgebra> : RingOpsND { * @param j the second dimension to be transposed * @return transposed tensor */ - public fun Tensor.transpose(i: Int = -2, j: Int = -1): Tensor + public fun StructureND.transpose(i: Int = -2, j: Int = -1): Tensor /** * Returns a new tensor with the same data as the self tensor but of a different shape. @@ -186,7 +186,7 @@ public interface TensorAlgebra> : RingOpsND { * @param shape the desired size * @return tensor with new shape */ - public fun Tensor.view(shape: IntArray): Tensor + public fun StructureND.view(shape: IntArray): Tensor /** * View this tensor as the same size as [other]. @@ -196,7 +196,7 @@ public interface TensorAlgebra> : RingOpsND { * @param other the result tensor has the same size as other. * @return the result tensor with the same size as other. */ - public fun Tensor.viewAs(other: Tensor): Tensor + public fun StructureND.viewAs(other: StructureND): Tensor /** * Matrix product of two tensors. @@ -227,7 +227,7 @@ public interface TensorAlgebra> : RingOpsND { * @param other tensor to be multiplied. * @return a mathematical product of two tensors. */ - public infix fun Tensor.dot(other: Tensor): Tensor + public infix fun StructureND.dot(other: StructureND): Tensor /** * Creates a tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) @@ -262,7 +262,7 @@ public interface TensorAlgebra> : RingOpsND { /** * @return the sum of all elements in the input tensor. */ - public fun Tensor.sum(): T + public fun StructureND.sum(): T /** * Returns the sum of each row of the input tensor in the given dimension [dim]. @@ -275,12 +275,12 @@ public interface TensorAlgebra> : RingOpsND { * @param keepDim whether the output tensor has [dim] retained or not. * @return the sum of each row of the input tensor in the given dimension [dim]. */ - public fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor + public fun StructureND.sum(dim: Int, keepDim: Boolean): Tensor /** - * @return the minimum value of all elements in the input tensor. + * @return the minimum value of all elements in the input tensor or null if there are no values */ - public fun Tensor.min(): T + public fun StructureND.min(): T? /** * Returns the minimum value of each row of the input tensor in the given dimension [dim]. @@ -293,12 +293,12 @@ public interface TensorAlgebra> : RingOpsND { * @param keepDim whether the output tensor has [dim] retained or not. * @return the minimum value of each row of the input tensor in the given dimension [dim]. */ - public fun Tensor.min(dim: Int, keepDim: Boolean): Tensor + public fun StructureND.min(dim: Int, keepDim: Boolean): Tensor /** - * Returns the maximum value of all elements in the input tensor. + * Returns the maximum value of all elements in the input tensor or null if there are no values */ - public fun Tensor.max(): T + public fun StructureND.max(): T? /** * Returns the maximum value of each row of the input tensor in the given dimension [dim]. @@ -311,7 +311,7 @@ public interface TensorAlgebra> : RingOpsND { * @param keepDim whether the output tensor has [dim] retained or not. * @return the maximum value of each row of the input tensor in the given dimension [dim]. */ - public fun Tensor.max(dim: Int, keepDim: Boolean): Tensor + public fun StructureND.max(dim: Int, keepDim: Boolean): Tensor /** * Returns the index of maximum value of each row of the input tensor in the given dimension [dim]. @@ -324,7 +324,7 @@ public interface TensorAlgebra> : RingOpsND { * @param keepDim whether the output tensor has [dim] retained or not. * @return the index of maximum value of each row of the input tensor in the given dimension [dim]. */ - public fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor + public fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor override fun add(left: StructureND, right: StructureND): Tensor = left + right 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 f3c5d2540..f53a0ca55 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 @@ -85,7 +85,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.divAssign(other: Tensor) { + override fun Tensor.divAssign(other: StructureND) { val newOther = broadcastTo(other.tensor, tensor.shape) for (i in 0 until tensor.indices.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= 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 3d343604b..be87f8019 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 @@ -115,7 +115,7 @@ public open class DoubleTensorAlgebra : TensorLinearStructure(shape).indices().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray() ) - override operator fun Tensor.get(i: Int): DoubleTensor { + override operator fun StructureND.get(i: Int): DoubleTensor { val lastShape = tensor.shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) val newStart = newShape.reduce(Int::times) * i + tensor.bufferStart @@ -160,7 +160,7 @@ public open class DoubleTensorAlgebra : * * @return tensor filled with the scalar value `0.0`, with the same shape as `input` tensor. */ - public fun Tensor.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) + public fun StructureND.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) /** * Returns a tensor filled with the scalar value `1.0`, with the shape defined by the variable argument [shape]. @@ -198,9 +198,8 @@ public open class DoubleTensorAlgebra : * * @return a copy of the `input` tensor with a copied buffer. */ - public fun Tensor.copy(): DoubleTensor { - return DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) - } + public fun StructureND.copy(): DoubleTensor = + DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) override fun Double.plus(other: StructureND): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> @@ -209,7 +208,7 @@ public open class DoubleTensorAlgebra : return DoubleTensor(other.shape, resBuffer) } - override fun StructureND.plus(value: Double): DoubleTensor = value + tensor + override fun StructureND.plus(arg: Double): DoubleTensor = arg + tensor override fun StructureND.plus(other: StructureND): DoubleTensor { checkShapesCompatible(tensor, other.tensor) @@ -345,7 +344,7 @@ public open class DoubleTensorAlgebra : return DoubleTensor(tensor.shape, resBuffer) } - override fun Tensor.transpose(i: Int, j: Int): DoubleTensor { + override fun StructureND.transpose(i: Int, j: Int): DoubleTensor { val ii = tensor.minusIndex(i) val jj = tensor.minusIndex(j) checkTranspose(tensor.dimension, ii, jj) @@ -369,15 +368,15 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun Tensor.view(shape: IntArray): DoubleTensor { + override fun StructureND.view(shape: IntArray): DoubleTensor { checkView(tensor, shape) return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) } - override fun Tensor.viewAs(other: Tensor): DoubleTensor = + override fun StructureND.viewAs(other: StructureND): DoubleTensor = tensor.view(other.shape) - override infix fun Tensor.dot(other: Tensor): DoubleTensor { + override infix fun StructureND.dot(other: StructureND): DoubleTensor { if (tensor.shape.size == 1 && other.shape.size == 1) { return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.mutableBuffer.array().sum())) } @@ -569,10 +568,10 @@ public open class DoubleTensorAlgebra : */ public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) - internal inline fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = + internal inline fun StructureND.fold(foldFunction: (DoubleArray) -> Double): Double = foldFunction(tensor.copyArray()) - internal inline fun Tensor.foldDim( + internal inline fun StructureND.foldDim( foldFunction: (DoubleArray) -> Double, dim: Int, keepDim: Boolean, @@ -596,30 +595,30 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun Tensor.sum(): Double = tensor.fold { it.sum() } + override fun StructureND.sum(): Double = tensor.fold { it.sum() } - override fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor = + override fun StructureND.sum(dim: Int, keepDim: Boolean): DoubleTensor = foldDim({ x -> x.sum() }, dim, keepDim) - override fun Tensor.min(): Double = this.fold { it.minOrNull()!! } + override fun StructureND.min(): Double = this.fold { it.minOrNull()!! } - override fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor = + override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = foldDim({ x -> x.minOrNull()!! }, dim, keepDim) - override fun Tensor.max(): Double = this.fold { it.maxOrNull()!! } + override fun StructureND.max(): Double = this.fold { it.maxOrNull()!! } - override fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor = + override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) - override fun Tensor.argMax(dim: Int, keepDim: Boolean): DoubleTensor = + override fun StructureND.argMax(dim: Int, keepDim: Boolean): DoubleTensor = foldDim({ x -> x.withIndex().maxByOrNull { it.value }?.index!!.toDouble() }, dim, keepDim) - override fun Tensor.mean(): Double = this.fold { it.sum() / tensor.numElements } + override fun StructureND.mean(): Double = this.fold { it.sum() / tensor.numElements } - override fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor = + override fun StructureND.mean(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( { arr -> check(dim < dimension) { "Dimension $dim out of range $dimension" } @@ -629,12 +628,12 @@ public open class DoubleTensorAlgebra : keepDim ) - override fun Tensor.std(): Double = this.fold { arr -> + override fun StructureND.std(): Double = this.fold { arr -> val mean = arr.sum() / tensor.numElements sqrt(arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1)) } - override fun Tensor.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + override fun StructureND.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( { arr -> check(dim < dimension) { "Dimension $dim out of range $dimension" } val mean = arr.sum() / shape[dim] @@ -644,12 +643,12 @@ public open class DoubleTensorAlgebra : keepDim ) - override fun Tensor.variance(): Double = this.fold { arr -> + override fun StructureND.variance(): Double = this.fold { arr -> val mean = arr.sum() / tensor.numElements arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1) } - override fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + override fun StructureND.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( { arr -> check(dim < dimension) { "Dimension $dim out of range $dimension" } val mean = arr.sum() / shape[dim] @@ -672,7 +671,7 @@ public open class DoubleTensorAlgebra : * @param tensors the [List] of 1-dimensional tensors with same shape * @return `M`. */ - public fun cov(tensors: List>): DoubleTensor { + public fun cov(tensors: List>): DoubleTensor { check(tensors.isNotEmpty()) { "List must have at least 1 element" } val n = tensors.size val m = tensors[0].shape[0] @@ -689,43 +688,43 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun Tensor.exp(): DoubleTensor = tensor.map { exp(it) } + override fun StructureND.exp(): DoubleTensor = tensor.map { exp(it) } - override fun Tensor.ln(): DoubleTensor = tensor.map { ln(it) } + override fun StructureND.ln(): DoubleTensor = tensor.map { ln(it) } - override fun Tensor.sqrt(): DoubleTensor = tensor.map { sqrt(it) } + override fun StructureND.sqrt(): DoubleTensor = tensor.map { sqrt(it) } - override fun Tensor.cos(): DoubleTensor = tensor.map { cos(it) } + override fun StructureND.cos(): DoubleTensor = tensor.map { cos(it) } - override fun Tensor.acos(): DoubleTensor = tensor.map { acos(it) } + override fun StructureND.acos(): DoubleTensor = tensor.map { acos(it) } - override fun Tensor.cosh(): DoubleTensor = tensor.map { cosh(it) } + override fun StructureND.cosh(): DoubleTensor = tensor.map { cosh(it) } - override fun Tensor.acosh(): DoubleTensor = tensor.map { acosh(it) } + override fun StructureND.acosh(): DoubleTensor = tensor.map { acosh(it) } - override fun Tensor.sin(): DoubleTensor = tensor.map { sin(it) } + override fun StructureND.sin(): DoubleTensor = tensor.map { sin(it) } - override fun Tensor.asin(): DoubleTensor = tensor.map { asin(it) } + override fun StructureND.asin(): DoubleTensor = tensor.map { asin(it) } - override fun Tensor.sinh(): DoubleTensor = tensor.map { sinh(it) } + override fun StructureND.sinh(): DoubleTensor = tensor.map { sinh(it) } - override fun Tensor.asinh(): DoubleTensor = tensor.map { asinh(it) } + override fun StructureND.asinh(): DoubleTensor = tensor.map { asinh(it) } - override fun Tensor.tan(): DoubleTensor = tensor.map { tan(it) } + override fun StructureND.tan(): DoubleTensor = tensor.map { tan(it) } - override fun Tensor.atan(): DoubleTensor = tensor.map { atan(it) } + override fun StructureND.atan(): DoubleTensor = tensor.map { atan(it) } - override fun Tensor.tanh(): DoubleTensor = tensor.map { tanh(it) } + override fun StructureND.tanh(): DoubleTensor = tensor.map { tanh(it) } - override fun Tensor.atanh(): DoubleTensor = tensor.map { atanh(it) } + override fun StructureND.atanh(): DoubleTensor = tensor.map { atanh(it) } - override fun Tensor.ceil(): DoubleTensor = tensor.map { ceil(it) } + override fun StructureND.ceil(): DoubleTensor = tensor.map { ceil(it) } - override fun Tensor.floor(): DoubleTensor = tensor.map { floor(it) } + override fun StructureND.floor(): DoubleTensor = tensor.map { floor(it) } - override fun Tensor.inv(): DoubleTensor = invLU(1e-9) + override fun StructureND.inv(): DoubleTensor = invLU(1e-9) - override fun Tensor.det(): DoubleTensor = detLU(1e-9) + override fun StructureND.det(): DoubleTensor = detLU(1e-9) /** * Computes the LU factorization of a matrix or batches of matrices `input`. @@ -736,7 +735,7 @@ public open class DoubleTensorAlgebra : * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. */ - public fun Tensor.luFactor(epsilon: Double): Pair = + public fun StructureND.luFactor(epsilon: Double): Pair = computeLU(tensor, epsilon) ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") @@ -749,7 +748,7 @@ public open class DoubleTensorAlgebra : * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. */ - public fun Tensor.luFactor(): Pair = luFactor(1e-9) + public fun StructureND.luFactor(): Pair = luFactor(1e-9) /** * Unpacks the data and pivots from a LU factorization of a tensor. @@ -763,7 +762,7 @@ public open class DoubleTensorAlgebra : * @return triple of `P`, `L` and `U` tensors */ public fun luPivot( - luTensor: Tensor, + luTensor: StructureND, pivotsTensor: Tensor, ): Triple { checkSquareMatrix(luTensor.shape) @@ -806,7 +805,7 @@ public open class DoubleTensorAlgebra : * Used when checking the positive definiteness of the input matrix or matrices. * @return a pair of `Q` and `R` tensors. */ - public fun Tensor.cholesky(epsilon: Double): DoubleTensor { + public fun StructureND.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) checkPositiveDefinite(tensor, epsilon) @@ -819,9 +818,9 @@ public open class DoubleTensorAlgebra : return lTensor } - override fun Tensor.cholesky(): DoubleTensor = cholesky(1e-6) + override fun StructureND.cholesky(): DoubleTensor = cholesky(1e-6) - override fun Tensor.qr(): Pair { + override fun StructureND.qr(): Pair { checkSquareMatrix(shape) val qTensor = zeroesLike() val rTensor = zeroesLike() @@ -837,7 +836,7 @@ public open class DoubleTensorAlgebra : return qTensor to rTensor } - override fun Tensor.svd(): Triple = + override fun StructureND.svd(): Triple = svd(epsilon = 1e-10) /** @@ -853,7 +852,7 @@ public open class DoubleTensorAlgebra : * i.e., the precision with which the cosine approaches 1 in an iterative algorithm. * @return a triple `Triple(U, S, V)`. */ - public fun Tensor.svd(epsilon: Double): Triple { + public fun StructureND.svd(epsilon: Double): Triple { val size = tensor.dimension val commonShape = tensor.shape.sliceArray(0 until size - 2) val (n, m) = tensor.shape.sliceArray(size - 2 until size) @@ -886,7 +885,7 @@ public open class DoubleTensorAlgebra : return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) } - override fun Tensor.symEig(): Pair = symEig(epsilon = 1e-15) + override fun StructureND.symEig(): Pair = symEig(epsilon = 1e-15) /** * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, @@ -896,7 +895,7 @@ public open class DoubleTensorAlgebra : * and when the cosine approaches 1 in the SVD algorithm. * @return a pair `eigenvalues to eigenvectors`. */ - public fun Tensor.symEig(epsilon: Double): Pair { + public fun StructureND.symEig(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) fun MutableStructure2D.cleanSym(n: Int) { @@ -931,7 +930,7 @@ public open class DoubleTensorAlgebra : * with zero. * @return the determinant. */ - public fun Tensor.detLU(epsilon: Double = 1e-9): DoubleTensor { + public fun StructureND.detLU(epsilon: Double = 1e-9): DoubleTensor { checkSquareMatrix(tensor.shape) val luTensor = tensor.copy() val pivotsTensor = tensor.setUpPivots() @@ -964,7 +963,7 @@ public open class DoubleTensorAlgebra : * @param epsilon error in the LU algorithm—permissible error when comparing the determinant of a matrix with zero * @return the multiplicative inverse of a matrix. */ - public fun Tensor.invLU(epsilon: Double = 1e-9): DoubleTensor { + public fun StructureND.invLU(epsilon: Double = 1e-9): DoubleTensor { val (luTensor, pivotsTensor) = luFactor(epsilon) val invTensor = luTensor.zeroesLike() @@ -989,12 +988,12 @@ public open class DoubleTensorAlgebra : * @param epsilon permissible error when comparing the determinant of a matrix with zero. * @return triple of `P`, `L` and `U` tensors. */ - public fun Tensor.lu(epsilon: Double = 1e-9): Triple { + public fun StructureND.lu(epsilon: Double = 1e-9): Triple { val (lu, pivots) = tensor.luFactor(epsilon) return luPivot(lu, pivots) } - override fun Tensor.lu(): Triple = lu(1e-9) + override fun StructureND.lu(): Triple = lu(1e-9) } public val Double.Companion.tensorAlgebra: DoubleTensorAlgebra.Companion get() = DoubleTensorAlgebra -- 2.34.1 From 64629561afed6465ef74bc8f51b892c94d17adac Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 28 Oct 2021 10:52:40 +0300 Subject: [PATCH 052/102] [WIP] TensorFlow refactoring --- .../tensorflow/DoubleTensorFlowAlgebra.kt | 26 +++++-- .../kmath/tensorflow/TensorFlowAlgebra.kt | 78 +++++++++---------- 2 files changed, 58 insertions(+), 46 deletions(-) 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 864205e17..44420cd76 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 @@ -3,11 +3,13 @@ package space.kscience.kmath.tensorflow import org.tensorflow.Graph import org.tensorflow.Output import org.tensorflow.ndarray.NdArray -import org.tensorflow.ndarray.Shape import org.tensorflow.op.core.Constant import org.tensorflow.types.TFloat64 import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.tensors.api.Tensor +import space.kscience.kmath.nd.DefaultStrides +import space.kscience.kmath.nd.Shape +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.DoubleField public class DoubleTensorFlowOutput( graph: Graph, @@ -18,14 +20,28 @@ public class DoubleTensorFlowOutput( public class DoubleTensorFlowAlgebra internal constructor( graph: Graph -) : TensorFlowAlgebra(graph) { +) : TensorFlowAlgebra(graph) { - override fun Tensor.asTensorFlow(): TensorFlowOutput = + override val elementAlgebra: DoubleField get() = DoubleField + + override fun structureND( + shape: Shape, + initializer: DoubleField.(IntArray) -> Double + ): StructureND { + val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> + DefaultStrides(shape).forEach { index -> + array.setDouble(elementAlgebra.initializer(index), *index.toLongArray()) + } + } + return DoubleTensorFlowOutput(graph, ops.constant(res).asOutput()) + } + + override fun StructureND.asTensorFlow(): TensorFlowOutput = if (this is TensorFlowOutput && output.type() == TFloat64::class.java) { @Suppress("UNCHECKED_CAST") this as TensorFlowOutput } else { - val res = TFloat64.tensorOf(Shape.of(*shape.toLongArray())) { array -> + val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> @OptIn(PerformancePitfall::class) elements().forEach { (index, value) -> array.setDouble(value, *index.toLongArray()) 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 12c1211db..e73620d01 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 @@ -11,6 +11,8 @@ import org.tensorflow.op.core.Constant import org.tensorflow.types.family.TType import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.Shape +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.Ring import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra @@ -28,13 +30,7 @@ public value class TensorFlowArray(public val tensor: NdArray) : Tensor override fun get(index: IntArray): T = tensor.getObject(*index.toLongArray()) - @PerformancePitfall - override fun elements(): Sequence> = sequence { - tensor.scalars().forEachIndexed { index: LongArray, ndArray: NdArray -> - //yield(index.toIntArray() to ndArray.scalar) - TODO() - } - } + //TODO implement native element sequence override fun set(index: IntArray, value: T) { tensor.setObject(value, *index.toLongArray()) @@ -70,23 +66,23 @@ public abstract class TensorFlowOutput( } -public abstract class TensorFlowAlgebra internal constructor( +public abstract class TensorFlowAlgebra> internal constructor( protected val graph: Graph -) : TensorAlgebra { +) : TensorAlgebra { protected val ops: Ops by lazy { Ops.create(graph) } - protected abstract fun Tensor.asTensorFlow(): TensorFlowOutput + protected abstract fun StructureND.asTensorFlow(): TensorFlowOutput protected abstract fun Output.wrap(): TensorFlowOutput protected abstract fun const(value: T): Constant - override fun Tensor.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) + override fun StructureND.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) get(Shape(0)) else null - private inline fun Tensor.biOp( - other: Tensor, + private inline fun StructureND.biOp( + other: StructureND, operation: (left: Operand, right: Operand) -> Operand ): TensorFlowOutput { val left = asTensorFlow().output @@ -95,7 +91,7 @@ public abstract class TensorFlowAlgebra internal constructor( } private inline fun T.biOp( - other: Tensor, + other: StructureND, operation: (left: Operand, right: Operand) -> Operand ): TensorFlowOutput { val left = const(this) @@ -103,7 +99,7 @@ public abstract class TensorFlowAlgebra internal constructor( return operation(left, right).asOutput().wrap() } - private inline fun Tensor.biOp( + private inline fun StructureND.biOp( value: T, operation: (left: Operand, right: Operand) -> Operand ): TensorFlowOutput { @@ -113,7 +109,7 @@ public abstract class TensorFlowAlgebra internal constructor( } private inline fun Tensor.inPlaceOp( - other: Tensor, + other: StructureND, operation: (left: Operand, right: Operand) -> Operand ): Unit { val origin = asTensorFlow() @@ -132,46 +128,46 @@ public abstract class TensorFlowAlgebra internal constructor( origin.output = operation(left, right).asOutput() } - private inline fun unOp(value: Tensor, operation: (Operand) -> Operand): TensorFlowOutput = + private inline fun unOp(value: StructureND, operation: (Operand) -> Operand): TensorFlowOutput = operation(value.asTensorFlow().output).asOutput().wrap() - override fun T.plus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::add) + override fun T.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) - override fun Tensor.plus(value: T): TensorFlowOutput = biOp(value, ops.math::add) + override fun StructureND.plus(arg: T): TensorFlowOutput = biOp(arg, ops.math::add) - override fun Tensor.plus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::add) + override fun StructureND.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) override fun Tensor.plusAssign(value: T): Unit = inPlaceOp(value, ops.math::add) - override fun Tensor.plusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::add) + override fun Tensor.plusAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::add) - override fun Tensor.minus(value: T): TensorFlowOutput = biOp(value, ops.math::sub) + override fun StructureND.minus(arg: T): TensorFlowOutput = biOp(arg, ops.math::sub) - override fun Tensor.minus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::sub) + override fun StructureND.minus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::sub) - override fun T.minus(other: Tensor): Tensor = biOp(other, ops.math::sub) + override fun T.minus(arg: StructureND): Tensor = biOp(arg, ops.math::sub) override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) - override fun Tensor.minusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::sub) + override fun Tensor.minusAssign(other: StructureND): Unit = inPlaceOp(other, ops.math::sub) - override fun T.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) + override fun T.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) - override fun Tensor.times(value: T): TensorFlowOutput = biOp(value, ops.math::mul) + override fun StructureND.times(arg: T): TensorFlowOutput = biOp(arg, ops.math::mul) - override fun Tensor.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) + override fun StructureND.times(other: StructureND): TensorFlowOutput = biOp(other, ops.math::mul) override fun Tensor.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul) - override fun Tensor.timesAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::mul) + override fun Tensor.timesAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::mul) - override fun Tensor.unaryMinus(): TensorFlowOutput = unOp(this, ops.math::neg) + override fun StructureND.unaryMinus(): TensorFlowOutput = unOp(this, ops.math::neg) - override fun Tensor.get(i: Int): Tensor { + override fun StructureND.get(i: Int): Tensor { TODO("Not yet implemented") } - override fun Tensor.transpose(i: Int, j: Int): Tensor = unOp(this) { + override fun StructureND.transpose(i: Int, j: Int): Tensor = unOp(this) { ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) } @@ -179,11 +175,11 @@ public abstract class TensorFlowAlgebra internal constructor( TODO("Not yet implemented") } - override fun Tensor.viewAs(other: Tensor): Tensor { + override fun Tensor.viewAs(other: StructureND): Tensor { TODO("Not yet implemented") } - override fun Tensor.dot(other: Tensor): TensorFlowOutput = biOp(other) { l, r -> + override fun StructureND.dot(other: StructureND): TensorFlowOutput = biOp(other) { l, r -> ops.linalg.matMul(l, r) } @@ -191,29 +187,29 @@ public abstract class TensorFlowAlgebra internal constructor( TODO("Not yet implemented") } - override fun Tensor.sum(): T = TODO("Not yet implemented") + override fun StructureND.sum(): T = TODO("Not yet implemented") - override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor { + override fun StructureND.sum(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } - override fun Tensor.min(): T { + override fun StructureND.min(): T { TODO("Not yet implemented") } - override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor { + override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } - override fun Tensor.max(): T { + override fun StructureND.max(): T { TODO("Not yet implemented") } - override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor { + override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } - override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor { + override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } } \ No newline at end of file -- 2.34.1 From 4db7398a288cec1939b4b3bbcd02908bd89c501a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 28 Oct 2021 10:58:22 +0300 Subject: [PATCH 053/102] Tensor algebra generified --- .../structures/StructureReadBenchmark.kt | 8 +-- .../kscience/kmath/complex/Quaternion.kt | 4 +- .../kscience/kmath/expressions/MstAlgebra.kt | 10 +-- .../kmath/linear/BufferedLinearSpace.kt | 2 + .../space/kscience/kmath/nd/AlgebraND.kt | 45 +++++++++++--- .../kscience/kmath/nd/BufferAlgebraND.kt | 6 ++ .../space/kscience/kmath/nd/BufferND.kt | 4 +- .../space/kscience/kmath/nd/DoubleFieldND.kt | 13 ++-- .../space/kscience/kmath/nd/ShapeIndexer.kt | 8 ++- .../space/kscience/kmath/nd/StructureND.kt | 6 +- .../kscience/kmath/operations/Algebra.kt | 12 ++-- .../kmath/operations/NumericAlgebra.kt | 4 +- .../kscience/kmath/operations/numbers.kt | 4 +- .../kscience/kmath/operations/BigNumbers.kt | 4 +- .../kmath/structures/LazyStructureND.kt | 2 +- .../kmath/histogram/IndexedHistogramSpace.kt | 2 +- .../histogram/MultivariateHistogramTest.kt | 2 +- .../kscience/kmath/jafama/KMathJafama.kt | 4 +- .../kmath/multik/MultikTensorAlgebra.kt | 46 +++++++------- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 4 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 30 ++++----- .../kmath/tensors/api/TensorAlgebra.kt | 62 +++++++++---------- .../api/TensorPartialDivisionAlgebra.kt | 8 +-- .../core/BroadcastDoubleTensorAlgebra.kt | 24 +++---- .../kmath/tensors/core/BufferedTensor.kt | 5 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 60 +++++++++--------- .../tensors/core/internal/tensorCastsUtils.kt | 2 +- .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 16 ++--- .../kmath/viktor/ViktorStructureND.kt | 2 +- 29 files changed, 221 insertions(+), 178 deletions(-) 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 84dd6538c..db77129a2 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt @@ -19,24 +19,24 @@ fun main() { measureTimeMillis { var res = 0.0 - strides.indices().forEach { res = structure[it] } + strides.asSequence().forEach { res = structure[it] } } // warmup val time1 = measureTimeMillis { var res = 0.0 - strides.indices().forEach { res = structure[it] } + strides.asSequence().forEach { res = structure[it] } } println("Structure reading finished in $time1 millis") val time2 = measureTimeMillis { var res = 0.0 - strides.indices().forEach { res = buffer[strides.offset(it)] } + strides.asSequence().forEach { res = buffer[strides.offset(it)] } } println("Buffer reading finished in $time2 millis") val time3 = measureTimeMillis { var res = 0.0 - strides.indices().forEach { res = array[strides.offset(it)] } + strides.asSequence().forEach { res = array[strides.offset(it)] } } println("Array reading finished in $time3 millis") } 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 47cc61313..ff9a8302a 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 @@ -166,8 +166,8 @@ public object QuaternionField : Field, Norm, override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z) override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z) - override operator fun Number.times(other: Quaternion): Quaternion = - Quaternion(toDouble() * other.w, toDouble() * other.x, toDouble() * other.y, toDouble() * other.z) + override operator fun Number.times(arg: Quaternion): Quaternion = + Quaternion(toDouble() * arg.w, toDouble() * arg.x, toDouble() * arg.y, toDouble() * arg.z) override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) 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 dd3c46207..ca0671ccb 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 @@ -38,8 +38,8 @@ public object MstGroup : Group, NumericAlgebra, ScaleOperations { override operator fun MST.unaryMinus(): MST.Unary = unaryOperationFunction(GroupOps.MINUS_OPERATION)(this) - override operator fun MST.minus(other: MST): MST.Binary = - binaryOperationFunction(GroupOps.MINUS_OPERATION)(this, other) + override operator fun MST.minus(arg: MST): MST.Binary = + binaryOperationFunction(GroupOps.MINUS_OPERATION)(this, arg) override fun scale(a: MST, value: Double): MST.Binary = binaryOperationFunction(RingOps.TIMES_OPERATION)(a, number(value)) @@ -72,7 +72,7 @@ public object MstRing : Ring, NumbersAddOps, ScaleOperations { override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus } - override operator fun MST.minus(other: MST): MST.Binary = MstGroup { this@minus - other } + override operator fun MST.minus(arg: MST): MST.Binary = MstGroup { this@minus - arg } override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstGroup.binaryOperationFunction(operation) @@ -103,7 +103,7 @@ public object MstField : Field, NumbersAddOps, ScaleOperations { override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } - override operator fun MST.minus(other: MST): MST.Binary = MstRing { this@minus - other } + override operator fun MST.minus(arg: MST): MST.Binary = MstRing { this@minus - arg } override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperationFunction(operation) @@ -144,7 +144,7 @@ public object MstExtendedField : ExtendedField, NumericAlgebra { override fun divide(left: MST, right: MST): MST.Binary = MstField.divide(left, right) override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus } - override operator fun MST.minus(other: MST): MST.Binary = MstField { this@minus - other } + override operator fun MST.minus(arg: MST): MST.Binary = MstField { this@minus - arg } override fun power(arg: MST, pow: Number): MST.Binary = binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) 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 f72b9bd81..410fb8505 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 @@ -29,6 +29,7 @@ public class BufferedLinearSpace>( override fun buildVector(size: Int, initializer: A.(Int) -> T): Point = bufferAlgebra.buffer(size) { elementAlgebra.initializer(it) } + @OptIn(PerformancePitfall::class) override fun Matrix.unaryMinus(): Matrix = ndAlgebra { asND().map { -it }.as2D() } @@ -83,6 +84,7 @@ public class BufferedLinearSpace>( } } + @OptIn(PerformancePitfall::class) override fun Matrix.times(value: T): Matrix = ndAlgebra { asND().map { it * value }.as2D() } 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 3d2d08fac..4e52c8ba9 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,6 +5,7 @@ package space.kscience.kmath.nd +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.reflect.KClass @@ -24,6 +25,8 @@ public fun Shape(shapeFirst: Int, vararg shapeRest: Int): Shape = intArrayOf(sha public interface WithShape { public val shape: Shape + + public val indices: ShapeIndexer get() = DefaultStrides(shape) } /** @@ -46,21 +49,37 @@ public interface AlgebraND> { /** * Maps elements from one structure to another one by applying [transform] to them. */ - public fun StructureND.map(transform: C.(T) -> T): StructureND + @PerformancePitfall("Very slow on remote execution algebras") + public fun StructureND.map(transform: C.(T) -> T): StructureND = structureND(shape) { index -> + elementAlgebra.transform(get(index)) + } /** * Maps elements from one structure to another one by applying [transform] to them alongside with their indices. */ - public fun StructureND.mapIndexed(transform: C.(index: IntArray, T) -> T): StructureND + @PerformancePitfall("Very slow on remote execution algebras") + public fun StructureND.mapIndexed(transform: C.(index: IntArray, T) -> T): StructureND = + structureND(shape) { index -> + elementAlgebra.transform(index, get(index)) + } /** * Combines two structures into one. */ - public fun zip(left: StructureND, right: StructureND, transform: C.(T, T) -> T): StructureND + @PerformancePitfall("Very slow on remote execution algebras") + public fun zip(left: StructureND, right: StructureND, transform: C.(T, T) -> T): StructureND { + require(left.shape.contentEquals(right.shape)) { + "Expected left and right of the same shape, but left - ${left.shape} and right - ${right.shape}" + } + return structureND(left.shape) { index -> + elementAlgebra.transform(left[index], right[index]) + } + } /** * Element-wise invocation of function working on [T] on a [StructureND]. */ + @PerformancePitfall public operator fun Function1.invoke(structure: StructureND): StructureND = structure.map { value -> this@invoke(value) } @@ -104,6 +123,7 @@ public interface GroupOpsND> : GroupOps>, * @param right the addend. * @return the sum. */ + @OptIn(PerformancePitfall::class) override fun add(left: StructureND, right: StructureND): StructureND = zip(left, right) { aValue, bValue -> add(aValue, bValue) } @@ -116,6 +136,7 @@ public interface GroupOpsND> : GroupOps>, * @param arg the addend. * @return the sum. */ + @OptIn(PerformancePitfall::class) public operator fun StructureND.plus(arg: T): StructureND = this.map { value -> add(arg, value) } /** @@ -125,25 +146,28 @@ public interface GroupOpsND> : GroupOps>, * @param arg the divisor. * @return the quotient. */ + @OptIn(PerformancePitfall::class) public operator fun StructureND.minus(arg: T): StructureND = this.map { value -> add(arg, -value) } /** * Adds an element to ND structure of it. * * @receiver the augend. - * @param other the addend. + * @param arg the addend. * @return the sum. */ - public operator fun T.plus(other: StructureND): StructureND = other.map { value -> add(this@plus, value) } + @OptIn(PerformancePitfall::class) + public operator fun T.plus(arg: StructureND): StructureND = arg.map { value -> add(this@plus, value) } /** * Subtracts an ND structure from an element of it. * * @receiver the dividend. - * @param other the divisor. + * @param arg the divisor. * @return the quotient. */ - public operator fun T.minus(other: StructureND): StructureND = other.map { value -> add(-this@minus, value) } + @OptIn(PerformancePitfall::class) + public operator fun T.minus(arg: StructureND): StructureND = arg.map { value -> add(-this@minus, value) } public companion object } @@ -166,6 +190,7 @@ public interface RingOpsND> : RingOps>, Gro * @param right the multiplier. * @return the product. */ + @OptIn(PerformancePitfall::class) override fun multiply(left: StructureND, right: StructureND): StructureND = zip(left, right) { aValue, bValue -> multiply(aValue, bValue) } @@ -178,6 +203,7 @@ public interface RingOpsND> : RingOps>, Gro * @param arg the multiplier. * @return the product. */ + @OptIn(PerformancePitfall::class) public operator fun StructureND.times(arg: T): StructureND = this.map { value -> multiply(arg, value) } /** @@ -187,6 +213,7 @@ public interface RingOpsND> : RingOps>, Gro * @param arg the multiplier. * @return the product. */ + @OptIn(PerformancePitfall::class) public operator fun T.times(arg: StructureND): StructureND = arg.map { value -> multiply(this@times, value) } public companion object @@ -214,6 +241,7 @@ public interface FieldOpsND> : * @param right the divisor. * @return the quotient. */ + @OptIn(PerformancePitfall::class) override fun divide(left: StructureND, right: StructureND): StructureND = zip(left, right) { aValue, bValue -> divide(aValue, bValue) } @@ -225,6 +253,7 @@ public interface FieldOpsND> : * @param arg the divisor. * @return the quotient. */ + @OptIn(PerformancePitfall::class) public operator fun StructureND.div(arg: T): StructureND = this.map { value -> divide(arg, value) } /** @@ -234,8 +263,10 @@ public interface FieldOpsND> : * @param arg the divisor. * @return the quotient. */ + @OptIn(PerformancePitfall::class) public operator fun T.div(arg: StructureND): StructureND = arg.map { divide(it, this@div) } + @OptIn(PerformancePitfall::class) override fun scale(a: StructureND, value: Double): StructureND = a.map { scale(it, value) } } 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 cf007e7c9..0e094a8c7 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,6 +7,7 @@ package space.kscience.kmath.nd +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.BufferFactory @@ -34,11 +35,14 @@ public interface BufferAlgebraND> : AlgebraND { } } + @PerformancePitfall override fun StructureND.map(transform: A.(T) -> T): BufferND = mapInline(toBufferND(), transform) + @PerformancePitfall override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): BufferND = mapIndexedInline(toBufferND(), transform) + @PerformancePitfall override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): BufferND = zipInline(left.toBufferND(), right.toBufferND(), transform) @@ -78,6 +82,7 @@ internal inline fun > BufferAlgebraND.zipInline( return BufferND(indexes, bufferAlgebra.zipInline(l.buffer, r.buffer, block)) } +@OptIn(PerformancePitfall::class) public open class BufferedGroupNDOps>( override val bufferAlgebra: BufferAlgebra, override val indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder @@ -101,6 +106,7 @@ public open class BufferedFieldOpsND>( indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder ) : this(BufferFieldOps(elementAlgebra, bufferFactory), indexerBuilder) + @OptIn(PerformancePitfall::class) override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } } 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 2b6fd3693..19924616d 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 @@ -19,7 +19,7 @@ import space.kscience.kmath.structures.MutableBufferFactory * @param buffer The underlying buffer. */ public open class BufferND( - public val indices: ShapeIndexer, + override val indices: ShapeIndexer, public open val buffer: Buffer, ) : StructureND { @@ -28,7 +28,7 @@ public open class BufferND( override val shape: IntArray get() = indices.shape @PerformancePitfall - override fun elements(): Sequence> = indices.indices().map { + override fun elements(): Sequence> = indices.asSequence().map { it to this[it] } 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 abb8e46ea..8cc5472a9 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,6 +5,7 @@ package space.kscience.kmath.nd +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.DoubleBuffer @@ -50,10 +51,12 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { block(lArray[it], rArray[it]) }) } + @OptIn(PerformancePitfall::class) override fun StructureND.map(transform: DoubleField.(Double) -> Double): BufferND = mapInline(toBufferND()) { DoubleField.transform(it) } + @OptIn(PerformancePitfall::class) override fun zip( left: StructureND, right: StructureND, @@ -92,11 +95,11 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D override fun StructureND.unaryPlus(): DoubleBufferND = toBufferND() - override fun StructureND.plus(other: StructureND): DoubleBufferND = - zipInline(toBufferND(), other.toBufferND()) { l: Double, r: Double -> l + r } + override fun StructureND.plus(arg: StructureND): DoubleBufferND = + zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l + r } - override fun StructureND.minus(other: StructureND): DoubleBufferND = - zipInline(toBufferND(), other.toBufferND()) { l: Double, r: Double -> l - r } + override fun StructureND.minus(arg: StructureND): DoubleBufferND = + zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l - r } override fun StructureND.times(other: StructureND): DoubleBufferND = zipInline(toBufferND(), other.toBufferND()) { l: Double, r: Double -> l * r } @@ -107,7 +110,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D override fun StructureND.div(k: Number): DoubleBufferND = mapInline(toBufferND()) { it / k.toDouble() } - override fun Number.times(other: StructureND): DoubleBufferND = other * this + override fun Number.times(arg: StructureND): DoubleBufferND = arg * this override fun StructureND.plus(arg: Double): DoubleBufferND = mapInline(toBufferND()) { it + arg } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt index 1ce6b7519..20e180dd1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt @@ -10,7 +10,7 @@ import kotlin.native.concurrent.ThreadLocal /** * A converter from linear index to multivariate index */ -public interface ShapeIndexer{ +public interface ShapeIndexer: Iterable{ public val shape: Shape /** @@ -33,7 +33,9 @@ public interface ShapeIndexer{ /** * Iterate over ND indices in a natural order */ - public fun indices(): Sequence + public fun asSequence(): Sequence + + override fun iterator(): Iterator = asSequence().iterator() override fun equals(other: Any?): Boolean override fun hashCode(): Int @@ -58,7 +60,7 @@ public abstract class Strides: ShapeIndexer { /** * Iterate over ND indices in a natural order */ - public override fun indices(): Sequence = (0 until linearSize).asSequence().map(::index) + public override fun asSequence(): Sequence = (0 until linearSize).asSequence().map(::index) } /** 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 496abf60f..614d97950 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 @@ -28,12 +28,12 @@ public interface StructureFeature : Feature * * @param T the type of items. */ -public interface StructureND : Featured { +public interface StructureND : Featured, WithShape { /** * The shape of structure i.e., non-empty sequence of non-negative integers that specify sizes of dimensions of * this structure. */ - public val shape: Shape + override val shape: Shape /** * The count of dimensions in this structure. It should be equal to size of [shape]. @@ -54,7 +54,7 @@ public interface StructureND : Featured { * @return the lazy sequence of pairs of indices to values. */ @PerformancePitfall - public fun elements(): Sequence> + public fun elements(): Sequence> = indices.asSequence().map { it to get(it) } /** * Feature is some additional structure information that allows to access it special properties or hints. 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 d0b0c0b73..c6af75237 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 @@ -149,19 +149,19 @@ public interface GroupOps : Algebra { * Addition of two elements. * * @receiver the augend. - * @param other the addend. + * @param arg the addend. * @return the sum. */ - public operator fun T.plus(other: T): T = add(this, other) + public operator fun T.plus(arg: T): T = add(this, arg) /** * Subtraction of two elements. * * @receiver the minuend. - * @param other the subtrahend. + * @param arg the subtrahend. * @return the difference. */ - public operator fun T.minus(other: T): T = add(this, -other) + public operator fun T.minus(arg: T): T = add(this, -arg) // Dynamic dispatch of operations override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> +arg } @@ -219,9 +219,9 @@ public interface RingOps : GroupOps { * Multiplies this element by scalar. * * @receiver the multiplier. - * @param other the multiplicand. + * @param arg the multiplicand. */ - public operator fun T.times(other: T): T = multiply(this, other) + public operator fun T.times(arg: T): T = multiply(this, arg) override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { TIMES_OPERATION -> ::multiply 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 6be3449f9..9d9fc0885 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 @@ -139,10 +139,10 @@ public interface ScaleOperations : Algebra { * Multiplication of this number by element. * * @receiver the multiplier. - * @param other the multiplicand. + * @param arg the multiplicand. * @return the product. */ - public operator fun Number.times(other: T): T = other * this + public operator fun Number.times(arg: T): T = arg * this } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 1168dc6ba..0b111349c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -228,8 +228,8 @@ public object ByteRing : Ring, Norm, NumericAlgebra { override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte() override inline fun Byte.unaryMinus(): Byte = (-this).toByte() - override inline fun Byte.plus(other: Byte): Byte = (this + other).toByte() - override inline fun Byte.minus(other: Byte): Byte = (this - other).toByte() + override inline fun Byte.plus(arg: Byte): Byte = (this + arg).toByte() + override inline fun Byte.minus(arg: Byte): Byte = (this - arg).toByte() override inline fun Byte.times(other: Byte): Byte = (this * other).toByte() } diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt index 3a9c242fc..f63efbef2 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt @@ -19,7 +19,7 @@ public object JBigIntegerField : Ring, NumericAlgebra { override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong()) override fun add(left: BigInteger, right: BigInteger): BigInteger = left.add(right) - override operator fun BigInteger.minus(other: BigInteger): BigInteger = subtract(other) + override operator fun BigInteger.minus(arg: BigInteger): BigInteger = subtract(arg) override fun multiply(left: BigInteger, right: BigInteger): BigInteger = left.multiply(right) override operator fun BigInteger.unaryMinus(): BigInteger = negate() @@ -40,7 +40,7 @@ public abstract class JBigDecimalFieldBase internal constructor( get() = BigDecimal.ONE override fun add(left: BigDecimal, right: BigDecimal): BigDecimal = left.add(right) - override operator fun BigDecimal.minus(other: BigDecimal): BigDecimal = subtract(other) + override operator fun BigDecimal.minus(arg: BigDecimal): BigDecimal = subtract(arg) override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble()) override fun scale(a: BigDecimal, value: Double): BigDecimal = 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 3eb6f3aa6..1feb43f33 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 @@ -28,7 +28,7 @@ public class LazyStructureND( @OptIn(PerformancePitfall::class) override fun elements(): Sequence> { val strides = DefaultStrides(shape) - val res = runBlocking { strides.indices().toList().map { index -> index to await(index) } } + val res = runBlocking { strides.asSequence().toList().map { index -> index to await(index) } } return res.asSequence() } } diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt index a495577c3..f36f45389 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt @@ -38,7 +38,7 @@ public class IndexedHistogram, V : Any>( override val dimension: Int get() = context.shape.size override val bins: Iterable> - get() = DefaultStrides(context.shape).indices().map { + get() = DefaultStrides(context.shape).asSequence().map { context.produceBin(it, values[it]) }.asIterable() 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 23dd076e1..e07488741 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 @@ -70,7 +70,7 @@ internal class MultivariateHistogramTest { } val res = histogram1 - histogram2 assertTrue { - DefaultStrides(shape).indices().all { index -> + DefaultStrides(shape).asSequence().all { index -> res.values[index] <= histogram1.values[index] } } diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt index 645a14e30..9ff7ffc9c 100644 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt @@ -57,8 +57,8 @@ public object JafamaDoubleField : ExtendedField, Norm, S override inline fun norm(arg: Double): Double = FastMath.abs(arg) override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(other: Double): Double = this + other - override inline fun Double.minus(other: Double): Double = this - other + override inline fun Double.plus(arg: Double): Double = this + arg + override inline fun Double.minus(arg: Double): Double = this - arg override inline fun Double.times(other: Double): Double = this * other override inline fun Double.div(other: Double): Double = this / other } diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index ec0d4c6d9..02959d4fb 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -59,7 +59,7 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { val strides = DefaultStrides(shape) val memoryView = initMemoryView(strides.linearSize, type) - strides.indices().forEachIndexed { linearIndex, tensorIndex -> + strides.asSequence().forEachIndexed { linearIndex, tensorIndex -> memoryView[linearIndex] = elementAlgebra.initializer(tensorIndex) } return MultikTensor(NDArray(memoryView, shape = shape, dim = DN(shape.size))) @@ -131,14 +131,14 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra get(intArrayOf(0)) } else null - override fun T.plus(other: StructureND): MultikTensor = - other.plus(this) + override fun T.plus(arg: StructureND): MultikTensor = + arg.plus(this) override fun StructureND.plus(arg: T): MultikTensor = asMultik().array.deepCopy().apply { plusAssign(arg) }.wrap() - override fun StructureND.plus(other: StructureND): MultikTensor = - asMultik().array.plus(other.asMultik().array).wrap() + override fun StructureND.plus(arg: StructureND): MultikTensor = + asMultik().array.plus(arg.asMultik().array).wrap() override fun Tensor.plusAssign(value: T) { if (this is MultikTensor) { @@ -148,21 +148,21 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra } } - override fun Tensor.plusAssign(other: StructureND) { + override fun Tensor.plusAssign(arg: StructureND) { if (this is MultikTensor) { - array.plusAssign(other.asMultik().array) + array.plusAssign(arg.asMultik().array) } else { - mapInPlace { index, t -> elementAlgebra.add(t, other[index]) } + mapInPlace { index, t -> elementAlgebra.add(t, arg[index]) } } } - override fun T.minus(other: StructureND): MultikTensor = (-(other.asMultik().array - this)).wrap() + override fun T.minus(arg: StructureND): MultikTensor = (-(arg.asMultik().array - this)).wrap() override fun StructureND.minus(arg: T): MultikTensor = asMultik().array.deepCopy().apply { minusAssign(arg) }.wrap() - override fun StructureND.minus(other: StructureND): MultikTensor = - asMultik().array.minus(other.asMultik().array).wrap() + override fun StructureND.minus(arg: StructureND): MultikTensor = + asMultik().array.minus(arg.asMultik().array).wrap() override fun Tensor.minusAssign(value: T) { if (this is MultikTensor) { @@ -172,11 +172,11 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra } } - override fun Tensor.minusAssign(other: StructureND) { + override fun Tensor.minusAssign(arg: StructureND) { if (this is MultikTensor) { - array.minusAssign(other.asMultik().array) + array.minusAssign(arg.asMultik().array) } else { - mapInPlace { index, t -> elementAlgebra.run { t - other[index] } } + mapInPlace { index, t -> elementAlgebra.run { t - arg[index] } } } } @@ -186,8 +186,8 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra override fun StructureND.times(arg: T): Tensor = asMultik().array.deepCopy().apply { timesAssign(arg) }.wrap() - override fun StructureND.times(other: StructureND): MultikTensor = - asMultik().array.times(other.asMultik().array).wrap() + override fun StructureND.times(arg: StructureND): MultikTensor = + asMultik().array.times(arg.asMultik().array).wrap() override fun Tensor.timesAssign(value: T) { if (this is MultikTensor) { @@ -197,11 +197,11 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra } } - override fun Tensor.timesAssign(other: StructureND) { + override fun Tensor.timesAssign(arg: StructureND) { if (this is MultikTensor) { - array.timesAssign(other.asMultik().array) + array.timesAssign(arg.asMultik().array) } else { - mapInPlace { index, t -> elementAlgebra.multiply(t, other[index]) } + mapInPlace { index, t -> elementAlgebra.multiply(t, arg[index]) } } } @@ -212,7 +212,7 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra override fun StructureND.transpose(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() - override fun StructureND.view(shape: IntArray): MultikTensor { + override fun Tensor.view(shape: IntArray): MultikTensor { require(shape.all { it > 0 }) require(shape.fold(1, Int::times) == this.shape.size) { "Cannot reshape array of size ${this.shape.size} into a new shape ${ @@ -231,7 +231,7 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra }.wrap() } - override fun StructureND.viewAs(other: StructureND): MultikTensor = view(other.shape) + override fun Tensor.viewAs(other: StructureND): MultikTensor = view(other.shape) override fun StructureND.dot(other: StructureND): MultikTensor = if (this.shape.size == 1 && other.shape.size == 1) { @@ -283,8 +283,8 @@ public abstract class MultikDivisionTensorAlgebra> override fun StructureND.div(arg: T): MultikTensor = asMultik().array.deepCopy().apply { divAssign(arg) }.wrap() - override fun StructureND.div(other: StructureND): MultikTensor = - asMultik().array.div(other.asMultik().array).wrap() + override fun StructureND.div(arg: StructureND): MultikTensor = + asMultik().array.div(arg.asMultik().array).wrap() override fun Tensor.divAssign(value: T) { if (this is MultikTensor) { 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 1f312849a..b1cc1f834 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 @@ -76,8 +76,8 @@ public sealed interface Nd4jArrayGroupOps> : GroupOpsND override fun add(left: StructureND, right: StructureND): Nd4jArrayStructure = left.ndArray.add(right.ndArray).wrap() - override operator fun StructureND.minus(other: StructureND): Nd4jArrayStructure = - ndArray.sub(other.ndArray).wrap() + override operator fun StructureND.minus(arg: StructureND): Nd4jArrayStructure = + ndArray.sub(arg.ndArray).wrap() override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() 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 3fb03c964..33765b40a 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 @@ -51,29 +51,29 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe return structureND(left.shape) { index -> elementAlgebra.transform(left[index], right[index]) } } - override fun T.plus(other: StructureND): Nd4jArrayStructure = other.ndArray.add(this).wrap() + override fun T.plus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.add(this).wrap() override fun StructureND.plus(arg: T): Nd4jArrayStructure = ndArray.add(arg).wrap() - override fun StructureND.plus(other: StructureND): Nd4jArrayStructure = ndArray.add(other.ndArray).wrap() + override fun StructureND.plus(arg: StructureND): Nd4jArrayStructure = ndArray.add(arg.ndArray).wrap() override fun Tensor.plusAssign(value: T) { ndArray.addi(value) } - override fun Tensor.plusAssign(other: StructureND) { - ndArray.addi(other.ndArray) + override fun Tensor.plusAssign(arg: StructureND) { + ndArray.addi(arg.ndArray) } - override fun T.minus(other: StructureND): Nd4jArrayStructure = other.ndArray.rsub(this).wrap() + override fun T.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() override fun StructureND.minus(arg: T): Nd4jArrayStructure = ndArray.sub(arg).wrap() - override fun StructureND.minus(other: StructureND): Nd4jArrayStructure = ndArray.sub(other.ndArray).wrap() + override fun StructureND.minus(arg: StructureND): Nd4jArrayStructure = ndArray.sub(arg.ndArray).wrap() override fun Tensor.minusAssign(value: T) { ndArray.rsubi(value) } - override fun Tensor.minusAssign(other: StructureND) { - ndArray.subi(other.ndArray) + override fun Tensor.minusAssign(arg: StructureND) { + ndArray.subi(arg.ndArray) } override fun T.times(arg: StructureND): Nd4jArrayStructure = arg.ndArray.mul(this).wrap() @@ -81,14 +81,14 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe override fun StructureND.times(arg: T): Nd4jArrayStructure = ndArray.mul(arg).wrap() - override fun StructureND.times(other: StructureND): Nd4jArrayStructure = ndArray.mul(other.ndArray).wrap() + override fun StructureND.times(arg: StructureND): Nd4jArrayStructure = ndArray.mul(arg.ndArray).wrap() override fun Tensor.timesAssign(value: T) { ndArray.muli(value) } - override fun Tensor.timesAssign(other: StructureND) { - ndArray.mmuli(other.ndArray) + override fun Tensor.timesAssign(arg: StructureND) { + ndArray.mmuli(arg.ndArray) } override fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() @@ -105,8 +105,8 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe override fun StructureND.max(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.max(keepDim, dim).wrap() - override fun StructureND.view(shape: IntArray): Nd4jArrayStructure = ndArray.reshape(shape).wrap() - override fun StructureND.viewAs(other: StructureND): Nd4jArrayStructure = view(other.shape) + override fun Tensor.view(shape: IntArray): Nd4jArrayStructure = ndArray.reshape(shape).wrap() + override fun Tensor.viewAs(other: StructureND): Nd4jArrayStructure = view(other.shape) override fun StructureND.argMax(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndBase.get().argmax(ndArray, keepDim, dim).wrap() @@ -142,7 +142,7 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe override fun T.div(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rdiv(this).wrap() override fun StructureND.div(arg: T): Nd4jArrayStructure = ndArray.div(arg).wrap() - override fun StructureND.div(other: StructureND): Nd4jArrayStructure = ndArray.div(other.ndArray).wrap() + override fun StructureND.div(arg: StructureND): Nd4jArrayStructure = ndArray.div(arg.ndArray).wrap() override fun Tensor.divAssign(value: T) { ndArray.divi(value) @@ -172,7 +172,7 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): Nd4jArrayStructure { val array: INDArray = Nd4j.zeros(*shape) val indices = DefaultStrides(shape) - indices.indices().forEach { index -> + indices.asSequence().forEach { index -> array.putScalar(index, elementAlgebra.initializer(index)) } return array.wrap() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 28d7c4677..8c445cf2d 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -32,13 +32,13 @@ public interface TensorAlgebra> : RingOpsND { valueOrNull() ?: throw IllegalArgumentException("Inconsistent value for tensor of with $shape shape") /** - * Each element of the tensor [other] is added to this value. + * Each element of the tensor [arg] is added to this value. * The resulting tensor is returned. * - * @param other tensor to be added. - * @return the sum of this value and tensor [other]. + * @param arg tensor to be added. + * @return the sum of this value and tensor [arg]. */ - override operator fun T.plus(other: StructureND): Tensor + override operator fun T.plus(arg: StructureND): Tensor /** * Adds the scalar [arg] to each element of this tensor and returns a new resulting tensor. @@ -49,13 +49,13 @@ public interface TensorAlgebra> : RingOpsND { override operator fun StructureND.plus(arg: T): Tensor /** - * Each element of the tensor [other] is added to each element of this tensor. + * Each element of the tensor [arg] is added to each element of this tensor. * The resulting tensor is returned. * - * @param other tensor to be added. - * @return the sum of this tensor and [other]. + * @param arg tensor to be added. + * @return the sum of this tensor and [arg]. */ - override operator fun StructureND.plus(other: StructureND): Tensor + override operator fun StructureND.plus(arg: StructureND): Tensor /** * Adds the scalar [value] to each element of this tensor. @@ -65,20 +65,20 @@ public interface TensorAlgebra> : RingOpsND { public operator fun Tensor.plusAssign(value: T) /** - * Each element of the tensor [other] is added to each element of this tensor. + * Each element of the tensor [arg] is added to each element of this tensor. * - * @param other tensor to be added. + * @param arg tensor to be added. */ - public operator fun Tensor.plusAssign(other: StructureND) + public operator fun Tensor.plusAssign(arg: StructureND) /** - * Each element of the tensor [other] is subtracted from this value. + * Each element of the tensor [arg] is subtracted from this value. * The resulting tensor is returned. * - * @param other tensor to be subtracted. - * @return the difference between this value and tensor [other]. + * @param arg tensor to be subtracted. + * @return the difference between this value and tensor [arg]. */ - override operator fun T.minus(other: StructureND): Tensor + override operator fun T.minus(arg: StructureND): Tensor /** * Subtracts the scalar [arg] from each element of this tensor and returns a new resulting tensor. @@ -89,13 +89,13 @@ public interface TensorAlgebra> : RingOpsND { override operator fun StructureND.minus(arg: T): Tensor /** - * Each element of the tensor [other] is subtracted from each element of this tensor. + * Each element of the tensor [arg] is subtracted from each element of this tensor. * The resulting tensor is returned. * - * @param other tensor to be subtracted. - * @return the difference between this tensor and [other]. + * @param arg tensor to be subtracted. + * @return the difference between this tensor and [arg]. */ - override operator fun StructureND.minus(other: StructureND): Tensor + override operator fun StructureND.minus(arg: StructureND): Tensor /** * Subtracts the scalar [value] from each element of this tensor. @@ -105,11 +105,11 @@ public interface TensorAlgebra> : RingOpsND { public operator fun Tensor.minusAssign(value: T) /** - * Each element of the tensor [other] is subtracted from each element of this tensor. + * Each element of the tensor [arg] is subtracted from each element of this tensor. * - * @param other tensor to be subtracted. + * @param arg tensor to be subtracted. */ - public operator fun Tensor.minusAssign(other: StructureND) + public operator fun Tensor.minusAssign(arg: StructureND) /** @@ -130,13 +130,13 @@ public interface TensorAlgebra> : RingOpsND { override operator fun StructureND.times(arg: T): Tensor /** - * Each element of the tensor [other] is multiplied by each element of this tensor. + * Each element of the tensor [arg] is multiplied by each element of this tensor. * The resulting tensor is returned. * - * @param other tensor to be multiplied. - * @return the product of this tensor and [other]. + * @param arg tensor to be multiplied. + * @return the product of this tensor and [arg]. */ - override operator fun StructureND.times(other: StructureND): Tensor + override operator fun StructureND.times(arg: StructureND): Tensor /** * Multiplies the scalar [value] by each element of this tensor. @@ -146,11 +146,11 @@ public interface TensorAlgebra> : RingOpsND { public operator fun Tensor.timesAssign(value: T) /** - * Each element of the tensor [other] is multiplied by each element of this tensor. + * Each element of the tensor [arg] is multiplied by each element of this tensor. * - * @param other tensor to be multiplied. + * @param arg tensor to be multiplied. */ - public operator fun Tensor.timesAssign(other: StructureND) + public operator fun Tensor.timesAssign(arg: StructureND) /** * Numerical negative, element-wise. @@ -186,7 +186,7 @@ public interface TensorAlgebra> : RingOpsND { * @param shape the desired size * @return tensor with new shape */ - public fun StructureND.view(shape: IntArray): Tensor + public fun Tensor.view(shape: IntArray): Tensor /** * View this tensor as the same size as [other]. @@ -196,7 +196,7 @@ public interface TensorAlgebra> : RingOpsND { * @param other the result tensor has the same size as other. * @return the result tensor with the same size as other. */ - public fun StructureND.viewAs(other: StructureND): Tensor + public fun Tensor.viewAs(other: StructureND): Tensor /** * Matrix product of two tensors. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index dece54834..304cc66cc 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -35,13 +35,13 @@ public interface TensorPartialDivisionAlgebra> : TensorAlgebra.div(arg: T): Tensor /** - * Each element of the tensor [other] is divided by each element of this tensor. + * Each element of the tensor [arg] is divided by each element of this tensor. * The resulting tensor is returned. * - * @param other tensor to be divided by. - * @return the division of this tensor by [other]. + * @param arg tensor to be divided by. + * @return the division of this tensor by [arg]. */ - override operator fun StructureND.div(other: StructureND): Tensor + override operator fun StructureND.div(arg: StructureND): Tensor override fun divide(left: StructureND, right: StructureND): StructureND = left.div(right) 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 f53a0ca55..83d1f7b35 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 @@ -19,8 +19,8 @@ import space.kscience.kmath.tensors.core.internal.tensor */ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - override fun StructureND.plus(other: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) + override fun StructureND.plus(arg: StructureND): DoubleTensor { + val broadcast = broadcastTensors(tensor, arg.tensor) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> @@ -29,16 +29,16 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.plusAssign(other: StructureND) { - val newOther = broadcastTo(other.tensor, tensor.shape) + override fun Tensor.plusAssign(arg: StructureND) { + val newOther = broadcastTo(arg.tensor, tensor.shape) for (i in 0 until tensor.indices.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] += newOther.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun StructureND.minus(other: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) + override fun StructureND.minus(arg: StructureND): DoubleTensor { + val broadcast = broadcastTensors(tensor, arg.tensor) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> @@ -47,16 +47,16 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.minusAssign(other: StructureND) { - val newOther = broadcastTo(other.tensor, tensor.shape) + override fun Tensor.minusAssign(arg: StructureND) { + val newOther = broadcastTo(arg.tensor, tensor.shape) for (i in 0 until tensor.indices.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] -= newOther.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun StructureND.times(other: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) + override fun StructureND.times(arg: StructureND): DoubleTensor { + val broadcast = broadcastTensors(tensor, arg.tensor) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> @@ -66,8 +66,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.timesAssign(other: StructureND) { - val newOther = broadcastTo(other.tensor, tensor.shape) + override fun Tensor.timesAssign(arg: StructureND) { + val newOther = broadcastTo(arg.tensor, tensor.shape) for (i in 0 until tensor.indices.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] *= newOther.mutableBuffer.array()[tensor.bufferStart + i] 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 ba3331067..eab4d3d5b 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 @@ -23,8 +23,7 @@ public open class BufferedTensor internal constructor( /** * Buffer strides based on [TensorLinearStructure] implementation */ - public val indices: Strides - get() = TensorLinearStructure(shape) + override val indices: Strides get() = TensorLinearStructure(shape) /** * Number of elements in tensor @@ -39,7 +38,7 @@ public open class BufferedTensor internal constructor( } @PerformancePitfall - override fun elements(): Sequence> = indices.indices().map { + override fun elements(): Sequence> = indices.asSequence().map { it to get(it) } } 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 be87f8019..8b6f6403f 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 @@ -112,7 +112,7 @@ public open class DoubleTensorAlgebra : */ override fun structureND(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): DoubleTensor = fromArray( shape, - TensorLinearStructure(shape).indices().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray() + TensorLinearStructure(shape).asSequence().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray() ) override operator fun StructureND.get(i: Int): DoubleTensor { @@ -201,19 +201,19 @@ public open class DoubleTensorAlgebra : public fun StructureND.copy(): DoubleTensor = DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) - override fun Double.plus(other: StructureND): DoubleTensor { - val resBuffer = DoubleArray(other.tensor.numElements) { i -> - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] + this + override fun Double.plus(arg: StructureND): DoubleTensor { + val resBuffer = DoubleArray(arg.tensor.numElements) { i -> + arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + this } - return DoubleTensor(other.shape, resBuffer) + return DoubleTensor(arg.shape, resBuffer) } override fun StructureND.plus(arg: Double): DoubleTensor = arg + tensor - override fun StructureND.plus(other: StructureND): DoubleTensor { - checkShapesCompatible(tensor, other.tensor) + override fun StructureND.plus(arg: StructureND): DoubleTensor { + checkShapesCompatible(tensor, arg.tensor) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] + other.tensor.mutableBuffer.array()[i] + tensor.mutableBuffer.array()[i] + arg.tensor.mutableBuffer.array()[i] } return DoubleTensor(tensor.shape, resBuffer) } @@ -224,19 +224,19 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.plusAssign(other: StructureND) { - checkShapesCompatible(tensor, other.tensor) + override fun Tensor.plusAssign(arg: StructureND) { + checkShapesCompatible(tensor, arg.tensor) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] += - other.tensor.mutableBuffer.array()[tensor.bufferStart + i] + arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun Double.minus(other: StructureND): DoubleTensor { - val resBuffer = DoubleArray(other.tensor.numElements) { i -> - this - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] + override fun Double.minus(arg: StructureND): DoubleTensor { + val resBuffer = DoubleArray(arg.tensor.numElements) { i -> + this - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] } - return DoubleTensor(other.shape, resBuffer) + return DoubleTensor(arg.shape, resBuffer) } override fun StructureND.minus(arg: Double): DoubleTensor { @@ -246,10 +246,10 @@ public open class DoubleTensorAlgebra : return DoubleTensor(tensor.shape, resBuffer) } - override fun StructureND.minus(other: StructureND): DoubleTensor { - checkShapesCompatible(tensor, other) + override fun StructureND.minus(arg: StructureND): DoubleTensor { + checkShapesCompatible(tensor, arg) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] - other.tensor.mutableBuffer.array()[i] + tensor.mutableBuffer.array()[i] - arg.tensor.mutableBuffer.array()[i] } return DoubleTensor(tensor.shape, resBuffer) } @@ -260,11 +260,11 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.minusAssign(other: StructureND) { - checkShapesCompatible(tensor, other) + override fun Tensor.minusAssign(arg: StructureND) { + checkShapesCompatible(tensor, arg) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] -= - other.tensor.mutableBuffer.array()[tensor.bufferStart + i] + arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } @@ -277,11 +277,11 @@ public open class DoubleTensorAlgebra : override fun StructureND.times(arg: Double): DoubleTensor = arg * tensor - override fun StructureND.times(other: StructureND): DoubleTensor { - checkShapesCompatible(tensor, other) + override fun StructureND.times(arg: StructureND): DoubleTensor { + checkShapesCompatible(tensor, arg) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[tensor.bufferStart + i] * - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] + arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] } return DoubleTensor(tensor.shape, resBuffer) } @@ -292,11 +292,11 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.timesAssign(other: StructureND) { - checkShapesCompatible(tensor, other) + override fun Tensor.timesAssign(arg: StructureND) { + checkShapesCompatible(tensor, arg) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] *= - other.tensor.mutableBuffer.array()[tensor.bufferStart + i] + arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } @@ -368,12 +368,12 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun StructureND.view(shape: IntArray): DoubleTensor { + override fun Tensor.view(shape: IntArray): DoubleTensor { checkView(tensor, shape) return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) } - override fun StructureND.viewAs(other: StructureND): DoubleTensor = + override fun Tensor.viewAs(other: StructureND): DoubleTensor = tensor.view(other.shape) override infix fun StructureND.dot(other: StructureND): DoubleTensor { @@ -584,7 +584,7 @@ public open class DoubleTensorAlgebra : } val resNumElements = resShape.reduce(Int::times) val resTensor = DoubleTensor(resShape, DoubleArray(resNumElements) { 0.0 }, 0) - for (index in resTensor.indices.indices()) { + for (index in resTensor.indices.asSequence()) { val prefix = index.take(dim).toIntArray() val suffix = index.takeLast(dimension - dim - 1).toIntArray() resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index 4123ff923..d3d327f66 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -22,7 +22,7 @@ internal fun BufferedTensor.asTensor(): DoubleTensor = internal fun StructureND.copyToBufferedTensor(): BufferedTensor = BufferedTensor( this.shape, - TensorLinearStructure(this.shape).indices().map(this::get).toMutableList().asMutableBuffer(), 0 + TensorLinearStructure(this.shape).asSequence().map(this::get).toMutableList().asMutableBuffer(), 0 ) internal fun StructureND.toBufferedTensor(): BufferedTensor = when (this) { diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt index aaa113e56..c50404c9c 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 @@ -28,7 +28,7 @@ public open class ViktorFieldOpsND : override fun structureND(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = F64Array(*shape).apply { - DefaultStrides(shape).indices().forEach { index -> + DefaultStrides(shape).asSequence().forEach { index -> set(value = DoubleField.initializer(index), indices = index) } }.asStructure() @@ -37,7 +37,7 @@ public open class ViktorFieldOpsND : override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = F64Array(*shape).apply { - DefaultStrides(shape).indices().forEach { index -> + DefaultStrides(shape).asSequence().forEach { index -> set(value = DoubleField.transform(this@map[index]), indices = index) } }.asStructure() @@ -45,7 +45,7 @@ public open class ViktorFieldOpsND : override fun StructureND.mapIndexed( transform: DoubleField.(index: IntArray, Double) -> Double, ): ViktorStructureND = F64Array(*shape).apply { - DefaultStrides(shape).indices().forEach { index -> + DefaultStrides(shape).asSequence().forEach { index -> set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index) } }.asStructure() @@ -57,7 +57,7 @@ public open class ViktorFieldOpsND : ): ViktorStructureND { require(left.shape.contentEquals(right.shape)) return F64Array(*left.shape).apply { - DefaultStrides(left.shape).indices().forEach { index -> + DefaultStrides(left.shape).asSequence().forEach { index -> set(value = DoubleField.transform(left[index], right[index]), indices = index) } }.asStructure() @@ -69,11 +69,11 @@ public open class ViktorFieldOpsND : override fun scale(a: StructureND, value: Double): ViktorStructureND = (a.f64Buffer * value).asStructure() - override fun StructureND.plus(other: StructureND): ViktorStructureND = - (f64Buffer + other.f64Buffer).asStructure() + override fun StructureND.plus(arg: StructureND): ViktorStructureND = + (f64Buffer + arg.f64Buffer).asStructure() - override fun StructureND.minus(other: StructureND): ViktorStructureND = - (f64Buffer - other.f64Buffer).asStructure() + override fun StructureND.minus(arg: StructureND): ViktorStructureND = + (f64Buffer - arg.f64Buffer).asStructure() override fun StructureND.times(k: Number): ViktorStructureND = (f64Buffer * k.toDouble()).asStructure() 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 0d29983f9..4926652ed 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 @@ -22,7 +22,7 @@ public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructur @PerformancePitfall override fun elements(): Sequence> = - DefaultStrides(shape).indices().map { it to get(it) } + DefaultStrides(shape).asSequence().map { it to get(it) } } public fun F64Array.asStructure(): ViktorStructureND = ViktorStructureND(this) -- 2.34.1 From 46e7da9ae00ae6470201624583adc47e2187a840 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 28 Oct 2021 11:18:16 +0300 Subject: [PATCH 054/102] Tensor algebra generified --- .../space/kscience/kmath/nd/DoubleFieldND.kt | 8 ++--- .../kscience/kmath/operations/Algebra.kt | 4 +-- .../kmath/operations/DoubleBufferOps.kt | 14 ++++---- .../kscience/kmath/operations/numbers.kt | 36 +++++++++---------- .../kscience/kmath/jafama/KMathJafama.kt | 12 +++---- .../kmath/multik/MultikTensorAlgebra.kt | 6 ++-- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 4 +-- .../api/TensorPartialDivisionAlgebra.kt | 6 ++-- .../core/BroadcastDoubleTensorAlgebra.kt | 8 ++--- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 14 ++++---- 10 files changed, 56 insertions(+), 56 deletions(-) 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 8cc5472a9..7285fdb24 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 @@ -81,8 +81,8 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D override fun StructureND.unaryMinus(): DoubleBufferND = mapInline(toBufferND()) { -it } - override fun StructureND.div(other: StructureND): DoubleBufferND = - zipInline(toBufferND(), other.toBufferND()) { l, r -> l / r } + override fun StructureND.div(arg: StructureND): DoubleBufferND = + zipInline(toBufferND(), arg.toBufferND()) { l, r -> l / r } override fun divide(left: StructureND, right: StructureND): DoubleBufferND = zipInline(left.toBufferND(), right.toBufferND()) { l: Double, r: Double -> l / r } @@ -101,8 +101,8 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D override fun StructureND.minus(arg: StructureND): DoubleBufferND = zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l - r } - override fun StructureND.times(other: StructureND): DoubleBufferND = - zipInline(toBufferND(), other.toBufferND()) { l: Double, r: Double -> l * r } + override fun StructureND.times(arg: StructureND): DoubleBufferND = + zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l * r } override fun StructureND.times(k: Number): DoubleBufferND = mapInline(toBufferND()) { it * k.toDouble() } 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 c6af75237..0e5c6de1f 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 @@ -270,10 +270,10 @@ public interface FieldOps : RingOps { * Division of two elements. * * @receiver the dividend. - * @param other the divisor. + * @param arg the divisor. * @return the quotient. */ - public operator fun T.div(other: T): T = divide(this, other) + public operator fun T.div(arg: T): T = divide(this, arg) override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { DIV_OPERATION -> ::divide 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 29b25aae8..3d51b3d32 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 @@ -34,18 +34,18 @@ public abstract class DoubleBufferOps : ExtendedFieldOps>, Norm.plus(other: Buffer): DoubleBuffer = add(this, other) + override fun Buffer.plus(arg: Buffer): DoubleBuffer = add(this, arg) - override fun Buffer.minus(other: Buffer): DoubleBuffer { - require(other.size == this.size) { - "The size of the first buffer ${this.size} should be the same as for second one: ${other.size} " + override fun Buffer.minus(arg: Buffer): DoubleBuffer { + require(arg.size == this.size) { + "The size of the first buffer ${this.size} should be the same as for second one: ${arg.size} " } - return if (this is DoubleBuffer && other is DoubleBuffer) { + return if (this is DoubleBuffer && arg is DoubleBuffer) { val aArray = this.array - val bArray = other.array + val bArray = arg.array DoubleBuffer(DoubleArray(this.size) { aArray[it] - bArray[it] }) - } else DoubleBuffer(DoubleArray(this.size) { this[it] - other[it] }) + } else DoubleBuffer(DoubleArray(this.size) { this[it] - arg[it] }) } // diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 0b111349c..ceb85f3ab 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -102,10 +102,10 @@ public object DoubleField : ExtendedField, Norm, ScaleOp override inline fun norm(arg: Double): Double = abs(arg) override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(other: Double): Double = this + other - override inline fun Double.minus(other: Double): Double = this - other - override inline fun Double.times(other: Double): Double = this * other - override inline fun Double.div(other: Double): Double = this / other + override inline fun Double.plus(arg: Double): Double = this + arg + override inline fun Double.minus(arg: Double): Double = this - arg + override inline fun Double.times(arg: Double): Double = this * arg + override inline fun Double.div(arg: Double): Double = this / arg } public val Double.Companion.algebra: DoubleField get() = DoubleField @@ -155,10 +155,10 @@ public object FloatField : ExtendedField, Norm { override inline fun norm(arg: Float): Float = abs(arg) override inline fun Float.unaryMinus(): Float = -this - override inline fun Float.plus(other: Float): Float = this + other - override inline fun Float.minus(other: Float): Float = this - other - override inline fun Float.times(other: Float): Float = this * other - override inline fun Float.div(other: Float): Float = this / other + override inline fun Float.plus(arg: Float): Float = this + arg + override inline fun Float.minus(arg: Float): Float = this - arg + override inline fun Float.times(arg: Float): Float = this * arg + override inline fun Float.div(arg: Float): Float = this / arg } public val Float.Companion.algebra: FloatField get() = FloatField @@ -180,9 +180,9 @@ public object IntRing : Ring, Norm, NumericAlgebra { override inline fun norm(arg: Int): Int = abs(arg) override inline fun Int.unaryMinus(): Int = -this - override inline fun Int.plus(other: Int): Int = this + other - override inline fun Int.minus(other: Int): Int = this - other - override inline fun Int.times(other: Int): Int = this * other + override inline fun Int.plus(arg: Int): Int = this + arg + override inline fun Int.minus(arg: Int): Int = this - arg + override inline fun Int.times(arg: Int): Int = this * arg } public val Int.Companion.algebra: IntRing get() = IntRing @@ -204,9 +204,9 @@ public object ShortRing : Ring, Norm, NumericAlgebra override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort() override inline fun Short.unaryMinus(): Short = (-this).toShort() - override inline fun Short.plus(other: Short): Short = (this + other).toShort() - override inline fun Short.minus(other: Short): Short = (this - other).toShort() - override inline fun Short.times(other: Short): Short = (this * other).toShort() + override inline fun Short.plus(arg: Short): Short = (this + arg).toShort() + override inline fun Short.minus(arg: Short): Short = (this - arg).toShort() + override inline fun Short.times(arg: Short): Short = (this * arg).toShort() } public val Short.Companion.algebra: ShortRing get() = ShortRing @@ -230,7 +230,7 @@ public object ByteRing : Ring, Norm, NumericAlgebra { override inline fun Byte.unaryMinus(): Byte = (-this).toByte() override inline fun Byte.plus(arg: Byte): Byte = (this + arg).toByte() override inline fun Byte.minus(arg: Byte): Byte = (this - arg).toByte() - override inline fun Byte.times(other: Byte): Byte = (this * other).toByte() + override inline fun Byte.times(arg: Byte): Byte = (this * arg).toByte() } public val Byte.Companion.algebra: ByteRing get() = ByteRing @@ -252,9 +252,9 @@ public object LongRing : Ring, Norm, NumericAlgebra { override fun norm(arg: Long): Long = abs(arg) override inline fun Long.unaryMinus(): Long = (-this) - override inline fun Long.plus(other: Long): Long = (this + other) - override inline fun Long.minus(other: Long): Long = (this - other) - override inline fun Long.times(other: Long): Long = (this * other) + override inline fun Long.plus(arg: Long): Long = (this + arg) + override inline fun Long.minus(arg: Long): Long = (this - arg) + override inline fun Long.times(arg: Long): Long = (this * arg) } public val Long.Companion.algebra: LongRing get() = LongRing diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt index 9ff7ffc9c..64a935705 100644 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt @@ -59,8 +59,8 @@ public object JafamaDoubleField : ExtendedField, Norm, S override inline fun Double.unaryMinus(): Double = -this override inline fun Double.plus(arg: Double): Double = this + arg override inline fun Double.minus(arg: Double): Double = this - arg - override inline fun Double.times(other: Double): Double = this * other - override inline fun Double.div(other: Double): Double = this / other + override inline fun Double.times(arg: Double): Double = this * arg + override inline fun Double.div(arg: Double): Double = this / arg } /** @@ -108,8 +108,8 @@ public object StrictJafamaDoubleField : ExtendedField, Norm> } } - override fun Tensor.divAssign(other: StructureND) { + override fun Tensor.divAssign(arg: StructureND) { if (this is MultikTensor) { - array.divAssign(other.asMultik().array) + array.divAssign(arg.asMultik().array) } else { - mapInPlace { index, t -> elementAlgebra.divide(t, other[index]) } + mapInPlace { index, t -> elementAlgebra.divide(t, arg[index]) } } } } 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 33765b40a..a537c0629 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 @@ -148,8 +148,8 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe ndArray.divi(value) } - override fun Tensor.divAssign(other: StructureND) { - ndArray.divi(other.ndArray) + override fun Tensor.divAssign(arg: StructureND) { + ndArray.divi(arg.ndArray) } override fun StructureND.variance(dim: Int, keepDim: Boolean): Nd4jArrayStructure = diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index 304cc66cc..0a1e09081 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -53,9 +53,9 @@ public interface TensorPartialDivisionAlgebra> : TensorAlgebra.divAssign(value: T) /** - * Each element of this tensor is divided by each element of the [other] tensor. + * Each element of this tensor is divided by each element of the [arg] tensor. * - * @param other tensor to be divided by. + * @param arg tensor to be divided by. */ - public operator fun Tensor.divAssign(other: StructureND) + public operator fun Tensor.divAssign(arg: StructureND) } 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 83d1f7b35..7353ecab1 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 @@ -74,8 +74,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { } } - override fun StructureND.div(other: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) + override fun StructureND.div(arg: StructureND): DoubleTensor { + val broadcast = broadcastTensors(tensor, arg.tensor) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> @@ -85,8 +85,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.divAssign(other: StructureND) { - val newOther = broadcastTo(other.tensor, tensor.shape) + override fun Tensor.divAssign(arg: StructureND) { + val newOther = broadcastTo(arg.tensor, tensor.shape) for (i in 0 until tensor.indices.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= newOther.mutableBuffer.array()[tensor.bufferStart + i] 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 8b6f6403f..d7aa18c3d 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 @@ -314,11 +314,11 @@ public open class DoubleTensorAlgebra : return DoubleTensor(shape, resBuffer) } - override fun StructureND.div(other: StructureND): DoubleTensor { - checkShapesCompatible(tensor, other) + override fun StructureND.div(arg: StructureND): DoubleTensor { + checkShapesCompatible(tensor, arg) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[other.tensor.bufferStart + i] / - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] + tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] / + arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] } return DoubleTensor(tensor.shape, resBuffer) } @@ -329,11 +329,11 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.divAssign(other: StructureND) { - checkShapesCompatible(tensor, other) + override fun Tensor.divAssign(arg: StructureND) { + checkShapesCompatible(tensor, arg) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= - other.tensor.mutableBuffer.array()[tensor.bufferStart + i] + arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } -- 2.34.1 From db06d10cc28a12bf7529375939878c53cdeb96c2 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 28 Oct 2021 19:25:10 +0100 Subject: [PATCH 055/102] dot fixed for tensorflow --- .../space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt | 4 +++- .../kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) 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 e73620d01..90485a9ad 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 @@ -180,7 +180,9 @@ public abstract class TensorFlowAlgebra> internal cons } override fun StructureND.dot(other: StructureND): TensorFlowOutput = biOp(other) { l, r -> - ops.linalg.matMul(l, r) + ops.linalg.matMul( + if (l.asTensor().shape().numDimensions() == 1) ops.expandDims(l,ops.constant(0)) else l, + if (r.asTensor().shape().numDimensions() == 1) ops.expandDims(r,ops.constant(-1)) else r) } override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): Tensor = ops.run { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 8c445cf2d..672e37b98 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -208,7 +208,7 @@ public interface TensorAlgebra> : RingOpsND { * * 3. If the first argument is 1-dimensional and the second argument is 2-dimensional, * a 1 is prepended to its dimension for the purpose of the matrix multiply. - * After the matrix multiply, the prepended dimension is removed. + * After the matrix multiply, depending on the implementation the prepended dimension might be removed. * * 4. If the first argument is 2-dimensional and the second argument is 1-dimensional, * the matrix-vector product is returned. -- 2.34.1 From b65197f577d0d0dbebd3d8dc1f8b14797bf346f9 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 1 Nov 2021 19:45:02 +0300 Subject: [PATCH 056/102] revert parts of tensor api to tensors --- .../kscience/kmath/benchmarks/DotBenchmark.kt | 11 ++ .../space/kscience/kmath/nd/AlgebraND.kt | 2 +- .../space/kscience/kmath/nd/BufferND.kt | 6 - .../kscience/kmath/operations/Algebra.kt | 10 ++ .../kmath/multik/MultikDoubleAlgebra.kt | 136 ++++++++++++++++++ .../kmath/multik/MultikTensorAlgebra.kt | 39 +++-- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 4 +- .../tensors/api/AnalyticTensorAlgebra.kt | 6 +- .../kmath/tensors/api/TensorAlgebra.kt | 4 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 4 +- 10 files changed, 188 insertions(+), 34 deletions(-) create mode 100644 kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 64f9b5dff..9203c269e 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -13,6 +13,7 @@ import space.kscience.kmath.commons.linear.CMLinearSpace import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.linearSpace +import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.Buffer import kotlin.random.Random @@ -58,6 +59,16 @@ internal class DotBenchmark { blackhole.consume(matrix1 dot matrix2) } +// @Benchmark +// fun tensorDot(blackhole: Blackhole) = with(Double.tensorAlgebra) { +// blackhole.consume(matrix1 dot matrix2) +// } + + @Benchmark + fun multikDot(blackhole: Blackhole) = with(Double.multikAlgebra) { + blackhole.consume(matrix1 dot matrix2) + } + @Benchmark fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace(Buffer.Companion::auto)) { blackhole.consume(matrix1 dot matrix2) 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 4e52c8ba9..113bd4c52 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 @@ -35,7 +35,7 @@ public interface WithShape { * @param T the type of ND-structure element. * @param C the type of the element context. */ -public interface AlgebraND> { +public interface AlgebraND>: Algebra> { /** * The algebra over elements of ND structure. */ 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 19924616d..515988159 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,6 @@ 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 @@ -27,11 +26,6 @@ public open class BufferND( override val shape: IntArray get() = indices.shape - @PerformancePitfall - override fun elements(): Sequence> = indices.asSequence().map { - it to this[it] - } - override fun toString(): String = StructureND.toString(this) } 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 0e5c6de1f..992c0e015 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 @@ -6,6 +6,7 @@ package space.kscience.kmath.operations import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI /** * Stub for DSL the [Algebra] is. @@ -99,6 +100,14 @@ public interface Algebra { */ public fun binaryOperation(operation: String, left: T, right: T): T = binaryOperationFunction(operation)(left, right) + + /** + * Export an algebra element, so it could be accessed even after algebra scope is closed. + * This method must be used on algebras where data is stored externally or any local algebra state is used. + * By default (if not overridden), exports the object itself. + */ + @UnstableKMathAPI + public fun export(arg: T): T = arg } public fun Algebra.bindSymbolOrNull(symbol: Symbol): T? = bindSymbolOrNull(symbol.identity) @@ -162,6 +171,7 @@ public interface GroupOps : Algebra { * @return the difference. */ public operator fun T.minus(arg: T): T = add(this, -arg) + // Dynamic dispatch of operations override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> +arg } diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt new file mode 100644 index 000000000..e5fef6c1e --- /dev/null +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt @@ -0,0 +1,136 @@ +package space.kscience.kmath.multik + +import org.jetbrains.kotlinx.multik.ndarray.data.DN +import org.jetbrains.kotlinx.multik.ndarray.data.DataType +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra +import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra +import space.kscience.kmath.tensors.api.Tensor + +public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra(), + AnalyticTensorAlgebra, LinearOpsTensorAlgebra { + override val elementAlgebra: DoubleField get() = DoubleField + override val type: DataType get() = DataType.DoubleDataType + + override fun StructureND.mean(): Double = multikStat.mean(asMultik().array) + + override fun StructureND.mean(dim: Int, keepDim: Boolean): Tensor = + multikStat.mean(asMultik().array, dim).wrap() + + override fun StructureND.std(): Double { + TODO("Not yet implemented") + } + + override fun StructureND.std(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.variance(): Double { + TODO("Not yet implemented") + } + + override fun StructureND.variance(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.exp(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.ln(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.sqrt(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.cos(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.acos(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.cosh(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.acosh(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.sin(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.asin(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.sinh(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.asinh(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.tan(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.atan(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.tanh(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.atanh(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.ceil(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.floor(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.det(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.inv(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.cholesky(): Tensor { + TODO("Not yet implemented") + } + + override fun StructureND.qr(): Pair, Tensor> { + TODO("Not yet implemented") + } + + override fun StructureND.lu(): Triple, Tensor, Tensor> { + TODO("Not yet implemented") + } + + override fun StructureND.svd(): Triple, Tensor, Tensor> { + TODO("Not yet implemented") + } + + override fun StructureND.symEig(): Pair, Tensor> { + TODO("Not yet implemented") + } +} + +public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra +public val DoubleField.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra + diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index c8fc23a2c..e3b940e3c 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -7,11 +7,9 @@ package space.kscience.kmath.multik -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.linalg.dot -import org.jetbrains.kotlinx.multik.api.mk -import org.jetbrains.kotlinx.multik.api.ndarrayOf -import org.jetbrains.kotlinx.multik.api.zeros +import org.jetbrains.kotlinx.multik.api.* +import org.jetbrains.kotlinx.multik.api.linalg.LinAlg +import org.jetbrains.kotlinx.multik.api.math.Math import org.jetbrains.kotlinx.multik.ndarray.data.* import org.jetbrains.kotlinx.multik.ndarray.operations.* import space.kscience.kmath.misc.PerformancePitfall @@ -52,10 +50,16 @@ private fun MultiArray.asD2Array(): D2Array { else throw ClassCastException("Cannot cast MultiArray to NDArray.") } -public abstract class MultikTensorAlgebra> : TensorAlgebra where T : Number, T : Comparable { +public abstract class MultikTensorAlgebra> : TensorAlgebra + where T : Number, T : Comparable { public abstract val type: DataType + protected val multikMath: Math = mk.math + protected val multikLinAl: LinAlg = mk.linalg + protected val multikStat: Statistics = mk.stat + + override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { val strides = DefaultStrides(shape) val memoryView = initMemoryView(strides.linearSize, type) @@ -65,6 +69,7 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra return MultikTensor(NDArray(memoryView, shape = shape, dim = DN(shape.size))) } + @OptIn(PerformancePitfall::class) override fun StructureND.map(transform: A.(T) -> T): MultikTensor = if (this is MultikTensor) { val data = initMemoryView(array.size, type) var count = 0 @@ -76,6 +81,7 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra } } + @OptIn(PerformancePitfall::class) override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): MultikTensor = if (this is MultikTensor) { val array = asMultik().array @@ -96,6 +102,7 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra } } + @OptIn(PerformancePitfall::class) override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): MultikTensor { require(left.shape.contentEquals(right.shape)) { "ND array shape mismatch" } //TODO replace by ShapeMismatchException val leftArray = left.asMultik().array @@ -208,9 +215,9 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra override fun StructureND.unaryMinus(): MultikTensor = asMultik().array.unaryMinus().wrap() - override fun StructureND.get(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() + override fun Tensor.get(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() - override fun StructureND.transpose(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() + override fun Tensor.transpose(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() override fun Tensor.view(shape: IntArray): MultikTensor { require(shape.all { it > 0 }) @@ -236,12 +243,12 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra override fun StructureND.dot(other: StructureND): MultikTensor = if (this.shape.size == 1 && other.shape.size == 1) { Multik.ndarrayOf( - asMultik().array.asD1Array() dot other.asMultik().array.asD1Array() - ).asDNArray().wrap() + multikLinAl.linAlgEx.dotVV(asMultik().array.asD1Array(), other.asMultik().array.asD1Array()) + ).wrap() } else if (this.shape.size == 2 && other.shape.size == 2) { - (asMultik().array.asD2Array() dot other.asMultik().array.asD2Array()).asDNArray().wrap() + multikLinAl.linAlgEx.dotMM(asMultik().array.asD2Array(), other.asMultik().array.asD2Array()).wrap() } else if (this.shape.size == 2 && other.shape.size == 1) { - (asMultik().array.asD2Array() dot other.asMultik().array.asD1Array()).asDNArray().wrap() + multikLinAl.linAlgEx.dotMV(asMultik().array.asD2Array(), other.asMultik().array.asD1Array()).wrap() } else { TODO("Not implemented for broadcasting") } @@ -303,14 +310,6 @@ public abstract class MultikDivisionTensorAlgebra> } } -public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra() { - override val elementAlgebra: DoubleField get() = DoubleField - override val type: DataType get() = DataType.DoubleDataType -} - -public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra -public val DoubleField.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra - public object MultikFloatAlgebra : MultikDivisionTensorAlgebra() { override val elementAlgebra: FloatField get() = FloatField override val type: DataType get() = DataType.FloatDataType 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 a537c0629..58309736d 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 @@ -92,8 +92,8 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe } override fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() - override fun StructureND.get(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() - override fun StructureND.transpose(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() + override fun Tensor.get(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() + override fun Tensor.transpose(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() override fun StructureND.dot(other: StructureND): Nd4jArrayStructure = ndArray.mmul(other.ndArray).wrap() override fun StructureND.min(dim: Int, keepDim: Boolean): Nd4jArrayStructure = diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index debfb3ef0..c756584a4 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.tensors.api +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Field @@ -121,4 +122,7 @@ public interface AnalyticTensorAlgebra> : TensorPartialDivisionA //For information: https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor public fun StructureND.floor(): Tensor -} \ No newline at end of file +} + +@UnstableKMathAPI +public fun > ATA.exp(arg: StructureND): Tensor = arg.exp() \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 8c445cf2d..e12bce209 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -166,7 +166,7 @@ public interface TensorAlgebra> : RingOpsND { * @param i index of the extractable tensor * @return subtensor of the original tensor with index [i] */ - public operator fun StructureND.get(i: Int): Tensor + public operator fun Tensor.get(i: Int): Tensor /** * Returns a tensor that is a transposed version of this tensor. The given dimensions [i] and [j] are swapped. @@ -176,7 +176,7 @@ public interface TensorAlgebra> : RingOpsND { * @param j the second dimension to be transposed * @return transposed tensor */ - public fun StructureND.transpose(i: Int = -2, j: Int = -1): Tensor + public fun Tensor.transpose(i: Int = -2, j: Int = -1): Tensor /** * Returns a new tensor with the same data as the self tensor but of a different shape. 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 d7aa18c3d..35df2df8a 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 @@ -115,7 +115,7 @@ public open class DoubleTensorAlgebra : TensorLinearStructure(shape).asSequence().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray() ) - override operator fun StructureND.get(i: Int): DoubleTensor { + override operator fun Tensor.get(i: Int): DoubleTensor { val lastShape = tensor.shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) val newStart = newShape.reduce(Int::times) * i + tensor.bufferStart @@ -344,7 +344,7 @@ public open class DoubleTensorAlgebra : return DoubleTensor(tensor.shape, resBuffer) } - override fun StructureND.transpose(i: Int, j: Int): DoubleTensor { + override fun Tensor.transpose(i: Int, j: Int): DoubleTensor { val ii = tensor.minusIndex(i) val jj = tensor.minusIndex(j) checkTranspose(tensor.dimension, ii, jj) -- 2.34.1 From a994b8a50c7ce737e4c95f8a2e136f233130e5f3 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 1 Nov 2021 17:55:10 +0000 Subject: [PATCH 057/102] fix argmax --- .../kmath/multik/MultikTensorAlgebra.kt | 2 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 4 +- .../kmath/tensors/api/TensorAlgebra.kt | 2 +- .../kmath/tensors/core/BufferedTensor.kt | 1 - .../kmath/tensors/core/DoubleTensorAlgebra.kt | 33 +++++---- .../kscience/kmath/tensors/core/IntTensor.kt | 6 +- .../tensors/core/TensorLinearStructure.kt | 74 +++++++++++++++++++ .../core/internal/TensorLinearStructure.kt | 71 ------------------ .../tensors/core/internal/tensorCastsUtils.kt | 1 + 9 files changed, 102 insertions(+), 92 deletions(-) create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt delete mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index e3b940e3c..0c3cf6b14 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -277,7 +277,7 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra TODO("Not yet implemented") } - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { + override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } } 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 58309736d..d7dd6e71b 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 @@ -108,8 +108,8 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe override fun Tensor.view(shape: IntArray): Nd4jArrayStructure = ndArray.reshape(shape).wrap() override fun Tensor.viewAs(other: StructureND): Nd4jArrayStructure = view(other.shape) - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Nd4jArrayStructure = - ndBase.get().argmax(ndArray, keepDim, dim).wrap() + override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor = + ndBase.get().argmax(ndArray, keepDim, dim).asIntStructure() override fun StructureND.mean(dim: Int, keepDim: Boolean): Nd4jArrayStructure = ndArray.mean(keepDim, dim).wrap() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index e12bce209..60fc470fb 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -324,7 +324,7 @@ public interface TensorAlgebra> : RingOpsND { * @param keepDim whether the output tensor has [dim] retained or not. * @return the index of maximum value of each row of the input tensor in the given dimension [dim]. */ - public fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor + public fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor override fun add(left: StructureND, right: StructureND): Tensor = left + right 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 eab4d3d5b..54d8f54dc 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 @@ -9,7 +9,6 @@ import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.Strides import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.TensorLinearStructure /** * Represents [Tensor] over a [MutableBuffer] intended to be used through [DoubleTensor] and [IntTensor] 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 35df2df8a..5e7ae262f 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 @@ -10,6 +10,7 @@ import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.indices import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra @@ -571,11 +572,11 @@ public open class DoubleTensorAlgebra : internal inline fun StructureND.fold(foldFunction: (DoubleArray) -> Double): Double = foldFunction(tensor.copyArray()) - internal inline fun StructureND.foldDim( - foldFunction: (DoubleArray) -> Double, + internal inline fun StructureND.foldDim( + foldFunction: (DoubleArray) -> R, dim: Int, keepDim: Boolean, - ): DoubleTensor { + ): BufferedTensor { check(dim < dimension) { "Dimension $dim out of range $dimension" } val resShape = if (keepDim) { shape.take(dim).toIntArray() + intArrayOf(1) + shape.takeLast(dimension - dim - 1).toIntArray() @@ -583,37 +584,39 @@ public open class DoubleTensorAlgebra : shape.take(dim).toIntArray() + shape.takeLast(dimension - dim - 1).toIntArray() } val resNumElements = resShape.reduce(Int::times) - val resTensor = DoubleTensor(resShape, DoubleArray(resNumElements) { 0.0 }, 0) - for (index in resTensor.indices.asSequence()) { + val init = foldFunction(DoubleArray(1){0.0}) + val resTensor = BufferedTensor(resShape, + MutableBuffer.auto(resNumElements) { init }, 0) + for (index in resTensor.indices) { val prefix = index.take(dim).toIntArray() val suffix = index.takeLast(dimension - dim - 1).toIntArray() resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> tensor[prefix + intArrayOf(i) + suffix] }) } - return resTensor } override fun StructureND.sum(): Double = tensor.fold { it.sum() } override fun StructureND.sum(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.sum() }, dim, keepDim) + foldDim({ x -> x.sum() }, dim, keepDim).toDoubleTensor() override fun StructureND.min(): Double = this.fold { it.minOrNull()!! } override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.minOrNull()!! }, dim, keepDim) + foldDim({ x -> x.minOrNull()!! }, dim, keepDim).toDoubleTensor() override fun StructureND.max(): Double = this.fold { it.maxOrNull()!! } override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) + foldDim({ x -> x.maxOrNull()!! }, dim, keepDim).toDoubleTensor() - override fun StructureND.argMax(dim: Int, keepDim: Boolean): DoubleTensor = + + override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = foldDim({ x -> - x.withIndex().maxByOrNull { it.value }?.index!!.toDouble() - }, dim, keepDim) + x.withIndex().maxByOrNull { it.value }?.index!! + }, dim, keepDim).toIntTensor() override fun StructureND.mean(): Double = this.fold { it.sum() / tensor.numElements } @@ -626,7 +629,7 @@ public open class DoubleTensorAlgebra : }, dim, keepDim - ) + ).toDoubleTensor() override fun StructureND.std(): Double = this.fold { arr -> val mean = arr.sum() / tensor.numElements @@ -641,7 +644,7 @@ public open class DoubleTensorAlgebra : }, dim, keepDim - ) + ).toDoubleTensor() override fun StructureND.variance(): Double = this.fold { arr -> val mean = arr.sum() / tensor.numElements @@ -656,7 +659,7 @@ public open class DoubleTensorAlgebra : }, dim, keepDim - ) + ).toDoubleTensor() private fun cov(x: DoubleTensor, y: DoubleTensor): Double { val n = x.shape[0] 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 dd9f9c0c1..715d9035f 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 @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.structures.IntBuffer +import space.kscience.kmath.tensors.core.internal.array /** * Default [BufferedTensor] implementation for [Int] values @@ -14,4 +15,7 @@ public class IntTensor internal constructor( shape: IntArray, buffer: IntArray, offset: Int = 0 -) : BufferedTensor(shape, IntBuffer(buffer), offset) +) : BufferedTensor(shape, IntBuffer(buffer), offset){ + public fun asDouble() : DoubleTensor = + DoubleTensor(shape, mutableBuffer.array().map{ it.toDouble()}.toDoubleArray(), bufferStart) +} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt new file mode 100644 index 000000000..19eefc2f8 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.nd.Strides +import kotlin.math.max + +/** + * This [Strides] implementation follows the last dimension first convention + * For more information: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html + * + * @param shape the shape of the tensor. + */ +public class TensorLinearStructure(override val shape: IntArray) : Strides() { + override val strides: IntArray + get() = stridesFromShape(shape) + + override fun index(offset: Int): IntArray = + indexFromOffset(offset, strides, shape.size) + + override val linearSize: Int + get() = shape.reduce(Int::times) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as TensorLinearStructure + + if (!shape.contentEquals(other.shape)) return false + + return true + } + + override fun hashCode(): Int { + return shape.contentHashCode() + } + + public companion object { + + public fun stridesFromShape(shape: IntArray): IntArray { + val nDim = shape.size + val res = IntArray(nDim) + if (nDim == 0) + return res + + var current = nDim - 1 + res[current] = 1 + + while (current > 0) { + res[current - 1] = max(1, shape[current]) * res[current] + current-- + } + return res + } + + public fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { + val res = IntArray(nDim) + var current = offset + var strideIndex = 0 + + while (strideIndex < nDim) { + res[strideIndex] = (current / strides[strideIndex]) + current %= strides[strideIndex] + strideIndex++ + } + return res + } + } + +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt deleted file mode 100644 index 57668722a..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.nd.Strides -import kotlin.math.max - - -internal fun stridesFromShape(shape: IntArray): IntArray { - val nDim = shape.size - val res = IntArray(nDim) - if (nDim == 0) - return res - - var current = nDim - 1 - res[current] = 1 - - while (current > 0) { - res[current - 1] = max(1, shape[current]) * res[current] - current-- - } - return res -} - -internal fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { - val res = IntArray(nDim) - var current = offset - var strideIndex = 0 - - while (strideIndex < nDim) { - res[strideIndex] = (current / strides[strideIndex]) - current %= strides[strideIndex] - strideIndex++ - } - return res -} - -/** - * This [Strides] implementation follows the last dimension first convention - * For more information: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html - * - * @param shape the shape of the tensor. - */ -internal class TensorLinearStructure(override val shape: IntArray) : Strides() { - override val strides: IntArray - get() = stridesFromShape(shape) - - override fun index(offset: Int): IntArray = - indexFromOffset(offset, strides, shape.size) - - override val linearSize: Int - get() = shape.reduce(Int::times) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as TensorLinearStructure - - if (!shape.contentEquals(other.shape)) return false - - return true - } - - override fun hashCode(): Int { - return shape.contentHashCode() - } -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index d3d327f66..602430b03 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.BufferedTensor import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.IntTensor +import space.kscience.kmath.tensors.core.TensorLinearStructure internal fun BufferedTensor.asTensor(): IntTensor = IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) -- 2.34.1 From 62e7073ed2637d888e5f43075af8677d483dc55c Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 1 Nov 2021 18:03:46 +0000 Subject: [PATCH 058/102] example fixed --- .../main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt index cdfc06922..1a2a94534 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt @@ -163,7 +163,7 @@ class NeuralNetwork(private val layers: List) { for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) { train(xBatch, yBatch) } - println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true))}") + println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true).asDouble())}") } } @@ -230,7 +230,7 @@ fun main() = BroadcastDoubleTensorAlgebra { val prediction = model.predict(xTest) // process raw prediction via argMax - val predictionLabels = prediction.argMax(1, true) + val predictionLabels = prediction.argMax(1, true).asDouble() // find out accuracy val acc = accuracy(yTest, predictionLabels) -- 2.34.1 From 726864ed0ee53dc5210abca75f8b851a0d6a33c6 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 3 Nov 2021 12:55:29 +0300 Subject: [PATCH 059/102] Refactoring of power --- CHANGELOG.md | 1 + .../kscience/kmath/complex/ComplexFieldND.kt | 11 +- .../kmath/expressions/SimpleAutoDiff.kt | 6 +- .../kscience/kmath/nd/BufferAlgebraND.kt | 40 ++++-- .../space/kscience/kmath/nd/DoubleFieldND.kt | 46 +++++-- .../kscience/kmath/operations/Algebra.kt | 55 ++++++++ .../kmath/operations/BufferAlgebra.kt | 14 +- .../kmath/operations/DoubleBufferField.kt | 17 ++- .../kmath/operations/DoubleBufferOps.kt | 124 ++++++------------ .../kmath/operations/OptionalOperations.kt | 12 +- .../kmath/operations/algebraExtensions.kt | 43 ------ .../kscience/kmath/operations/numbers.kt | 25 ++-- .../kscience/kmath/operations/isInteger.kt | 6 + .../kscience/kmath/operations/isInteger.kt | 6 + .../kscience/kmath/operations/isInteger.kt | 6 + .../kmath/kotlingrad/AdaptingTests.kt | 2 +- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 2 +- .../tensors/api/AnalyticTensorAlgebra.kt | 31 ++++- .../core/BroadcastDoubleTensorAlgebra.kt | 4 + .../kmath/tensors/core/DoubleTensorAlgebra.kt | 13 ++ .../tensors/core/tensorAlgebraExtensions.kt | 3 + .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 10 +- 22 files changed, 296 insertions(+), 181 deletions(-) create mode 100644 kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt create mode 100644 kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt create mode 100644 kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 6733c1211..857ed060b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - `BigInt` operation performance improvement and fixes by @zhelenskiy (#328) - Integration between `MST` and Symja `IExpr` - Complex power +- Separate methods for UInt, Int and Number powers. NaN safety. ### Changed - Exponential operations merged with hyperbolic functions 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 9d5b1cddd..2eaa17ded 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 @@ -18,7 +18,7 @@ import kotlin.contracts.contract */ @OptIn(UnstableKMathAPI::class) public sealed class ComplexFieldOpsND : BufferedFieldOpsND(ComplexField.bufferAlgebra), - ScaleOperations>, ExtendedFieldOps> { + ScaleOperations>, ExtendedFieldOps>, PowerOperations> { override fun StructureND.toBufferND(): BufferND = when (this) { is BufferND -> this @@ -33,9 +33,6 @@ public sealed class ComplexFieldOpsND : BufferedFieldOpsND, value: Double): BufferND = mapInline(a.toBufferND()) { it * value } - override fun power(arg: StructureND, pow: Number): BufferND = - mapInline(arg.toBufferND()) { power(it, pow) } - override fun exp(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { exp(it) } override fun ln(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { ln(it) } @@ -53,6 +50,9 @@ public sealed class ComplexFieldOpsND : BufferedFieldOpsND): BufferND = mapInline(arg.toBufferND()) { acosh(it) } override fun atanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atanh(it) } + override fun power(arg: StructureND, pow: Number): StructureND = + mapInline(arg.toBufferND()) { power(it,pow) } + public companion object : ComplexFieldOpsND() } @@ -63,7 +63,8 @@ public val ComplexField.bufferAlgebra: BufferFieldOps @OptIn(UnstableKMathAPI::class) public class ComplexFieldND(override val shape: Shape) : - ComplexFieldOpsND(), FieldND, NumbersAddOps> { + ComplexFieldOpsND(), FieldND, + NumbersAddOps> { override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions 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 704c4edd8..aa9dd01ce 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 @@ -252,7 +252,7 @@ public class SimpleAutoDiffExpression>( * Generate [AutoDiffProcessor] for [SimpleAutoDiffExpression] */ public fun > simpleAutoDiff( - field: F + field: F, ): AutoDiffProcessor, SimpleAutoDiffField> = AutoDiffProcessor { function -> SimpleAutoDiffExpression(field, function) @@ -272,8 +272,8 @@ public fun > SimpleAutoDiffField.sqrt(x: Aut public fun > SimpleAutoDiffField.pow( x: AutoDiffValue, y: Double, -): AutoDiffValue = derive(const { power(x.value, y) }) { z -> - x.d += z.d * y * power(x.value, y - 1) +): AutoDiffValue = derive(const { x.value.pow(y)}) { z -> + x.d += z.d * y * x.value.pow(y - 1) } public fun > SimpleAutoDiffField.pow( 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 0e094a8c7..d25b455f4 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 @@ -53,21 +53,28 @@ public interface BufferAlgebraND> : AlgebraND { public inline fun > BufferAlgebraND.mapInline( arg: BufferND, - crossinline transform: A.(T) -> T + crossinline transform: A.(T) -> T, ): BufferND { val indexes = arg.indices - return BufferND(indexes, bufferAlgebra.mapInline(arg.buffer, transform)) + val buffer = arg.buffer + return BufferND( + indexes, + bufferAlgebra.run { + bufferFactory(buffer.size) { elementAlgebra.transform(buffer[it]) } + } + ) } internal inline fun > BufferAlgebraND.mapIndexedInline( arg: BufferND, - crossinline transform: A.(index: IntArray, arg: T) -> T + crossinline transform: A.(index: IntArray, arg: T) -> T, ): BufferND { val indexes = arg.indices + val buffer = arg.buffer return BufferND( indexes, - bufferAlgebra.mapIndexedInline(arg.buffer) { offset, value -> - transform(indexes.index(offset), value) + bufferAlgebra.run { + bufferFactory(buffer.size) { elementAlgebra.transform(indexes.index(it), buffer[it]) } } ) } @@ -75,35 +82,42 @@ internal inline fun > BufferAlgebraND.mapIndexedInline( internal inline fun > BufferAlgebraND.zipInline( l: BufferND, r: BufferND, - crossinline block: A.(l: T, r: T) -> T + crossinline block: A.(l: T, r: T) -> T, ): BufferND { require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } val indexes = l.indices - return BufferND(indexes, bufferAlgebra.zipInline(l.buffer, r.buffer, block)) + val lbuffer = l.buffer + val rbuffer = r.buffer + return BufferND( + indexes, + bufferAlgebra.run { + bufferFactory(lbuffer.size) { elementAlgebra.block(lbuffer[it], rbuffer[it]) } + } + ) } @OptIn(PerformancePitfall::class) public open class BufferedGroupNDOps>( override val bufferAlgebra: BufferAlgebra, - override val indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder + override val indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, ) : GroupOpsND, BufferAlgebraND { override fun StructureND.unaryMinus(): StructureND = map { -it } } public open class BufferedRingOpsND>( bufferAlgebra: BufferAlgebra, - indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder + indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, ) : BufferedGroupNDOps(bufferAlgebra, indexerBuilder), RingOpsND public open class BufferedFieldOpsND>( bufferAlgebra: BufferAlgebra, - indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder + indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, ) : BufferedRingOpsND(bufferAlgebra, indexerBuilder), FieldOpsND { public constructor( elementAlgebra: A, bufferFactory: BufferFactory, - indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder + indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, ) : this(BufferFieldOps(elementAlgebra, bufferFactory), indexerBuilder) @OptIn(PerformancePitfall::class) @@ -117,11 +131,11 @@ public val > BufferAlgebra.nd: BufferedFieldOpsND ge public fun > BufferAlgebraND.structureND( vararg shape: Int, - initializer: A.(IntArray) -> T + initializer: A.(IntArray) -> T, ): BufferND = structureND(shape, initializer) public fun , A> A.structureND( - initializer: EA.(IntArray) -> T + initializer: EA.(IntArray) -> T, ): BufferND where A : BufferAlgebraND, A : WithShape = structureND(shape, initializer) //// group factories 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 7285fdb24..8baeac21f 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 @@ -11,7 +11,7 @@ import space.kscience.kmath.operations.* import space.kscience.kmath.structures.DoubleBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract -import kotlin.math.pow +import kotlin.math.pow as kpow public class DoubleBufferND( indexes: ShapeIndexer, @@ -30,9 +30,9 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D } } - private inline fun mapInline( + protected inline fun mapInline( arg: DoubleBufferND, - transform: (Double) -> Double + transform: (Double) -> Double, ): DoubleBufferND { val indexes = arg.indices val array = arg.buffer.array @@ -42,7 +42,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D private inline fun zipInline( l: DoubleBufferND, r: DoubleBufferND, - block: (l: Double, r: Double) -> Double + block: (l: Double, r: Double) -> Double, ): DoubleBufferND { require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } val indexes = l.indices @@ -60,7 +60,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D override fun zip( left: StructureND, right: StructureND, - transform: DoubleField.(Double, Double) -> Double + transform: DoubleField.(Double, Double) -> Double, ): BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> DoubleField.transform(l, r) } override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND { @@ -123,9 +123,6 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D override fun scale(a: StructureND, value: Double): DoubleBufferND = mapInline(a.toBufferND()) { it * value } - override fun power(arg: StructureND, pow: Number): DoubleBufferND = - mapInline(arg.toBufferND()) { it.pow(pow.toDouble()) } - override fun exp(arg: StructureND): DoubleBufferND = mapInline(arg.toBufferND()) { kotlin.math.exp(it) } @@ -173,7 +170,38 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D @OptIn(UnstableKMathAPI::class) public class DoubleFieldND(override val shape: Shape) : - DoubleFieldOpsND(), FieldND, NumbersAddOps> { + DoubleFieldOpsND(), FieldND, NumbersAddOps>, + ExtendedField> { + + override fun power(arg: StructureND, pow: UInt): DoubleBufferND = mapInline(arg.toBufferND()) { + it.kpow(pow.toInt()) + } + + override fun power(arg: StructureND, pow: Int): DoubleBufferND = mapInline(arg.toBufferND()) { + it.kpow(pow) + } + + override fun power(arg: StructureND, pow: Number): DoubleBufferND = if(pow.isInteger()){ + power(arg, pow.toInt()) + } else { + val dpow = pow.toDouble() + mapInline(arg.toBufferND()) { + if (it < 0) throw IllegalArgumentException("Can't raise negative $it to a fractional power") + else it.kpow(dpow) + } + } + + override fun sinh(arg: StructureND): DoubleBufferND = super.sinh(arg) + + override fun cosh(arg: StructureND): DoubleBufferND = super.cosh(arg) + + override fun tanh(arg: StructureND): DoubleBufferND = super.tan(arg) + + override fun asinh(arg: StructureND): DoubleBufferND = super.asinh(arg) + + override fun acosh(arg: StructureND): DoubleBufferND = super.acosh(arg) + + override fun atanh(arg: StructureND): DoubleBufferND = super.atanh(arg) override fun number(value: Number): DoubleBufferND { val d = value.toDouble() // minimize conversions 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 992c0e015..244b9fea7 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 @@ -7,6 +7,7 @@ package space.kscience.kmath.operations import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring.Companion.optimizedPower /** * Stub for DSL the [Algebra] is. @@ -257,6 +258,40 @@ public interface Ring : Group, RingOps { * The neutral element of multiplication */ public val one: T + + /** + * Raises [arg] to the integer power [pow]. + */ + public fun power(arg: T, pow: UInt): T = optimizedPower(arg, pow) + + public companion object{ + /** + * Raises [arg] to the non-negative integer power [exponent]. + * + * Special case: 0 ^ 0 is 1. + * + * @receiver the algebra to provide multiplication. + * @param arg the base. + * @param exponent the exponent. + * @return the base raised to the power. + * @author Evgeniy Zhelenskiy + */ + internal fun Ring.optimizedPower(arg: T, exponent: UInt): T = when { + arg == zero && exponent > 0U -> zero + arg == one -> arg + arg == -one -> powWithoutOptimization(arg, exponent % 2U) + else -> powWithoutOptimization(arg, exponent) + } + + private fun Ring.powWithoutOptimization(base: T, exponent: UInt): T = when (exponent) { + 0U -> one + 1U -> base + else -> { + val pre = powWithoutOptimization(base, exponent shr 1).let { it * it } + if (exponent and 1U == 0U) pre else pre * base + } + } + } } /** @@ -307,4 +342,24 @@ public interface FieldOps : RingOps { */ public interface Field : Ring, FieldOps, ScaleOperations, NumericAlgebra { override fun number(value: Number): T = scale(one, value.toDouble()) + + public fun power(arg: T, pow: Int): T = optimizedPower(arg, pow) + + public companion object{ + /** + * Raises [arg] to the integer power [exponent]. + * + * Special case: 0 ^ 0 is 1. + * + * @receiver the algebra to provide multiplication and division. + * @param arg the base. + * @param exponent the exponent. + * @return the base raised to the power. + * @author Iaroslav Postovalov, Evgeniy Zhelenskiy + */ + private fun Field.optimizedPower(arg: T, exponent: Int): T = when { + exponent < 0 -> one / (this as Ring).optimizedPower(arg, if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt()) + else -> (this as Ring).optimizedPower(arg, exponent.toUInt()) + } + } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt index bc05f3904..634a115c7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.operations +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.DoubleBuffer @@ -34,11 +35,13 @@ public interface BufferAlgebra> : Algebra> { public fun Buffer.zip(other: Buffer, block: A.(left: T, right: T) -> T): Buffer = zipInline(this, other, block) + @UnstableKMathAPI override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { val operationFunction = elementAlgebra.unaryOperationFunction(operation) return { arg -> bufferFactory(arg.size) { operationFunction(arg[it]) } } } + @UnstableKMathAPI override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { val operationFunction = elementAlgebra.binaryOperationFunction(operation) return { left, right -> @@ -50,7 +53,7 @@ public interface BufferAlgebra> : Algebra> { /** * Inline map */ -public inline fun > BufferAlgebra.mapInline( +private inline fun > BufferAlgebra.mapInline( buffer: Buffer, crossinline block: A.(T) -> T ): Buffer = bufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) } @@ -58,7 +61,7 @@ public inline fun > BufferAlgebra.mapInline( /** * Inline map */ -public inline fun > BufferAlgebra.mapIndexedInline( +private inline fun > BufferAlgebra.mapIndexedInline( buffer: Buffer, crossinline block: A.(index: Int, arg: T) -> T ): Buffer = bufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) } @@ -66,7 +69,7 @@ public inline fun > BufferAlgebra.mapIndexedInline( /** * Inline zip */ -public inline fun > BufferAlgebra.zipInline( +private inline fun > BufferAlgebra.zipInline( l: Buffer, r: Buffer, crossinline block: A.(l: T, r: T) -> T @@ -126,7 +129,7 @@ public fun > BufferAlgebra.atanh(arg: Buff mapInline(arg) { atanh(it) } public fun > BufferAlgebra.pow(arg: Buffer, pow: Number): Buffer = - mapInline(arg) { power(it, pow) } + mapInline(arg) {it.pow(pow) } public open class BufferRingOps>( @@ -138,9 +141,11 @@ public open class BufferRingOps>( override fun multiply(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l * r } override fun Buffer.unaryMinus(): Buffer = map { -it } + @UnstableKMathAPI override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = super.unaryOperationFunction(operation) + @UnstableKMathAPI override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = super.binaryOperationFunction(operation) } @@ -160,6 +165,7 @@ public open class BufferFieldOps>( override fun scale(a: Buffer, value: Double): Buffer = a.map { scale(it, value) } override fun Buffer.unaryMinus(): Buffer = map { -it } + @UnstableKMathAPI override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = super.binaryOperationFunction(operation) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt index 060ea5a7e..0deb647a3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt @@ -5,6 +5,8 @@ package space.kscience.kmath.operations +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField.pow import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer @@ -27,7 +29,20 @@ public class DoubleBufferField(public val size: Int) : ExtendedField): DoubleBuffer = super.acosh(arg) - override fun atanh(arg: Buffer): DoubleBuffer= super.atanh(arg) + override fun atanh(arg: Buffer): DoubleBuffer = super.atanh(arg) + + override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (pow.isInteger()) { + arg.mapInline { it.pow(pow.toInt()) } + } else { + arg.mapInline { + if(it<0) throw IllegalArgumentException("Negative argument $it could not be raised to the fractional power") + it.pow(pow.toDouble()) + } + } + + @UnstableKMathAPI + override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = + super.unaryOperationFunction(operation) // override fun number(value: Number): Buffer = DoubleBuffer(size) { value.toDouble() } // 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 3d51b3d32..28238c466 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 @@ -6,21 +6,32 @@ package space.kscience.kmath.operations import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.asBuffer import kotlin.math.* /** * [ExtendedFieldOps] over [DoubleBuffer]. */ -public abstract class DoubleBufferOps : ExtendedFieldOps>, Norm, Double> { +public abstract class DoubleBufferOps : + BufferAlgebra, ExtendedFieldOps>, Norm, Double> { - override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { - DoubleBuffer(size) { -array[it] } - } else { - DoubleBuffer(size) { -get(it) } - } + override val elementAlgebra: DoubleField get() = DoubleField + override val bufferFactory: BufferFactory get() = ::DoubleBuffer + + @UnstableKMathAPI + override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = + super.unaryOperationFunction(operation) + + @UnstableKMathAPI + override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = + super.binaryOperationFunction(operation) + + override fun Buffer.unaryMinus(): DoubleBuffer = mapInline { -it } override fun add(left: Buffer, right: Buffer): DoubleBuffer { require(right.size == left.size) { @@ -92,101 +103,46 @@ public abstract class DoubleBufferOps : ExtendedFieldOps>, Norm): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) }) - } else DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) }) + override fun sin(arg: Buffer): DoubleBuffer = arg.mapInline(::sin) - override fun cos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) }) - } else DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) }) + override fun cos(arg: Buffer): DoubleBuffer = arg.mapInline(::cos) - override fun tan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { tan(array[it]) }) - } else DoubleBuffer(DoubleArray(arg.size) { tan(arg[it]) }) + override fun tan(arg: Buffer): DoubleBuffer = arg.mapInline(::tan) - override fun asin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { asin(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { asin(arg[it]) }) + override fun asin(arg: Buffer): DoubleBuffer = arg.mapInline(::asin) - override fun acos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { acos(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { acos(arg[it]) }) + override fun acos(arg: Buffer): DoubleBuffer = arg.mapInline(::acos) - override fun atan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { atan(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { atan(arg[it]) }) + override fun atan(arg: Buffer): DoubleBuffer = arg.mapInline(::atan) - override fun sinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { sinh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { sinh(arg[it]) }) + override fun sinh(arg: Buffer): DoubleBuffer = arg.mapInline(::sinh) - override fun cosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { cosh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { cosh(arg[it]) }) + override fun cosh(arg: Buffer): DoubleBuffer = arg.mapInline(::cosh) - override fun tanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { tanh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { tanh(arg[it]) }) + override fun tanh(arg: Buffer): DoubleBuffer = arg.mapInline(::tanh) - override fun asinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { asinh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { asinh(arg[it]) }) + override fun asinh(arg: Buffer): DoubleBuffer = arg.mapInline(::asinh) - override fun acosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { acosh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { acosh(arg[it]) }) + override fun acosh(arg: Buffer): DoubleBuffer = arg.mapInline(::acosh) - override fun atanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { atanh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { atanh(arg[it]) }) + override fun atanh(arg: Buffer): DoubleBuffer = arg.mapInline(::atanh) - override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) }) - } else - DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) }) + override fun exp(arg: Buffer): DoubleBuffer = arg.mapInline(::exp) - override fun exp(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) }) - } else DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) }) - - override fun ln(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) }) - } else { - DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) }) - } + override fun ln(arg: Buffer): DoubleBuffer = arg.mapInline(::ln) override fun norm(arg: Buffer): Double = DoubleL2Norm.norm(arg) - override fun scale(a: Buffer, value: Double): DoubleBuffer = if (a is DoubleBuffer) { - val aArray = a.array - DoubleBuffer(DoubleArray(a.size) { aArray[it] * value }) - } else DoubleBuffer(DoubleArray(a.size) { a[it] * value }) + override fun scale(a: Buffer, value: Double): DoubleBuffer = a.mapInline { it * value } - public companion object : DoubleBufferOps() + public companion object : DoubleBufferOps() { + public inline fun Buffer.mapInline(block: (Double) -> Double): DoubleBuffer = + if (this is DoubleBuffer) { + DoubleArray(size) { block(array[it]) }.asBuffer() + } else { + DoubleArray(size) { block(get(it)) }.asBuffer() + } + } } public object DoubleL2Norm : Norm, Double> { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt index d32e03533..332617158 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt @@ -74,14 +74,21 @@ public interface TrigonometricOperations : Algebra { } } +/** + * Check if number is an integer from platform point of view + */ +public expect fun Number.isInteger(): Boolean + /** * A context extension to include power operations based on exponentiation. * * @param T the type of element of this structure. */ -public interface PowerOperations : Algebra { +public interface PowerOperations : FieldOps { + /** - * Raises [arg] to the power [pow]. + * Raises [arg] to a power if possible (negative number could not be raised to a fractional power). + * Throws [IllegalArgumentException] if not possible. */ public fun power(arg: T, pow: Number): T @@ -108,6 +115,7 @@ public interface PowerOperations : Algebra { } } + /** * A container for operations related to `exp` and `ln` functions. * 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 b26ebb2ea..493d90d2f 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 @@ -96,46 +96,3 @@ public fun Iterable.averageWith(space: S): T where S : Ring, S : Sc public fun Sequence.averageWith(space: S): T where S : Ring, S : ScaleOperations = space.average(this) -/** - * Raises [arg] to the non-negative integer power [exponent]. - * - * Special case: 0 ^ 0 is 1. - * - * @receiver the algebra to provide multiplication. - * @param arg the base. - * @param exponent the exponent. - * @return the base raised to the power. - * @author Evgeniy Zhelenskiy - */ -public fun Ring.power(arg: T, exponent: UInt): T = when { - arg == zero && exponent > 0U -> zero - arg == one -> arg - arg == -one -> powWithoutOptimization(arg, exponent % 2U) - else -> powWithoutOptimization(arg, exponent) -} - -private fun Ring.powWithoutOptimization(base: T, exponent: UInt): T = when (exponent) { - 0U -> one - 1U -> base - else -> { - val pre = powWithoutOptimization(base, exponent shr 1).let { it * it } - if (exponent and 1U == 0U) pre else pre * base - } -} - - -/** - * Raises [arg] to the integer power [exponent]. - * - * Special case: 0 ^ 0 is 1. - * - * @receiver the algebra to provide multiplication and division. - * @param arg the base. - * @param exponent the exponent. - * @return the base raised to the power. - * @author Iaroslav Postovalov, Evgeniy Zhelenskiy - */ -public fun Field.power(arg: T, exponent: Int): T = when { - exponent < 0 -> one / (this as Ring).power(arg, if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt()) - else -> (this as Ring).power(arg, exponent.toUInt()) -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index ceb85f3ab..7c8030168 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -13,9 +13,8 @@ import kotlin.math.pow as kpow public interface ExtendedFieldOps : FieldOps, TrigonometricOperations, - PowerOperations, ExponentialOperations, - ScaleOperations { + ScaleOperations { override fun tan(arg: T): T = sin(arg) / cos(arg) override fun tanh(arg: T): T = sinh(arg) / cosh(arg) @@ -26,7 +25,6 @@ public interface ExtendedFieldOps : TrigonometricOperations.ACOS_OPERATION -> ::acos TrigonometricOperations.ASIN_OPERATION -> ::asin TrigonometricOperations.ATAN_OPERATION -> ::atan - PowerOperations.SQRT_OPERATION -> ::sqrt ExponentialOperations.EXP_OPERATION -> ::exp ExponentialOperations.LN_OPERATION -> ::ln ExponentialOperations.COSH_OPERATION -> ::cosh @@ -42,7 +40,7 @@ public interface ExtendedFieldOps : /** * Advanced Number-like field that implements basic operations. */ -public interface ExtendedField : ExtendedFieldOps, Field, NumericAlgebra{ +public interface ExtendedField : ExtendedFieldOps, Field, PowerOperations, NumericAlgebra { override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) @@ -50,6 +48,11 @@ public interface ExtendedField : ExtendedFieldOps, Field, NumericAlgebr override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0 + override fun unaryOperationFunction(operation: String): (arg: T) -> T { + return if (operation == PowerOperations.SQRT_OPERATION) ::sqrt + else super.unaryOperationFunction(operation) + } + override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = when (operation) { PowerOperations.POW_OPERATION -> ::power @@ -69,7 +72,7 @@ public object DoubleField : ExtendedField, Norm, ScaleOp override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { - PowerOperations.POW_OPERATION -> ::power + PowerOperations.POW_OPERATION -> { l, r -> l.kpow(r) } else -> super.binaryOperationFunction(operation) } @@ -94,8 +97,13 @@ public object DoubleField : ExtendedField, Norm, ScaleOp override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg) override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg) - override inline fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg) - override inline fun power(arg: Double, pow: Number): Double = arg.kpow(pow.toDouble()) + override fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg) + override fun power(arg: Double, pow: Number): Double = when { + pow.isInteger() -> arg.kpow(pow.toInt()) + arg < 0 -> throw IllegalArgumentException("Can't raise negative $arg to a fractional power $pow") + else -> arg.kpow(pow.toDouble()) + } + override inline fun exp(arg: Double): Double = kotlin.math.exp(arg) override inline fun ln(arg: Double): Double = kotlin.math.ln(arg) @@ -122,7 +130,7 @@ public object FloatField : ExtendedField, Norm { override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = when (operation) { - PowerOperations.POW_OPERATION -> ::power + PowerOperations.POW_OPERATION -> { l, r -> l.kpow(r) } else -> super.binaryOperationFunction(operation) } @@ -149,6 +157,7 @@ public object FloatField : ExtendedField, Norm { override inline fun sqrt(arg: Float): Float = kotlin.math.sqrt(arg) override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat()) + override inline fun exp(arg: Float): Float = kotlin.math.exp(arg) override inline fun ln(arg: Float): Float = kotlin.math.ln(arg) diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt new file mode 100644 index 000000000..c15669145 --- /dev/null +++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -0,0 +1,6 @@ +package space.kscience.kmath.operations + +/** + * Check if number is an integer + */ +public actual fun Number.isInteger(): Boolean = js("Number").isInteger(this) as Boolean \ No newline at end of file diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt new file mode 100644 index 000000000..746d1e530 --- /dev/null +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -0,0 +1,6 @@ +package space.kscience.kmath.operations + +/** + * Check if number is an integer + */ +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-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt new file mode 100644 index 000000000..746d1e530 --- /dev/null +++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -0,0 +1,6 @@ +package space.kscience.kmath.operations + +/** + * Check if number is an integer + */ +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-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt index 67332a680..4047b9a67 100644 --- a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt +++ b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt @@ -62,6 +62,6 @@ internal class AdaptingTests { .parseMath() .compileToExpression(DoubleField) - assertEquals(actualDerivative(x to 0.1), expectedDerivative(x to 0.1)) + assertEquals(actualDerivative(x to -0.1), expectedDerivative(x to -0.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 b1cc1f834..dd27bc817 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 @@ -155,7 +155,7 @@ public sealed interface Nd4jArrayField> : FieldOpsND, * Represents intersection of [ExtendedField] and [Field] over [Nd4jArrayStructure]. */ public sealed interface Nd4jArrayExtendedFieldOps> : - ExtendedFieldOps>, Nd4jArrayField { + ExtendedFieldOps>, Nd4jArrayField, PowerOperations> { override fun sin(arg: StructureND): StructureND = Transforms.sin(arg.ndArray).wrap() override fun cos(arg: StructureND): StructureND = Transforms.cos(arg.ndArray).wrap() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index c756584a4..743105fdf 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.tensors.api -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.ExtendedFieldOps import space.kscience.kmath.operations.Field @@ -15,7 +15,8 @@ import space.kscience.kmath.operations.Field * * @param T the type of items closed under analytic functions in the tensors. */ -public interface AnalyticTensorAlgebra> : TensorPartialDivisionAlgebra { +public interface AnalyticTensorAlgebra> : + TensorPartialDivisionAlgebra, ExtendedFieldOps> { /** * @return the mean of all elements in the input tensor. @@ -122,7 +123,27 @@ public interface AnalyticTensorAlgebra> : TensorPartialDivisionA //For information: https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor public fun StructureND.floor(): Tensor -} + override fun sin(arg: StructureND): StructureND = arg.sin() -@UnstableKMathAPI -public fun > ATA.exp(arg: StructureND): Tensor = arg.exp() \ No newline at end of file + override fun cos(arg: StructureND): StructureND = arg.cos() + + override fun asin(arg: StructureND): StructureND = arg.asin() + + override fun acos(arg: StructureND): StructureND = arg.acos() + + override fun atan(arg: StructureND): StructureND = arg.atan() + + override fun exp(arg: StructureND): StructureND = arg.exp() + + override fun ln(arg: StructureND): StructureND = arg.ln() + + override fun sinh(arg: StructureND): StructureND = arg.sinh() + + override fun cosh(arg: StructureND): StructureND = arg.cosh() + + override fun asinh(arg: StructureND): StructureND = arg.asinh() + + override fun acosh(arg: StructureND): StructureND = arg.acosh() + + override fun atanh(arg: StructureND): StructureND = arg.atanh() +} \ No newline at end of file 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 7353ecab1..10c747777 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,6 +5,7 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.tensors.api.Tensor @@ -17,6 +18,8 @@ import space.kscience.kmath.tensors.core.internal.tensor * Basic linear algebra operations implemented with broadcasting. * For more information: https://pytorch.org/docs/stable/notes/broadcasting.html */ + +@PerformancePitfall public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun StructureND.plus(arg: StructureND): DoubleTensor { @@ -99,5 +102,6 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { * Compute a value using broadcast double tensor algebra */ @UnstableKMathAPI +@PerformancePitfall public fun DoubleTensorAlgebra.withBroadcast(block: BroadcastDoubleTensorAlgebra.() -> R): R = BroadcastDoubleTensorAlgebra.block() \ No newline at end of file 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 5e7ae262f..bae49c037 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 @@ -3,8 +3,12 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ + +@file:OptIn(PerformancePitfall::class) + package space.kscience.kmath.tensors.core +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as1D @@ -39,6 +43,7 @@ public open class DoubleTensorAlgebra : * @param transform the function to be applied to each element of the tensor. * @return the resulting tensor after applying the function. */ + @PerformancePitfall @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.map(transform: DoubleField.(Double) -> Double): DoubleTensor { val tensor = this.tensor @@ -52,6 +57,7 @@ public open class DoubleTensorAlgebra : ) } + @PerformancePitfall @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.mapIndexed(transform: DoubleField.(index: IntArray, Double) -> Double): DoubleTensor { val tensor = this.tensor @@ -65,6 +71,7 @@ public open class DoubleTensorAlgebra : ) } + @PerformancePitfall override fun zip( left: StructureND, right: StructureND, @@ -377,6 +384,7 @@ public open class DoubleTensorAlgebra : override fun Tensor.viewAs(other: StructureND): DoubleTensor = tensor.view(other.shape) + @PerformancePitfall override infix fun StructureND.dot(other: StructureND): DoubleTensor { if (tensor.shape.size == 1 && other.shape.size == 1) { return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.mutableBuffer.array().sum())) @@ -691,14 +699,19 @@ public open class DoubleTensorAlgebra : return resTensor } + @OptIn(PerformancePitfall::class) override fun StructureND.exp(): DoubleTensor = tensor.map { exp(it) } + @OptIn(PerformancePitfall::class) override fun StructureND.ln(): DoubleTensor = tensor.map { ln(it) } + @OptIn(PerformancePitfall::class) override fun StructureND.sqrt(): DoubleTensor = tensor.map { sqrt(it) } + @OptIn(PerformancePitfall::class) override fun StructureND.cos(): DoubleTensor = tensor.map { cos(it) } + @OptIn(PerformancePitfall::class) override fun StructureND.acos(): DoubleTensor = tensor.map { acos(it) } override fun StructureND.cosh(): DoubleTensor = tensor.map { cosh(it) } 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 916388ba9..1e6dfd52e 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 @@ -3,8 +3,11 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ +@file:OptIn(PerformancePitfall::class) + package space.kscience.kmath.tensors.core +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.Shape import kotlin.jvm.JvmName 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 c50404c9c..e43bbbc6f 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 @@ -6,17 +6,20 @@ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64Array +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedFieldOps import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.operations.PowerOperations @OptIn(UnstableKMathAPI::class) @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public open class ViktorFieldOpsND : FieldOpsND, - ExtendedFieldOps> { + ExtendedFieldOps>, + PowerOperations> { public val StructureND.f64Buffer: F64Array get() = when (this) { @@ -35,6 +38,7 @@ public open class ViktorFieldOpsND : override fun StructureND.unaryMinus(): StructureND = -1 * this + @PerformancePitfall override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = F64Array(*shape).apply { DefaultStrides(shape).asSequence().forEach { index -> @@ -42,6 +46,7 @@ public open class ViktorFieldOpsND : } }.asStructure() + @PerformancePitfall override fun StructureND.mapIndexed( transform: DoubleField.(index: IntArray, Double) -> Double, ): ViktorStructureND = F64Array(*shape).apply { @@ -50,6 +55,7 @@ public open class ViktorFieldOpsND : } }.asStructure() + @PerformancePitfall override fun zip( left: StructureND, right: StructureND, @@ -110,7 +116,7 @@ public open class ViktorFieldOpsND : public val DoubleField.viktorAlgebra: ViktorFieldOpsND get() = ViktorFieldOpsND public open class ViktorFieldND( - override val shape: Shape + override val shape: Shape, ) : ViktorFieldOpsND(), FieldND, NumbersAddOps> { override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } -- 2.34.1 From 0e1e97a3ffc766be5cad8b13b59c1b21a77a9f6e Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 4 Nov 2021 10:58:27 +0300 Subject: [PATCH 060/102] Multik integration finished (for now) --- .../kmath/operations/DoubleBufferOps.kt | 10 +- .../kmath/multik/MultikDoubleAlgebra.kt | 143 ++++-------------- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 75 ++++----- .../kmath/tensors/core/internal/linUtils.kt | 2 +- 4 files changed, 65 insertions(+), 165 deletions(-) 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 28238c466..b0cce91d3 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 @@ -17,12 +17,15 @@ import kotlin.math.* /** * [ExtendedFieldOps] over [DoubleBuffer]. */ -public abstract class DoubleBufferOps : - BufferAlgebra, ExtendedFieldOps>, Norm, Double> { +public abstract class DoubleBufferOps : BufferAlgebra, ExtendedFieldOps>, + Norm, Double> { override val elementAlgebra: DoubleField get() = DoubleField override val bufferFactory: BufferFactory get() = ::DoubleBuffer + override fun Buffer.map(block: DoubleField.(Double) -> Double): DoubleBuffer = + mapInline { DoubleField.block(it) } + @UnstableKMathAPI override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = super.unaryOperationFunction(operation) @@ -87,8 +90,7 @@ public abstract class DoubleBufferOps : val aArray = left.array val bArray = right.array DoubleBuffer(DoubleArray(left.size) { aArray[it] * bArray[it] }) - } else - DoubleBuffer(DoubleArray(left.size) { left[it] * right[it] }) + } else DoubleBuffer(DoubleArray(left.size) { left[it] * right[it] }) } override fun divide(left: Buffer, right: Buffer): DoubleBuffer { diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt index e5fef6c1e..4f18ee573 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt @@ -1,134 +1,47 @@ package space.kscience.kmath.multik -import org.jetbrains.kotlinx.multik.ndarray.data.DN import org.jetbrains.kotlinx.multik.ndarray.data.DataType import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.DoubleField -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.operations.ExponentialOperations +import space.kscience.kmath.operations.TrigonometricOperations public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra(), - AnalyticTensorAlgebra, LinearOpsTensorAlgebra { + TrigonometricOperations>, ExponentialOperations> { override val elementAlgebra: DoubleField get() = DoubleField override val type: DataType get() = DataType.DoubleDataType - override fun StructureND.mean(): Double = multikStat.mean(asMultik().array) + override fun sin(arg: StructureND): MultikTensor = multikMath.mathEx.sin(arg.asMultik().array).wrap() - override fun StructureND.mean(dim: Int, keepDim: Boolean): Tensor = - multikStat.mean(asMultik().array, dim).wrap() + override fun cos(arg: StructureND): MultikTensor = multikMath.mathEx.cos(arg.asMultik().array).wrap() - override fun StructureND.std(): Double { - TODO("Not yet implemented") + override fun tan(arg: StructureND): MultikTensor = sin(arg) / cos(arg) + + override fun asin(arg: StructureND): MultikTensor = arg.map { asin(it) } + + override fun acos(arg: StructureND): MultikTensor = arg.map { acos(it) } + + override fun atan(arg: StructureND): MultikTensor = arg.map { atan(it) } + + override fun exp(arg: StructureND): MultikTensor = multikMath.mathEx.exp(arg.asMultik().array).wrap() + + override fun ln(arg: StructureND): MultikTensor = multikMath.mathEx.log(arg.asMultik().array).wrap() + + override fun sinh(arg: StructureND): MultikTensor = (exp(arg) - exp(-arg)) / 2.0 + + override fun cosh(arg: StructureND): MultikTensor = (exp(arg) + exp(-arg)) / 2.0 + + override fun tanh(arg: StructureND): MultikTensor { + val expPlus = exp(arg) + val expMinus = exp(-arg) + return (expPlus - expMinus) / (expPlus + expMinus) } - override fun StructureND.std(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") - } + override fun asinh(arg: StructureND): MultikTensor = arg.map { asinh(it) } - override fun StructureND.variance(): Double { - TODO("Not yet implemented") - } + override fun acosh(arg: StructureND): MultikTensor = arg.map { acosh(it) } - override fun StructureND.variance(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.exp(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.ln(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.sqrt(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.cos(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.acos(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.cosh(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.acosh(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.sin(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.asin(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.sinh(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.asinh(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.tan(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.atan(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.tanh(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.atanh(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.ceil(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.floor(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.det(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.inv(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.cholesky(): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.qr(): Pair, Tensor> { - TODO("Not yet implemented") - } - - override fun StructureND.lu(): Triple, Tensor, Tensor> { - TODO("Not yet implemented") - } - - override fun StructureND.svd(): Triple, Tensor, Tensor> { - TODO("Not yet implemented") - } - - override fun StructureND.symEig(): Pair, Tensor> { - TODO("Not yet implemented") - } + override fun atanh(arg: StructureND): MultikTensor = arg.map { atanh(it) } } public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra 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 bae49c037..864900adb 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 @@ -75,9 +75,9 @@ public open class DoubleTensorAlgebra : override fun zip( left: StructureND, right: StructureND, - transform: DoubleField.(Double, Double) -> Double + transform: DoubleField.(Double, Double) -> Double, ): DoubleTensor { - require(left.shape.contentEquals(right.shape)){ + require(left.shape.contentEquals(right.shape)) { "The shapes in zip are not equal: left - ${left.shape}, right - ${right.shape}" } val leftTensor = left.tensor @@ -422,14 +422,11 @@ public open class DoubleTensorAlgebra : for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { val (a, b) = ab - dotHelper(a.as2D(), b.as2D(), res.as2D(), l, m1, n) + dotTo(a.as2D(), b.as2D(), res.as2D(), l, m1, n) } if (penultimateDim) { - return resTensor.view( - resTensor.shape.dropLast(2).toIntArray() + - intArrayOf(resTensor.shape.last()) - ) + return resTensor.view(resTensor.shape.dropLast(2).toIntArray() + intArrayOf(resTensor.shape.last())) } if (lastDim) { return resTensor.view(resTensor.shape.dropLast(1).toIntArray()) @@ -441,7 +438,7 @@ public open class DoubleTensorAlgebra : diagonalEntries: Tensor, offset: Int, dim1: Int, - dim2: Int + dim2: Int, ): DoubleTensor { val n = diagonalEntries.shape.size val d1 = minusIndexFrom(n + 1, dim1) @@ -577,13 +574,13 @@ public open class DoubleTensorAlgebra : */ public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) - internal inline fun StructureND.fold(foldFunction: (DoubleArray) -> Double): Double = + private inline fun StructureND.fold(foldFunction: (DoubleArray) -> Double): Double = foldFunction(tensor.copyArray()) - internal inline fun StructureND.foldDim( - foldFunction: (DoubleArray) -> R, + private inline fun StructureND.foldDim( dim: Int, keepDim: Boolean, + foldFunction: (DoubleArray) -> R, ): BufferedTensor { check(dim < dimension) { "Dimension $dim out of range $dimension" } val resShape = if (keepDim) { @@ -592,7 +589,7 @@ public open class DoubleTensorAlgebra : shape.take(dim).toIntArray() + shape.takeLast(dimension - dim - 1).toIntArray() } val resNumElements = resShape.reduce(Int::times) - val init = foldFunction(DoubleArray(1){0.0}) + val init = foldFunction(DoubleArray(1) { 0.0 }) val resTensor = BufferedTensor(resShape, MutableBuffer.auto(resNumElements) { init }, 0) for (index in resTensor.indices) { @@ -608,66 +605,59 @@ public open class DoubleTensorAlgebra : override fun StructureND.sum(): Double = tensor.fold { it.sum() } override fun StructureND.sum(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.sum() }, dim, keepDim).toDoubleTensor() + foldDim(dim, keepDim) { x -> x.sum() }.toDoubleTensor() override fun StructureND.min(): Double = this.fold { it.minOrNull()!! } override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.minOrNull()!! }, dim, keepDim).toDoubleTensor() + foldDim(dim, keepDim) { x -> x.minOrNull()!! }.toDoubleTensor() override fun StructureND.max(): Double = this.fold { it.maxOrNull()!! } override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.maxOrNull()!! }, dim, keepDim).toDoubleTensor() + foldDim(dim, keepDim) { x -> x.maxOrNull()!! }.toDoubleTensor() override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = - foldDim({ x -> + foldDim(dim, keepDim) { x -> x.withIndex().maxByOrNull { it.value }?.index!! - }, dim, keepDim).toIntTensor() + }.toIntTensor() override fun StructureND.mean(): Double = this.fold { it.sum() / tensor.numElements } - override fun StructureND.mean(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - arr.sum() / shape[dim] - }, - dim, - keepDim - ).toDoubleTensor() + override fun StructureND.mean(dim: Int, keepDim: Boolean): DoubleTensor = foldDim(dim, keepDim) { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + arr.sum() / shape[dim] + }.toDoubleTensor() - override fun StructureND.std(): Double = this.fold { arr -> + override fun StructureND.std(): Double = fold { arr -> val mean = arr.sum() / tensor.numElements sqrt(arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1)) } override fun StructureND.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val mean = arr.sum() / shape[dim] - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) - }, dim, keepDim - ).toDoubleTensor() + ) { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val mean = arr.sum() / shape[dim] + sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) + }.toDoubleTensor() - override fun StructureND.variance(): Double = this.fold { arr -> + override fun StructureND.variance(): Double = fold { arr -> val mean = arr.sum() / tensor.numElements arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1) } override fun StructureND.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val mean = arr.sum() / shape[dim] - arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) - }, dim, keepDim - ).toDoubleTensor() + ) { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val mean = arr.sum() / shape[dim] + arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) + }.toDoubleTensor() private fun cov(x: DoubleTensor, y: DoubleTensor): Double { val n = x.shape[0] @@ -699,19 +689,14 @@ public open class DoubleTensorAlgebra : return resTensor } - @OptIn(PerformancePitfall::class) override fun StructureND.exp(): DoubleTensor = tensor.map { exp(it) } - @OptIn(PerformancePitfall::class) override fun StructureND.ln(): DoubleTensor = tensor.map { ln(it) } - @OptIn(PerformancePitfall::class) override fun StructureND.sqrt(): DoubleTensor = tensor.map { sqrt(it) } - @OptIn(PerformancePitfall::class) override fun StructureND.cos(): DoubleTensor = tensor.map { cos(it) } - @OptIn(PerformancePitfall::class) override fun StructureND.acos(): DoubleTensor = tensor.map { acos(it) } override fun StructureND.cosh(): DoubleTensor = tensor.map { cosh(it) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index d31e02677..290809cfd 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -53,7 +53,7 @@ internal val BufferedTensor.matrices: VirtualBuffer> internal fun BufferedTensor.matrixSequence(): Sequence> = matrices.asSequence() -internal fun dotHelper( +internal fun dotTo( a: MutableStructure2D, b: MutableStructure2D, res: MutableStructure2D, -- 2.34.1 From 6c2abdaab03de31084ece8b53f4e53c4c0e5c17a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 10 Nov 2021 20:04:29 +0300 Subject: [PATCH 061/102] First tensorflow test. --- kmath-tensorflow/build.gradle.kts | 1 + .../tensorflow/DoubleTensorFlowAlgebra.kt | 27 ++++- .../kmath/tensorflow/IntTensorFlowAlgebra.kt | 21 ++++ .../kmath/tensorflow/TensorFlowAlgebra.kt | 104 ++++++++++-------- .../kmath/tensorflow/DoubleTensorFlowOps.kt | 19 ++++ .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 2 + 6 files changed, 127 insertions(+), 47 deletions(-) create mode 100644 kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt create mode 100644 kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt diff --git a/kmath-tensorflow/build.gradle.kts b/kmath-tensorflow/build.gradle.kts index fa77a272a..c8307f01f 100644 --- a/kmath-tensorflow/build.gradle.kts +++ b/kmath-tensorflow/build.gradle.kts @@ -7,6 +7,7 @@ description = "Google tensorflow connector" dependencies { api(project(":kmath-tensors")) api("org.tensorflow:tensorflow-core-api:0.3.3") + testImplementation("org.tensorflow:tensorflow-core-platform:0.3.3") } readme { 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 44420cd76..eb8245944 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 @@ -5,6 +5,7 @@ import org.tensorflow.Output import org.tensorflow.ndarray.NdArray import org.tensorflow.op.core.Constant import org.tensorflow.types.TFloat64 +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.Shape @@ -13,20 +14,22 @@ import space.kscience.kmath.operations.DoubleField public class DoubleTensorFlowOutput( graph: Graph, - output: Output + output: Output, ) : TensorFlowOutput(graph, output) { - override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = output.asTensor() + + override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TFloat64 + } public class DoubleTensorFlowAlgebra internal constructor( - graph: Graph + graph: Graph, ) : TensorFlowAlgebra(graph) { override val elementAlgebra: DoubleField get() = DoubleField override fun structureND( shape: Shape, - initializer: DoubleField.(IntArray) -> Double + initializer: DoubleField.(IntArray) -> Double, ): StructureND { val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> DefaultStrides(shape).forEach { index -> @@ -53,4 +56,20 @@ public class DoubleTensorFlowAlgebra internal constructor( override fun Output.wrap(): TensorFlowOutput = DoubleTensorFlowOutput(graph, this) override fun const(value: Double): Constant = ops.constant(value) + + +} + +public fun DoubleField.produceWithTF( + block: DoubleTensorFlowAlgebra.() -> StructureND, +): StructureND = Graph().use { graph -> + val scope = DoubleTensorFlowAlgebra(graph) + scope.export(scope.block()) +} + +public fun DoubleField.produceMapWithTF( + block: DoubleTensorFlowAlgebra.() -> Map>, +): Map> = Graph().use { graph -> + val scope = DoubleTensorFlowAlgebra(graph) + scope.block().mapValues { scope.export(it.value) } } \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt new file mode 100644 index 000000000..084a445e0 --- /dev/null +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt @@ -0,0 +1,21 @@ +package space.kscience.kmath.tensorflow + +import org.tensorflow.Graph +import org.tensorflow.Output +import org.tensorflow.ndarray.NdArray +import org.tensorflow.types.TInt32 +import org.tensorflow.types.TInt64 + +public class IntTensorFlowOutput( + graph: Graph, + output: Output, +) : TensorFlowOutput(graph, output) { + override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TInt32 +} + +public class LongTensorFlowOutput( + graph: Graph, + output: Output, +) : TensorFlowOutput(graph, output) { + override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TInt64 +} \ No newline at end of file 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 e73620d01..1f978c0fc 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 @@ -8,8 +8,13 @@ import org.tensorflow.Session import org.tensorflow.ndarray.NdArray import org.tensorflow.op.Ops import org.tensorflow.op.core.Constant +import org.tensorflow.op.core.Max +import org.tensorflow.op.core.Min +import org.tensorflow.op.core.Sum +import org.tensorflow.types.TInt32 import org.tensorflow.types.family.TType import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Ring @@ -38,8 +43,8 @@ public value class TensorFlowArray(public val tensor: NdArray) : Tensor } public abstract class TensorFlowOutput( - private val graph: Graph, - output: Output + protected val graph: Graph, + output: Output, ) : TensorFlowTensor { public var output: Output = output @@ -49,9 +54,10 @@ public abstract class TensorFlowOutput( protected abstract fun org.tensorflow.Tensor.actualizeTensor(): NdArray - private val actualTensor by lazy { - val session = Session(graph) - TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor()) + internal val actualTensor by lazy { + Session(graph).use { session -> + TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor()) + } } override fun get(index: IntArray): T = actualTensor[index] @@ -66,9 +72,9 @@ public abstract class TensorFlowOutput( } -public abstract class TensorFlowAlgebra> internal constructor( - protected val graph: Graph -) : TensorAlgebra { +public abstract class TensorFlowAlgebra> internal constructor( + protected val graph: Graph, +) : TensorAlgebra { protected val ops: Ops by lazy { Ops.create(graph) } @@ -83,7 +89,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun StructureND.biOp( other: StructureND, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { val left = asTensorFlow().output val right = other.asTensorFlow().output @@ -92,7 +98,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun T.biOp( other: StructureND, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { val left = const(this) val right = other.asTensorFlow().output @@ -101,7 +107,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun StructureND.biOp( value: T, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { val left = asTensorFlow().output val right = const(value) @@ -110,7 +116,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun Tensor.inPlaceOp( other: StructureND, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): Unit { val origin = asTensorFlow() val left = origin.output @@ -120,7 +126,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun Tensor.inPlaceOp( value: T, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): Unit { val origin = asTensorFlow() val left = origin.output @@ -128,8 +134,8 @@ public abstract class TensorFlowAlgebra> internal cons origin.output = operation(left, right).asOutput() } - private inline fun unOp(value: StructureND, operation: (Operand) -> Operand): TensorFlowOutput = - operation(value.asTensorFlow().output).asOutput().wrap() + private inline fun StructureND.unOp(operation: (Operand) -> Operand): TensorFlowOutput = + operation(asTensorFlow().output).asOutput().wrap() override fun T.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) @@ -149,67 +155,79 @@ public abstract class TensorFlowAlgebra> internal cons override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) - override fun Tensor.minusAssign(other: StructureND): Unit = inPlaceOp(other, ops.math::sub) + override fun Tensor.minusAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::sub) override fun T.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) override fun StructureND.times(arg: T): TensorFlowOutput = biOp(arg, ops.math::mul) - override fun StructureND.times(other: StructureND): TensorFlowOutput = biOp(other, ops.math::mul) + override fun StructureND.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) override fun Tensor.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul) override fun Tensor.timesAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::mul) - override fun StructureND.unaryMinus(): TensorFlowOutput = unOp(this, ops.math::neg) + override fun StructureND.unaryMinus(): TensorFlowOutput = unOp(ops.math::neg) - override fun StructureND.get(i: Int): Tensor { + override fun Tensor.get(i: Int): Tensor = unOp { TODO("Not yet implemented") } - override fun StructureND.transpose(i: Int, j: Int): Tensor = unOp(this) { + override fun Tensor.transpose(i: Int, j: Int): Tensor = unOp { ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) } - override fun Tensor.view(shape: IntArray): Tensor { - TODO("Not yet implemented") + override fun Tensor.view(shape: IntArray): Tensor = unOp { + ops.reshape(it, ops.constant(shape)) } - override fun Tensor.viewAs(other: StructureND): Tensor { - TODO("Not yet implemented") + override fun Tensor.viewAs(other: StructureND): Tensor = biOp(other) { l, r -> + ops.reshape(l, ops.shape(r)) } override fun StructureND.dot(other: StructureND): TensorFlowOutput = biOp(other) { l, r -> ops.linalg.matMul(l, r) } - override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): Tensor = ops.run { - TODO("Not yet implemented") + override fun diagonalEmbedding( + diagonalEntries: Tensor, + offset: Int, + dim1: Int, + dim2: Int, + ): TensorFlowOutput = diagonalEntries.unOp { + TODO() } - override fun StructureND.sum(): T = TODO("Not yet implemented") + override fun StructureND.sum(): T = unOp { + ops.sum(it, ops.constant(intArrayOf())) + }.value() - override fun StructureND.sum(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") + override fun StructureND.sum(dim: Int, keepDim: Boolean): TensorFlowOutput = unOp { + ops.sum(it, ops.constant(dim), Sum.keepDims(keepDim)) } - override fun StructureND.min(): T { - TODO("Not yet implemented") + override fun StructureND.min(): T = unOp { + ops.min(it, ops.constant(intArrayOf())) + }.value() + + override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor = unOp { + ops.min(it, ops.constant(dim), Min.keepDims(keepDim)) } - override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") + override fun StructureND.max(): T = unOp { + ops.max(it, ops.constant(intArrayOf())) + }.value() + + override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor = unOp { + ops.max(it, ops.constant(dim), Max.keepDims(keepDim)) } - override fun StructureND.max(): T { - TODO("Not yet implemented") - } + override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor = IntTensorFlowOutput( + graph, + ops.math.argMax(asTensorFlow().output, ops.constant(dim), TInt32::class.java).output() + ).actualTensor - override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") - } + @OptIn(UnstableKMathAPI::class) + override fun export(arg: StructureND): StructureND = + if (arg is TensorFlowOutput) arg.actualTensor else arg } \ No newline at end of file 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 new file mode 100644 index 000000000..b7a4b94b4 --- /dev/null +++ b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt @@ -0,0 +1,19 @@ +package space.kscience.kmath.tensorflow + +import org.junit.jupiter.api.Test +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.structureND +import space.kscience.kmath.operations.DoubleField + +class DoubleTensorFlowOps { + @Test + fun basicOps() { + val res = DoubleField.produceWithTF { + val initial = structureND(2, 2) { 1.0 } + + initial + (initial * 2.0) + } + println(StructureND.toString(res)) + } + +} \ No newline at end of file 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 e43bbbc6f..a6ab55624 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 @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ +@file:OptIn(PerformancePitfall::class) + package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64Array -- 2.34.1 From f231d722c6b3d7fb43c1640a16e4332c29333bf4 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Mon, 15 Nov 2021 22:42:00 +0700 Subject: [PATCH 062/102] Multiple performance improvements related to ASM 1. Argument values are cached in locals 2. Optimized Expression.invoke function 3. lambda=indy is used in kmath-core --- benchmarks/build.gradle.kts | 6 +- .../ExpressionsInterpretersBenchmark.kt | 4 +- .../benchmarks/addBenchmarkProperties.kt | 2 +- examples/build.gradle.kts | 4 +- .../space/kscience/kmath/ast/expressions.kt | 12 ++-- .../kotlin/space/kscience/kmath/asm/asm.kt | 46 +++++++++++----- .../kscience/kmath/asm/internal/AsmBuilder.kt | 55 +++++++++++++------ kmath-core/build.gradle.kts | 19 +++++-- .../kscience/kmath/expressions/Expression.kt | 27 +++++++-- 9 files changed, 127 insertions(+), 48 deletions(-) diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index cca3d312d..130cc84a3 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -72,9 +72,9 @@ benchmark { } fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() { - warmups = 1 + warmups = 2 iterations = 5 - iterationTime = 1000 + iterationTime = 2000 iterationTimeUnit = "ms" } @@ -143,7 +143,7 @@ kotlin.sourceSets.all { tasks.withType { kotlinOptions { jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xlambdas=indy" } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index 63e1511bd..b824a0d69 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -62,9 +62,11 @@ internal class ExpressionsInterpretersBenchmark { private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { val random = Random(0) var sum = 0.0 + val m = HashMap() repeat(times) { - sum += expr(x to random.nextDouble()) + m[x] = random.nextDouble() + sum += expr(m) } blackhole.consume(sum) 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 72c9ff0ad..568bfe535 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -54,7 +54,7 @@ fun Project.addBenchmarkProperties() { LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant() } - if (resDirectory == null) { + if (resDirectory == null || !(resDirectory.resolve("jvm.json")).exists()) { "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." } else { val reports = diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 7b1bce26a..05e562143 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -64,9 +64,9 @@ kotlin.sourceSets.all { } tasks.withType { - kotlinOptions{ + kotlinOptions { jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt index 887d76c42..b37d120fb 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt @@ -5,18 +5,22 @@ package space.kscience.kmath.ast +import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.expressions.MstField +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.interpret import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke fun main() { val expr = MstField { x * 2.0 + number(2.0) / x - 16.0 - } + }.compileToExpression(DoubleField) + + val m = HashMap() repeat(10000000) { - expr.interpret(DoubleField, x to 1.0) + m[x] = 1.0 + expr(m) } -} \ No newline at end of file +} 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 2426d6ee4..9a7c4b023 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 @@ -26,7 +26,19 @@ import space.kscience.kmath.operations.bindSymbolOrNull */ @PublishedApi internal fun MST.compileWith(type: Class, algebra: Algebra): Expression { - fun AsmBuilder.visit(node: MST): Unit = when (node) { + fun AsmBuilder.variablesVisitor(node: MST): Unit = when (node) { + is Symbol -> prepareVariable(node.identity) + is Unary -> variablesVisitor(node.value) + + is Binary -> { + variablesVisitor(node.left) + variablesVisitor(node.right) + } + + else -> Unit + } + + fun AsmBuilder.expressionVisitor(node: MST): Unit = when (node) { is Symbol -> { val symbol = algebra.bindSymbolOrNull(node) @@ -40,39 +52,47 @@ internal fun MST.compileWith(type: Class, algebra: Algebra): Exp is Unary -> when { algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant( - algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) + algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)), + ) - else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) } + else -> buildCall(algebra.unaryOperationFunction(node.operation)) { expressionVisitor(node.value) } } is Binary -> when { algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant( algebra.binaryOperationFunction(node.operation).invoke( algebra.number((node.left as Numeric).value), - algebra.number((node.right as Numeric).value) + algebra.number((node.right as Numeric).value), ) ) algebra is NumericAlgebra && node.left is Numeric -> buildCall( - algebra.leftSideNumberOperationFunction(node.operation)) { - visit(node.left) - visit(node.right) + algebra.leftSideNumberOperationFunction(node.operation), + ) { + expressionVisitor(node.left) + expressionVisitor(node.right) } algebra is NumericAlgebra && node.right is Numeric -> buildCall( - algebra.rightSideNumberOperationFunction(node.operation)) { - visit(node.left) - visit(node.right) + algebra.rightSideNumberOperationFunction(node.operation), + ) { + expressionVisitor(node.left) + expressionVisitor(node.right) } else -> buildCall(algebra.binaryOperationFunction(node.operation)) { - visit(node.left) - visit(node.right) + expressionVisitor(node.left) + expressionVisitor(node.right) } } } - return AsmBuilder(type, buildName(this)) { visit(this@compileWith) }.instance + return AsmBuilder( + type, + buildName(this), + { variablesVisitor(this@compileWith) }, + { expressionVisitor(this@compileWith) }, + ).instance } diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index 418d6141b..4e29c77e0 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -10,8 +10,7 @@ import org.objectweb.asm.Opcodes.* import org.objectweb.asm.Type.* import org.objectweb.asm.commons.InstructionAdapter import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.* import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType import java.nio.file.Paths @@ -26,13 +25,14 @@ import kotlin.io.path.writeBytes * * @property T the type of AsmExpression to unwrap. * @property className the unique class name of new loaded class. - * @property callbackAtInvokeL0 the function to apply to this object when generating invoke method, label 0. + * @property expressionResultCallback the function to apply to this object when generating expression value. * @author Iaroslav Postovalov */ internal class AsmBuilder( classOfT: Class<*>, private val className: String, - private val callbackAtInvokeL0: AsmBuilder.() -> Unit, + private val variablesPrepareCallback: AsmBuilder.() -> Unit, + private val expressionResultCallback: AsmBuilder.() -> Unit, ) { /** * Internal classloader of [AsmBuilder] with alias to define class from byte array. @@ -66,12 +66,17 @@ internal class AsmBuilder( */ private lateinit var invokeMethodVisitor: InstructionAdapter + /** + * Local variables indices are indices of symbols in this list. + */ + private val argumentsLocals = mutableListOf() + /** * Subclasses, loads and instantiates [Expression] for given parameters. * * The built instance is cached. */ - @Suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST", "UNUSED_VARIABLE") val instance: Expression by lazy { val hasConstants: Boolean @@ -94,26 +99,28 @@ internal class AsmBuilder( ).instructionAdapter { invokeMethodVisitor = this visitCode() - val l0 = label() - callbackAtInvokeL0() + val preparingVariables = label() + variablesPrepareCallback() + val expressionResult = label() + expressionResultCallback() areturn(tType) - val l1 = label() + val end = label() visitLocalVariable( "this", classType.descriptor, null, - l0, - l1, + preparingVariables, + end, 0, ) visitLocalVariable( "arguments", MAP_TYPE.descriptor, - "L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;", - l0, - l1, + "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", + preparingVariables, + end, 1, ) @@ -199,7 +206,7 @@ internal class AsmBuilder( val binary = classWriter.toByteArray() val cls = classLoader.defineClass(className, binary) - if (System.getProperty("space.kscience.communicator.prettyapi.dump.generated.classes") == "1") + if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") Paths.get("$className.class").writeBytes(binary) val l = MethodHandles.publicLookup() @@ -256,9 +263,11 @@ internal class AsmBuilder( } /** - * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. + * Stores value variable [name] into a local. Should be called within [variablesPrepareCallback] before using + * [loadVariable]. */ - fun loadVariable(name: String): Unit = invokeMethodVisitor.run { + fun prepareVariable(name: String): Unit = invokeMethodVisitor.run { + if (name in argumentsLocals) return@run load(1, MAP_TYPE) aconst(name) @@ -270,8 +279,22 @@ internal class AsmBuilder( ) checkcast(tType) + var idx = argumentsLocals.indexOf(name) + + if (idx == -1) { + argumentsLocals += name + idx = argumentsLocals.lastIndex + } + + store(2 + idx, tType) } + /** + * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored + * with [prepareVariable] first. + */ + fun loadVariable(name: String): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tType) + inline fun buildCall(function: Function, parameters: AsmBuilder.() -> Unit) { contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces } diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index e4436c1df..143e576f7 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -5,10 +5,21 @@ plugins { // id("com.xcporter.metaview") version "0.0.5" } -kotlin.sourceSets { - commonMain { - dependencies { - api(project(":kmath-memory")) +kotlin { + jvm { + compilations.all { + kotlinOptions { + freeCompilerArgs = + freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" + } + } + } + + sourceSets { + commonMain { + dependencies { + api(project(":kmath-memory")) + } } } } 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 edd020c9a..bd3e6d0ba 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 @@ -29,7 +29,7 @@ public fun interface Expression { * * @return a value. */ -public operator fun Expression.invoke(): T = invoke(emptyMap()) +public operator fun Expression.invoke(): T = this(emptyMap()) /** * Calls this expression from arguments. @@ -38,7 +38,13 @@ public operator fun Expression.invoke(): T = invoke(emptyMap()) * @return a value. */ @JvmName("callBySymbol") -public operator fun Expression.invoke(vararg pairs: Pair): T = invoke(mapOf(*pairs)) +public operator fun Expression.invoke(vararg pairs: Pair): T = this( + when (pairs.size) { + 0 -> emptyMap() + 1 -> mapOf(pairs[0]) + else -> hashMapOf(*pairs) + } +) /** * Calls this expression from arguments. @@ -47,8 +53,21 @@ public operator fun Expression.invoke(vararg pairs: Pair): T = * @return a value. */ @JvmName("callByString") -public operator fun Expression.invoke(vararg pairs: Pair): T = - invoke(mapOf(*pairs).mapKeys { StringSymbol(it.key) }) +public operator fun Expression.invoke(vararg pairs: Pair): T = this( + when (pairs.size) { + 0 -> emptyMap() + + 1 -> { + val (k, v) = pairs[0] + mapOf(StringSymbol(k) to v) + } + + else -> hashMapOf(*Array>(pairs.size) { + val (k, v) = pairs[it] + StringSymbol(k) to v + }) + } +) /** -- 2.34.1 From 7b50400de5ad44ee123da699e7b8136130942117 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 16 Nov 2021 14:03:12 +0700 Subject: [PATCH 063/102] Provide specializations of AsmBuilder for Double, Long, Int --- README.md | 16 +- .../ExpressionsInterpretersBenchmark.kt | 13 +- .../space/kscience/kmath/ast/expressions.kt | 6 +- kmath-ast/README.md | 6 +- kmath-ast/build.gradle.kts | 4 + .../kmath/ast/TestCompilerOperations.kt | 24 + .../kmath/wasm/internal/WasmBuilder.kt | 36 +- .../kotlin/space/kscience/kmath/wasm/wasm.kt | 18 - .../kotlin/space/kscience/kmath/asm/asm.kt | 90 +++- .../kscience/kmath/asm/internal/AsmBuilder.kt | 356 +-------------- .../asm/internal/ByteArrayClassLoader.kt | 1 + .../kmath/asm/internal/GenericAsmBuilder.kt | 325 ++++++++++++++ .../kmath/asm/internal/PrimitiveAsmBuilder.kt | 411 ++++++++++++++++++ .../kmath/asm/internal/mapIntrinsics.kt | 1 + .../kotlin/space/kscience/kmath/ast/utils.kt | 21 +- kmath-complex/README.md | 6 +- kmath-core/README.md | 6 +- .../kscience/kmath/expressions/Symbol.kt | 4 +- kmath-ejml/README.md | 6 +- kmath-for-real/README.md | 6 +- kmath-functions/README.md | 6 +- kmath-jafama/README.md | 6 +- kmath-kotlingrad/README.md | 6 +- kmath-nd4j/README.md | 6 +- kmath-tensors/README.md | 6 +- 25 files changed, 961 insertions(+), 425 deletions(-) create mode 100644 kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt create mode 100644 kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt create mode 100644 kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt diff --git a/README.md b/README.md index db069d4e0..8604873ae 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,12 @@ One can still use generic algebras though. > **Maturity**: DEVELOPMENT


+* ### [kmath-multik](kmath-multik) +> +> +> **Maturity**: PROTOTYPE +
+ * ### [kmath-nd4j](kmath-nd4j) > > @@ -252,6 +258,12 @@ One can still use generic algebras though.
+* ### [kmath-optimization](kmath-optimization) +> +> +> **Maturity**: EXPERIMENTAL +
+ * ### [kmath-stat](kmath-stat) > > @@ -319,8 +331,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:0.3.0-dev-14") - // api("space.kscience:kmath-core-jvm:0.3.0-dev-14") for jvm-specific version + api("space.kscience:kmath-core:0.3.0-dev-17") + // api("space.kscience:kmath-core-jvm:0.3.0-dev-17") for jvm-specific version } ``` diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index b824a0d69..4c6b92248 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -11,6 +11,7 @@ import kotlinx.benchmark.Scope import kotlinx.benchmark.State import space.kscience.kmath.asm.compileToExpression 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 @@ -35,7 +36,14 @@ internal class ExpressionsInterpretersBenchmark { * Benchmark case for [Expression] created with [compileToExpression]. */ @Benchmark - fun asmExpression(blackhole: Blackhole) = invokeAndSum(asm, blackhole) + fun asmGenericExpression(blackhole: Blackhole) = invokeAndSum(asmGeneric, blackhole) + + + /** + * Benchmark case for [Expression] created with [compileToExpression]. + */ + @Benchmark + fun asmPrimitiveExpression(blackhole: Blackhole) = invokeAndSum(asmPrimitive, blackhole) /** * Benchmark case for [Expression] implemented manually with `kotlin.math` functions. @@ -87,7 +95,8 @@ internal class ExpressionsInterpretersBenchmark { } private val mst = node.toExpression(DoubleField) - private val asm = node.compileToExpression(DoubleField) + private val asmPrimitive = node.compileToExpression(DoubleField) + private val asmGeneric = node.compileToExpression(DoubleField as Algebra) private val raw = Expression { args -> val x = args[x]!! diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt index b37d120fb..3c68f9bb5 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt @@ -6,15 +6,15 @@ package space.kscience.kmath.ast import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.expressions.MstField +import space.kscience.kmath.expressions.MstExtendedField import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke fun main() { - val expr = MstField { - x * 2.0 + number(2.0) / x - 16.0 + val expr = MstExtendedField { + x * 2.0 + number(2.0) / x - number(16.0) + asinh(x) / sin(x) }.compileToExpression(DoubleField) val m = HashMap() diff --git a/kmath-ast/README.md b/kmath-ast/README.md index 686506f6f..5e3366881 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Performance and visualization extensions to MST API. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-17`. **Gradle:** ```gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-14' + implementation 'space.kscience:kmath-ast:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-14") + implementation("space.kscience:kmath-ast:0.3.0-dev-17") } ``` diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 9de7e9980..586652349 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -55,6 +55,10 @@ tasks.dokkaHtml { dependsOn(tasks.build) } +tasks.jvmTest { + jvmArgs = (jvmArgs ?: emptyList()) + listOf("-Dspace.kscience.kmath.ast.dump.generated.classes=1") +} + readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt index f5b1e2842..00344410c 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt @@ -44,6 +44,30 @@ internal class TestCompilerOperations { assertEquals(1.0, expr(x to 0.0)) } + @Test + fun testTangent() = runCompilerTest { + val expr = MstExtendedField { tan(x) }.compileToExpression(DoubleField) + assertEquals(0.0, expr(x to 0.0)) + } + + @Test + fun testArcSine() = runCompilerTest { + val expr = MstExtendedField { asin(x) }.compileToExpression(DoubleField) + assertEquals(0.0, expr(x to 0.0)) + } + + @Test + fun testArcCosine() = runCompilerTest { + val expr = MstExtendedField { acos(x) }.compileToExpression(DoubleField) + assertEquals(0.0, expr(x to 1.0)) + } + + @Test + fun testAreaHyperbolicSine() = runCompilerTest { + val expr = MstExtendedField { asinh(x) }.compileToExpression(DoubleField) + assertEquals(0.0, expr(x to 0.0)) + } + @Test fun testSubtract() = runCompilerTest { val expr = MstExtendedField { x - x }.compileToExpression(DoubleField) 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 b04c4d48f..6039d5c27 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 @@ -18,12 +18,12 @@ import space.kscience.kmath.internal.webassembly.Module as WasmModule private val spreader = eval("(obj, args) => obj(...args)") @Suppress("UnsafeCastFromDynamic") -internal sealed class WasmBuilder( - val binaryenType: Type, - val algebra: Algebra, - val target: MST, -) where T : Number { - val keys: MutableList = mutableListOf() +internal sealed class WasmBuilder( + protected val binaryenType: Type, + protected val algebra: Algebra, + protected val target: MST, +) { + protected val keys: MutableList = mutableListOf() lateinit var ctx: BinaryenModule open fun visitSymbolic(mst: Symbol): ExpressionRef { @@ -41,30 +41,36 @@ internal sealed class WasmBuilder( abstract fun visitNumeric(mst: Numeric): ExpressionRef - open fun visitUnary(mst: Unary): ExpressionRef = + protected open fun visitUnary(mst: Unary): ExpressionRef = error("Unary operation ${mst.operation} not defined in $this") - open fun visitBinary(mst: Binary): ExpressionRef = + protected open fun visitBinary(mst: Binary): ExpressionRef = error("Binary operation ${mst.operation} not defined in $this") - open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()") + protected open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()") - fun visit(mst: MST): ExpressionRef = when (mst) { + protected fun visit(mst: MST): ExpressionRef = when (mst) { is Symbol -> visitSymbolic(mst) is Numeric -> visitNumeric(mst) is Unary -> when { algebra is NumericAlgebra && mst.value is Numeric -> visitNumeric( - Numeric(algebra.unaryOperationFunction(mst.operation)(algebra.number((mst.value as Numeric).value)))) + Numeric(algebra.unaryOperationFunction(mst.operation)(algebra.number((mst.value as Numeric).value))) + ) else -> visitUnary(mst) } is Binary -> when { - algebra is NumericAlgebra && mst.left is Numeric && mst.right is Numeric -> visitNumeric(Numeric( - algebra.binaryOperationFunction(mst.operation) - .invoke(algebra.number((mst.left as Numeric).value), algebra.number((mst.right as Numeric).value)) - )) + algebra is NumericAlgebra && mst.left is Numeric && mst.right is Numeric -> visitNumeric( + Numeric( + algebra.binaryOperationFunction(mst.operation) + .invoke( + algebra.number((mst.left as Numeric).value), + algebra.number((mst.right as Numeric).value) + ) + ) + ) else -> visitBinary(mst) } 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 5b28b8782..393a02e3d 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 @@ -16,24 +16,6 @@ import space.kscience.kmath.operations.IntRing import space.kscience.kmath.wasm.internal.DoubleWasmBuilder import space.kscience.kmath.wasm.internal.IntWasmBuilder -/** - * Compiles an [MST] to WASM in the context of reals. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun DoubleField.expression(mst: MST): Expression = - DoubleWasmBuilder(mst).instance - -/** - * Compiles an [MST] to WASM in the context of integers. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun IntRing.expression(mst: MST): Expression = - IntWasmBuilder(mst).instance - /** * Create a compiled expression with given [MST] and given [algebra]. * 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 9a7c4b023..19b400cbd 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 @@ -3,18 +3,18 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ +@file:Suppress("UNUSED_PARAMETER") + package space.kscience.kmath.asm -import space.kscience.kmath.asm.internal.AsmBuilder -import space.kscience.kmath.asm.internal.buildName +import space.kscience.kmath.asm.internal.* import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.MST.* import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbolOrNull +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* /** * Compiles given MST to an Expression using AST compiler. @@ -26,7 +26,7 @@ import space.kscience.kmath.operations.bindSymbolOrNull */ @PublishedApi internal fun MST.compileWith(type: Class, algebra: Algebra): Expression { - fun AsmBuilder.variablesVisitor(node: MST): Unit = when (node) { + fun GenericAsmBuilder.variablesVisitor(node: MST): Unit = when (node) { is Symbol -> prepareVariable(node.identity) is Unary -> variablesVisitor(node.value) @@ -38,7 +38,7 @@ internal fun MST.compileWith(type: Class, algebra: Algebra): Exp else -> Unit } - fun AsmBuilder.expressionVisitor(node: MST): Unit = when (node) { + fun GenericAsmBuilder.expressionVisitor(node: MST): Unit = when (node) { is Symbol -> { val symbol = algebra.bindSymbolOrNull(node) @@ -87,7 +87,7 @@ internal fun MST.compileWith(type: Class, algebra: Algebra): Exp } } - return AsmBuilder( + return GenericAsmBuilder( type, buildName(this), { variablesVisitor(this@compileWith) }, @@ -114,3 +114,77 @@ public inline fun MST.compile(algebra: Algebra, arguments: */ public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = compileToExpression(algebra).invoke(*arguments) + + +/** + * Create a compiled expression with given [MST] and given [algebra]. + * + * @author Iaroslav Postovalov + */ +public fun MST.compileToExpression(algebra: IntRing): Expression = IntAsmBuilder(this).instance + +/** + * Compile given MST to expression and evaluate it against [arguments]. + * + * @author Iaroslav Postovalov + */ +public fun MST.compile(algebra: IntRing, arguments: Map): Int = + compileToExpression(algebra).invoke(arguments) + +/** + * Compile given MST to expression and evaluate it against [arguments]. + * + * @author Iaroslav Postovalov + */ +public fun MST.compile(algebra: IntRing, vararg arguments: Pair): Int = + compileToExpression(algebra)(*arguments) + + +/** + * Create a compiled expression with given [MST] and given [algebra]. + * + * @author Iaroslav Postovalov + */ +public fun MST.compileToExpression(algebra: LongRing): Expression = LongAsmBuilder(this).instance + + +/** + * Compile given MST to expression and evaluate it against [arguments]. + * + * @author Iaroslav Postovalov + */ +public fun MST.compile(algebra: LongRing, arguments: Map): Long = + compileToExpression(algebra).invoke(arguments) + + +/** + * Compile given MST to expression and evaluate it against [arguments]. + * + * @author Iaroslav Postovalov + */ +public fun MST.compile(algebra: LongRing, vararg arguments: Pair): Long = + compileToExpression(algebra)(*arguments) + + +/** + * Create a compiled expression with given [MST] and given [algebra]. + * + * @author Iaroslav Postovalov + */ +public fun MST.compileToExpression(algebra: DoubleField): Expression = DoubleAsmBuilder(this).instance + +/** + * Compile given MST to expression and evaluate it against [arguments]. + * + * @author Iaroslav Postovalov + */ +public fun MST.compile(algebra: DoubleField, arguments: Map): Double = + compileToExpression(algebra).invoke(arguments) + +/** + * Compile given MST to expression and evaluate it against [arguments]. + * + * @author Iaroslav Postovalov + */ +public fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = + compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index 4e29c77e0..2a7b3dea9 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -1,377 +1,47 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - package space.kscience.kmath.asm.internal -import org.objectweb.asm.* -import org.objectweb.asm.Opcodes.* -import org.objectweb.asm.Type.* -import org.objectweb.asm.commons.InstructionAdapter -import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader -import space.kscience.kmath.expressions.* -import java.lang.invoke.MethodHandles -import java.lang.invoke.MethodType -import java.nio.file.Paths -import java.util.stream.Collectors.toMap -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.io.path.writeBytes +import org.objectweb.asm.Type +import space.kscience.kmath.expressions.Expression -/** - * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. - * This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class. - * - * @property T the type of AsmExpression to unwrap. - * @property className the unique class name of new loaded class. - * @property expressionResultCallback the function to apply to this object when generating expression value. - * @author Iaroslav Postovalov - */ -internal class AsmBuilder( - classOfT: Class<*>, - private val className: String, - private val variablesPrepareCallback: AsmBuilder.() -> Unit, - private val expressionResultCallback: AsmBuilder.() -> Unit, -) { +internal abstract class AsmBuilder { /** - * Internal classloader of [AsmBuilder] with alias to define class from byte array. + * Internal classloader with alias to define class from byte array. */ - private class ClassLoader(parent: java.lang.ClassLoader) : java.lang.ClassLoader(parent) { + class ByteArrayClassLoader(parent: ClassLoader) : ClassLoader(parent) { fun defineClass(name: String?, b: ByteArray): Class<*> = defineClass(name, b, 0, b.size) } - /** - * The instance of [ClassLoader] used by this builder. - */ - private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader) - - /** - * ASM type for [T]. - */ - private val tType: Type = classOfT.asm - - /** - * ASM type for new class. - */ - private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) - - /** - * List of constants to provide to the subclass. - */ - private val constants: MutableList = mutableListOf() - - /** - * Method visitor of `invoke` method of the subclass. - */ - private lateinit var invokeMethodVisitor: InstructionAdapter - - /** - * Local variables indices are indices of symbols in this list. - */ - private val argumentsLocals = mutableListOf() - - /** - * Subclasses, loads and instantiates [Expression] for given parameters. - * - * The built instance is cached. - */ - @Suppress("UNCHECKED_CAST", "UNUSED_VARIABLE") - val instance: Expression by lazy { - val hasConstants: Boolean - - val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { - visit( - V1_8, - ACC_PUBLIC or ACC_FINAL or ACC_SUPER, - classType.internalName, - "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", - OBJECT_TYPE.internalName, - arrayOf(EXPRESSION_TYPE.internalName), - ) - - visitMethod( - ACC_PUBLIC or ACC_FINAL, - "invoke", - getMethodDescriptor(tType, MAP_TYPE), - "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", - null, - ).instructionAdapter { - invokeMethodVisitor = this - visitCode() - val preparingVariables = label() - variablesPrepareCallback() - val expressionResult = label() - expressionResultCallback() - areturn(tType) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - preparingVariables, - end, - 0, - ) - - visitLocalVariable( - "arguments", - MAP_TYPE.descriptor, - "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", - preparingVariables, - end, - 1, - ) - - visitMaxs(0, 2) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, - "invoke", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), - null, - null, - ).instructionAdapter { - visitCode() - val l0 = label() - load(0, OBJECT_TYPE) - load(1, MAP_TYPE) - invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) - areturn(tType) - val l1 = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - l0, - l1, - 0, - ) - - visitMaxs(0, 2) - visitEnd() - } - - hasConstants = constants.isNotEmpty() - - if (hasConstants) - visitField( - access = ACC_PRIVATE or ACC_FINAL, - name = "constants", - descriptor = OBJECT_ARRAY_TYPE.descriptor, - signature = null, - value = null, - block = FieldVisitor::visitEnd, - ) - - visitMethod( - ACC_PUBLIC, - "", - getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), - null, - null, - ).instructionAdapter { - val l0 = label() - load(0, classType) - invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) - label() - load(0, classType) - - if (hasConstants) { - label() - load(0, classType) - load(1, OBJECT_ARRAY_TYPE) - putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) - } - - label() - visitInsn(RETURN) - val l4 = label() - visitLocalVariable("this", classType.descriptor, null, l0, l4, 0) - - if (hasConstants) - visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, 1) - - visitMaxs(0, 3) - visitEnd() - } - - visitEnd() - } - - val binary = classWriter.toByteArray() - val cls = classLoader.defineClass(className, binary) - - if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") - Paths.get("$className.class").writeBytes(binary) - - val l = MethodHandles.publicLookup() - - (if (hasConstants) - l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java))(constants.toTypedArray()) - else - l.findConstructor(cls, MethodType.methodType(Void.TYPE))()) as Expression - } - - /** - * Loads [java.lang.Object] constant from constants. - */ - fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { - val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex - invokeMethodVisitor.load(0, classType) - getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) - iconst(idx) - visitInsn(AALOAD) - if (type != OBJECT_TYPE) checkcast(type) - } - - /** - * Either loads a numeric constant [value] from the class's constants field or boxes a primitive - * constant from the constant pool. - */ - fun loadNumberConstant(value: Number) { - val boxed = value.javaClass.asm - val primitive = BOXED_TO_PRIMITIVES[boxed] - - if (primitive != null) { - when (primitive) { - BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) - FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) - LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) - INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - } - - val r = PRIMITIVES_TO_BOXED.getValue(primitive) - - invokeMethodVisitor.invokestatic( - r.internalName, - "valueOf", - getMethodDescriptor(r, primitive), - false, - ) - - return - } - - loadObjectConstant(value, boxed) - } - - /** - * Stores value variable [name] into a local. Should be called within [variablesPrepareCallback] before using - * [loadVariable]. - */ - fun prepareVariable(name: String): Unit = invokeMethodVisitor.run { - if (name in argumentsLocals) return@run - load(1, MAP_TYPE) - aconst(name) - - invokestatic( - MAP_INTRINSICS_TYPE.internalName, - "getOrFail", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), - false, - ) - - checkcast(tType) - var idx = argumentsLocals.indexOf(name) - - if (idx == -1) { - argumentsLocals += name - idx = argumentsLocals.lastIndex - } - - store(2 + idx, tType) - } - - /** - * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored - * with [prepareVariable] first. - */ - fun loadVariable(name: String): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tType) - - inline fun buildCall(function: Function, parameters: AsmBuilder.() -> Unit) { - contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } - val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces } - - val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount - ?: error("Provided function object doesn't contain invoke method") - - val type = getType(`interface`) - loadObjectConstant(function, type) - parameters(this) - - invokeMethodVisitor.invokeinterface( - type.internalName, - "invoke", - getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE }), - ) - - invokeMethodVisitor.checkcast(tType) - } - - companion object { - /** - * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. - */ - private val BOXED_TO_PRIMITIVES: Map by lazy { - hashMapOf( - Byte::class.java.asm to BYTE_TYPE, - Short::class.java.asm to SHORT_TYPE, - Integer::class.java.asm to INT_TYPE, - Long::class.java.asm to LONG_TYPE, - Float::class.java.asm to FLOAT_TYPE, - Double::class.java.asm to DOUBLE_TYPE, - ) - } - - /** - * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. - */ - private val PRIMITIVES_TO_BOXED: Map by lazy { - BOXED_TO_PRIMITIVES.entries.stream().collect( - toMap(Map.Entry::value, Map.Entry::key), - ) - } + protected val classLoader = ByteArrayClassLoader(javaClass.classLoader) + protected companion object { /** * ASM type for [Expression]. */ - val EXPRESSION_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Expression") } + val EXPRESSION_TYPE: Type by lazy { Type.getObjectType("space/kscience/kmath/expressions/Expression") } /** * ASM type for [java.util.Map]. */ - val MAP_TYPE: Type by lazy { getObjectType("java/util/Map") } + val MAP_TYPE: Type by lazy { Type.getObjectType("java/util/Map") } /** * ASM type for [java.lang.Object]. */ - val OBJECT_TYPE: Type by lazy { getObjectType("java/lang/Object") } - - /** - * ASM type for array of [java.lang.Object]. - */ - val OBJECT_ARRAY_TYPE: Type by lazy { getType("[Ljava/lang/Object;") } + val OBJECT_TYPE: Type by lazy { Type.getObjectType("java/lang/Object") } /** * ASM type for [java.lang.String]. */ - val STRING_TYPE: Type by lazy { getObjectType("java/lang/String") } + val STRING_TYPE: Type by lazy { Type.getObjectType("java/lang/String") } /** * ASM type for MapIntrinsics. */ - val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") } + val MAP_INTRINSICS_TYPE: Type by lazy { Type.getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") } /** * ASM Type for [space.kscience.kmath.expressions.Symbol]. */ - val SYMBOL_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Symbol") } + val SYMBOL_TYPE: Type by lazy { Type.getObjectType("space/kscience/kmath/expressions/Symbol") } } } diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt new file mode 100644 index 000000000..afff48ef6 --- /dev/null +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt @@ -0,0 +1 @@ +package space.kscience.kmath.asm.internal diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt new file mode 100644 index 000000000..1b45b0625 --- /dev/null +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt @@ -0,0 +1,325 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.asm.internal + +import org.objectweb.asm.* +import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.Type.* +import org.objectweb.asm.commons.InstructionAdapter +import space.kscience.kmath.expressions.* +import java.lang.invoke.MethodHandles +import java.lang.invoke.MethodType +import java.nio.file.Paths +import java.util.stream.Collectors.toMap +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.io.path.writeBytes + +/** + * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. + * This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class. + * + * @property T the type of AsmExpression to unwrap. + * @property className the unique class name of new loaded class. + * @property expressionResultCallback the function to apply to this object when generating expression value. + * @author Iaroslav Postovalov + */ +internal class GenericAsmBuilder( + classOfT: Class<*>, + private val className: String, + private val variablesPrepareCallback: GenericAsmBuilder.() -> Unit, + private val expressionResultCallback: GenericAsmBuilder.() -> Unit, +) : AsmBuilder() { + /** + * ASM type for [T]. + */ + private val tType: Type = classOfT.asm + + /** + * ASM type for new class. + */ + private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) + + /** + * List of constants to provide to the subclass. + */ + private val constants = mutableListOf() + + /** + * Method visitor of `invoke` method of the subclass. + */ + private lateinit var invokeMethodVisitor: InstructionAdapter + + /** + * Local variables indices are indices of symbols in this list. + */ + private val argumentsLocals = mutableListOf() + + /** + * Subclasses, loads and instantiates [Expression] for given parameters. + * + * The built instance is cached. + */ + @Suppress("UNCHECKED_CAST", "UNUSED_VARIABLE") + val instance: Expression by lazy { + val hasConstants: Boolean + + val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { + visit( + V1_8, + ACC_PUBLIC or ACC_FINAL or ACC_SUPER, + classType.internalName, + "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", + OBJECT_TYPE.internalName, + arrayOf(EXPRESSION_TYPE.internalName), + ) + + visitMethod( + ACC_PUBLIC or ACC_FINAL, + "invoke", + getMethodDescriptor(tType, MAP_TYPE), + "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", + null, + ).instructionAdapter { + invokeMethodVisitor = this + visitCode() + val preparingVariables = label() + variablesPrepareCallback() + val expressionResult = label() + expressionResultCallback() + areturn(tType) + val end = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + preparingVariables, + end, + 0, + ) + + visitLocalVariable( + "arguments", + MAP_TYPE.descriptor, + "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", + preparingVariables, + end, + 1, + ) + + visitMaxs(0, 0) + visitEnd() + } + + visitMethod( + ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, + "invoke", + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), + null, + null, + ).instructionAdapter { + visitCode() + val start = label() + load(0, OBJECT_TYPE) + load(1, MAP_TYPE) + invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) + areturn(tType) + val end = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + start, + end, + 0, + ) + + visitMaxs(0, 0) + visitEnd() + } + + hasConstants = constants.isNotEmpty() + + if (hasConstants) + visitField( + access = ACC_PRIVATE or ACC_FINAL, + name = "constants", + descriptor = OBJECT_ARRAY_TYPE.descriptor, + signature = null, + value = null, + block = FieldVisitor::visitEnd, + ) + + visitMethod( + ACC_PUBLIC, + "", + getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), + null, + null, + ).instructionAdapter { + val l0 = label() + load(0, classType) + invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) + label() + load(0, classType) + + if (hasConstants) { + label() + load(0, classType) + load(1, OBJECT_ARRAY_TYPE) + putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) + } + + label() + visitInsn(RETURN) + val l4 = label() + visitLocalVariable("this", classType.descriptor, null, l0, l4, 0) + + if (hasConstants) + visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, 1) + + visitMaxs(0, 0) + visitEnd() + } + + visitEnd() + } + + val binary = classWriter.toByteArray() + val cls = classLoader.defineClass(className, binary) + + if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") + Paths.get("${className.split('.').last()}.class").writeBytes(binary) + + val l = MethodHandles.publicLookup() + + (if (hasConstants) + l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java))(constants.toTypedArray()) + else + l.findConstructor(cls, MethodType.methodType(Void.TYPE))()) as Expression + } + + /** + * Loads [java.lang.Object] constant from constants. + */ + fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { + val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex + invokeMethodVisitor.load(0, classType) + getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) + iconst(idx) + visitInsn(AALOAD) + if (type != OBJECT_TYPE) checkcast(type) + } + + /** + * Either loads a numeric constant [value] from the class's constants field or boxes a primitive + * constant from the constant pool. + */ + fun loadNumberConstant(value: Number) { + val boxed = value.javaClass.asm + val primitive = BOXED_TO_PRIMITIVES[boxed] + + if (primitive != null) { + when (primitive) { + BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) + FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) + LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) + INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + } + + val r = boxed + + invokeMethodVisitor.invokestatic( + r.internalName, + "valueOf", + getMethodDescriptor(r, primitive), + false, + ) + + return + } + + loadObjectConstant(value, boxed) + } + + /** + * Stores value variable [name] into a local. Should be called within [variablesPrepareCallback] before using + * [loadVariable]. + */ + fun prepareVariable(name: String): Unit = invokeMethodVisitor.run { + if (name in argumentsLocals) return@run + load(1, MAP_TYPE) + aconst(name) + + invokestatic( + MAP_INTRINSICS_TYPE.internalName, + "getOrFail", + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), + false, + ) + + checkcast(tType) + var idx = argumentsLocals.indexOf(name) + + if (idx == -1) { + argumentsLocals += name + idx = argumentsLocals.lastIndex + } + + store(2 + idx, tType) + } + + /** + * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored + * with [prepareVariable] first. + */ + fun loadVariable(name: String): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tType) + + inline fun buildCall(function: Function, parameters: GenericAsmBuilder.() -> Unit) { + contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } + val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces } + + val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount + ?: error("Provided function object doesn't contain invoke method") + + val type = getType(`interface`) + loadObjectConstant(function, type) + parameters(this) + + invokeMethodVisitor.invokeinterface( + type.internalName, + "invoke", + getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE }), + ) + + invokeMethodVisitor.checkcast(tType) + } + + private companion object { + /** + * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. + */ + private val BOXED_TO_PRIMITIVES: Map by lazy { + hashMapOf( + Byte::class.java.asm to BYTE_TYPE, + Short::class.java.asm to SHORT_TYPE, + Integer::class.java.asm to INT_TYPE, + Long::class.java.asm to LONG_TYPE, + Float::class.java.asm to FLOAT_TYPE, + Double::class.java.asm to DOUBLE_TYPE, + ) + } + + /** + * ASM type for array of [java.lang.Object]. + */ + val OBJECT_ARRAY_TYPE: Type by lazy { getType("[Ljava/lang/Object;") } + } +} 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 new file mode 100644 index 000000000..2819368ed --- /dev/null +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt @@ -0,0 +1,411 @@ +package space.kscience.kmath.asm.internal + +import org.objectweb.asm.ClassWriter +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.expressions.Expression +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.operations.* +import java.lang.invoke.MethodHandles +import java.lang.invoke.MethodType +import java.nio.file.Paths +import kotlin.io.path.writeBytes + +internal sealed class PrimitiveAsmBuilder( + protected val algebra: Algebra, + classOfT: Class<*>, + protected val classOfTPrimitive: Class<*>, + protected val target: MST, +) : AsmBuilder() { + private val className: String = buildName(target) + + /** + * ASM type for [T]. + */ + private val tType: Type = classOfT.asm + + /** + * ASM type for [T]. + */ + protected val tTypePrimitive: Type = classOfTPrimitive.asm + + /** + * ASM type for new class. + */ + private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) + + /** + * Method visitor of `invoke` method of the subclass. + */ + protected lateinit var invokeMethodVisitor: InstructionAdapter + + /** + * Local variables indices are indices of symbols in this list. + */ + private val argumentsLocals = mutableListOf() + + /** + * Subclasses, loads and instantiates [Expression] for given parameters. + * + * The built instance is cached. + */ + @Suppress("UNCHECKED_CAST", "UNUSED_VARIABLE") + val instance: Expression by lazy { + val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { + visit( + Opcodes.V1_8, + Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_SUPER, + classType.internalName, + "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", + OBJECT_TYPE.internalName, + arrayOf(EXPRESSION_TYPE.internalName), + ) + + visitMethod( + Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL, + "invoke", + getMethodDescriptor(tType, MAP_TYPE), + "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", + null, + ).instructionAdapter { + invokeMethodVisitor = this + visitCode() + val preparingVariables = label() + visitVariables(target) + val expressionResult = label() + visitExpression(target) + box() + areturn(tType) + val end = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + preparingVariables, + end, + 0, + ) + + visitLocalVariable( + "arguments", + MAP_TYPE.descriptor, + "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", + preparingVariables, + end, + 1, + ) + + visitMaxs(0, 0) + visitEnd() + } + + visitMethod( + Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_BRIDGE or Opcodes.ACC_SYNTHETIC, + "invoke", + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), + null, + null, + ).instructionAdapter { + visitCode() + val start = label() + load(0, OBJECT_TYPE) + load(1, MAP_TYPE) + invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) + areturn(tType) + val end = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + start, + end, + 0, + ) + + visitMaxs(0, 0) + visitEnd() + } + + visitMethod( + Opcodes.ACC_PUBLIC, + "", + getMethodDescriptor(VOID_TYPE), + null, + null, + ).instructionAdapter { + val start = label() + load(0, classType) + invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) + label() + load(0, classType) + label() + visitInsn(Opcodes.RETURN) + val end = label() + visitLocalVariable("this", classType.descriptor, null, start, end, 0) + visitMaxs(0, 0) + visitEnd() + } + + visitEnd() + } + + val binary = classWriter.toByteArray() + val cls = classLoader.defineClass(className, binary) + + if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") + Paths.get("${className.split('.').last()}.class").writeBytes(binary) + + MethodHandles.publicLookup().findConstructor(cls, MethodType.methodType(Void.TYPE))() as Expression + } + + /** + * Either loads a numeric constant [value] from the class's constants field or boxes a primitive + * constant from the constant pool. + */ + fun loadNumberConstant(value: Number) { + when (tTypePrimitive) { + BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) + FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) + LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) + INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + } + } + + /** + * Stores value variable [name] into a local. Should be called within [variablesPrepareCallback] before using + * [loadVariable]. + */ + fun prepareVariable(name: String): Unit = invokeMethodVisitor.run { + if (name in argumentsLocals) return@run + load(1, MAP_TYPE) + aconst(name) + + invokestatic( + MAP_INTRINSICS_TYPE.internalName, + "getOrFail", + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), + false, + ) + + checkcast(tType) + var idx = argumentsLocals.indexOf(name) + + if (idx == -1) { + argumentsLocals += name + idx = argumentsLocals.lastIndex + } + + unbox() + store(2 + idx, tTypePrimitive) + } + + /** + * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored + * with [prepareVariable] first. + */ + fun loadVariable(name: String): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tTypePrimitive) + + private fun unbox() = invokeMethodVisitor.run { + invokevirtual( + NUMBER_TYPE.internalName, + "${classOfTPrimitive.simpleName}Value", + getMethodDescriptor(tTypePrimitive), + false + ) + } + + private fun box() = invokeMethodVisitor.run { + invokestatic(tType.internalName, "valueOf", getMethodDescriptor(tType, tTypePrimitive), false) + } + + protected fun visitVariables(node: MST): Unit = when (node) { + is Symbol -> prepareVariable(node.identity) + is MST.Unary -> visitVariables(node.value) + + is MST.Binary -> { + visitVariables(node.left) + visitVariables(node.right) + } + + else -> Unit + } + + protected fun visitExpression(mst: MST): Unit = when (mst) { + is Symbol -> loadVariable(mst.identity) + is MST.Numeric -> loadNumberConstant(mst.value) + + is MST.Unary -> when { + algebra is NumericAlgebra && mst.value is MST.Numeric -> { + loadNumberConstant( + MST.Numeric( + algebra.unaryOperationFunction(mst.operation)(algebra.number((mst.value as MST.Numeric).value)), + ).value, + ) + } + + else -> visitUnary(mst) + } + + is MST.Binary -> when { + algebra is NumericAlgebra && mst.left is MST.Numeric && mst.right is MST.Numeric -> { + loadNumberConstant( + MST.Numeric( + algebra.binaryOperationFunction(mst.operation)( + algebra.number((mst.left as MST.Numeric).value), + algebra.number((mst.right as MST.Numeric).value), + ), + ).value, + ) + } + + else -> visitBinary(mst) + } + } + + protected open fun visitUnary(mst: MST.Unary) { + visitExpression(mst.value) + } + + protected open fun visitBinary(mst: MST.Binary) { + visitExpression(mst.left) + visitExpression(mst.right) + } + + protected companion object { + /** + * ASM type for [java.lang.Number]. + */ + val NUMBER_TYPE: Type by lazy { getObjectType("java/lang/Number") } + } +} + +internal class DoubleAsmBuilder(target: MST) : + PrimitiveAsmBuilder(DoubleField, java.lang.Double::class.java, java.lang.Double.TYPE, target) { + + private fun buildUnaryJavaMathCall(name: String) { + invokeMethodVisitor.invokestatic( + MATH_TYPE.internalName, + name, + getMethodDescriptor(tTypePrimitive, tTypePrimitive), + false, + ) + } + + private fun buildBinaryJavaMathCall(name: String) { + invokeMethodVisitor.invokestatic( + MATH_TYPE.internalName, + name, + getMethodDescriptor(tTypePrimitive, tTypePrimitive, tTypePrimitive), + false, + ) + } + + private fun buildUnaryKotlinMathCall(name: String) { + invokeMethodVisitor.invokestatic( + MATH_KT_TYPE.internalName, + name, + getMethodDescriptor(tTypePrimitive, tTypePrimitive), + false, + ) + } + + override fun visitUnary(mst: MST.Unary) { + super.visitUnary(mst) + + when (mst.operation) { + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DNEG) + GroupOps.PLUS_OPERATION -> Unit + PowerOperations.SQRT_OPERATION -> buildUnaryJavaMathCall("sqrt") + TrigonometricOperations.SIN_OPERATION -> buildUnaryJavaMathCall("sin") + TrigonometricOperations.COS_OPERATION -> buildUnaryJavaMathCall("cos") + TrigonometricOperations.TAN_OPERATION -> buildUnaryJavaMathCall("tan") + TrigonometricOperations.ASIN_OPERATION -> buildUnaryJavaMathCall("asin") + TrigonometricOperations.ACOS_OPERATION -> buildUnaryJavaMathCall("acos") + TrigonometricOperations.ATAN_OPERATION -> buildUnaryJavaMathCall("atan") + ExponentialOperations.SINH_OPERATION -> buildUnaryJavaMathCall("sqrt") + ExponentialOperations.COSH_OPERATION -> buildUnaryJavaMathCall("cosh") + ExponentialOperations.TANH_OPERATION -> buildUnaryJavaMathCall("tanh") + ExponentialOperations.ASINH_OPERATION -> buildUnaryKotlinMathCall("asinh") + ExponentialOperations.ACOSH_OPERATION -> buildUnaryKotlinMathCall("acosh") + ExponentialOperations.ATANH_OPERATION -> buildUnaryKotlinMathCall("atanh") + ExponentialOperations.EXP_OPERATION -> buildUnaryJavaMathCall("exp") + ExponentialOperations.LN_OPERATION -> buildUnaryJavaMathCall("log") + else -> super.visitUnary(mst) + } + } + + override fun visitBinary(mst: MST.Binary) { + super.visitBinary(mst) + + when (mst.operation) { + GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DADD) + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DSUB) + RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DMUL) + FieldOps.DIV_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DDIV) + PowerOperations.POW_OPERATION -> buildBinaryJavaMathCall("pow") + else -> super.visitBinary(mst) + } + } + + companion object { + val MATH_TYPE: Type by lazy { getObjectType("java/lang/Math") } + val MATH_KT_TYPE: Type by lazy { getObjectType("kotlin/math/MathKt") } + } +} + +internal class IntAsmBuilder(target: MST) : + PrimitiveAsmBuilder(IntRing, Integer::class.java, Integer.TYPE, target) { + override fun visitUnary(mst: MST.Unary) { + super.visitUnary(mst) + + when (mst.operation) { + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.INEG) + GroupOps.PLUS_OPERATION -> Unit + else -> super.visitUnary(mst) + } + } + + override fun visitBinary(mst: MST.Binary) { + super.visitBinary(mst) + + when (mst.operation) { + GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.IADD) + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.ISUB) + RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.IMUL) + else -> super.visitBinary(mst) + } + } +} + +internal class LongAsmBuilder(target: MST) : + PrimitiveAsmBuilder(LongRing, java.lang.Long::class.java, java.lang.Long.TYPE, target) { + override fun visitUnary(mst: MST.Unary) { + super.visitUnary(mst) + + when (mst.operation) { + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.LNEG) + GroupOps.PLUS_OPERATION -> Unit + else -> super.visitUnary(mst) + } + } + + override fun visitBinary(mst: MST.Binary) { + super.visitBinary(mst) + + when (mst.operation) { + GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.LADD) + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.LSUB) + RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.LMUL) + else -> super.visitBinary(mst) + } + } +} + diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt index 40d9d8fe6..b8a2a9669 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt @@ -14,4 +14,5 @@ import space.kscience.kmath.expressions.Symbol * * @author Iaroslav Postovalov */ +@Suppress("unused") internal fun Map.getOrFail(key: String): V = getValue(Symbol(key)) diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt index a0bdd68a0..1ea4cd0be 100644 --- a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.ast import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing import kotlin.contracts.InvocationKind @@ -15,7 +16,21 @@ import kotlin.contracts.contract import space.kscience.kmath.asm.compile as asmCompile import space.kscience.kmath.asm.compileToExpression as asmCompileToExpression -private object AsmCompilerTestContext : CompilerTestContext { +private object GenericAsmCompilerTestContext : CompilerTestContext { + override fun MST.compileToExpression(algebra: IntRing): Expression = + asmCompileToExpression(algebra as Algebra) + + override fun MST.compile(algebra: IntRing, arguments: Map): Int = + asmCompile(algebra as Algebra, arguments) + + override fun MST.compileToExpression(algebra: DoubleField): Expression = + asmCompileToExpression(algebra as Algebra) + + override fun MST.compile(algebra: DoubleField, arguments: Map): Double = + asmCompile(algebra as Algebra, arguments) +} + +private object PrimitiveAsmCompilerTestContext : CompilerTestContext { override fun MST.compileToExpression(algebra: IntRing): Expression = asmCompileToExpression(algebra) override fun MST.compile(algebra: IntRing, arguments: Map): Int = asmCompile(algebra, arguments) override fun MST.compileToExpression(algebra: DoubleField): Expression = asmCompileToExpression(algebra) @@ -24,7 +39,9 @@ private object AsmCompilerTestContext : CompilerTestContext { asmCompile(algebra, arguments) } + internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - action(AsmCompilerTestContext) + action(GenericAsmCompilerTestContext) + action(PrimitiveAsmCompilerTestContext) } diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 110529b72..92f2435ba 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,7 +8,7 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-17`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-14' + implementation 'space.kscience:kmath-complex:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-14") + implementation("space.kscience:kmath-complex:0.3.0-dev-17") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index 4ea493f44..e765ad50c 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-17`. **Gradle:** ```gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-14' + implementation 'space.kscience:kmath-core:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-14") + implementation("space.kscience:kmath-core:0.3.0-dev-17") } ``` diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt index cd49e4519..fcfd57e82 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt @@ -9,8 +9,8 @@ import kotlin.jvm.JvmInline import kotlin.properties.ReadOnlyProperty /** - * A marker interface for a symbol. A symbol must have an identity. - * Ic + * A marker interface for a symbol. A symbol must have an identity with equality relation based on it. + * Other properties are to store additional, transient data only. */ public interface Symbol : MST { /** diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index f88f53000..fcd092bf1 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-17`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-14' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-14") + implementation("space.kscience:kmath-ejml:0.3.0-dev-17") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index d449b4540..938327612 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-17`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-14' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0-dev-14") + implementation("space.kscience:kmath-for-real:0.3.0-dev-17") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index d0beae2c8..3d4beee47 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-17`. **Gradle:** ```gradle @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-14' + implementation 'space.kscience:kmath-functions:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0-dev-14") + implementation("space.kscience:kmath-functions:0.3.0-dev-17") } ``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index 3c5d4e19d..760244751 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,7 +7,7 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-17`. **Gradle:** ```gradle @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0-dev-14' + implementation 'space.kscience:kmath-jafama:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0-dev-14") + implementation("space.kscience:kmath-jafama:0.3.0-dev-17") } ``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index aeb44ea13..588ccb9b4 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-17`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-14' + implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-14") + implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-17") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 5cbb31d5a..7ca9cd4fd 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-17`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-14' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-14") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-17") } ``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index b19a55381..42ce91336 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-14`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-17`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-14' + implementation 'space.kscience:kmath-tensors:0.3.0-dev-17' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-14") + implementation("space.kscience:kmath-tensors:0.3.0-dev-17") } ``` -- 2.34.1 From 70ac232c15d37d049c4413f552e67057dc0e1d54 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 16 Nov 2021 14:27:20 +0700 Subject: [PATCH 064/102] Relax type requirements in algebraExtensions.kt from Ring to Group --- .../kmath/operations/algebraExtensions.kt | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) 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 493d90d2f..1ed0414de 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 @@ -6,55 +6,55 @@ package space.kscience.kmath.operations /** - * Returns the sum of all elements in the iterable in this [Ring]. + * Returns the sum of all elements in the iterable in this [Group]. * * @receiver the algebra that provides addition. * @param data the iterable to sum up. * @return the sum. */ -public fun Ring.sum(data: Iterable): T = data.fold(zero) { left, right -> +public fun Group.sum(data: Iterable): T = data.fold(zero) { left, right -> add(left, right) } //TODO replace by sumOf with multi-receivers /** - * Returns the sum of all elements in the sequence in this [Ring]. + * Returns the sum of all elements in the sequence in this [Group]. * * @receiver the algebra that provides addition. * @param data the sequence to sum up. * @return the sum. */ -public fun Ring.sum(data: Sequence): T = data.fold(zero) { left, right -> +public fun Group.sum(data: Sequence): T = data.fold(zero) { left, right -> add(left, right) } /** - * Returns an average value of elements in the iterable in this [Ring]. + * Returns an average value of elements in the iterable in this [Group]. * * @receiver the algebra that provides addition and division. * @param data the iterable to find average. * @return the average value. * @author Iaroslav Postovalov */ -public fun S.average(data: Iterable): T where S : Ring, S : ScaleOperations = +public fun S.average(data: Iterable): T where S : Group, S : ScaleOperations = sum(data) / data.count() /** - * Returns an average value of elements in the sequence in this [Ring]. + * Returns an average value of elements in the sequence in this [Group]. * * @receiver the algebra that provides addition and division. * @param data the sequence to find average. * @return the average value. * @author Iaroslav Postovalov */ -public fun S.average(data: Sequence): T where S : Ring, S : ScaleOperations = +public fun S.average(data: Sequence): T where S : Group, S : ScaleOperations = sum(data) / data.count() /** * Absolute of the comparable [value] */ -public fun > Ring.abs(value: T): T = if (value > zero) value else -value +public fun > Group.abs(value: T): T = if (value > zero) value else -value /** * Returns the sum of all elements in the iterable in provided space. @@ -63,7 +63,7 @@ public fun > Ring.abs(value: T): T = if (value > zero) valu * @param group the algebra that provides addition. * @return the sum. */ -public fun Iterable.sumWith(group: Ring): T = group.sum(this) +public fun Iterable.sumWith(group: Group): T = group.sum(this) /** * Returns the sum of all elements in the sequence in provided space. @@ -72,27 +72,27 @@ public fun Iterable.sumWith(group: Ring): T = group.sum(this) * @param group the algebra that provides addition. * @return the sum. */ -public fun Sequence.sumWith(group: Ring): T = group.sum(this) +public fun Sequence.sumWith(group: Group): T = group.sum(this) /** - * Returns an average value of elements in the iterable in this [Ring]. + * Returns an average value of elements in the iterable in this [Group]. * * @receiver the iterable to find average. * @param space the algebra that provides addition and division. * @return the average value. * @author Iaroslav Postovalov */ -public fun Iterable.averageWith(space: S): T where S : Ring, S : ScaleOperations = +public fun Iterable.averageWith(space: S): T where S : Group, S : ScaleOperations = space.average(this) /** - * Returns an average value of elements in the sequence in this [Ring]. + * Returns an average value of elements in the sequence in this [Group]. * * @receiver the sequence to find average. * @param space the algebra that provides addition and division. * @return the average value. * @author Iaroslav Postovalov */ -public fun Sequence.averageWith(space: S): T where S : Ring, S : ScaleOperations = +public fun Sequence.averageWith(space: S): T where S : Group, S : ScaleOperations = space.average(this) -- 2.34.1 From 7ceb0b69b8a4b95f3510b5281f1618b62524f1dd Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 16 Nov 2021 18:04:44 +0700 Subject: [PATCH 065/102] Revert license removal and update copyright --- .gitignore | 5 +- .idea/copyright/kmath.xml | 6 + .idea/copyright/profiles_settings.xml | 21 + .idea/scopes/Apply_copyright.xml | 3 + .../kmath/benchmarks/ArrayBenchmark.kt | 2 +- .../kmath/benchmarks/BigIntBenchmark.kt | 2 +- .../kmath/benchmarks/BufferBenchmark.kt | 2 +- .../kscience/kmath/benchmarks/DotBenchmark.kt | 2 +- .../ExpressionsInterpretersBenchmark.kt | 2 +- .../kmath/benchmarks/JafamaBenchmark.kt | 2 +- .../benchmarks/MatrixInverseBenchmark.kt | 2 +- .../kmath/benchmarks/NDFieldBenchmark.kt | 2 +- .../kmath/benchmarks/ViktorBenchmark.kt | 2 +- .../kmath/benchmarks/ViktorLogBenchmark.kt | 2 +- .../kscience/kmath/benchmarks/JmhReport.kt | 2 +- .../benchmarks/addBenchmarkProperties.kt | 2 +- .../kmath/ejml/codegen/ejmlCodegen.kt | 2 +- docs/images/KM.svg | 2 +- docs/images/KM_mono.svg | 2 +- docs/images/KMath.svg | 2 +- docs/images/KMath_mono.svg | 2 +- .../space/kscience/kmath/ast/astRendering.kt | 2 +- .../space/kscience/kmath/ast/expressions.kt | 2 +- .../kscience/kmath/ast/kotlingradSupport.kt | 2 +- .../space/kscience/kmath/ast/symjaSupport.kt | 2 +- .../space/kscience/kmath/fit/chiSquared.kt | 2 +- .../kscience/kmath/functions/integrate.kt | 2 +- .../kscience/kmath/functions/interpolate.kt | 2 +- .../kmath/functions/interpolateSquare.kt | 2 +- .../kmath/functions/matrixIntegration.kt | 2 +- .../space/kscience/kmath/jafama/JafamaDemo.kt | 2 +- .../kscience/kmath/linear/dotPerformance.kt | 2 +- .../space/kscience/kmath/linear/gradient.kt | 2 +- .../kscience/kmath/operations/BigIntDemo.kt | 2 +- .../kscience/kmath/operations/complexDemo.kt | 2 +- .../kmath/operations/mixedNDOperations.kt | 5 + .../kmath/stat/DistributionBenchmark.kt | 2 +- .../kscience/kmath/stat/DistributionDemo.kt | 2 +- .../kscience/kmath/structures/ComplexND.kt | 2 +- .../kscience/kmath/structures/NDField.kt | 2 +- .../kmath/structures/StreamDoubleFieldND.kt | 2 +- .../structures/StructureReadBenchmark.kt | 2 +- .../structures/StructureWriteBenchmark.kt | 2 +- .../kmath/structures/typeSafeDimensions.kt | 2 +- .../kscience/kmath/tensors/OLSWithSVD.kt | 2 +- .../space/kscience/kmath/tensors/PCA.kt | 2 +- .../kmath/tensors/dataSetNormalization.kt | 2 +- .../tensors/linearSystemSolvingWithLUP.kt | 2 +- .../space/kscience/kmath/tensors/multik.kt | 2 +- .../kscience/kmath/tensors/neuralNetwork.kt | 2 +- gradlew | 269 ++++++----- .../kotlin/space/kscience/kmath/ast/parser.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 +- .../ast/rendering/multiplatformToString.kt | 2 +- .../kscience/kmath/ast/rendering/phases.kt | 2 +- .../TestCompilerConsistencyWithInterpreter.kt | 2 +- .../kmath/ast/TestCompilerOperations.kt | 2 +- .../kmath/ast/TestCompilerVariables.kt | 2 +- .../space/kscience/kmath/ast/TestParser.kt | 2 +- .../kmath/ast/TestParserPrecedence.kt | 2 +- .../kmath/ast/rendering/TestFeatures.kt | 2 +- .../kscience/kmath/ast/rendering/TestLatex.kt | 2 +- .../kmath/ast/rendering/TestMathML.kt | 2 +- .../kmath/ast/rendering/TestStages.kt | 2 +- .../kscience/kmath/ast/rendering/TestUtils.kt | 2 +- .../kotlin/space/kscience/kmath/ast/utils.kt | 2 +- .../ast/rendering/multiplatformToString.kt | 2 +- .../space/kscience/kmath/estree/estree.kt | 2 +- .../kmath/estree/internal/ESTreeBuilder.kt | 2 +- .../internal/astring/astring.typealises.kt | 2 +- .../kmath/internal/astring/astring.kt | 2 +- .../internal/astring/astring.typealises.kt | 2 +- .../kscience/kmath/internal/base64/base64.kt | 2 +- .../kmath/internal/binaryen/index.binaryen.kt | 2 +- .../binaryen/index.binaryen.typealiases.kt | 2 +- .../kmath/internal/emitter/emitter.kt | 2 +- .../internal/estree/estree.extensions.kt | 2 +- .../kscience/kmath/internal/estree/estree.kt | 2 +- .../kscience/kmath/internal/stream/stream.kt | 2 +- .../internal/tsstdlib/lib.es2015.iterable.kt | 2 +- .../kmath/internal/tsstdlib/lib.es5.kt | 2 +- .../lib.dom.WebAssembly.module_dukat.kt | 2 +- .../nonDeclarations.WebAssembly.kt | 2 +- .../kmath/wasm/internal/WasmBuilder.kt | 2 +- .../wasm/internal/f64StandardFunctions.kt | 2 +- .../kotlin/space/kscience/kmath/wasm/wasm.kt | 2 +- .../kscience/kmath/ast/TestExecutionTime.kt | 2 +- .../kotlin/space/kscience/kmath/ast/utils.kt | 2 +- .../kscience/kmath/wasm/TestWasmSpecific.kt | 2 +- .../kotlin/space/kscience/kmath/asm/asm.kt | 2 +- .../kscience/kmath/asm/internal/AsmBuilder.kt | 5 + .../asm/internal/ByteArrayClassLoader.kt | 5 + .../kmath/asm/internal/GenericAsmBuilder.kt | 2 +- .../kmath/asm/internal/PrimitiveAsmBuilder.kt | 5 + .../kmath/asm/internal/codegenUtils.kt | 2 +- .../kmath/asm/internal/mapIntrinsics.kt | 2 +- .../ast/rendering/multiplatformToString.kt | 2 +- .../kotlin/space/kscience/kmath/ast/utils.kt | 2 +- .../DerivativeStructureExpression.kt | 2 +- .../integration/CMGaussRuleIntegrator.kt | 2 +- .../kmath/commons/integration/CMIntegrator.kt | 2 +- .../kscience/kmath/commons/linear/CMMatrix.kt | 2 +- .../kscience/kmath/commons/linear/CMSolver.kt | 2 +- .../random/CMRandomGeneratorWrapper.kt | 2 +- .../commons/transform/Transformations.kt | 2 +- .../DerivativeStructureExpressionTest.kt | 2 +- .../commons/integration/IntegrationTest.kt | 2 +- .../commons/optimization/OptimizeTest.kt | 2 +- .../space/kscience/kmath/complex/Complex.kt | 2 +- .../kscience/kmath/complex/ComplexFieldND.kt | 2 +- .../kscience/kmath/complex/Quaternion.kt | 2 +- .../kmath/complex/ComplexBufferSpecTest.kt | 2 +- .../kmath/complex/ComplexFieldTest.kt | 2 +- .../kscience/kmath/complex/ComplexTest.kt | 2 +- .../complex/ExpressionFieldForComplexTest.kt | 2 +- .../kmath/complex/QuaternionFieldTest.kt | 2 +- .../space/kscience/kmath/data/ColumnarData.kt | 2 +- .../kscience/kmath/data/XYColumnarData.kt | 2 +- .../kscience/kmath/data/XYZColumnarData.kt | 2 +- .../space/kscience/kmath/domains/Domain.kt | 2 +- .../kscience/kmath/domains/DoubleDomain.kt | 2 +- .../kmath/domains/HyperSquareDomain.kt | 2 +- .../kmath/domains/UnconstrainedDomain.kt | 2 +- .../kmath/domains/UnivariateDomain.kt | 2 +- .../expressions/DifferentiableExpression.kt | 2 +- .../kscience/kmath/expressions/Expression.kt | 2 +- .../FunctionalExpressionAlgebra.kt | 2 +- .../space/kscience/kmath/expressions/MST.kt | 2 +- .../kscience/kmath/expressions/MstAlgebra.kt | 2 +- .../kmath/expressions/SimpleAutoDiff.kt | 2 +- .../kscience/kmath/expressions/Symbol.kt | 2 +- .../kmath/expressions/SymbolIndexer.kt | 2 +- .../kmath/linear/BufferedLinearSpace.kt | 2 +- .../kmath/linear/DoubleLinearSpace.kt | 2 +- .../kscience/kmath/linear/LinearSolver.kt | 2 +- .../kscience/kmath/linear/LinearSpace.kt | 2 +- .../kscience/kmath/linear/LupDecomposition.kt | 2 +- .../kscience/kmath/linear/MatrixBuilder.kt | 2 +- .../kscience/kmath/linear/MatrixFeatures.kt | 2 +- .../kscience/kmath/linear/MatrixWrapper.kt | 2 +- .../kscience/kmath/linear/VirtualMatrix.kt | 2 +- .../space/kscience/kmath/misc/annotations.kt | 2 +- .../space/kscience/kmath/misc/cumulative.kt | 2 +- .../space/kscience/kmath/misc/numbers.kt | 2 +- .../space/kscience/kmath/nd/AlgebraND.kt | 2 +- .../kscience/kmath/nd/BufferAlgebraND.kt | 2 +- .../space/kscience/kmath/nd/BufferND.kt | 2 +- .../space/kscience/kmath/nd/DoubleFieldND.kt | 2 +- .../space/kscience/kmath/nd/ShapeIndexer.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/algebraNDExtentions.kt | 2 +- .../kscience/kmath/operations/Algebra.kt | 2 +- .../space/kscience/kmath/operations/BigInt.kt | 2 +- .../kmath/operations/DoubleBufferField.kt | 2 +- .../kmath/operations/DoubleBufferOps.kt | 2 +- .../kscience/kmath/operations/LogicAlgebra.kt | 2 +- .../kmath/operations/NumericAlgebra.kt | 2 +- .../kmath/operations/OptionalOperations.kt | 2 +- .../kmath/operations/algebraExtensions.kt | 2 +- .../kmath/operations/bufferOperation.kt | 2 +- .../kscience/kmath/operations/numbers.kt | 2 +- .../kscience/kmath/structures/ArrayBuffer.kt | 2 +- .../space/kscience/kmath/structures/Buffer.kt | 2 +- .../kmath/structures/BufferAccessor2D.kt | 2 +- .../kscience/kmath/structures/DoubleBuffer.kt | 2 +- .../kmath/structures/FlaggedBuffer.kt | 2 +- .../kscience/kmath/structures/FloatBuffer.kt | 2 +- .../kscience/kmath/structures/IntBuffer.kt | 2 +- .../kscience/kmath/structures/ListBuffer.kt | 2 +- .../kscience/kmath/structures/LongBuffer.kt | 2 +- .../kscience/kmath/structures/MemoryBuffer.kt | 2 +- .../kmath/structures/MutableBuffer.kt | 2 +- .../kscience/kmath/structures/ShortBuffer.kt | 2 +- .../kmath/expressions/ExpressionFieldTest.kt | 2 +- .../kmath/expressions/InterpretTest.kt | 2 +- .../kmath/expressions/SimpleAutoDiffTest.kt | 2 +- .../kmath/linear/DoubleLUSolverTest.kt | 2 +- .../space/kscience/kmath/linear/MatrixTest.kt | 2 +- .../kscience/kmath/misc/CumulativeKtTest.kt | 2 +- .../kmath/operations/BigIntAlgebraTest.kt | 2 +- .../kmath/operations/BigIntConstructorTest.kt | 2 +- .../kmath/operations/BigIntConversionsTest.kt | 2 +- .../kmath/operations/BigIntOperationsTest.kt | 2 +- .../kmath/operations/DoubleFieldTest.kt | 2 +- .../kscience/kmath/structures/NDFieldTest.kt | 2 +- .../kmath/structures/NumberNDFieldTest.kt | 2 +- .../kmath/testutils/AlgebraicVerifier.kt | 2 +- .../kscience/kmath/testutils/FieldVerifier.kt | 2 +- .../kscience/kmath/testutils/RingVerifier.kt | 2 +- .../kscience/kmath/testutils/SpaceVerifier.kt | 2 +- .../space/kscience/kmath/misc/numbers.kt | 2 +- .../kscience/kmath/operations/isInteger.kt | 5 + .../space/kscience/kmath/misc/numbersJVM.kt | 2 +- .../kscience/kmath/operations/BigNumbers.kt | 2 +- .../kscience/kmath/operations/isInteger.kt | 5 + .../space/kscience/kmath/misc/numbers.kt | 2 +- .../kscience/kmath/operations/isInteger.kt | 5 + .../kscience/kmath/chains/BlockingChain.kt | 2 +- .../kmath/chains/BlockingDoubleChain.kt | 2 +- .../kscience/kmath/chains/BlockingIntChain.kt | 2 +- .../space/kscience/kmath/chains/Chain.kt | 2 +- .../space/kscience/kmath/chains/flowExtra.kt | 2 +- .../kmath/coroutines/coroutinesExtra.kt | 2 +- .../kscience/kmath/streaming/BufferFlow.kt | 2 +- .../kscience/kmath/streaming/RingBuffer.kt | 2 +- .../space/kscience/kmath/chains/ChainExt.kt | 2 +- .../kmath/structures/LazyStructureND.kt | 2 +- .../kmath/streaming/BufferFlowTest.kt | 2 +- .../kmath/streaming/RingBufferTest.kt | 2 +- .../kscience/kmath/dimensions/Dimension.kt | 2 +- .../kscience/kmath/dimensions/Wrappers.kt | 2 +- .../kscience/dimensions/DMatrixContextTest.kt | 2 +- .../kscience/kmath/dimensions/Dimension.kt | 2 +- .../kscience/kmath/dimensions/Dimension.kt | 2 +- .../kscience/kmath/dimensions/Dimension.kt | 2 +- .../kscience/kmath/ejml/EjmlLinearSpace.kt | 2 +- .../space/kscience/kmath/ejml/EjmlMatrix.kt | 2 +- .../space/kscience/kmath/ejml/EjmlVector.kt | 2 +- .../kscience/kmath/ejml/EjmlMatrixTest.kt | 2 +- .../kscience/kmath/ejml/EjmlVectorTest.kt | 2 +- .../space/kscience/kmath/real/RealMatrix.kt | 2 +- .../space/kscience/kmath/real/RealVector.kt | 2 +- .../kotlin/space/kscience/kmath/real/dot.kt | 2 +- .../kotlin/space/kscience/kmath/real/grids.kt | 2 +- .../space/kscience/kmath/real/realND.kt | 2 +- .../kscience/kmath/real/DoubleMatrixTest.kt | 2 +- .../kscience/kmath/real/DoubleVectorTest.kt | 2 +- .../space/kscience/kmath/real/GridTest.kt | 2 +- .../kscience/kmath/functions/Piecewise.kt | 2 +- .../kscience/kmath/functions/Polynomial.kt | 2 +- .../kscience/kmath/functions/functionTypes.kt | 2 +- .../kmath/integration/GaussIntegrator.kt | 2 +- .../integration/GaussIntegratorRuleFactory.kt | 2 +- .../kscience/kmath/integration/Integrand.kt | 2 +- .../kscience/kmath/integration/Integrator.kt | 2 +- .../integration/MultivariateIntegrand.kt | 2 +- .../kmath/integration/SimpsonIntegrator.kt | 2 +- .../kmath/integration/SplineIntegrator.kt | 2 +- .../kmath/integration/UnivariateIntegrand.kt | 2 +- .../kmath/interpolation/Interpolator.kt | 2 +- .../kmath/interpolation/LinearInterpolator.kt | 2 +- .../kmath/interpolation/SplineInterpolator.kt | 2 +- .../kmath/functions/PolynomialTest.kt | 2 +- .../kmath/integration/GaussIntegralTest.kt | 2 +- .../kmath/integration/SimpsonIntegralTest.kt | 2 +- .../kmath/integration/SplineIntegralTest.kt | 2 +- .../interpolation/LinearInterpolatorTest.kt | 2 +- .../interpolation/SplineInterpolatorTest.kt | 2 +- .../kmath/geometry/Euclidean2DSpace.kt | 2 +- .../kmath/geometry/Euclidean3DSpace.kt | 2 +- .../kscience/kmath/geometry/GeometrySpace.kt | 2 +- .../space/kscience/kmath/geometry/Line.kt | 2 +- .../kscience/kmath/geometry/Projections.kt | 5 + .../kscience/kmath/geometry/ReferenceFrame.kt | 2 +- .../kmath/geometry/Euclidean2DSpaceTest.kt | 5 + .../kmath/geometry/Euclidean3DSpaceTest.kt | 5 + .../kmath/geometry/ProjectionAlongTest.kt | 5 + .../kmath/geometry/ProjectionOntoLineTest.kt | 5 + .../kscience/kmath/geometry/Vector2DTest.kt | 5 + .../kscience/kmath/geometry/Vector3DTest.kt | 5 + .../kscience/kmath/geometry/testUtils.kt | 5 + .../space/kscience/kmath/histogram/Counter.kt | 2 +- .../kmath/histogram/DoubleHistogramSpace.kt | 2 +- .../kscience/kmath/histogram/Histogram.kt | 2 +- .../kmath/histogram/IndexedHistogramSpace.kt | 2 +- .../histogram/MultivariateHistogramTest.kt | 2 +- .../kmath/histogram/TreeHistogramSpace.kt | 2 +- .../kmath/histogram/UnivariateHistogram.kt | 2 +- .../kmath/histogram/TreeHistogramTest.kt | 2 +- .../kscience/kmath/jafama/KMathJafama.kt | 2 +- .../kscience/kmath/jupyter/KMathJupyter.kt | 2 +- .../kscience/kmath/kotlingrad/KMathNumber.kt | 2 +- .../kmath/kotlingrad/KotlingradExpression.kt | 2 +- .../kmath/kotlingrad/scalarsAdapters.kt | 2 +- .../kmath/kotlingrad/AdaptingTests.kt | 2 +- .../space/kscience/kmath/memory/Memory.kt | 2 +- .../space/kscience/kmath/memory/MemorySpec.kt | 2 +- .../kscience/kmath/memory/DataViewMemory.kt | 2 +- .../kscience/kmath/memory/ByteBufferMemory.kt | 2 +- .../kscience/kmath/memory/NativeMemory.kt | 2 +- .../kmath/multik/MultikDoubleAlgebra.kt | 5 + .../kmath/multik/MultikTensorAlgebra.kt | 2 +- .../kscience/kmath/multik/MultikNDTest.kt | 5 + .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 2 +- .../kscience/kmath/nd4j/Nd4jArrayIterator.kt | 2 +- .../kscience/kmath/nd4j/Nd4jArrayStructure.kt | 2 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 2 +- .../space/kscience/kmath/nd4j/arrays.kt | 2 +- .../kmath/nd4j/Nd4jArrayAlgebraTest.kt | 2 +- .../kmath/nd4j/Nd4jArrayStructureTest.kt | 2 +- .../kmath/distributions/Distribution.kt | 2 +- .../distributions/FactorizedDistribution.kt | 2 +- .../kmath/distributions/NormalDistribution.kt | 2 +- .../kscience/kmath/internal/InternalErf.kt | 2 +- .../kscience/kmath/internal/InternalGamma.kt | 2 +- .../kscience/kmath/internal/InternalUtils.kt | 2 +- .../AhrensDieterExponentialSampler.kt | 2 +- .../AhrensDieterMarsagliaTsangGammaSampler.kt | 2 +- .../samplers/AliasMethodDiscreteSampler.kt | 2 +- .../kmath/samplers/BoxMullerSampler.kt | 2 +- .../kmath/samplers/GaussianSampler.kt | 2 +- .../samplers/KempSmallMeanPoissonSampler.kt | 2 +- .../MarsagliaNormalizedGaussianSampler.kt | 2 +- .../samplers/NormalizedGaussianSampler.kt | 2 +- .../kscience/kmath/samplers/PoissonSampler.kt | 2 +- .../ZigguratNormalizedGaussianSampler.kt | 2 +- .../space/kscience/kmath/stat/MCScope.kt | 2 +- .../kotlin/space/kscience/kmath/stat/Mean.kt | 2 +- .../space/kscience/kmath/stat/Median.kt | 2 +- .../space/kscience/kmath/stat/RandomChain.kt | 2 +- .../kscience/kmath/stat/RandomGenerator.kt | 2 +- .../space/kscience/kmath/stat/Sampler.kt | 2 +- .../kscience/kmath/stat/SamplerAlgebra.kt | 2 +- .../space/kscience/kmath/stat/Statistic.kt | 2 +- .../kmath/stat/UniformDistribution.kt | 2 +- .../kmath/stat/RandomSourceGenerator.kt | 2 +- .../kmath/stat/CommonsDistributionsTest.kt | 2 +- .../space/kscience/kmath/stat/MCScopeTest.kt | 2 +- .../space/kscience/kmath/stat/SamplerTest.kt | 2 +- .../kscience/kmath/stat/StatisticTest.kt | 2 +- .../kscience/kmath/symja/SymjaExpression.kt | 2 +- .../space/kscience/kmath/symja/adapters.kt | 2 +- .../tensors/api/AnalyticTensorAlgebra.kt | 2 +- .../tensors/api/LinearOpsTensorAlgebra.kt | 2 +- .../kscience/kmath/tensors/api/Tensor.kt | 2 +- .../kmath/tensors/api/TensorAlgebra.kt | 2 +- .../api/TensorPartialDivisionAlgebra.kt | 2 +- .../core/BroadcastDoubleTensorAlgebra.kt | 2 +- .../kmath/tensors/core/BufferedTensor.kt | 2 +- .../kmath/tensors/core/DoubleTensor.kt | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 2 +- .../kscience/kmath/tensors/core/IntTensor.kt | 2 +- .../tensors/core/internal/broadcastUtils.kt | 2 +- .../kmath/tensors/core/internal/checks.kt | 2 +- .../kmath/tensors/core/internal/linUtils.kt | 2 +- .../tensors/core/internal/tensorCastsUtils.kt | 2 +- .../kmath/tensors/core/internal/utils.kt | 2 +- .../tensors/core/tensorAlgebraExtensions.kt | 2 +- .../kmath/tensors/core/tensorCasts.kt | 2 +- .../kmath/tensors/core/TestBroadcasting.kt | 2 +- .../core/TestDoubleAnalyticTensorAlgebra.kt | 2 +- .../core/TestDoubleLinearOpsAlgebra.kt | 2 +- .../kmath/tensors/core/TestDoubleTensor.kt | 2 +- .../tensors/core/TestDoubleTensorAlgebra.kt | 2 +- .../kscience/kmath/viktor/ViktorBuffer.kt | 2 +- .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 2 +- .../kmath/viktor/ViktorStructureND.kt | 2 +- license/COPYRIGHT.txt | 15 + license/COPYRIGHT_HEADER.txt | 4 + license/LICENSE.txt | 202 ++++++++ license/README.md | 53 ++ license/third_party/cm_license.txt | 457 ++++++++++++++++++ license/third_party/crng_license.txt | 275 +++++++++++ license/third_party/numky_license.txt | 201 ++++++++ 362 files changed, 1817 insertions(+), 445 deletions(-) create mode 100644 .idea/copyright/kmath.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/scopes/Apply_copyright.xml create mode 100644 license/COPYRIGHT.txt create mode 100644 license/COPYRIGHT_HEADER.txt create mode 100644 license/LICENSE.txt create mode 100644 license/README.md create mode 100644 license/third_party/cm_license.txt create mode 100644 license/third_party/crng_license.txt create mode 100644 license/third_party/numky_license.txt diff --git a/.gitignore b/.gitignore index d6c4af4e3..79f3238e1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,6 @@ out/ .idea/ -!.idea/copyright/ -!.idea/scopes/ .vscode/ @@ -18,3 +16,6 @@ out/ # Generated by javac -h and runtime *.class *.log + +!/.idea/copyright/ +!/.idea/scopes/ diff --git a/.idea/copyright/kmath.xml b/.idea/copyright/kmath.xml new file mode 100644 index 000000000..17e44e4d0 --- /dev/null +++ b/.idea/copyright/kmath.xml @@ -0,0 +1,6 @@ + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 000000000..b538bdf41 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/scopes/Apply_copyright.xml b/.idea/scopes/Apply_copyright.xml new file mode 100644 index 000000000..a2575f774 --- /dev/null +++ b/.idea/scopes/Apply_copyright.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt index 17983e88c..ff933997f 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 f2b2d4d7a..188a48ca7 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt index 5cf194b67..39819d407 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 9203c269e..63165baaa 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index 4c6b92248..f3a52ab5f 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt index 9c6551302..5d4eee7c0 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt index 5d331af9a..4ff687aac 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 b5af5aa19..e3b3dde05 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index 6b4d5759b..de301678c 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index a9d1e68fc..dfdd89d74 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 6859de845..eaa0f59d8 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 568bfe535..ca1c330a1 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 cfebf61e7..7f8cb35b3 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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("KDocUnresolvedReference") diff --git a/docs/images/KM.svg b/docs/images/KM.svg index f5ec452c7..6f80e4d08 100644 --- a/docs/images/KM.svg +++ b/docs/images/KM.svg @@ -1,7 +1,7 @@ \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt index 7f2780548..6ebd0eff6 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast 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 bf5916fa5..2df3d3cc7 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering 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 5439c42fa..8b5819b84 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering 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 24bac425a..fdef35ebd 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering 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 81b7d2afb..ee23ab408 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering 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 2f285c600..362c07d72 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering 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 8b76b6f19..90f78a152 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt index 3e33d6415..291399cee 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering 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 ecea2d104..c0271fbb5 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt index 802d4c10e..1edb5923e 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt index 00344410c..be8a92f3e 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt index 8d9a2301f..af1a2e338 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt index 4c834a9ca..b838245e1 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt index 9776da45c..bb6bb3ce1 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt index ae429d97e..a40c785b9 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt index aba713c43..43f31baba 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt index 658ecd47a..145055494 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt index 4485605a6..09ec127c7 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt index 6b418821b..bf87b6fd0 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt index ef9f3145a..ec7436188 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt index 2e69a536f..521907d2c 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering 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 316fdeeff..0c15e994c 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.estree diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt index 850f20be7..4907d8225 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.estree.internal diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt index c7faf73e0..eb5c1e3dd 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.estree.internal.astring diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt index c36860654..cca2d83af 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:JsModule("astring") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt index 0a5b059ba..93b4f6ce6 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.internal.astring diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt index 26186c453..86e0cede7 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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( diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt index 13e3a49e2..42b6ac7d8 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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( diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt index 8e449627c..523b13b40 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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("PackageDirectoryMismatch", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt index d85857de8..1f7b09af8 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.internal.emitter diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt index 122a3a397..3aa31f921 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.internal.estree diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt index ad079dbd0..b62b8c06c 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:Suppress("ClassName") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt index caab91731..52be5530f 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.internal.stream diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt index 5c091e3a1..9c012e3a3 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.internal.tsstdlib diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt index bb7fd44ca..0cd395f2c 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt index 52dd64a5e..3754c3eff 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:JsQualifier("WebAssembly") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt index d59a52701..c5023c384 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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( 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 6039d5c27..622e6e6ec 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.wasm.internal diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt index fe9c22c18..21a88b5d0 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.wasm.internal 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 393a02e3d..806091715 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.wasm diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt index f8c429d5a..8cfa3a87e 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt index 3c2a9bd13..0d896c6f6 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt index 6c91df866..8ae5fcb36 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.wasm 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 19b400cbd..c39345f3a 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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("UNUSED_PARAMETER") diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index 2a7b3dea9..7d3d513de 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.asm.internal import org.objectweb.asm.Type diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt index afff48ef6..10eee7c6b 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt @@ -1 +1,6 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.asm.internal diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt index 1b45b0625..28f4a226f 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.asm.internal 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 2819368ed..3e019589a 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 @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.asm.internal import org.objectweb.asm.ClassWriter diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt index 5e2e7d8c6..06e040e93 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.asm.internal diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt index b8a2a9669..3a5ef74f7 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:JvmName("MapIntrinsics") diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt index 3e5253084..556adbe7d 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt index 1ea4cd0be..47f1cc476 100644 --- a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index 4d2bd6237..82694d95a 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.expressions diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt index 5152b04f9..e0a2f4931 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.integration 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 76a2f297c..257429fa7 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.integration 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 14e7fc365..aa7e0a638 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.linear diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt index d1fb441b0..9bb5deffd 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.linear diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt index 28294cf14..6aeebb68c 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.random diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt index 73ab91542..40168971e 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.transform 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 eaebc84dc..56252ab34 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.expressions 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 bab3aecb6..c5573fef1 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.integration 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 c670ceead..0977dc247 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.commons.optimization 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 879cfe94e..d3c414838 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.complex 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 2eaa17ded..46d4b7c5c 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.complex 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 ff9a8302a..3ef3428c6 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.complex diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt index 87239654d..17a077ea7 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.complex diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt index 90e624343..cbaaa815b 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.complex diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt index a37006f75..7ad7f883d 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.complex diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt index 00ae5ede1..4279471d4 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.complex diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt index 319460c74..6784f3516 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.complex 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 53c4b4d1e..e06b774fd 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.data 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 ffec339bf..2fce772cc 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.data 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 a4a08f626..e99ae0698 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.data diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt index 0c4d2307b..b5a84cf6c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.domains 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 aee1d52c5..ee1bebde0 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.domains 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 7ea3e22c4..bd5514623 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.domains 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 040bb80b0..32a5fc56c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt index a5add6a0b..9020ef8cb 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt index 758b992a9..12b7df0ea 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 bd3e6d0ba..33f53202c 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 661680565..5f194f2ea 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt index fe50902b1..7533024a1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 ca0671ccb..4bd2a6c53 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 aa9dd01ce..96fc73249 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt index fcfd57e82..8ab2bec31 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 e8005096c..bf37e9615 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 410fb8505..36cbd9064 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear 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 91db33bce..4e6debc60 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt index 54d90baa8..fae9e7c91 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear 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 5349ad864..715fad07b 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear 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 95dd6d45c..fb57f2343 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear 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 727b644c3..029612bc5 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt index 4c2b5c73c..b70e9d8a9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear 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 a40c0384c..b1812f49d 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt index be1677ecd..fb2b1e547 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt index 2b3a4ab03..73ecd6492 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt index 413f44960..ee7f1d8be 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt index e048eb746..f879a06d5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 113bd4c52..a071c1eb3 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd 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 d25b455f4..b09344d12 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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) 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 515988159..539499794 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd 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 8baeac21f..d01a8ee95 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt index 20e180dd1..c6ff79587 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd 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 827f0e21e..8152adaa5 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd 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 3dcc77334..4ccb15eef 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd 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 e3552c02e..cf8559869 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd 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 614d97950..d948cf36f 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt index 0e694bcb3..53f946fbd 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd 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 244b9fea7..45ba32c13 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 5a713049e..99268348b 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt index 0deb647a3..8ec3c3aea 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 b0cce91d3..a5e1c42e2 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 d50f1e79e..9037525e1 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 9d9fc0885..d0405c705 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt index 332617158..709506fc4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 1ed0414de..539440de9 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt index 6bf3266e3..31b0c2841 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 7c8030168..07a137415 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt index 393ee99d6..3528b0460 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index c68bca2d9..58c6d5ded 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt index d6a48f42d..4d04a5235 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt index 3b554ab07..f4388a477 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt index 700a4f17f..b3c537280 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt index dc7903cbf..e7e98fc71 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt index ca078746c..35b722e2b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt index 666722177..65d9dc77d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt index a0b5c78fa..c69f4646d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures 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 3e08dbbb1..1dadaf7d4 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt index 97185b918..429c1a64b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt index 1d2b0188a..20691511b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt index d0b3c7751..80c5943cf 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 8bf852653..156334b2e 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt index 7d8ff6202..201890933 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 79153d95d..70e010f2e 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear 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 0e2369e35..25d187bf0 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt index aa7abd8ff..e5f3f337f 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 75100b116..0527f5252 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt index c121c86ae..eec3dc3bf 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt index 78dcdfe19..85f368f3e 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt index 11b8b161c..26d6af224 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt index 9be75d68e..76171fedd 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt index 82172af62..b7b89d107 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures 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 61eb6acc8..d33eb5112 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt index 544e05707..ddd8fc3ea 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.testutils diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt index d0a312bb2..20a7b6a72 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.testutils diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt index 3b0b49f31..daf18834a 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.testutils diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt index 4afa97ce5..951197fc6 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.testutils diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt index a24243cb4..68a3c995b 100644 --- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt index c15669145..24b81322e 100644 --- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.operations /** diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt index c50919e88..5ba0dbc9b 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt index f63efbef2..6e22c2381 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt index 746d1e530..b2f9b957b 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.operations /** diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt index a24243cb4..68a3c995b 100644 --- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt index 746d1e530..b2f9b957b 100644 --- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.operations /** diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt index a41a30f55..87aebff61 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.chains diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt index 7b4d1f2af..25e20291e 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.chains diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt index f13d9907c..ac0327d0b 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.chains 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 403472f28..f8d2549e5 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.chains diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt index 1620f029c..7bf54d50f 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.chains 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 3b90222dd..1f17efe49 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.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 914139a3e..4d4493aa4 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.streaming diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt index 573b406e2..abe1c9df9 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.streaming diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt index 0e36706cf..dd6e39071 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.chains 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 1feb43f33..ac9eb773a 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt index 057ac5feb..9b67f7253 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.streaming diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt index a3143a1ac..305b97e5d 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.streaming diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 53482f020..e57c22834 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.dimensions diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt index c47f43723..f04536f04 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.dimensions diff --git a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt index efa3170a3..59260fe73 100644 --- a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt +++ b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.dimensions diff --git a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 324c78108..610e8b4c0 100644 --- a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.dimensions diff --git a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 8fc683ed6..e6d8b3b35 100644 --- a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:JvmName("DimensionJVM") diff --git a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 001d68935..64edbe935 100644 --- a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.dimensions 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 25333157a..32030dfe3 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.ejml diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt index 9ad0f9c77..27fd3fc53 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.ejml diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt index a6de1b657..37995c27e 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.ejml 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 5b8b2af98..209bb5b27 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.ejml diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt index c87a01436..9592bfa6c 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.ejml 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 c1ee8b48f..671e272ab 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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(PerformancePitfall::class) diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt index cca1c3551..7b9740c35 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.real diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt index 883a63f46..dc5c58be0 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.real 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 fba999e6c..1926ef02c 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.real diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt index 56f50acbc..52362f4b4 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.real 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 3277410c0..4a0e8de1d 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.real diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt index 771981772..e77b96c12 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.real 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 ec1ed8f50..8fed8d10e 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.real 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 4225a7572..16af7f555 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.functions diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index e862c0b9d..a36d36f52 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.functions diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt index 52b7e50db..88b24c756 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.functions 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 2b426d204..9785d7744 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration 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 94c73832b..778d85e66 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt index ca96e80fe..05e2e5c55 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt index 868ecd0fd..1cf15b42f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt index 1546894f5..96b81aaa6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration 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 f65cc8423..7815757aa 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration 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 6abe89aad..15d548641 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration 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 bd2a20594..6fd75e6e6 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration 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 5f89a9619..b13adefa5 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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) 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 eff9cd97d..edd0e6b0a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.interpolation 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 ac9708d01..39c33ee69 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.interpolation diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index 21e5473a0..05c16d17e 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.functions 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 533389a6e..9f48a15ea 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration 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 eaf7abbfd..9f2d71554 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration 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 4dffb276f..afeba0be4 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.integration diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt index c3388c265..bec678bae 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.interpolation diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt index 42f41ab80..3adaab2d1 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.interpolation 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 5e3cbff83..d00575bcc 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 96f307ed6..e12563b46 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 3d3f8b653..d4245c744 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 d9dc57ec2..8c6ccb55e 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 205bc17e7..5e299f450 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 @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.geometry /** diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt index 7bb95c009..a7a28b596 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt index 5913b2fa9..6b5f474bc 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.geometry import kotlin.math.sqrt 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 2c74cbd27..0bc91e77e 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 @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.geometry import kotlin.test.Test diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt index 55fc39aad..dfb65a57c 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.geometry import kotlin.test.Test 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 ab6ef3628..076025110 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 @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.geometry import kotlin.test.Test diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt index 89ee23354..5e45b4870 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.geometry import space.kscience.kmath.operations.toList diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt index 70f8f4ebd..55bab4775 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.geometry import space.kscience.kmath.operations.toList 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 1277c0130..0f957529d 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 @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.geometry import kotlin.math.abs diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt index 4f5a1ceba..3e5d93768 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.histogram diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt index c452edc9c..28eade060 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.histogram diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt index 946aa814b..4e803fc63 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.histogram diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt index f36f45389..0c7dd81e1 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.histogram 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 e07488741..923cc98de 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.histogram diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt index cc54d7e1a..f8a3a6a8b 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.histogram diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt index d5b74fb9b..723577cd9 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.histogram 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 e71602c7b..28a1b03cb 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.histogram diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt index 64a935705..91d952a76 100644 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.jafama 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 9731908b3..504ad693e 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.jupyter diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt index 0f10c6cdd..f4386f434 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.kotlingrad diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt index 84171101f..0d4e457af 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.kotlingrad diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt index 11e5853a8..4d01677af 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.kotlingrad diff --git a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt index 4047b9a67..7f065490c 100644 --- a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt +++ b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.kotlingrad 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 9f73ae2f3..e8e51e9e2 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt index 2f2af4d9c..1ee1cf4e2 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 db5eb556e..6153743fc 100644 --- a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt +++ b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 6e60514f8..aef68fd80 100644 --- a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt +++ b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 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 d13da1191..5146d9689 100644 --- a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt +++ b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt index 4f18ee573..1dc318517 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.multik import org.jetbrains.kotlinx.multik.ndarray.data.DataType diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index 0c3cf6b14..250ef7e7f 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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("unused") diff --git a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt index 66ba7db2d..404541776 100644 --- a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt +++ b/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.multik import org.junit.jupiter.api.Test 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 dd27bc817..e29a3f467 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd4j diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt index 5ae6f6b01..d4cad8996 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd4j 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 82f560fdb..2a0fdc86c 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd4j 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 d7dd6e71b..ceb384f0d 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd4j diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt index cc9211b20..3ca756600 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd4j 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 103416120..9d30c2027 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd4j 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 ff55ad521..30d01338f 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.nd4j diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt index 298bbc858..3d3f95f8f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.distributions diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt index 067b47796..1218f13c5 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.distributions diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt index 24429cf32..66e041f05 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.distributions diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt index 5b3cb1859..25668446c 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.internal diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt index 18abd669f..6e7eb039d 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.internal diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt index 77ba02a25..3997a77b3 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.internal diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt index 5f923fe5f..77d29981f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt index 063e055ce..993215d41 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt index b00db5b30..5390a2e09 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt index 14aa26275..b3c014553 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt index e5d1ecb49..9219df43e 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt index 16f91570f..0105731c4 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt index 5e636f246..0a68e5c88 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt index ceb324e8d..83f87e832 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt index d3ff05b06..f0f94900e 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt index bda6f9819..b534fdc14 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt index 5e1e577ba..0e06fa162 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt index 2a9bd3cd4..aff7d03d9 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt index 664e4e8e7..c587277f9 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt index 61e472334..d4bc36b5b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt index 98ee6402a..f280a78aa 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index 0b3b52cab..4c11fdd65 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt index e0be72d4b..1f442c09b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt index 107161514..43cd5b402 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt index 4c0d08720..970a3aab5 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt index a8e6a3362..202a1c8dd 100644 --- a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt +++ b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt index 2b6b1ca60..19c01e099 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt index 0c3d9cb0d..075d7f3e5 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt index 4060c0505..1dbbf591b 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt index 777b93c29..9eb84899c 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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 diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt index a343256fa..3067b5efb 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.symja diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt index a7ca298a9..30c37c799 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.symja diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index 743105fdf..3ed34ae5e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.api diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index e8fa7dacd..0bddc3f9c 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.api diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt index e0f296057..482bb5244 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.api diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 60fc470fb..33889c2f8 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.api diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index 0a1e09081..9c492cda1 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.api 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 10c747777..e412ab5bb 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core 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 54d8f54dc..73a89502c 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core 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 ad7831fb9..8e5116336 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core 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 864900adb..ae1a053af 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-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 715d9035f..e3d7c3d35 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core 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 3787c0972..9d37423e5 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core.internal diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt index 3a3b30485..a2d445b45 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core.internal diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index 290809cfd..2fb5b949f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core.internal diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index 602430b03..a5cdb2f47 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core.internal 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 553ed6add..85cc91b1d 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core.internal 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 1e6dfd52e..d8e8df31e 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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(PerformancePitfall::class) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt index feade56de..5dc8114dd 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 1171b5217..6788ae792 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index ba8182da2..1e21379b4 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index c50c99b54..e025d4b71 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core 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 2686df19e..d808637c7 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 2aee03b82..03357f1e1 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.tensors.core diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt index 32fb65b8a..4eedcb5ee 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.viktor 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 e43bbbc6f..ef7702014 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.viktor 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 4926652ed..25ca3a10e 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 @@ -1,6 +1,6 @@ /* * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * 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.viktor diff --git a/license/COPYRIGHT.txt b/license/COPYRIGHT.txt new file mode 100644 index 000000000..7bf2faffd --- /dev/null +++ b/license/COPYRIGHT.txt @@ -0,0 +1,15 @@ +/* + * Copyright 2018-2021 KMath contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ \ No newline at end of file diff --git a/license/COPYRIGHT_HEADER.txt b/license/COPYRIGHT_HEADER.txt new file mode 100644 index 000000000..3e7d28489 --- /dev/null +++ b/license/COPYRIGHT_HEADER.txt @@ -0,0 +1,4 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ \ No newline at end of file diff --git a/license/LICENSE.txt b/license/LICENSE.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/license/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/license/README.md b/license/README.md new file mode 100644 index 000000000..376321684 --- /dev/null +++ b/license/README.md @@ -0,0 +1,53 @@ +The Apache 2 license (given in full in LICENSE.txt) applies to all code in this repository, which is copyright by the +contributors of KMath. The following sections of the repository contain third-party code, to which different licenses +may apply: + +## KMath Libraries + +The following modules contain third-party code and are incorporated into the KMath Libraries: + +- Path: kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt + - License: Apache 2 ([cm](third_party/cm_license.txt)) + - Origin: Derived from Apache Commons Math, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt + - License: Apache 2 ([cm](third_party/cm_license.txt)) + - Origin: Derived from Apache Commons Math, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LoessInterpolator.kt + - License: Apache 2 ([cm](third_party/cm_license.txt)) + - Origin: Derived from Apache Commons Math, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt + - License: Apache 2 ([cm](third_party/cm_license.txt)) + - Origin: Derived from Apache Commons Math, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt + - License: Apache 2 ([numky](third_party/numky_license.txt)) + - Origin: Initial implementation was taken from Numky +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation diff --git a/license/third_party/cm_license.txt b/license/third_party/cm_license.txt new file mode 100644 index 000000000..6172c3fb2 --- /dev/null +++ b/license/third_party/cm_license.txt @@ -0,0 +1,457 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +Apache Commons Math includes the following code provided to the ASF under the +Apache License 2.0: + + - The inverse error function implementation in the Erf class is based on CUDA + code developed by Mike Giles, Oxford-Man Institute of Quantitative Finance, + and published in GPU Computing Gems, volume 2, 2010 (grant received on + March 23th 2013) + - The LinearConstraint, LinearObjectiveFunction, LinearOptimizer, + RelationShip, SimplexSolver and SimplexTableau classes in package + org.apache.commons.math3.optimization.linear include software developed by + Benjamin McCann (http://www.benmccann.com) and distributed with + the following copyright: Copyright 2009 Google Inc. (grant received on + March 16th 2009) + - The class "org.apache.commons.math3.exception.util.LocalizedFormatsTest" which + is an adapted version of "OrekitMessagesTest" test class for the Orekit library + - The "org.apache.commons.math3.analysis.interpolation.HermiteInterpolator" + has been imported from the Orekit space flight dynamics library. + +=============================================================================== + + + +APACHE COMMONS MATH DERIVATIVE WORKS: + +The Apache commons-math library includes a number of subcomponents +whose implementation is derived from original sources written +in C or Fortran. License terms of the original sources +are reproduced below. + +=============================================================================== +For the lmder, lmpar and qrsolv Fortran routine from minpack and translated in +the LevenbergMarquardtOptimizer class in package +org.apache.commons.math3.optimization.general +Original source copyright and license statement: + +Minpack Copyright Notice (1999) University of Chicago. All rights reserved + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimer. + +2. Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials +provided with the distribution. + +3. The end-user documentation included with the +redistribution, if any, must include the following +acknowledgment: + + "This product includes software developed by the + University of Chicago, as Operator of Argonne National + Laboratory. + +Alternately, this acknowledgment may appear in the software +itself, if and wherever such third-party acknowledgments +normally appear. + +4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" +WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE +UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND +THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE +OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY +OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR +USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF +THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) +DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION +UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL +BE CORRECTED. + +5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT +HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF +ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, +INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF +ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF +PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER +SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT +(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, +EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE +POSSIBILITY OF SUCH LOSS OR DAMAGES. +=============================================================================== + +Copyright and license statement for the odex Fortran routine developed by +E. Hairer and G. Wanner and translated in GraggBulirschStoerIntegrator class +in package org.apache.commons.math3.ode.nonstiff: + + +Copyright (c) 2004, Ernst Hairer + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +=============================================================================== + +Copyright and license statement for the original Mersenne twister C +routines translated in MersenneTwister class in package +org.apache.commons.math3.random: + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================== + +The initial code for shuffling an array (originally in class +"org.apache.commons.math3.random.RandomDataGenerator", now replaced by +a method in class "org.apache.commons.math3.util.MathArrays") was +inspired from the algorithm description provided in +"Algorithms", by Ian Craw and John Pulham (University of Aberdeen 1999). +The textbook (containing a proof that the shuffle is uniformly random) is +available here: + http://citeseerx.ist.psu.edu/viewdoc/download;?doi=10.1.1.173.1898&rep=rep1&type=pdf + +=============================================================================== +License statement for the direction numbers in the resource files for Sobol sequences. + +----------------------------------------------------------------------------- +Licence pertaining to sobol.cc and the accompanying sets of direction numbers + +----------------------------------------------------------------------------- +Copyright (c) 2008, Frances Y. Kuo and Stephen Joe +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the copyright holders nor the names of the + University of New South Wales and the University of Waikato + and its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +=============================================================================== + +The initial commit of package "org.apache.commons.math3.ml.neuralnet" is +an adapted version of code developed in the context of the Data Processing +and Analysis Consortium (DPAC) of the "Gaia" project of the European Space +Agency (ESA). +=============================================================================== + +The initial commit of the class "org.apache.commons.math3.special.BesselJ" is +an adapted version of code translated from the netlib Fortran program, rjbesl +http://www.netlib.org/specfun/rjbesl by R.J. Cody at Argonne National +Laboratory (USA). There is no license or copyright statement included with the +original Fortran sources. +=============================================================================== + + +The BracketFinder (package org.apache.commons.math3.optimization.univariate) +and PowellOptimizer (package org.apache.commons.math3.optimization.general) +classes are based on the Python code in module "optimize.py" (version 0.5) +developed by Travis E. Oliphant for the SciPy library (http://www.scipy.org/) +Copyright © 2003-2009 SciPy Developers. + +SciPy license +Copyright © 2001, 2002 Enthought, Inc. +All rights reserved. + +Copyright © 2003-2013 SciPy Developers. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Enthought nor the names of the SciPy Developers may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +=============================================================================== diff --git a/license/third_party/crng_license.txt b/license/third_party/crng_license.txt new file mode 100644 index 000000000..dec0e2a5c --- /dev/null +++ b/license/third_party/crng_license.txt @@ -0,0 +1,275 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +================================================================================ + +Class "org.apache.commons.rng.core.source64.MersenneTwister64" contains +Java code partly ported from the reference implementation in C. +That source file contained the following notice: + + Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +================================================================================ + +Class "org.apache.commons.rng.core.source32.MersenneTwister" contains +Java code partly ported from the reference implementation in C. +That source file contained the following notice: + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +================================================================================ \ No newline at end of file diff --git a/license/third_party/numky_license.txt b/license/third_party/numky_license.txt new file mode 100644 index 000000000..f49a4e16e --- /dev/null +++ b/license/third_party/numky_license.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file -- 2.34.1 From e38b2e1c536b2d1f19cb6ae803b257d01368c196 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 17 Nov 2021 19:03:20 +0700 Subject: [PATCH 066/102] Only dump ASM classes during tests if according property is passed to Gradle --- kmath-ast/build.gradle.kts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 586652349..331d8c614 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -55,9 +55,10 @@ tasks.dokkaHtml { dependsOn(tasks.build) } -tasks.jvmTest { - jvmArgs = (jvmArgs ?: emptyList()) + listOf("-Dspace.kscience.kmath.ast.dump.generated.classes=1") -} +if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") + tasks.jvmTest { + jvmArgs = (jvmArgs ?: emptyList()) + listOf("-Dspace.kscience.kmath.ast.dump.generated.classes=1") + } readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL -- 2.34.1 From 0f7a25762e98b48f7b7331c1714342cffc32b798 Mon Sep 17 00:00:00 2001 From: Alexis Manin Date: Sat, 13 Nov 2021 09:03:05 +0100 Subject: [PATCH 067/102] feat(Core): add a permutation sorting prototype for buffers This is a Buffer extension function to create a list of permuted indices that represent the sequence of naturally sorted buffer elements --- .../space/kscience/kmath/misc/sorting.kt | 40 +++++++++++ .../space/kscience/kmath/misc/PermSortTest.kt | 72 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt create mode 100644 kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt 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 new file mode 100644 index 000000000..a72ef19cc --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.misc + +import kotlin.comparisons.* +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.indices + +/** + * Return a new list filled with buffer indices. Indice order is defined by sorting associated buffer value. + * This feature allows to sort buffer values without reordering its content. + * + * @param descending True to revert sort order from highest to lowest values. Default to ascending order. + * @return List of buffer indices, sorted by associated value. + */ +@PerformancePitfall +@UnstableKMathAPI +public fun > Buffer.permSort(descending : Boolean = false) : IntArray { + if (size < 2) return IntArray(size) + + val comparator = if (descending) compareByDescending { get(it) } else compareBy { get(it) } + + /* TODO: optimisation : keep a constant big array of indices (Ex: from 0 to 4096), then create indice + * arrays more efficiently by copying subpart of cached one. For bigger needs, we could copy entire + * cached array, then fill remaining indices manually. Not done for now, because: + * 1. doing it right would require some statistics about common used buffer sizes. + * 2. Some benchmark would be needed to ensure it would really provide better performance + */ + val packedIndices = IntArray(size) { idx -> idx } + + /* TODO: find an efficient way to sort in-place instead, and return directly the IntArray. + * Not done for now, because no standard utility is provided yet. An open issue exists for this. + * See: https://youtrack.jetbrains.com/issue/KT-37860 + */ + return packedIndices.sortedWith(comparator).toIntArray() +} 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 new file mode 100644 index 000000000..cb47f2d4b --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ + +package space.kscience.kmath.misc + +import kotlin.collections.mutableListOf +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.test.fail + +import space.kscience.kmath.structures.IntBuffer + +class PermSortTest { + + /** + * Permutation on empty buffer should immediately return an empty array. + */ + @Test + fun testOnEmptyBuffer() { + val emptyBuffer = IntBuffer(0) {it} + var permutations = emptyBuffer.permSort() + assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") + permutations = emptyBuffer.permSort(true) + assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") + } + + @Test + fun testOnSingleValueBuffer() { + testPermutation(1) + } + + @Test + public fun testOnSomeValues() { + testPermutation(10) + } + + private fun testPermutation(bufferSize: Int) { + + val seed = Random.nextLong() + println("Test randomization seed: $seed") + + val buffer = Random(seed).buffer(bufferSize) + val indices = buffer.permSort() + + assertEquals(bufferSize, indices.size) + // Ensure no doublon is present in indices + assertEquals(indices.toSet().size, indices.size) + + for (i in 0 until (bufferSize-1)) { + val current = buffer[indices[i]] + val next = buffer[indices[i+1]] + assertTrue(current <= next, "Permutation indices not properly sorted") + } + + val descIndices = buffer.permSort(true) + assertEquals(bufferSize, descIndices.size) + // Ensure no doublon is present in indices + assertEquals(descIndices.toSet().size, descIndices.size) + + for (i in 0 until (bufferSize-1)) { + val current = buffer[descIndices[i]] + val next = buffer[descIndices[i+1]] + assertTrue(current >= next, "Permutation indices not properly sorted in descending order") + } + } + + private fun Random.buffer(size : Int) = IntBuffer(size) { nextInt() } +} -- 2.34.1 From 06a6a99ef0577ab13400de290f5fbfa9978f2717 Mon Sep 17 00:00:00 2001 From: Alexis Manin Date: Thu, 18 Nov 2021 17:44:53 +0100 Subject: [PATCH 068/102] feat(Core): add new flavors of permSort: allow user to specify a comparator (sort with) or a custom field to use in buffer values (sort by). --- .../space/kscience/kmath/misc/sorting.kt | 35 +++++++++++----- .../space/kscience/kmath/misc/PermSortTest.kt | 41 ++++++++++++++++--- 2 files changed, 61 insertions(+), 15 deletions(-) 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 a72ef19cc..a144e49b4 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,23 +6,38 @@ package space.kscience.kmath.misc import kotlin.comparisons.* -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices /** * Return a new list filled with buffer indices. Indice order is defined by sorting associated buffer value. * This feature allows to sort buffer values without reordering its content. - * - * @param descending True to revert sort order from highest to lowest values. Default to ascending order. + * * @return List of buffer indices, sorted by associated value. */ @PerformancePitfall @UnstableKMathAPI -public fun > Buffer.permSort(descending : Boolean = false) : IntArray { - if (size < 2) return IntArray(size) +public fun > Buffer.permSort() : IntArray = _permSortWith(compareBy { get(it) }) - val comparator = if (descending) compareByDescending { get(it) } else compareBy { get(it) } +@PerformancePitfall +@UnstableKMathAPI +public fun > Buffer.permSortDescending() : IntArray = _permSortWith(compareByDescending { get(it) }) + +@PerformancePitfall +@UnstableKMathAPI +public fun > Buffer.permSortBy(selector: (V) -> C) : IntArray = _permSortWith(compareBy { selector(get(it)) }) + +@PerformancePitfall +@UnstableKMathAPI +public fun > Buffer.permSortByDescending(selector: (V) -> C) : IntArray = _permSortWith(compareByDescending { selector(get(it)) }) + +@PerformancePitfall +@UnstableKMathAPI +public fun Buffer.permSortWith(comparator : Comparator) : IntArray = _permSortWith { i1, i2 -> comparator.compare(get(i1), get(i2)) } + +@PerformancePitfall +@UnstableKMathAPI +private fun Buffer._permSortWith(comparator : Comparator) : IntArray { + if (size < 2) return IntArray(size) /* TODO: optimisation : keep a constant big array of indices (Ex: from 0 to 4096), then create indice * arrays more efficiently by copying subpart of cached one. For bigger needs, we could copy entire @@ -31,10 +46,10 @@ public fun > Buffer.permSort(descending : Boolean = false) : * 2. Some benchmark would be needed to ensure it would really provide better performance */ val packedIndices = IntArray(size) { idx -> idx } - - /* TODO: find an efficient way to sort in-place instead, and return directly the IntArray. + + /* TODO: find an efficient way to sort in-place instead, and return directly the IntArray. * Not done for now, because no standard utility is provided yet. An open issue exists for this. - * See: https://youtrack.jetbrains.com/issue/KT-37860 + * See: https://youtrack.jetbrains.com/issue/KT-37860 */ return packedIndices.sortedWith(comparator).toIntArray() } 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 cb47f2d4b..0a2bb9138 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,17 +5,24 @@ package space.kscience.kmath.misc -import kotlin.collections.mutableListOf +import space.kscience.kmath.misc.PermSortTest.Platform.* import kotlin.random.Random import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -import kotlin.test.fail import space.kscience.kmath.structures.IntBuffer +import space.kscience.kmath.structures.asBuffer +import kotlin.test.assertContentEquals class PermSortTest { + private enum class Platform { + ANDROID, JVM, JS, NATIVE, WASM + } + + private val platforms = Platform.values().asBuffer() + /** * Permutation on empty buffer should immediately return an empty array. */ @@ -24,7 +31,7 @@ class PermSortTest { val emptyBuffer = IntBuffer(0) {it} var permutations = emptyBuffer.permSort() assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") - permutations = emptyBuffer.permSort(true) + permutations = emptyBuffer.permSortDescending() assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") } @@ -34,10 +41,34 @@ class PermSortTest { } @Test - public fun testOnSomeValues() { + fun testOnSomeValues() { testPermutation(10) } + @Test + fun testPermSortBy() { + val permutations = platforms.permSortBy { it.name } + val expected = listOf(ANDROID, JS, JVM, NATIVE, WASM) + assertContentEquals(expected, permutations.map { platforms[it] }, "Ascending PermSort by name") + } + + @Test + fun testPermSortByDescending() { + val permutations = platforms.permSortByDescending { it.name } + val expected = listOf(WASM, NATIVE, JVM, JS, ANDROID) + assertContentEquals(expected, permutations.map { platforms[it] }, "Descending PermSort by name") + } + + @Test + fun testPermSortWith() { + var permutations = platforms.permSortWith { p1, p2 -> p1.name.length.compareTo(p2.name.length) } + val expected = listOf(JS, JVM, WASM, NATIVE, ANDROID) + assertContentEquals(expected, permutations.map { platforms[it] }, "PermSort using custom ascending comparator") + + permutations = platforms.permSortWith(compareByDescending { it.name.length }) + assertContentEquals(expected.reversed(), permutations.map { platforms[it] }, "PermSort using custom descending comparator") + } + private fun testPermutation(bufferSize: Int) { val seed = Random.nextLong() @@ -56,7 +87,7 @@ class PermSortTest { assertTrue(current <= next, "Permutation indices not properly sorted") } - val descIndices = buffer.permSort(true) + val descIndices = buffer.permSortDescending() assertEquals(bufferSize, descIndices.size) // Ensure no doublon is present in indices assertEquals(descIndices.toSet().size, descIndices.size) -- 2.34.1 From 24799a691f23805fba77342d31b9ced16617fc84 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 23 Nov 2021 10:32:51 +0300 Subject: [PATCH 069/102] Add inc/dec to counters --- .../space/kscience/kmath/histogram/Counter.kt | 26 ++++++++++++++++--- .../kmath/histogram/DoubleHistogramSpace.kt | 2 +- .../kmath/histogram/IndexedHistogramSpace.kt | 1 - .../kmath/histogram/TreeHistogramSpace.kt | 2 +- .../kmath/tensorflow/TensorFlowAlgebra.kt | 4 ++- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt index 4f5a1ceba..5755e05f7 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.histogram import kotlinx.atomicfu.atomic import kotlinx.atomicfu.getAndUpdate import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.Group /** * Common representation for atomic counters @@ -18,7 +18,7 @@ public interface Counter { public val value: T public companion object { - public fun real(): ObjectCounter = ObjectCounter(DoubleField) + public fun double(): ObjectCounter = ObjectCounter(DoubleField) } } @@ -32,6 +32,16 @@ public class IntCounter : Counter { override val value: Int get() = innerValue.value } +public operator fun IntCounter.inc(): IntCounter { + add(1) + return this +} + +public operator fun IntCounter.dec(): IntCounter { + add(-1) + return this +} + public class LongCounter : Counter { private val innerValue = atomic(0L) @@ -42,7 +52,17 @@ public class LongCounter : Counter { override val value: Long get() = innerValue.value } -public class ObjectCounter(public val group: Ring) : Counter { +public operator fun LongCounter.inc(): LongCounter { + add(1L) + return this +} + +public operator fun LongCounter.dec(): LongCounter { + add(-1L) + return this +} + +public class ObjectCounter(private val group: Group) : Counter { private val innerValue = atomic(group.zero) override fun add(delta: T) { diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt index c452edc9c..39121f301 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt @@ -74,7 +74,7 @@ public class DoubleHistogramSpace( } override fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram { - val ndCounter = StructureND.auto(shape) { Counter.real() } + val ndCounter = StructureND.auto(shape) { Counter.double() } val hBuilder = HistogramBuilder { point, value -> val index = getIndex(point) ndCounter[index].add(value.toDouble()) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt index f36f45389..cbf0bea1a 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt @@ -41,7 +41,6 @@ public class IndexedHistogram, V : Any>( get() = DefaultStrides(context.shape).asSequence().map { context.produceBin(it, values[it]) }.asIterable() - } /** diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt index cc54d7e1a..4103fa653 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt @@ -39,7 +39,7 @@ public class TreeHistogram( @PublishedApi internal class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain) : UnivariateHistogramBuilder { - internal class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : + internal class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.double()) : ClosedFloatingPointRange by domain.range private val bins: TreeMap = TreeMap() 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 1f545d121..7ad91c267 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 @@ -232,4 +232,6 @@ public abstract class TensorFlowAlgebra> internal con @OptIn(UnstableKMathAPI::class) override fun export(arg: StructureND): StructureND = if (arg is TensorFlowOutput) arg.actualTensor else arg -} \ No newline at end of file +} + +//TODO add TensorFlow expressions \ No newline at end of file -- 2.34.1 From d2e311048078c7d2f6279277f2c9f2a31c7bb0a7 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 24 Nov 2021 03:48:43 +0700 Subject: [PATCH 070/102] Update gradle-tools, do Kotlin 1.6.0 migrations --- benchmarks/build.gradle.kts | 8 +++---- build.gradle.kts | 8 +++---- buildSrc/build.gradle.kts | 6 +++--- examples/build.gradle.kts | 8 +++---- kmath-ast/build.gradle.kts | 2 +- .../random/CMRandomGeneratorWrapper.kt | 3 --- kmath-core/build.gradle.kts | 21 +++++++------------ .../space/kscience/kmath/misc/annotations.kt | 6 +++--- .../kmath/operations/BufferAlgebra.kt | 5 ----- .../kmath/operations/DoubleBufferField.kt | 1 - .../kmath/operations/DoubleBufferOps.kt | 2 -- kmath-coroutines/build.gradle.kts | 6 +++--- kmath-jafama/build.gradle.kts | 2 +- kmath-jupyter/build.gradle.kts | 4 ++-- kmath-optimization/build.gradle.kts | 4 ++++ kmath-tensors/build.gradle.kts | 6 +++++- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 1 - settings.gradle.kts | 9 +------- 18 files changed, 42 insertions(+), 60 deletions(-) diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 130cc84a3..ea9934a52 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -48,7 +48,7 @@ kotlin { implementation(project(":kmath-nd4j")) implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-viktor")) - implementation(projects.kmathMultik) + implementation(project(":kmath-multik")) implementation("org.nd4j:nd4j-native:1.0.0-M1") // uncomment if your system supports AVX2 // val os = System.getProperty("os.name") @@ -134,9 +134,9 @@ afterEvaluate { kotlin.sourceSets.all { with(languageSettings) { - useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") - useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") - useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") + optIn("kotlin.contracts.ExperimentalContracts") + optIn("kotlin.ExperimentalUnsignedTypes") + optIn("space.kscience.kmath.misc.UnstableKMathAPI") } } diff --git a/build.gradle.kts b/build.gradle.kts index c2347f7be..919356c0f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -39,7 +39,7 @@ subprojects { localDirectory.set(kotlinDir) remoteUrl.set( - URL("https://github.com/mipt-npm/${rootProject.name}/tree/master/${this@subprojects.name}/$kotlinDirPath") + URL("https://github.com/mipt-npm/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath") ) } @@ -64,9 +64,9 @@ subprojects { readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") ksciencePublish { - vcs("https://github.com/mipt-npm/kmath") - space(publish = true) - sonatype(publish = true) + github("kmath", publish = false) + space() + sonatype() } apiValidation.nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 36a1ffd9e..072309332 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,6 +1,6 @@ plugins { `kotlin-dsl` - kotlin("plugin.serialization") version "1.4.31" + kotlin("plugin.serialization") version "1.5.21" } repositories { @@ -10,8 +10,8 @@ repositories { } dependencies { - api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") - api("ru.mipt.npm:gradle-tools:0.10.2") + api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2") + api("ru.mipt.npm:gradle-tools:0.10.7") api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.3.1") } diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 05e562143..990b564e1 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -32,7 +32,7 @@ dependencies { //jafama implementation(project(":kmath-jafama")) //multik - implementation(projects.kmathMultik) + implementation(project(":kmath-multik")) implementation("org.nd4j:nd4j-native:1.0.0-beta7") @@ -57,9 +57,9 @@ dependencies { kotlin.sourceSets.all { with(languageSettings) { - useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") - useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") - useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") + optIn("kotlin.contracts.ExperimentalContracts") + optIn("kotlin.ExperimentalUnsignedTypes") + optIn("space.kscience.kmath.misc.UnstableKMathAPI") } } diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 331d8c614..15b1d0900 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -20,7 +20,7 @@ kotlin.js { kotlin.sourceSets { filter { it.name.contains("test", true) } .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) - .forEach { it.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } + .forEach { it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") } commonMain { dependencies { diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt index 6aeebb68c..194be6002 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt @@ -38,10 +38,7 @@ public class CMRandomGeneratorWrapper( override fun nextInt(): Int = generator.nextInt() override fun nextInt(n: Int): Int = generator.nextInt(n) - - @PerformancePitfall override fun nextGaussian(): Double = runBlocking { GaussianSampler(0.0, 1.0).next(generator) } - override fun nextDouble(): Double = generator.nextDouble() override fun nextLong(): Long = generator.nextLong() } diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 143e576f7..490868a0b 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -5,21 +5,14 @@ plugins { // id("com.xcporter.metaview") version "0.0.5" } -kotlin { - jvm { - compilations.all { - kotlinOptions { - freeCompilerArgs = - freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" - } - } - } +kotlin.sourceSets { + filter { it.name.contains("test", true) } + .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) + .forEach { it.optIn("space.kscience.kmath.misc.PerformancePitfall") } - sourceSets { - commonMain { - dependencies { - api(project(":kmath-memory")) - } + commonMain { + dependencies { + api(project(":kmath-memory")) } } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt index 73ecd6492..7c612b6a9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt @@ -12,7 +12,7 @@ package space.kscience.kmath.misc * in some way that may break some code. */ @MustBeDocumented -@Retention(value = AnnotationRetention.SOURCE) +@Retention(value = AnnotationRetention.BINARY) @RequiresOptIn("This API is unstable and could change in future", RequiresOptIn.Level.WARNING) public annotation class UnstableKMathAPI @@ -21,10 +21,10 @@ public annotation class UnstableKMathAPI * slow-down in some cases. Refer to the documentation and benchmark it to be sure. */ @MustBeDocumented -@Retention(value = AnnotationRetention.SOURCE) +@Retention(value = AnnotationRetention.BINARY) @RequiresOptIn( "Refer to the documentation to use this API in performance-critical code", - RequiresOptIn.Level.WARNING + RequiresOptIn.Level.WARNING, ) public annotation class PerformancePitfall( val message: String = "Potential performance problem" diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt index 634a115c7..653552044 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -35,13 +35,11 @@ public interface BufferAlgebra> : Algebra> { public fun Buffer.zip(other: Buffer, block: A.(left: T, right: T) -> T): Buffer = zipInline(this, other, block) - @UnstableKMathAPI override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { val operationFunction = elementAlgebra.unaryOperationFunction(operation) return { arg -> bufferFactory(arg.size) { operationFunction(arg[it]) } } } - @UnstableKMathAPI override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { val operationFunction = elementAlgebra.binaryOperationFunction(operation) return { left, right -> @@ -141,11 +139,9 @@ public open class BufferRingOps>( override fun multiply(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l * r } override fun Buffer.unaryMinus(): Buffer = map { -it } - @UnstableKMathAPI override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = super.unaryOperationFunction(operation) - @UnstableKMathAPI override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = super.binaryOperationFunction(operation) } @@ -165,7 +161,6 @@ public open class BufferFieldOps>( override fun scale(a: Buffer, value: Double): Buffer = a.map { scale(it, value) } override fun Buffer.unaryMinus(): Buffer = map { -it } - @UnstableKMathAPI override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = super.binaryOperationFunction(operation) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt index 8ec3c3aea..f2f7326aa 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt @@ -40,7 +40,6 @@ public class DoubleBufferField(public val size: Int) : ExtendedField) -> Buffer = super.unaryOperationFunction(operation) 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 a5e1c42e2..0ee591acc 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 @@ -26,11 +26,9 @@ public abstract class DoubleBufferOps : BufferAlgebra, Exte override fun Buffer.map(block: DoubleField.(Double) -> Double): DoubleBuffer = mapInline { DoubleField.block(it) } - @UnstableKMathAPI override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = super.unaryOperationFunction(operation) - @UnstableKMathAPI override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = super.binaryOperationFunction(operation) diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts index 317691ae5..aa30c412b 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -7,9 +7,9 @@ plugins { kotlin.sourceSets { all { with(languageSettings) { - useExperimentalAnnotation("kotlinx.coroutines.InternalCoroutinesApi") - useExperimentalAnnotation("kotlinx.coroutines.ExperimentalCoroutinesApi") - useExperimentalAnnotation("kotlinx.coroutines.FlowPreview") + optIn("kotlinx.coroutines.InternalCoroutinesApi") + optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") + optIn("kotlinx.coroutines.FlowPreview") } } diff --git a/kmath-jafama/build.gradle.kts b/kmath-jafama/build.gradle.kts index 9cf328d0b..925a2bc60 100644 --- a/kmath-jafama/build.gradle.kts +++ b/kmath-jafama/build.gradle.kts @@ -23,5 +23,5 @@ readme { } kotlin.sourceSets.all { - languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") + languageSettings.optIn("space.kscience.kmath.misc.UnstableKMathAPI") } diff --git a/kmath-jupyter/build.gradle.kts b/kmath-jupyter/build.gradle.kts index 5bd08c485..ca1a5485f 100644 --- a/kmath-jupyter/build.gradle.kts +++ b/kmath-jupyter/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { api(project(":kmath-for-real")) } -kscience{ +kscience { useHtml() } @@ -18,7 +18,7 @@ readme { } kotlin.sourceSets.all { - languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") + languageSettings.optIn("space.kscience.kmath.misc.UnstableKMathAPI") } tasks.processJupyterApiResources { diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts index 68b82ad65..b920b9267 100644 --- a/kmath-optimization/build.gradle.kts +++ b/kmath-optimization/build.gradle.kts @@ -8,6 +8,10 @@ kscience { } kotlin.sourceSets { + all { + languageSettings.optIn("space.kscience.kmath.misc.UnstableKMathAPI") + } + commonMain { dependencies { api(project(":kmath-coroutines")) diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index d084878ea..66316d21d 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -6,9 +6,13 @@ plugins { kotlin.sourceSets { all { - languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") + languageSettings.optIn("space.kscience.kmath.misc.UnstableKMathAPI") } + filter { it.name.contains("test", true) } + .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) + .forEach { it.optIn("space.kscience.kmath.misc.PerformancePitfall") } + commonMain { dependencies { api(project(":kmath-core")) 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 ae1a053af..dc3ec43e9 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 @@ -384,7 +384,6 @@ public open class DoubleTensorAlgebra : override fun Tensor.viewAs(other: StructureND): DoubleTensor = tensor.view(other.shape) - @PerformancePitfall override infix fun StructureND.dot(other: StructureND): DoubleTensor { if (tensor.shape.size == 1 && other.shape.size == 1) { return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.mutableBuffer.array().sum())) diff --git a/settings.gradle.kts b/settings.gradle.kts index e73381bf2..343e937e1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,14 +5,10 @@ pluginManagement { gradlePluginPortal() } - val kotlinVersion = "1.6.0-RC" - val toolsVersion = "0.10.5" + val kotlinVersion = "1.6.0" plugins { id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - id("ru.mipt.npm.gradle.project") version toolsVersion - id("ru.mipt.npm.gradle.jvm") version toolsVersion - id("ru.mipt.npm.gradle.mpp") version toolsVersion kotlin("multiplatform") version kotlinVersion kotlin("plugin.allopen") version kotlinVersion } @@ -20,9 +16,6 @@ pluginManagement { rootProject.name = "kmath" -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -enableFeaturePreview("VERSION_CATALOGS") - include( ":kmath-memory", ":kmath-complex", -- 2.34.1 From 5ba7d74bd249a02e742ad2e0bbcde83bf4bc0858 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Thu, 25 Nov 2021 23:26:08 +0700 Subject: [PATCH 071/102] Completely specialized expression types for Int, Long, Double and compilation of MST to it --- .../ExpressionsInterpretersBenchmark.kt | 20 +- .../space/kscience/kmath/ast/expressions.kt | 6 +- .../kmath/ast/TestCompilerVariables.kt | 16 +- .../lib.dom.WebAssembly.module_dukat.kt | 4 +- .../kmath/wasm/internal/WasmBuilder.kt | 190 +++---- .../kotlin/space/kscience/kmath/wasm/wasm.kt | 11 +- .../kotlin/space/kscience/kmath/asm/asm.kt | 28 +- .../kscience/kmath/asm/internal/AsmBuilder.kt | 13 +- .../asm/internal/ByteArrayClassLoader.kt | 6 - .../kmath/asm/internal/GenericAsmBuilder.kt | 14 +- .../kmath/asm/internal/PrimitiveAsmBuilder.kt | 464 +++++++++++------- kmath-core/build.gradle.kts | 5 +- .../kscience/kmath/expressions/Expression.kt | 132 +++++ kmath-kotlingrad/build.gradle.kts | 5 + .../kscience/kmath/internal/InternalGamma.kt | 2 +- 15 files changed, 615 insertions(+), 301 deletions(-) delete mode 100644 kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index f3a52ab5f..db3524e67 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -38,6 +38,22 @@ internal class ExpressionsInterpretersBenchmark { @Benchmark fun asmGenericExpression(blackhole: Blackhole) = invokeAndSum(asmGeneric, blackhole) + /** + * Benchmark case for [Expression] created with [compileToExpression]. + */ + @Benchmark + fun asmPrimitiveExpressionArray(blackhole: Blackhole) { + val random = Random(0) + var sum = 0.0 + val m = DoubleArray(1) + + repeat(times) { + m[xIdx] = random.nextDouble() + sum += asmPrimitive(m) + } + + blackhole.consume(sum) + } /** * Benchmark case for [Expression] created with [compileToExpression]. @@ -82,7 +98,6 @@ internal class ExpressionsInterpretersBenchmark { private companion object { private val x by symbol - private val algebra = DoubleField private const val times = 1_000_000 private val functional = DoubleField.expression { @@ -95,7 +110,10 @@ internal class ExpressionsInterpretersBenchmark { } private val mst = node.toExpression(DoubleField) + private val asmPrimitive = node.compileToExpression(DoubleField) + private val xIdx = asmPrimitive.indexer.indexOf(x) + private val asmGeneric = node.compileToExpression(DoubleField as Algebra) private val raw = Expression { args -> diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt index ffafdc99d..907f1bbe4 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.ast import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.expressions.MstExtendedField -import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke @@ -17,10 +16,11 @@ fun main() { x * 2.0 + number(2.0) / x - number(16.0) + asinh(x) / sin(x) }.compileToExpression(DoubleField) - val m = HashMap() + val m = DoubleArray(expr.indexer.symbols.size) + val xIdx = expr.indexer.indexOf(x) repeat(10000000) { - m[x] = 1.0 + m[xIdx] = 1.0 expr(m) } } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt index af1a2e338..859e56032 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt @@ -7,7 +7,9 @@ package space.kscience.kmath.ast import space.kscience.kmath.expressions.MstRing import space.kscience.kmath.expressions.Symbol.Companion.x +import space.kscience.kmath.expressions.Symbol.Companion.y import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing import space.kscience.kmath.operations.invoke import kotlin.test.Test @@ -16,11 +18,23 @@ import kotlin.test.assertFailsWith internal class TestCompilerVariables { @Test - fun testVariable() = runCompilerTest { + fun testNoVariables() = runCompilerTest { + val expr = "0".parseMath().compileToExpression(IntRing) + assertEquals(0, expr()) + } + + @Test + fun testOneVariable() = runCompilerTest { val expr = MstRing { x }.compileToExpression(IntRing) assertEquals(1, expr(x to 1)) } + @Test + fun testTwoVariables() = runCompilerTest { + val expr = "y+x/y+x".parseMath().compileToExpression(DoubleField) + assertEquals(8.0, expr(x to 4.0, y to 2.0)) + } + @Test fun testUndefinedVariableFails() = runCompilerTest { val expr = MstRing { x }.compileToExpression(IntRing) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt index 3754c3eff..90690abed 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt @@ -201,8 +201,8 @@ internal open external class Module { } @JsName("Instance") -internal open external class Instance(module: Module, importObject: Any = definedExternally) { - open var exports: Any +internal open external class Instance(module: Module, importObject: dynamic = definedExternally) { + open var exports: dynamic } @JsName("Memory") 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 622e6e6ec..2d6619bba 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,12 +5,11 @@ package space.kscience.kmath.wasm.internal -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.* import space.kscience.kmath.expressions.MST.* -import space.kscience.kmath.expressions.Symbol 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 @@ -18,65 +17,17 @@ import space.kscience.kmath.internal.webassembly.Module as WasmModule private val spreader = eval("(obj, args) => obj(...args)") @Suppress("UnsafeCastFromDynamic") -internal sealed class WasmBuilder( +internal sealed class WasmBuilder>( protected val binaryenType: Type, protected val algebra: Algebra, protected val target: MST, ) { protected val keys: MutableList = mutableListOf() - lateinit var ctx: BinaryenModule + protected lateinit var ctx: BinaryenModule - open fun visitSymbolic(mst: Symbol): ExpressionRef { - algebra.bindSymbolOrNull(mst)?.let { return visitNumeric(Numeric(it)) } + abstract val instance: E - var idx = keys.indexOf(mst) - - if (idx == -1) { - keys += mst - idx = keys.lastIndex - } - - return ctx.local.get(idx, binaryenType) - } - - abstract fun visitNumeric(mst: Numeric): ExpressionRef - - protected open fun visitUnary(mst: Unary): ExpressionRef = - error("Unary operation ${mst.operation} not defined in $this") - - protected open fun visitBinary(mst: Binary): ExpressionRef = - error("Binary operation ${mst.operation} not defined in $this") - - protected open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()") - - protected fun visit(mst: MST): ExpressionRef = when (mst) { - is Symbol -> visitSymbolic(mst) - is Numeric -> visitNumeric(mst) - - is Unary -> when { - algebra is NumericAlgebra && mst.value is Numeric -> visitNumeric( - Numeric(algebra.unaryOperationFunction(mst.operation)(algebra.number((mst.value as Numeric).value))) - ) - - else -> visitUnary(mst) - } - - is Binary -> when { - algebra is NumericAlgebra && mst.left is Numeric && mst.right is Numeric -> visitNumeric( - Numeric( - algebra.binaryOperationFunction(mst.operation) - .invoke( - algebra.number((mst.left as Numeric).value), - algebra.number((mst.right as Numeric).value) - ) - ) - ) - - else -> visitBinary(mst) - } - } - - val instance by lazy { + protected val executable = run { val c = WasmModule(with(createModule()) { ctx = this val expr = visit(target) @@ -97,41 +48,93 @@ internal sealed class WasmBuilder( res }) - val i = Instance(c, js("{}") as Any) - val symbols = keys - keys.clear() + Instance(c, js("{}")).exports.executable + } - Expression { args -> - val params = symbols.map(args::getValue).toTypedArray() - spreader(i.exports.asDynamic().executable, params) as T + protected open fun visitSymbol(node: Symbol): ExpressionRef { + algebra.bindSymbolOrNull(node)?.let { return visitNumeric(Numeric(it)) } + + var idx = keys.indexOf(node) + + if (idx == -1) { + keys += node + idx = keys.lastIndex + } + + return ctx.local.get(idx, binaryenType) + } + + protected abstract fun visitNumeric(node: Numeric): ExpressionRef + + protected open fun visitUnary(node: Unary): ExpressionRef = + error("Unary operation ${node.operation} not defined in $this") + + protected open fun visitBinary(mst: Binary): ExpressionRef = + error("Binary operation ${mst.operation} not defined in $this") + + protected open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()") + + protected fun visit(node: MST): ExpressionRef = when (node) { + is Symbol -> visitSymbol(node) + is Numeric -> visitNumeric(node) + + is Unary -> when { + algebra is NumericAlgebra && node.value is Numeric -> visitNumeric( + Numeric(algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) + ) + + else -> visitUnary(node) + } + + is Binary -> when { + algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> visitNumeric( + Numeric( + algebra.binaryOperationFunction(node.operation) + .invoke( + algebra.number((node.left as Numeric).value), + algebra.number((node.right as Numeric).value) + ) + ) + ) + + else -> visitBinary(node) } } } -internal class DoubleWasmBuilder(target: MST) : WasmBuilder(f64, DoubleField, target) { - override fun createModule(): BinaryenModule = readBinary(f64StandardFunctions) +@UnstableKMathAPI +internal class DoubleWasmBuilder(target: MST) : WasmBuilder(f64, DoubleField, target) { + override val instance by lazy { + object : DoubleExpression { + override val indexer = SimpleSymbolIndexer(keys) - override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.f64.const(mst.value) + override fun invoke(arguments: DoubleArray) = spreader(executable, arguments).unsafeCast() + } + } - override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) { - GroupOps.MINUS_OPERATION -> ctx.f64.neg(visit(mst.value)) - GroupOps.PLUS_OPERATION -> visit(mst.value) - PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(mst.value)) - TrigonometricOperations.SIN_OPERATION -> ctx.call("sin", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.COS_OPERATION -> ctx.call("cos", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.TAN_OPERATION -> ctx.call("tan", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.ASIN_OPERATION -> ctx.call("asin", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.ACOS_OPERATION -> ctx.call("acos", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.ATAN_OPERATION -> ctx.call("atan", arrayOf(visit(mst.value)), f64) - ExponentialOperations.SINH_OPERATION -> ctx.call("sinh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.COSH_OPERATION -> ctx.call("cosh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.TANH_OPERATION -> ctx.call("tanh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.ASINH_OPERATION -> ctx.call("asinh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.ACOSH_OPERATION -> ctx.call("acosh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.ATANH_OPERATION -> ctx.call("atanh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.EXP_OPERATION -> ctx.call("exp", arrayOf(visit(mst.value)), f64) - ExponentialOperations.LN_OPERATION -> ctx.call("log", arrayOf(visit(mst.value)), f64) - else -> super.visitUnary(mst) + override fun createModule() = readBinary(f64StandardFunctions) + + override fun visitNumeric(node: Numeric) = ctx.f64.const(node.value) + + override fun visitUnary(node: Unary): ExpressionRef = when (node.operation) { + GroupOps.MINUS_OPERATION -> ctx.f64.neg(visit(node.value)) + GroupOps.PLUS_OPERATION -> visit(node.value) + PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(node.value)) + TrigonometricOperations.SIN_OPERATION -> ctx.call("sin", arrayOf(visit(node.value)), f64) + TrigonometricOperations.COS_OPERATION -> ctx.call("cos", arrayOf(visit(node.value)), f64) + TrigonometricOperations.TAN_OPERATION -> ctx.call("tan", arrayOf(visit(node.value)), f64) + TrigonometricOperations.ASIN_OPERATION -> ctx.call("asin", arrayOf(visit(node.value)), f64) + TrigonometricOperations.ACOS_OPERATION -> ctx.call("acos", arrayOf(visit(node.value)), f64) + TrigonometricOperations.ATAN_OPERATION -> ctx.call("atan", arrayOf(visit(node.value)), f64) + ExponentialOperations.SINH_OPERATION -> ctx.call("sinh", arrayOf(visit(node.value)), f64) + ExponentialOperations.COSH_OPERATION -> ctx.call("cosh", arrayOf(visit(node.value)), f64) + ExponentialOperations.TANH_OPERATION -> ctx.call("tanh", arrayOf(visit(node.value)), f64) + ExponentialOperations.ASINH_OPERATION -> ctx.call("asinh", arrayOf(visit(node.value)), f64) + ExponentialOperations.ACOSH_OPERATION -> ctx.call("acosh", arrayOf(visit(node.value)), f64) + ExponentialOperations.ATANH_OPERATION -> ctx.call("atanh", arrayOf(visit(node.value)), f64) + ExponentialOperations.EXP_OPERATION -> ctx.call("exp", arrayOf(visit(node.value)), f64) + ExponentialOperations.LN_OPERATION -> ctx.call("log", arrayOf(visit(node.value)), f64) + else -> super.visitUnary(node) } override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { @@ -144,13 +147,22 @@ internal class DoubleWasmBuilder(target: MST) : WasmBuilder(f64, DoubleF } } -internal class IntWasmBuilder(target: MST) : WasmBuilder(i32, IntRing, target) { - override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.i32.const(mst.value) +@UnstableKMathAPI +internal class IntWasmBuilder(target: MST) : WasmBuilder(i32, IntRing, target) { + override val instance by lazy { + object : IntExpression { + override val indexer = SimpleSymbolIndexer(keys) - override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) { - GroupOps.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(mst.value)) - GroupOps.PLUS_OPERATION -> visit(mst.value) - else -> super.visitUnary(mst) + override fun invoke(arguments: IntArray) = spreader(executable, arguments).unsafeCast() + } + } + + override fun visitNumeric(node: Numeric) = ctx.i32.const(node.value) + + override fun visitUnary(node: Unary): ExpressionRef = when (node.operation) { + GroupOps.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(node.value)) + GroupOps.PLUS_OPERATION -> visit(node.value) + else -> super.visitUnary(node) } override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { 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 806091715..12e6b41af 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 @@ -3,13 +3,12 @@ * 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("UNUSED_PARAMETER") + package space.kscience.kmath.wasm import space.kscience.kmath.estree.compileWith -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.expressions.* import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing @@ -22,7 +21,7 @@ import space.kscience.kmath.wasm.internal.IntWasmBuilder * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: IntRing): Expression = compileWith(algebra) +public fun MST.compileToExpression(algebra: IntRing): IntExpression = IntWasmBuilder(this).instance /** @@ -50,7 +49,7 @@ public fun MST.compile(algebra: IntRing, vararg arguments: Pair): I * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: DoubleField): Expression = compileWith(algebra) +public fun MST.compileToExpression(algebra: DoubleField): Expression = DoubleWasmBuilder(this).instance /** 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 c39345f3a..8e426622d 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 @@ -8,11 +8,8 @@ package space.kscience.kmath.asm import space.kscience.kmath.asm.internal.* -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.* import space.kscience.kmath.expressions.MST.* -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.invoke import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* @@ -48,7 +45,13 @@ internal fun MST.compileWith(type: Class, algebra: Algebra): Exp loadVariable(node.identity) } - is Numeric -> loadNumberConstant(node.value) + is Numeric -> if (algebra is NumericAlgebra) { + if (Number::class.java.isAssignableFrom(type)) + loadNumberConstant(algebra.number(node.value) as Number) + else + loadObjectConstant(algebra.number(node.value)) + } else + error("Numeric nodes are not supported by $this") is Unary -> when { algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant( @@ -121,13 +124,15 @@ public inline fun MST.compile(algebra: Algebra, vararg argu * * @author Iaroslav Postovalov */ -public fun MST.compileToExpression(algebra: IntRing): Expression = IntAsmBuilder(this).instance +@UnstableKMathAPI +public fun MST.compileToExpression(algebra: IntRing): IntExpression = IntAsmBuilder(this).instance /** * Compile given MST to expression and evaluate it against [arguments]. * * @author Iaroslav Postovalov */ +@UnstableKMathAPI public fun MST.compile(algebra: IntRing, arguments: Map): Int = compileToExpression(algebra).invoke(arguments) @@ -136,6 +141,7 @@ public fun MST.compile(algebra: IntRing, arguments: Map): Int = * * @author Iaroslav Postovalov */ +@UnstableKMathAPI public fun MST.compile(algebra: IntRing, vararg arguments: Pair): Int = compileToExpression(algebra)(*arguments) @@ -145,7 +151,8 @@ public fun MST.compile(algebra: IntRing, vararg arguments: Pair): I * * @author Iaroslav Postovalov */ -public fun MST.compileToExpression(algebra: LongRing): Expression = LongAsmBuilder(this).instance +@UnstableKMathAPI +public fun MST.compileToExpression(algebra: LongRing): LongExpression = LongAsmBuilder(this).instance /** @@ -153,6 +160,7 @@ public fun MST.compileToExpression(algebra: LongRing): Expression = LongAs * * @author Iaroslav Postovalov */ +@UnstableKMathAPI public fun MST.compile(algebra: LongRing, arguments: Map): Long = compileToExpression(algebra).invoke(arguments) @@ -162,6 +170,7 @@ public fun MST.compile(algebra: LongRing, arguments: Map): Long = * * @author Iaroslav Postovalov */ +@UnstableKMathAPI public fun MST.compile(algebra: LongRing, vararg arguments: Pair): Long = compileToExpression(algebra)(*arguments) @@ -171,13 +180,15 @@ public fun MST.compile(algebra: LongRing, vararg arguments: Pair): * * @author Iaroslav Postovalov */ -public fun MST.compileToExpression(algebra: DoubleField): Expression = DoubleAsmBuilder(this).instance +@UnstableKMathAPI +public fun MST.compileToExpression(algebra: DoubleField): DoubleExpression = DoubleAsmBuilder(this).instance /** * Compile given MST to expression and evaluate it against [arguments]. * * @author Iaroslav Postovalov */ +@UnstableKMathAPI public fun MST.compile(algebra: DoubleField, arguments: Map): Double = compileToExpression(algebra).invoke(arguments) @@ -186,5 +197,6 @@ public fun MST.compile(algebra: DoubleField, arguments: Map): Do * * @author Iaroslav Postovalov */ +@UnstableKMathAPI public fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index 7d3d513de..a85079fc8 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.asm.internal import org.objectweb.asm.Type +import org.objectweb.asm.Type.getObjectType import space.kscience.kmath.expressions.Expression internal abstract class AsmBuilder { @@ -22,31 +23,31 @@ internal abstract class AsmBuilder { /** * ASM type for [Expression]. */ - val EXPRESSION_TYPE: Type by lazy { Type.getObjectType("space/kscience/kmath/expressions/Expression") } + val EXPRESSION_TYPE: Type = getObjectType("space/kscience/kmath/expressions/Expression") /** * ASM type for [java.util.Map]. */ - val MAP_TYPE: Type by lazy { Type.getObjectType("java/util/Map") } + val MAP_TYPE: Type = getObjectType("java/util/Map") /** * ASM type for [java.lang.Object]. */ - val OBJECT_TYPE: Type by lazy { Type.getObjectType("java/lang/Object") } + val OBJECT_TYPE: Type = getObjectType("java/lang/Object") /** * ASM type for [java.lang.String]. */ - val STRING_TYPE: Type by lazy { Type.getObjectType("java/lang/String") } + val STRING_TYPE: Type = getObjectType("java/lang/String") /** * ASM type for MapIntrinsics. */ - val MAP_INTRINSICS_TYPE: Type by lazy { Type.getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") } + val MAP_INTRINSICS_TYPE: Type = getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") /** * ASM Type for [space.kscience.kmath.expressions.Symbol]. */ - val SYMBOL_TYPE: Type by lazy { Type.getObjectType("space/kscience/kmath/expressions/Symbol") } + val SYMBOL_TYPE: Type = getObjectType("space/kscience/kmath/expressions/Symbol") } } diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt deleted file mode 100644 index 10eee7c6b..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/ByteArrayClassLoader.kt +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.asm.internal diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt index 28f4a226f..5eb739956 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt @@ -78,7 +78,7 @@ internal class GenericAsmBuilder( ) visitMethod( - ACC_PUBLIC or ACC_FINAL, + ACC_PUBLIC, "invoke", getMethodDescriptor(tType, MAP_TYPE), "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", @@ -116,7 +116,7 @@ internal class GenericAsmBuilder( } visitMethod( - ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, + ACC_PUBLIC or ACC_BRIDGE or ACC_SYNTHETIC, "invoke", getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), null, @@ -156,7 +156,7 @@ internal class GenericAsmBuilder( ) visitMethod( - ACC_PUBLIC, + ACC_PUBLIC or ACC_SYNTHETIC, "", getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), null, @@ -176,7 +176,7 @@ internal class GenericAsmBuilder( } label() - visitInsn(RETURN) + areturn(VOID_TYPE) val l4 = label() visitLocalVariable("this", classType.descriptor, null, l0, l4, 0) @@ -209,10 +209,10 @@ internal class GenericAsmBuilder( */ fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex - invokeMethodVisitor.load(0, classType) + load(0, classType) getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) iconst(idx) - visitInsn(AALOAD) + aload(OBJECT_TYPE) if (type != OBJECT_TYPE) checkcast(type) } @@ -320,6 +320,6 @@ internal class GenericAsmBuilder( /** * ASM type for array of [java.lang.Object]. */ - val OBJECT_ARRAY_TYPE: Type by lazy { getType("[Ljava/lang/Object;") } + val OBJECT_ARRAY_TYPE: Type = getType("[Ljava/lang/Object;") } } 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 3e019589a..bf1f42395 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 @@ -6,38 +6,49 @@ package space.kscience.kmath.asm.internal import org.objectweb.asm.ClassWriter -import org.objectweb.asm.Opcodes +import org.objectweb.asm.FieldVisitor +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.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.invoke +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 import java.nio.file.Paths import kotlin.io.path.writeBytes -internal sealed class PrimitiveAsmBuilder( - protected val algebra: Algebra, +@UnstableKMathAPI +internal sealed class PrimitiveAsmBuilder>( + protected val algebra: NumericAlgebra, classOfT: Class<*>, protected val classOfTPrimitive: Class<*>, + expressionParent: Class, protected val target: MST, ) : AsmBuilder() { private val className: String = buildName(target) /** - * ASM type for [T]. + * ASM type for [tType]. */ private val tType: Type = classOfT.asm /** - * ASM type for [T]. + * ASM type for [classOfTPrimitive]. */ protected val tTypePrimitive: Type = classOfTPrimitive.asm + /** + * ASM type for array of [classOfTPrimitive]. + */ + protected val tTypePrimitiveArray: Type = getType("[" + classOfTPrimitive.asm.descriptor) + + /** + * ASM type for expression parent. + */ + private val expressionParentType = expressionParent.asm + /** * ASM type for new class. */ @@ -49,58 +60,91 @@ internal sealed class PrimitiveAsmBuilder( protected lateinit var invokeMethodVisitor: InstructionAdapter /** - * Local variables indices are indices of symbols in this list. + * Indexer for arguments in [target]. */ - private val argumentsLocals = mutableListOf() + private val argumentsIndexer = mutableListOf() /** * Subclasses, loads and instantiates [Expression] for given parameters. * * The built instance is cached. */ - @Suppress("UNCHECKED_CAST", "UNUSED_VARIABLE") - val instance: Expression by lazy { + @Suppress("UNCHECKED_CAST") + val instance: E by lazy { val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { visit( - Opcodes.V1_8, - Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_SUPER, + V1_8, + ACC_PUBLIC or ACC_FINAL or ACC_SUPER, classType.internalName, - "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", + "${OBJECT_TYPE.descriptor}${expressionParentType.descriptor}", OBJECT_TYPE.internalName, - arrayOf(EXPRESSION_TYPE.internalName), + arrayOf(expressionParentType.internalName), ) + visitField( + access = ACC_PRIVATE or ACC_FINAL, + name = "indexer", + descriptor = SYMBOL_INDEXER_TYPE.descriptor, + signature = null, + value = null, + block = FieldVisitor::visitEnd, + ) visitMethod( - Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL, - "invoke", - getMethodDescriptor(tType, MAP_TYPE), - "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", + ACC_PUBLIC, + "getIndexer", + getMethodDescriptor(SYMBOL_INDEXER_TYPE), + null, null, ).instructionAdapter { - invokeMethodVisitor = this visitCode() - val preparingVariables = label() - visitVariables(target) - val expressionResult = label() - visitExpression(target) - box() - areturn(tType) + val start = label() + load(0, classType) + getfield(classType.internalName, "indexer", SYMBOL_INDEXER_TYPE.descriptor) + areturn(SYMBOL_INDEXER_TYPE) val end = label() visitLocalVariable( "this", classType.descriptor, null, - preparingVariables, + start, + end, + 0, + ) + + visitMaxs(0, 0) + visitEnd() + } + + visitMethod( + ACC_PUBLIC, + "invoke", + getMethodDescriptor(tTypePrimitive, tTypePrimitiveArray), + null, + null, + ).instructionAdapter { + invokeMethodVisitor = this + visitCode() + val start = label() + visitVariables(target, arrayMode = true) + visitExpression(target) + areturn(tTypePrimitive) + val end = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + start, end, 0, ) visitLocalVariable( "arguments", - MAP_TYPE.descriptor, - "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", - preparingVariables, + tTypePrimitiveArray.descriptor, + null, + start, end, 1, ) @@ -110,7 +154,45 @@ internal sealed class PrimitiveAsmBuilder( } visitMethod( - Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_BRIDGE or Opcodes.ACC_SYNTHETIC, + ACC_PUBLIC or ACC_FINAL, + "invoke", + getMethodDescriptor(tType, MAP_TYPE), + "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", + null, + ).instructionAdapter { + invokeMethodVisitor = this + visitCode() + val start = label() + visitVariables(target, arrayMode = false) + visitExpression(target) + box() + areturn(tType) + val end = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + start, + end, + 0, + ) + + visitLocalVariable( + "arguments", + MAP_TYPE.descriptor, + "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", + start, + end, + 1, + ) + + visitMaxs(0, 0) + visitEnd() + } + + visitMethod( + ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, "invoke", getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), null, @@ -138,21 +220,22 @@ internal sealed class PrimitiveAsmBuilder( } visitMethod( - Opcodes.ACC_PUBLIC, + ACC_PUBLIC or ACC_SYNTHETIC, "", - getMethodDescriptor(VOID_TYPE), + getMethodDescriptor(VOID_TYPE, SYMBOL_INDEXER_TYPE), null, null, ).instructionAdapter { val start = label() load(0, classType) invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) - label() load(0, classType) - label() - visitInsn(Opcodes.RETURN) + load(1, SYMBOL_INDEXER_TYPE) + putfield(classType.internalName, "indexer", SYMBOL_INDEXER_TYPE.descriptor) + areturn(VOID_TYPE) val end = label() visitLocalVariable("this", classType.descriptor, null, start, end, 0) + visitLocalVariable("indexer", SYMBOL_INDEXER_TYPE.descriptor, null, start, end, 1) visitMaxs(0, 0) visitEnd() } @@ -166,14 +249,16 @@ internal sealed class PrimitiveAsmBuilder( if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") Paths.get("${className.split('.').last()}.class").writeBytes(binary) - MethodHandles.publicLookup().findConstructor(cls, MethodType.methodType(Void.TYPE))() as Expression + MethodHandles + .publicLookup() + .findConstructor(cls, MethodType.methodType(Void.TYPE, SymbolIndexer::class.java)) + .invoke(SimpleSymbolIndexer(argumentsIndexer)) as E } /** - * Either loads a numeric constant [value] from the class's constants field or boxes a primitive - * constant from the constant pool. + * Loads a numeric constant [value] from the class's constants. */ - fun loadNumberConstant(value: Number) { + protected fun loadNumberConstant(value: Number) { when (tTypePrimitive) { BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) @@ -185,38 +270,50 @@ internal sealed class PrimitiveAsmBuilder( } /** - * Stores value variable [name] into a local. Should be called within [variablesPrepareCallback] before using - * [loadVariable]. + * Stores value variable [name] into a local. Should be called before using [loadVariable]. Should be called only + * once for a variable. */ - fun prepareVariable(name: String): Unit = invokeMethodVisitor.run { - if (name in argumentsLocals) return@run - load(1, MAP_TYPE) - aconst(name) + protected fun prepareVariable(name: Symbol, arrayMode: Boolean): Unit = invokeMethodVisitor.run { + var argumentIndex = argumentsIndexer.indexOf(name) - invokestatic( - MAP_INTRINSICS_TYPE.internalName, - "getOrFail", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), - false, - ) - - checkcast(tType) - var idx = argumentsLocals.indexOf(name) - - if (idx == -1) { - argumentsLocals += name - idx = argumentsLocals.lastIndex + if (argumentIndex == -1) { + argumentsIndexer += name + argumentIndex = argumentsIndexer.lastIndex } - unbox() - store(2 + idx, tTypePrimitive) + val localIndex = 2 + argumentIndex * tTypePrimitive.size + + if (arrayMode) { + load(1, tTypePrimitiveArray) + iconst(argumentIndex) + aload(tTypePrimitive) + store(localIndex, tTypePrimitive) + } else { + load(1, MAP_TYPE) + aconst(name.identity) + + invokestatic( + MAP_INTRINSICS_TYPE.internalName, + "getOrFail", + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), + false, + ) + + checkcast(tType) + unbox() + store(localIndex, tTypePrimitive) + } } /** * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored * with [prepareVariable] first. */ - fun loadVariable(name: String): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tTypePrimitive) + protected fun loadVariable(name: Symbol) { + val argumentIndex = argumentsIndexer.indexOf(name) + val localIndex = 2 + argumentIndex * tTypePrimitive.size + invokeMethodVisitor.load(localIndex, tTypePrimitive) + } private fun unbox() = invokeMethodVisitor.run { invokevirtual( @@ -231,102 +328,117 @@ internal sealed class PrimitiveAsmBuilder( invokestatic(tType.internalName, "valueOf", getMethodDescriptor(tType, tTypePrimitive), false) } - protected fun visitVariables(node: MST): Unit = when (node) { - is Symbol -> prepareVariable(node.identity) - is MST.Unary -> visitVariables(node.value) + private fun visitVariables( + node: MST, + arrayMode: Boolean, + alreadyLoaded: MutableList = mutableListOf() + ): Unit = when (node) { + is Symbol -> when (node) { + !in alreadyLoaded -> { + alreadyLoaded += node + prepareVariable(node, arrayMode) + } + else -> { + } + } + + is MST.Unary -> visitVariables(node.value, arrayMode, alreadyLoaded) is MST.Binary -> { - visitVariables(node.left) - visitVariables(node.right) + visitVariables(node.left, arrayMode, alreadyLoaded) + visitVariables(node.right, arrayMode, alreadyLoaded) } else -> Unit } - protected fun visitExpression(mst: MST): Unit = when (mst) { - is Symbol -> loadVariable(mst.identity) - is MST.Numeric -> loadNumberConstant(mst.value) + private fun visitExpression(node: MST): Unit = when (node) { + is Symbol -> { + val symbol = algebra.bindSymbolOrNull(node) - is MST.Unary -> when { - algebra is NumericAlgebra && mst.value is MST.Numeric -> { - loadNumberConstant( - MST.Numeric( - algebra.unaryOperationFunction(mst.operation)(algebra.number((mst.value as MST.Numeric).value)), - ).value, - ) - } - - else -> visitUnary(mst) + if (symbol != null) + loadNumberConstant(symbol) + else + loadVariable(node) } + is MST.Numeric -> loadNumberConstant(algebra.number(node.value)) + + is MST.Unary -> if (node.value is MST.Numeric) + loadNumberConstant( + algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as MST.Numeric).value)), + ) + else + visitUnary(node) + is MST.Binary -> when { - algebra is NumericAlgebra && mst.left is MST.Numeric && mst.right is MST.Numeric -> { - loadNumberConstant( - MST.Numeric( - algebra.binaryOperationFunction(mst.operation)( - algebra.number((mst.left as MST.Numeric).value), - algebra.number((mst.right as MST.Numeric).value), - ), - ).value, - ) - } + node.left is MST.Numeric && node.right is MST.Numeric -> loadNumberConstant( + algebra.binaryOperationFunction(node.operation)( + algebra.number((node.left as MST.Numeric).value), + algebra.number((node.right as MST.Numeric).value), + ), + ) - else -> visitBinary(mst) + else -> visitBinary(node) } } - protected open fun visitUnary(mst: MST.Unary) { - visitExpression(mst.value) - } + protected open fun visitUnary(node: MST.Unary) = visitExpression(node.value) - protected open fun visitBinary(mst: MST.Binary) { - visitExpression(mst.left) - visitExpression(mst.right) + protected open fun visitBinary(node: MST.Binary) { + visitExpression(node.left) + visitExpression(node.right) } protected companion object { /** * ASM type for [java.lang.Number]. */ - val NUMBER_TYPE: Type by lazy { getObjectType("java/lang/Number") } + val NUMBER_TYPE: Type = getObjectType("java/lang/Number") + + /** + * ASM type for [SymbolIndexer]. + */ + val SYMBOL_INDEXER_TYPE: Type = getObjectType("space/kscience/kmath/expressions/SymbolIndexer") } } -internal class DoubleAsmBuilder(target: MST) : - PrimitiveAsmBuilder(DoubleField, java.lang.Double::class.java, java.lang.Double.TYPE, target) { +@UnstableKMathAPI +internal class DoubleAsmBuilder(target: MST) : PrimitiveAsmBuilder( + DoubleField, + java.lang.Double::class.java, + java.lang.Double.TYPE, + DoubleExpression::class.java, + target, +) { - private fun buildUnaryJavaMathCall(name: String) { - invokeMethodVisitor.invokestatic( - MATH_TYPE.internalName, - name, - getMethodDescriptor(tTypePrimitive, tTypePrimitive), - false, - ) - } + private fun buildUnaryJavaMathCall(name: String) = invokeMethodVisitor.invokestatic( + MATH_TYPE.internalName, + name, + getMethodDescriptor(tTypePrimitive, tTypePrimitive), + false, + ) - private fun buildBinaryJavaMathCall(name: String) { - invokeMethodVisitor.invokestatic( - MATH_TYPE.internalName, - name, - getMethodDescriptor(tTypePrimitive, tTypePrimitive, tTypePrimitive), - false, - ) - } + @Suppress("SameParameterValue") + private fun buildBinaryJavaMathCall(name: String) = invokeMethodVisitor.invokestatic( + MATH_TYPE.internalName, + name, + getMethodDescriptor(tTypePrimitive, tTypePrimitive, tTypePrimitive), + false, + ) - private fun buildUnaryKotlinMathCall(name: String) { - invokeMethodVisitor.invokestatic( - MATH_KT_TYPE.internalName, - name, - getMethodDescriptor(tTypePrimitive, tTypePrimitive), - false, - ) - } + private fun buildUnaryKotlinMathCall(name: String) = invokeMethodVisitor.invokestatic( + MATH_KT_TYPE.internalName, + name, + getMethodDescriptor(tTypePrimitive, tTypePrimitive), + false, + ) - override fun visitUnary(mst: MST.Unary) { - super.visitUnary(mst) + override fun visitUnary(node: MST.Unary) { + super.visitUnary(node) - when (mst.operation) { - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DNEG) + when (node.operation) { + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(DNEG) GroupOps.PLUS_OPERATION -> Unit PowerOperations.SQRT_OPERATION -> buildUnaryJavaMathCall("sqrt") TrigonometricOperations.SIN_OPERATION -> buildUnaryJavaMathCall("sin") @@ -343,74 +455,86 @@ internal class DoubleAsmBuilder(target: MST) : ExponentialOperations.ATANH_OPERATION -> buildUnaryKotlinMathCall("atanh") ExponentialOperations.EXP_OPERATION -> buildUnaryJavaMathCall("exp") ExponentialOperations.LN_OPERATION -> buildUnaryJavaMathCall("log") - else -> super.visitUnary(mst) + else -> super.visitUnary(node) } } - override fun visitBinary(mst: MST.Binary) { - super.visitBinary(mst) + override fun visitBinary(node: MST.Binary) { + super.visitBinary(node) - when (mst.operation) { - GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DADD) - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DSUB) - RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DMUL) - FieldOps.DIV_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.DDIV) + when (node.operation) { + GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(DADD) + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(DSUB) + RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(DMUL) + FieldOps.DIV_OPERATION -> invokeMethodVisitor.visitInsn(DDIV) PowerOperations.POW_OPERATION -> buildBinaryJavaMathCall("pow") - else -> super.visitBinary(mst) + else -> super.visitBinary(node) } } - companion object { - val MATH_TYPE: Type by lazy { getObjectType("java/lang/Math") } - val MATH_KT_TYPE: Type by lazy { getObjectType("kotlin/math/MathKt") } + private companion object { + val MATH_TYPE: Type = getObjectType("java/lang/Math") + val MATH_KT_TYPE: Type = getObjectType("kotlin/math/MathKt") } } +@UnstableKMathAPI internal class IntAsmBuilder(target: MST) : - PrimitiveAsmBuilder(IntRing, Integer::class.java, Integer.TYPE, target) { - override fun visitUnary(mst: MST.Unary) { - super.visitUnary(mst) + PrimitiveAsmBuilder( + IntRing, + Integer::class.java, + Integer.TYPE, + IntExpression::class.java, + target + ) { + override fun visitUnary(node: MST.Unary) { + super.visitUnary(node) - when (mst.operation) { - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.INEG) + when (node.operation) { + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(INEG) GroupOps.PLUS_OPERATION -> Unit - else -> super.visitUnary(mst) + else -> super.visitUnary(node) } } - override fun visitBinary(mst: MST.Binary) { - super.visitBinary(mst) + override fun visitBinary(node: MST.Binary) { + super.visitBinary(node) - when (mst.operation) { - GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.IADD) - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.ISUB) - RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.IMUL) - else -> super.visitBinary(mst) + when (node.operation) { + GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(IADD) + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(ISUB) + RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(IMUL) + else -> super.visitBinary(node) } } } -internal class LongAsmBuilder(target: MST) : - PrimitiveAsmBuilder(LongRing, java.lang.Long::class.java, java.lang.Long.TYPE, target) { - override fun visitUnary(mst: MST.Unary) { - super.visitUnary(mst) +@UnstableKMathAPI +internal class LongAsmBuilder(target: MST) : PrimitiveAsmBuilder( + LongRing, + java.lang.Long::class.java, + java.lang.Long.TYPE, + LongExpression::class.java, + target, +) { + override fun visitUnary(node: MST.Unary) { + super.visitUnary(node) - when (mst.operation) { - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.LNEG) + when (node.operation) { + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(LNEG) GroupOps.PLUS_OPERATION -> Unit - else -> super.visitUnary(mst) + else -> super.visitUnary(node) } } - override fun visitBinary(mst: MST.Binary) { - super.visitBinary(mst) + override fun visitBinary(node: MST.Binary) { + super.visitBinary(node) - when (mst.operation) { - GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.LADD) - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.LSUB) - RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(Opcodes.LMUL) - else -> super.visitBinary(mst) + when (node.operation) { + GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(LADD) + GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(LSUB) + RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(LMUL) + else -> super.visitBinary(node) } } } - diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 490868a0b..4a35a54fb 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -8,7 +8,10 @@ plugins { kotlin.sourceSets { filter { it.name.contains("test", true) } .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) - .forEach { it.optIn("space.kscience.kmath.misc.PerformancePitfall") } + .forEach { + it.optIn("space.kscience.kmath.misc.PerformancePitfall") + it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") + } commonMain { dependencies { 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 33f53202c..5ba32f190 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,6 +5,7 @@ package space.kscience.kmath.expressions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Algebra import kotlin.jvm.JvmName import kotlin.properties.ReadOnlyProperty @@ -24,6 +25,81 @@ public fun interface Expression { public operator fun invoke(arguments: Map): T } +/** + * Specialization of [Expression] for [Double] allowing better performance because of using array. + */ +@UnstableKMathAPI +public interface DoubleExpression : Expression { + /** + * The indexer of this expression's arguments that should be used to build array for [invoke]. + * + * Implementations must fulfil the following requirement: for any argument symbol `x` and its value `y`, + * `indexer.indexOf(x) == arguments.indexOf(y)` if `arguments` is the array passed to [invoke]. + */ + public val indexer: SymbolIndexer + + public override operator fun invoke(arguments: Map): Double = + this(DoubleArray(indexer.symbols.size) { arguments.getValue(indexer.symbols[it]) }) + + /** + * Calls this expression from arguments. + * + * @param arguments the array of arguments. + * @return the value. + */ + public operator fun invoke(arguments: DoubleArray): Double +} + +/** + * Specialization of [Expression] for [Int] allowing better performance because of using array. + */ +@UnstableKMathAPI +public interface IntExpression : Expression { + /** + * The indexer of this expression's arguments that should be used to build array for [invoke]. + * + * Implementations must fulfil the following requirement: for any argument symbol `x` and its value `y`, + * `indexer.indexOf(x) == arguments.indexOf(y)` if `arguments` is the array passed to [invoke]. + */ + public val indexer: SymbolIndexer + + public override operator fun invoke(arguments: Map): Int = + this(IntArray(indexer.symbols.size) { arguments.getValue(indexer.symbols[it]) }) + + /** + * Calls this expression from arguments. + * + * @param arguments the array of arguments. + * @return the value. + */ + public operator fun invoke(arguments: IntArray): Int +} + +/** + * Specialization of [Expression] for [Long] allowing better performance because of using array. + */ +@UnstableKMathAPI +public interface LongExpression : Expression { + /** + * The indexer of this expression's arguments that should be used to build array for [invoke]. + * + * Implementations must fulfil the following requirement: for any argument symbol `x` and its value `y`, + * `indexer.indexOf(x) == arguments.indexOf(y)` if `arguments` is the array passed to [invoke]. + */ + public val indexer: SymbolIndexer + + public override operator fun invoke(arguments: Map): Long = + this(LongArray(indexer.symbols.size) { arguments.getValue(indexer.symbols[it]) }) + + /** + * Calls this expression from arguments. + * + * @param arguments the array of arguments. + * @return the value. + */ + public operator fun invoke(arguments: LongArray): Long +} + /** * Calls this expression without providing any arguments. * @@ -69,6 +145,62 @@ public operator fun Expression.invoke(vararg pairs: Pair): T = } ) +private val EMPTY_DOUBLE_ARRAY = DoubleArray(0) + +/** + * Calls this expression without providing any arguments. + * + * @return a value. + */ +@UnstableKMathAPI +public operator fun DoubleExpression.invoke(): Double = this(EMPTY_DOUBLE_ARRAY) + +/** + * Calls this expression from arguments. + * + * @param pairs the pairs of arguments to values. + * @return a value. + */ +@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) + +/** + * Calls this expression from arguments. + * + * @param pairs the pairs of arguments to values. + * @return a value. + */ +@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) + +/** + * Calls this expression from arguments. + * + * @param pairs the pairs of arguments to values. + * @return a value. + */ +@UnstableKMathAPI +public operator fun LongExpression.invoke(vararg arguments: Long): Long = this(arguments) /** * A context for expression construction diff --git a/kmath-kotlingrad/build.gradle.kts b/kmath-kotlingrad/build.gradle.kts index d222ed7d6..da7380e41 100644 --- a/kmath-kotlingrad/build.gradle.kts +++ b/kmath-kotlingrad/build.gradle.kts @@ -3,6 +3,11 @@ plugins { id("ru.mipt.npm.gradle.common") } +kotlin.sourceSets + .filter { it.name.contains("test", true) } + .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) + .forEach { it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") } + description = "Kotlin∇ integration module" dependencies { diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt index 6e7eb039d..63db1c56f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt @@ -145,7 +145,7 @@ internal object InternalGamma { } when { - n >= maxIterations -> throw error("Maximal iterations is exceeded $maxIterations") + n >= maxIterations -> error("Maximal iterations is exceeded $maxIterations") sum.isInfinite() -> 1.0 else -> exp(-x + a * ln(x) - logGamma(a)) * sum } -- 2.34.1 From cf5f886226a334897cd2ea04baee0861e4f08eca Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Mon, 29 Nov 2021 13:24:44 +0700 Subject: [PATCH 072/102] Rewrite the ArithmeticsEvaluator.number rule to handle well both floating-point numbers and integers --- .../kotlin/space/kscience/kmath/ast/parser.kt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt index 6ebd0eff6..012a6e65f 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt @@ -22,6 +22,7 @@ import space.kscience.kmath.operations.FieldOps import space.kscience.kmath.operations.GroupOps import space.kscience.kmath.operations.PowerOperations import space.kscience.kmath.operations.RingOps +import kotlin.math.floor /** * better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4. @@ -40,9 +41,22 @@ public object ArithmeticsEvaluator : Grammar() { private val div: Token by literalToken("/") private val minus: Token by literalToken("-") private val plus: Token by literalToken("+") + + @Suppress("unused") private val ws: Token by regexToken("\\s+".toRegex(), ignore = true) - private val number: Parser by num use { MST.Numeric(text.toDouble()) } + // TODO Rewrite as custom parser to handle numbers with better precision. Currently, numbers like 1e10 are handled while they could be stored as longs without precision loss. + private val number: Parser by num use { + val d = text.toDoubleOrNull() + + MST.Numeric( + if (d == null || d == floor(d) && !d.isInfinite()) { + text.toLongOrNull() ?: text.toDouble() + } else + d + ) + } + private val singular: Parser by id use { Symbol(text) } private val unaryFunction: Parser by (id and -lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) @@ -91,7 +105,8 @@ public object ArithmeticsEvaluator : Grammar() { } /** - * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or error. + * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or + * error. * * @receiver the string to parse. * @return the [MST] node. -- 2.34.1 From a9779fe38bfbda750384fb9cea456864d8468ccc Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 7 Dec 2021 12:00:31 +0700 Subject: [PATCH 073/102] Do numeric type conversion in JS MST compilers --- .../jsMain/kotlin/space/kscience/kmath/estree/estree.kt | 7 +++++-- .../space/kscience/kmath/wasm/internal/WasmBuilder.kt | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) 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 0c15e994c..a6b6e022b 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 @@ -28,11 +28,14 @@ internal fun MST.compileWith(algebra: Algebra): Expression { variable(node.identity) } - is Numeric -> constant(node.value) + is Numeric -> constant( + (algebra as? NumericAlgebra)?.number(node.value) ?: error("Numeric nodes are not supported by $this") + ) is Unary -> when { algebra is NumericAlgebra && node.value is Numeric -> constant( - algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) + algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)) + ) else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) } 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 2d6619bba..96090a633 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 @@ -114,7 +114,7 @@ internal class DoubleWasmBuilder(target: MST) : WasmBuilder ctx.f64.neg(visit(node.value)) @@ -157,7 +157,7 @@ internal class IntWasmBuilder(target: MST) : WasmBuilder(i32 } } - override fun visitNumeric(node: Numeric) = ctx.i32.const(node.value) + override fun visitNumeric(node: Numeric) = ctx.i32.const(node.value.toInt()) override fun visitUnary(node: Unary): ExpressionRef = when (node.operation) { GroupOps.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(node.value)) -- 2.34.1 From e11df4fdd5597e352eb558ea1aaa5071461e931a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 18 Dec 2021 21:57:06 +0300 Subject: [PATCH 074/102] Add inline to histogram builders --- .../space/kscience/kmath/histogram/UnivariateHistogram.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt index d5b74fb9b..91d0516c2 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt @@ -42,7 +42,7 @@ public interface UnivariateHistogram : Histogram { /** * Build and fill a [UnivariateHistogram]. Returns a read-only histogram. */ - public fun uniform( + public inline fun uniform( binSize: Double, start: Double = 0.0, builder: UnivariateHistogramBuilder.() -> Unit, @@ -51,7 +51,7 @@ public interface UnivariateHistogram : Histogram { /** * Build and fill a histogram with custom borders. Returns a read-only histogram. */ - public fun custom( + public inline fun custom( borders: DoubleArray, builder: UnivariateHistogramBuilder.() -> Unit, ): UnivariateHistogram = TreeHistogramSpace.custom(borders).fill(builder) -- 2.34.1 From 6255a46004bc628598fc7c1fd2043d6ebc0a1129 Mon Sep 17 00:00:00 2001 From: breandan Date: Sat, 25 Dec 2021 12:05:42 -0500 Subject: [PATCH 075/102] =?UTF-8?q?update=20Kotlin=E2=88=87=20and=20remove?= =?UTF-8?q?=20old=20maven=20repositories?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- benchmarks/build.gradle.kts | 6 ------ build.gradle.kts | 7 ------- examples/build.gradle.kts | 5 ----- kmath-kotlingrad/build.gradle.kts | 4 ++-- .../space/kscience/kmath/kotlingrad/KMathNumber.kt | 2 +- .../kmath/kotlingrad/KotlingradExpression.kt | 4 ++-- .../kscience/kmath/kotlingrad/scalarsAdapters.kt | 2 +- .../kscience/kmath/kotlingrad/AdaptingTests.kt | 14 +++++++------- 8 files changed, 13 insertions(+), 31 deletions(-) diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index cca3d312d..a6355e425 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -14,12 +14,6 @@ sourceSets.register("benchmarks") repositories { mavenCentral() maven("https://repo.kotlin.link") - maven("https://clojars.org/repo") - maven("https://jitpack.io") - - maven("http://logicrunch.research.it.uu.se/maven") { - isAllowInsecureProtocol = true - } } kotlin { diff --git a/build.gradle.kts b/build.gradle.kts index c2347f7be..cc5a5f5c1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,13 +7,6 @@ plugins { allprojects { repositories { - maven("https://clojars.org/repo") - maven("https://jitpack.io") - - maven("http://logicrunch.research.it.uu.se/maven") { - isAllowInsecureProtocol = true - } - maven("https://oss.sonatype.org/content/repositories/snapshots") mavenCentral() } diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 7b1bce26a..e0e38bad0 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -5,12 +5,7 @@ plugins { repositories { mavenCentral() maven("https://repo.kotlin.link") - maven("https://clojars.org/repo") - maven("https://jitpack.io") maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers") - maven("http://logicrunch.research.it.uu.se/maven") { - isAllowInsecureProtocol = true - } } dependencies { diff --git a/kmath-kotlingrad/build.gradle.kts b/kmath-kotlingrad/build.gradle.kts index d222ed7d6..c10a6af54 100644 --- a/kmath-kotlingrad/build.gradle.kts +++ b/kmath-kotlingrad/build.gradle.kts @@ -6,8 +6,8 @@ plugins { description = "Kotlin∇ integration module" dependencies { - api("com.github.breandan:kaliningraph:0.1.6") - api("com.github.breandan:kotlingrad:0.4.5") + api("ai.hypergraph:kaliningraph:0.1.9") + api("ai.hypergraph:kotlingrad:0.4.7") api(project(":kmath-core")) testImplementation(project(":kmath-ast")) } diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt index 0f10c6cdd..a61743a1b 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.kotlingrad -import edu.umontreal.kotlingrad.api.SConst +import ai.hypergraph.kotlingrad.api.SConst import space.kscience.kmath.operations.NumericAlgebra /** diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt index 84171101f..9187f35ae 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.kotlingrad -import edu.umontreal.kotlingrad.api.SFun -import edu.umontreal.kotlingrad.api.SVar +import ai.hypergraph.kotlingrad.api.SFun +import ai.hypergraph.kotlingrad.api.SVar import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.NumericAlgebra diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt index 11e5853a8..a0622b6ff 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.kotlingrad -import edu.umontreal.kotlingrad.api.* +import ai.hypergraph.kotlingrad.api.* import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.MstExtendedField import space.kscience.kmath.expressions.MstExtendedField.unaryMinus diff --git a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt index 67332a680..2937b5e9c 100644 --- a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt +++ b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.kotlingrad -import edu.umontreal.kotlingrad.api.* +import ai.hypergraph.kotlingrad.api.* import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.ast.parseMath import space.kscience.kmath.expressions.MstNumericAlgebra @@ -22,7 +22,7 @@ internal class AdaptingTests { fun symbol() { assertEquals(x.identity, x.toSVar>().name) val c2 = "kitten".parseMath().toSFun>() - if (c2 is SVar) assertTrue(c2.name == "kitten") else fail() + if (c2 is SVar<*>) assertTrue(c2.name == "kitten") else fail() } @Test @@ -30,17 +30,17 @@ internal class AdaptingTests { val c1 = MstNumericAlgebra.number(12354324) assertTrue(c1.toSConst().doubleValue == 12354324.0) val c2 = "0.234".parseMath().toSFun>() - if (c2 is SConst) assertTrue(c2.doubleValue == 0.234) else fail() + if (c2 is SConst<*>) assertTrue(c2.doubleValue == 0.234) else fail() val c3 = "1e-3".parseMath().toSFun>() - if (c3 is SConst) assertEquals(0.001, c3.value) else fail() + if (c3 is SConst<*>) assertEquals(0.001, c3.value) else fail() } @Test fun simpleFunctionShape() { val linear = "2*x+16".parseMath().toSFun>() - if (linear !is Sum) fail() - if (linear.left !is Prod) fail() - if (linear.right !is SConst) fail() + if (linear !is Sum<*>) fail() + if (linear.left !is Prod<*>) fail() + if (linear.right !is SConst<*>) fail() } @Test -- 2.34.1 From 2f96d619fc0a19e222a21b8ef742a6b4e14c4176 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 29 Dec 2021 20:08:26 +0300 Subject: [PATCH 076/102] Fix AST JS test --- .../kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt index 859e56032..93ef97b0f 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt @@ -19,8 +19,8 @@ import kotlin.test.assertFailsWith internal class TestCompilerVariables { @Test fun testNoVariables() = runCompilerTest { - val expr = "0".parseMath().compileToExpression(IntRing) - assertEquals(0, expr()) + val expr = "0".parseMath().compileToExpression(DoubleField) + assertEquals(0.0, expr(), 0.0001) } @Test -- 2.34.1 From 479d10616523af705219c899071810af4f921571 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 30 Dec 2021 18:50:47 +0300 Subject: [PATCH 077/102] install Kover plugin --- build.gradle.kts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 36bc3a73f..1da8f5d64 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,6 @@ -import java.net.URL - plugins { id("ru.mipt.npm.gradle.project") - kotlin("jupyter.api") apply false + id("org.jetbrains.kotlinx.kover") version "0.5.0-RC" } allprojects { @@ -32,7 +30,7 @@ subprojects { localDirectory.set(kotlinDir) remoteUrl.set( - URL("https://github.com/mipt-npm/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath") + java.net.URL("https://github.com/mipt-npm/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath") ) } -- 2.34.1 From dd8a4796f6494dbe99ec180b722610dd7f309e2a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Jan 2022 13:15:50 +0300 Subject: [PATCH 078/102] Update gradle plugin and build consistency --- build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 20 ++++++++++++---- buildSrc/gradle.properties | 14 +++++++++++ buildSrc/settings.gradle.kts | 24 +++++++++++++++++++ .../benchmarks/addBenchmarkProperties.kt | 13 ++++++---- .../kscience/kmath/stat/DistributionDemo.kt | 6 ++--- gradle.properties | 6 ++--- gradle/wrapper/gradle-wrapper.properties | 2 +- .../space/kscience/kmath/chains/Chain.kt | 15 +++++++----- .../space/kscience/kmath/stat/Sampler.kt | 9 ++++--- .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 2 +- settings.gradle.kts | 23 ++++++++++-------- 12 files changed, 97 insertions(+), 39 deletions(-) create mode 100644 buildSrc/gradle.properties create mode 100644 buildSrc/settings.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts index 1da8f5d64..b0797d397 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -55,7 +55,7 @@ subprojects { readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") ksciencePublish { - github("kmath", publish = false) + github("kmath") space() sonatype() } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 072309332..a7bf5c326 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,20 +1,30 @@ plugins { `kotlin-dsl` - kotlin("plugin.serialization") version "1.5.21" + `version-catalog` + alias(npmlibs.plugins.kotlin.plugin.serialization) } +java.targetCompatibility = JavaVersion.VERSION_11 + repositories { maven("https://repo.kotlin.link") mavenCentral() gradlePluginPortal() } +val toolsVersion: String by extra +val kotlinVersion = npmlibs.versions.kotlin.asProvider().get() +val benchmarksVersion = npmlibs.versions.kotlinx.benchmark.get() + dependencies { - api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2") - api("ru.mipt.npm:gradle-tools:0.10.7") - api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.3.1") + api("ru.mipt.npm:gradle-tools:$toolsVersion") + //plugins form benchmarks + api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion") + api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") + //to be used inside build-script only + implementation(npmlibs.kotlinx.serialization.json) } kotlin.sourceSets.all { - languageSettings.useExperimentalAnnotation("kotlin.ExperimentalStdlibApi") + languageSettings.optIn("kotlin.OptIn") } diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties new file mode 100644 index 000000000..6678f24a8 --- /dev/null +++ b/buildSrc/gradle.properties @@ -0,0 +1,14 @@ +# +# Copyright 2018-2021 KMath contributors. +# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. +# + +kotlin.code.style=official +kotlin.mpp.stability.nowarn=true + +kotlin.jupyter.add.scanner=false + +org.gradle.configureondemand=true +org.gradle.parallel=true + +toolsVersion=0.10.9-kotlin-1.6.10 diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 000000000..87ff205f6 --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1,24 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + + +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") +enableFeaturePreview("VERSION_CATALOGS") + +dependencyResolutionManagement { + + val toolsVersion: String by extra + + repositories { + maven("https://repo.kotlin.link") + mavenCentral() + } + + versionCatalogs { + create("npmlibs") { + from("ru.mipt.npm:version-catalog:$toolsVersion") + } + } +} 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 ca1c330a1..dc9327348 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -6,12 +6,15 @@ package space.kscience.kmath.benchmarks import kotlinx.benchmark.gradle.BenchmarksExtension -import kotlinx.serialization.* -import kotlinx.serialization.json.* +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json import org.gradle.api.Project import ru.mipt.npm.gradle.KScienceReadmeExtension -import java.time.* -import java.time.format.* +import java.time.LocalDateTime +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeFormatterBuilder +import java.time.format.SignStyle import java.time.temporal.ChronoField.* private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run { @@ -47,7 +50,7 @@ fun Project.addBenchmarkProperties() { rootProject.subprojects.forEach { p -> p.extensions.findByType(KScienceReadmeExtension::class.java)?.run { benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> - property("benchmark${cfg.name.replaceFirstChar(Char::uppercase)}") { + property("benchmark${cfg.name.capitalize()}") { val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}") val resDirectory = launches.listFiles()?.maxByOrNull { diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt index bde83cea9..15654971f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.stat import kotlinx.coroutines.runBlocking import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.collectWithState +import space.kscience.kmath.chains.combineWithState import space.kscience.kmath.distributions.NormalDistribution private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0) @@ -15,11 +15,11 @@ private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0 /** * Averaging. */ -private fun Chain.mean(): Chain = collectWithState(AveragingChainState(), { it.copy() }) { chain -> +private fun Chain.mean(): Chain = combineWithState(AveragingChainState(), { it.copy() }) { chain -> val next = chain.next() num++ value += next - return@collectWithState value / num + return@combineWithState value / num } diff --git a/gradle.properties b/gradle.properties index 959511c68..6678f24a8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,11 +6,9 @@ kotlin.code.style=official kotlin.mpp.stability.nowarn=true -#kotlin.mpp.enableGranularSourceSetsMetadata=true -#kotlin.native.enableDependencyPropagation=false - kotlin.jupyter.add.scanner=false org.gradle.configureondemand=true -org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G org.gradle.parallel=true + +toolsVersion=0.10.9-kotlin-1.6.10 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ffed3a254..2e6e5897b 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.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists 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 f8d2549e5..994255e38 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,6 +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 /** * A not-necessary-Markov chain of some type @@ -124,20 +125,22 @@ public fun Chain.filter(block: (T) -> Boolean): Chain = object : Chain /** * Map the whole chain */ -public fun Chain.collect(mapper: suspend (Chain) -> R): Chain = object : Chain { - override suspend fun next(): R = mapper(this@collect) - override suspend fun fork(): Chain = this@collect.fork().collect(mapper) +@UnstableKMathAPI +public fun Chain.combine(mapper: suspend (Chain) -> R): Chain = object : Chain { + override suspend fun next(): R = mapper(this@combine) + override suspend fun fork(): Chain = this@combine.fork().combine(mapper) } -public fun Chain.collectWithState( +@UnstableKMathAPI +public fun Chain.combineWithState( state: S, stateFork: (S) -> S, mapper: suspend S.(Chain) -> R, ): Chain = object : Chain { - override suspend fun next(): R = state.mapper(this@collectWithState) + override suspend fun next(): R = state.mapper(this@combineWithState) override suspend fun fork(): Chain = - this@collectWithState.fork().collectWithState(stateFork(state), stateFork, mapper) + this@combineWithState.fork().combineWithState(stateFork(state), stateFork, mapper) } /** diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index 4c11fdd65..0dd121f3b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -7,8 +7,11 @@ package space.kscience.kmath.stat import kotlinx.coroutines.flow.first import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.collect -import space.kscience.kmath.structures.* +import space.kscience.kmath.chains.combine +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferFactory +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.IntBuffer import kotlin.jvm.JvmName /** @@ -36,7 +39,7 @@ public fun Sampler.sampleBuffer( //creating temporary storage once val tmp = ArrayList(size) - return sample(generator).collect { chain -> + return sample(generator).combine { chain -> //clear list from previous run tmp.clear() //Fill list 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 ef7702014..dc0f1f97c 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 @@ -14,7 +14,7 @@ import space.kscience.kmath.operations.ExtendedFieldOps import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.PowerOperations -@OptIn(UnstableKMathAPI::class) +@OptIn(UnstableKMathAPI::class, PerformancePitfall::class) @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public open class ViktorFieldOpsND : FieldOpsND, diff --git a/settings.gradle.kts b/settings.gradle.kts index 343e937e1..7108b0cb4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,21 +1,24 @@ -pluginManagement { +rootProject.name = "kmath" + +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") +enableFeaturePreview("VERSION_CATALOGS") + +dependencyResolutionManagement { + + val toolsVersion: String by extra + repositories { maven("https://repo.kotlin.link") mavenCentral() - gradlePluginPortal() } - val kotlinVersion = "1.6.0" - - plugins { - id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - kotlin("multiplatform") version kotlinVersion - kotlin("plugin.allopen") version kotlinVersion + versionCatalogs { + create("npmlibs") { + from("ru.mipt.npm:version-catalog:$toolsVersion") + } } } -rootProject.name = "kmath" - include( ":kmath-memory", ":kmath-complex", -- 2.34.1 From 91d93b3bb2e319b66f1011ded39ad089bedf4fe5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 4 Jan 2022 19:45:24 +0300 Subject: [PATCH 079/102] restore metaspace --- build.gradle.kts | 2 +- gradle.properties | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index b0797d397..1b2d9d7c0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ allprojects { subprojects { if (name.startsWith("kmath")) apply() - afterEvaluate { + plugins.withId("org.jetbrains.dokka"){ tasks.withType { dependsOn(tasks["assemble"]) diff --git a/gradle.properties b/gradle.properties index 6678f24a8..130d294a2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,5 +10,6 @@ kotlin.jupyter.add.scanner=false org.gradle.configureondemand=true org.gradle.parallel=true +org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G toolsVersion=0.10.9-kotlin-1.6.10 -- 2.34.1 From d10815020da286b3400c8e9d19846e900423a759 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 25 Jan 2022 23:02:35 +0700 Subject: [PATCH 080/102] JS benchmarking --- benchmarks/build.gradle.kts | 24 +- .../ExpressionsInterpretersBenchmark.kt | 105 + buildSrc/build.gradle.kts | 2 +- .../kscience/kmath/ast/TestExecutionTime.kt | 114 - kotlin-js-store/yarn.lock | 2059 +++++++++++++++++ 5 files changed, 2183 insertions(+), 121 deletions(-) create mode 100644 benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt delete mode 100644 kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt create mode 100644 kotlin-js-store/yarn.lock diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index aa3d31247..3dc221bae 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -13,13 +13,22 @@ sourceSets.register("benchmarks") repositories { mavenCentral() - maven("https://repo.kotlin.link") } kotlin { jvm() + js(IR) { + nodejs() + } + sourceSets { + all { + languageSettings { + progressiveMode = true + } + } + val commonMain by getting { dependencies { implementation(project(":kmath-ast")) @@ -29,9 +38,8 @@ kotlin { implementation(project(":kmath-stat")) implementation(project(":kmath-dimensions")) implementation(project(":kmath-for-real")) - implementation(project(":kmath-jafama")) implementation(project(":kmath-tensors")) - implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.1") + implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.4.2") } } @@ -42,6 +50,7 @@ kotlin { implementation(project(":kmath-nd4j")) implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-viktor")) + implementation(project(":kmath-jafama")) implementation(project(":kmath-multik")) implementation("org.nd4j:nd4j-native:1.0.0-M1") // uncomment if your system supports AVX2 @@ -63,6 +72,7 @@ benchmark { // Setup configurations targets { register("jvm") + register("js") } fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() { @@ -88,7 +98,11 @@ benchmark { } configurations.register("expressions") { - commonConfiguration() + // Some extra precision + warmups = 2 + iterations = 10 + iterationTime = 2000 + iterationTimeUnit = "ms" include("ExpressionsInterpretersBenchmark") } @@ -125,7 +139,6 @@ afterEvaluate { } } - kotlin.sourceSets.all { with(languageSettings) { optIn("kotlin.contracts.ExperimentalContracts") @@ -141,7 +154,6 @@ tasks.withType { } } - readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL } diff --git a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt new file mode 100644 index 000000000..126a2e648 --- /dev/null +++ b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State +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 +import kotlin.math.sin +import kotlin.random.Random +import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression +import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression + +@State(Scope.Benchmark) +class ExpressionsInterpretersBenchmark { + /** + * Benchmark case for [Expression] created with [expressionInExtendedField]. + */ + @Benchmark + fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, blackhole) + + /** + * Benchmark case for [Expression] created with [toExpression]. + */ + @Benchmark + fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, blackhole) + + /** + * Benchmark case for [Expression] created with [compileToExpression]. + */ + @Benchmark + fun wasmExpression(blackhole: Blackhole) = invokeAndSum(wasm, blackhole) + + /** + * Benchmark case for [Expression] created with [compileToExpression]. + */ + @Benchmark + fun estreeExpression(blackhole: Blackhole) = invokeAndSum(estree, blackhole) + + /** + * Benchmark case for [Expression] implemented manually with `kotlin.math` functions. + */ + @Benchmark + fun rawExpression(blackhole: Blackhole) = invokeAndSum(raw, blackhole) + + /** + * Benchmark case for direct computation w/o [Expression]. + */ + @Benchmark + fun justCalculate(blackhole: Blackhole) { + val random = Random(0) + var sum = 0.0 + + repeat(times) { + val x = random.nextDouble() + sum += x * 2.0 + 2.0 / x - 16.0 / sin(x) + } + + blackhole.consume(sum) + } + + private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { + val random = Random(0) + var sum = 0.0 + val m = HashMap() + + repeat(times) { + m[x] = random.nextDouble() + sum += expr(m) + } + + blackhole.consume(sum) + } + + private companion object { + private val x by symbol + private const val times = 1_000_000 + + private val functional = DoubleField.expression { + val x = bindSymbol(Symbol.x) + x * number(2.0) + 2.0 / x - 16.0 / sin(x) + } + + private val node = MstExtendedField { + x * 2.0 + number(2.0) / x - number(16.0) / sin(x) + } + + private val mst = node.toExpression(DoubleField) + private val wasm = node.wasmCompileToExpression(DoubleField) + private val estree = node.estreeCompileToExpression(DoubleField) + + private val raw = Expression { args -> + val x = args[x]!! + x * 2.0 + 2.0 / x - 16.0 / sin(x) + } + } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index a7bf5c326..ceb220bd5 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -14,7 +14,7 @@ repositories { val toolsVersion: String by extra val kotlinVersion = npmlibs.versions.kotlin.asProvider().get() -val benchmarksVersion = npmlibs.versions.kotlinx.benchmark.get() +val benchmarksVersion = "0.4.2" dependencies { api("ru.mipt.npm:gradle-tools:$toolsVersion") diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt deleted file mode 100644 index 8cfa3a87e..000000000 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.bindSymbol -import space.kscience.kmath.operations.invoke -import kotlin.math.sin -import kotlin.random.Random -import kotlin.test.Ignore -import kotlin.test.Test -import kotlin.time.measureTime -import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression -import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression - -// TODO move to benchmarks when https://github.com/Kotlin/kotlinx-benchmark/pull/38 or similar feature is merged -@Ignore -internal class TestExecutionTime { - private companion object { - private const val times = 1_000_000 - private val x by symbol - private val algebra = DoubleField - - private val functional = algebra.expressionInExtendedField { - bindSymbol(x) * const(2.0) + const(2.0) / bindSymbol(x) - const(16.0) / sin(bindSymbol(x)) - } - - private val node = MstExtendedField { - x * number(2.0) + number(2.0) / x - number(16.0) / sin(x) - } - - private val mst = node.toExpression(algebra) - private val wasm = node.wasmCompileToExpression(algebra) - private val estree = node.estreeCompileToExpression(algebra) - - // In JavaScript, the expression below is implemented like - // _no_name_provided__125.prototype.invoke_178 = function (args) { - // var tmp = getValue(args, raw$_get_x__3(this._$x$delegate_2)) * 2.0 + 2.0 / getValue(args, raw$_get_x__3(this._$x$delegate_2)); - // var tmp0_sin_0_5 = getValue(args, raw$_get_x__3(this._$x$delegate_2)); - // return tmp - 16.0 / Math.sin(tmp0_sin_0_5); - // }; - - private val raw = Expression { args -> - val x = args[x]!! - algebra { x * 2.0 + 2.0 / x - 16.0 / sin(x) } - } - - private val justCalculate = { args: dynamic -> - val x = args[x].unsafeCast() - x * 2.0 + 2.0 / x - 16.0 / sin(x) - } - } - - private fun invokeAndSum(name: String, expr: Expression) { - println(name) - val rng = Random(0) - var sum = 0.0 - measureTime { - repeat(times) { sum += expr(x to rng.nextDouble()) } - }.also(::println) - } - - /** - * [Expression] created with [expressionInExtendedField]. - */ - @Test - fun functionalExpression() = invokeAndSum("functional", functional) - - /** - * [Expression] created with [mstExpression]. - */ - @Test - fun mstExpression() = invokeAndSum("mst", mst) - - /** - * [Expression] created with [wasmCompileToExpression]. - */ - @Test - fun wasmExpression() = invokeAndSum("wasm", wasm) - - /** - * [Expression] created with [estreeCompileToExpression]. - */ - @Test - fun estreeExpression() = invokeAndSum("estree", wasm) - - /** - * [Expression] implemented manually with `kotlin.math`. - */ - @Test - fun rawExpression() = invokeAndSum("raw", raw) - - /** - * Direct computation w/o [Expression]. - */ - @Test - fun justCalculateExpression() { - println("justCalculate") - val rng = Random(0) - var sum = 0.0 - measureTime { - repeat(times) { - val arg = rng.nextDouble() - val o = js("{}") - o["x"] = arg - sum += justCalculate(o) - } - }.also(::println) - } -} diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock new file mode 100644 index 000000000..e21abe604 --- /dev/null +++ b/kotlin-js-store/yarn.lock @@ -0,0 +1,2059 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.6" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz#d5e0706cf8c6acd8c6032f8d54070af261bbbb2f" + integrity sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA== + +"@types/component-emitter@^1.2.10": + version "1.2.11" + resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506" + integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ== + +"@types/cookie@^0.4.0": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cors@^2.8.8": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== + +"@types/eslint-scope@^3.7.0": + version "3.7.3" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" + integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.4.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.1.tgz#c48251553e8759db9e656de3efc846954ac32304" + integrity sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== + +"@types/json-schema@*", "@types/json-schema@^7.0.8": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/node@*", "@types/node@>=10.0.0": + version "17.0.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.12.tgz#f7aa331b27f08244888c47b7df126184bc2339c5" + integrity sha512-4YpbAsnJXWYK/fpTVFlMIcUIho2AYCi4wg5aNPrG1ng7fn/1/RZfCIpRCiBX+12RVa34RluilnvCqD+g3KiSiA== + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356" + integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg== + +"@webpack-cli/info@^1.4.0": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea" + integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA== + dependencies: + envinfo "^7.7.3" + +"@webpack-cli/serve@^1.6.0": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe" + integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abab@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + +accepts@~1.3.4: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + +acorn@^8.4.1: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +astring@1.7.5: + version "1.7.5" + resolved "https://registry.yarnpkg.com/astring/-/astring-1.7.5.tgz#a7d47fceaf32b052d33a3d07c511efeec67447ca" + integrity sha512-lobf6RWXb8c4uZ7Mdq0U12efYmpD1UFnyOWVJPTa3ukqZrMopav+2hdNu0hgBF0JIBFK9QgrBDfwYvh3DFJDAA== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-arraybuffer@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812" + integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI= + +base64id@2.0.0, base64id@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + +benchmark@*: + version "2.1.4" + resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629" + integrity sha1-CfPeMckWQl1JjMLuVloOvzwqVik= + dependencies: + lodash "^4.17.4" + platform "^1.3.3" + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +binaryen@101.0.0: + version "101.0.0" + resolved "https://registry.yarnpkg.com/binaryen/-/binaryen-101.0.0.tgz#42a9e4cc7a22e2c1d75a31d28005a9b518b2c555" + integrity sha512-FRmVxvrR8jtcf0qcukNAPZDM3dZ2sc9GmA/hKxBI7k3fFzREKh1cAs+ruQi+ITTKz7u/AuFMuVnbJwTh0ef/HQ== + +body-parser@^1.19.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" + integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== + dependencies: + bytes "3.1.1" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.9.6" + raw-body "2.4.2" + type-is "~1.6.18" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserslist@^4.14.5: + version "4.19.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== + dependencies: + caniuse-lite "^1.0.30001286" + electron-to-chromium "^1.4.17" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +bytes@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" + integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001286: + version "1.0.30001301" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz#ebc9086026534cab0dab99425d9c3b4425e5f450" + integrity sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA== + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chokidar@^3.5.1: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.14: + version "2.0.16" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" + integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== + +colors@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +component-emitter@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +connect@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + +cors@~2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-loader@6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.3.0.tgz#334d3500ff0a0c14cfbd4b0670088dbb5b5c1530" + integrity sha512-9NGvHOR+L6ps13Ilw/b216++Q8q+5RpJcVufCdW9S/9iCzs4KBDNa8qnA/n3FK/sSfWmH35PAIK/cfPi7LOSUg== + dependencies: + icss-utils "^5.1.0" + postcss "^8.2.15" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.0" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.1.0" + semver "^7.3.5" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU= + +date-format@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.3.tgz#f63de5dc08dc02efd8ef32bf2a6918e486f35873" + integrity sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +debug@^4.1.1, debug@^4.3.3, debug@~4.3.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dom-serialize@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs= + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +dukat@0.5.8-rc.4: + version "0.5.8-rc.4" + resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21" + integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA== + dependencies: + google-protobuf "3.12.2" + typescript "3.9.5" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.4.17: + version "1.4.52" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.52.tgz#ce44c6d6cc449e7688a4356b8c261cfeafa26833" + integrity sha512-JGkh8HEh5PnVrhU4HbpyyO0O791dVY6k7AdqfDeqbcRMeoGxtNHWT77deR2nhvbLe4dKpxjlDEvdEwrvRLGu2Q== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +engine.io-parser@~4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-4.0.3.tgz#83d3a17acfd4226f19e721bb22a1ee8f7662d2f6" + integrity sha512-xEAAY0msNnESNPc00e19y5heTPX4y/TJ36gr8t1voOaNmTojP9b3oK3BbJLFufW2XFPQaaijpFewm2g2Um3uqA== + dependencies: + base64-arraybuffer "0.1.4" + +engine.io@~4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-4.1.2.tgz#f96ceb56d4b39cc7ca5bd29a20e9c99c1ad1a765" + integrity sha512-t5z6zjXuVLhXDMiFJPYsPOWEER8B0tIsD3ETgw19S1yg9zryvUfY3Vhtk3Gf4sihw/bQGIqQ//gjvVlu+Ca0bQ== + dependencies: + accepts "~1.3.4" + base64id "2.0.0" + cookie "~0.4.1" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~4.0.0" + ws "~7.4.2" + +enhanced-resolve@^5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" + integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +ent@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= + +envinfo@^7.7.3: + version "7.8.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== + +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fastest-levenshtein@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" + integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" + integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== + +follow-redirects@^1.0.0: + version "1.14.7" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" + integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== + +format-util@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" + integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== + +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3, glob@^7.1.7: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +google-protobuf@3.12.2: + version "3.12.2" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" + integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +http-errors@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +interpret@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isbinaryfile@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf" + integrity sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +jest-worker@^27.4.1: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.6.tgz#5d2d93db419566cb680752ca0792780e71b3273e" + integrity sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-base64@3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.6.1.tgz#555aae398b74694b4037af1f8a5a6209d170efbe" + integrity sha512-Frdq2+tRRGLQUIQOgsIGSCd1VePCS2fsddTG5dTCqR0JHgltXWfsxnY0gIXPoMeRmdom6Oyq+UMOFg5suduOjQ== + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +karma-chrome-launcher@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz#805a586799a4d05f4e54f72a204979f3f3066738" + integrity sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg== + dependencies: + which "^1.2.1" + +karma-mocha@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d" + integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ== + dependencies: + minimist "^1.2.3" + +karma-sourcemap-loader@0.3.8: + version "0.3.8" + resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.8.tgz#d4bae72fb7a8397328a62b75013d2df937bdcf9c" + integrity sha512-zorxyAakYZuBcHRJE+vbrK2o2JXLFWK8VVjiT/6P+ltLBUGUvqTEkUiQ119MGdOrK7mrmxXHZF1/pfT6GgIZ6g== + dependencies: + graceful-fs "^4.1.2" + +karma-webpack@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.0.tgz#2a2c7b80163fe7ffd1010f83f5507f95ef39f840" + integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA== + dependencies: + glob "^7.1.3" + minimatch "^3.0.4" + webpack-merge "^4.1.5" + +karma@6.3.4: + version "6.3.4" + resolved "https://registry.yarnpkg.com/karma/-/karma-6.3.4.tgz#359899d3aab3d6b918ea0f57046fd2a6b68565e6" + integrity sha512-hbhRogUYIulfkBTZT7xoPrCYhRBnBoqbbL4fszWD0ReFGUxU+LYBr3dwKdAluaDQ/ynT9/7C+Lf7pPNW4gSx4Q== + dependencies: + body-parser "^1.19.0" + braces "^3.0.2" + chokidar "^3.5.1" + colors "^1.4.0" + connect "^3.7.0" + di "^0.0.1" + dom-serialize "^2.2.1" + glob "^7.1.7" + graceful-fs "^4.2.6" + http-proxy "^1.18.1" + isbinaryfile "^4.0.8" + lodash "^4.17.21" + log4js "^6.3.0" + mime "^2.5.2" + minimatch "^3.0.4" + qjobs "^1.2.0" + range-parser "^1.2.1" + rimraf "^3.0.2" + socket.io "^3.1.0" + source-map "^0.6.1" + tmp "^0.2.1" + ua-parser-js "^0.7.28" + yargs "^16.1.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +loader-runner@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" + integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log4js@^6.3.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.4.1.tgz#9d3a8bf2c31c1e213fe3fc398a6053f7a2bc53e8" + integrity sha512-iUiYnXqAmNKiIZ1XSAitQ4TmNs8CdZYTAWINARF3LjnsLN8tY5m0vRwd6uuWj/yNY0YHxeZodnbmxKFUOM2rMg== + dependencies: + date-format "^4.0.3" + debug "^4.3.3" + flatted "^3.2.4" + rfdc "^1.3.0" + streamroller "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +mime-db@1.51.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== + +mime-types@^2.1.27, mime-types@~2.1.24: + version "2.1.34" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" + integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + dependencies: + mime-db "1.51.0" + +mime@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mocha@9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.1.2.tgz#93f53175b0f0dc4014bd2d612218fccfcf3534d3" + integrity sha512-ta3LtJ+63RIBP03VBjMGtSqbe6cWXRejF9SyM9Zyli1CKZJZ+vfCTj3oW24V7wAphMJdpOFLoMI3hjJ1LWbs0w== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.2" + debug "4.3.2" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.1.7" + growl "1.10.5" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "3.0.4" + ms "2.1.3" + nanoid "3.1.25" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + workerpool "6.1.5" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.1.25: + version "3.1.25" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" + integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== + +nanoid@^3.1.30: + version "3.2.0" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" + integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +platform@^1.3.3: + version "1.3.6" + resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" + integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" + integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.9" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" + integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.2.15: + version "8.4.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" + integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qjobs@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== + +qs@6.9.6: + version "6.9.6" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" + integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" + integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== + dependencies: + bytes "3.1.1" + http-errors "1.8.1" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" + integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== + dependencies: + resolve "^1.9.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.9.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" + integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== + dependencies: + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +serialize-javascript@6.0.0, serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.3: + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== + +socket.io-adapter@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.1.0.tgz#edc5dc36602f2985918d631c1399215e97a1b527" + integrity sha512-+vDov/aTsLjViYTwS9fPy5pEtTkrbEKsw2M+oVSoFGw6OD1IpvlV1VPhUzNbofCQ8oyMbdYJqDtGdmHQK6TdPg== + +socket.io-parser@~4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.4.tgz#9ea21b0d61508d18196ef04a2c6b9ab630f4c2b0" + integrity sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g== + dependencies: + "@types/component-emitter" "^1.2.10" + component-emitter "~1.3.0" + debug "~4.3.1" + +socket.io@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-3.1.2.tgz#06e27caa1c4fc9617547acfbb5da9bc1747da39a" + integrity sha512-JubKZnTQ4Z8G4IZWtaAZSiRP3I/inpy8c/Bsx2jrwGrTbKeVU5xd6qkKMHpChYeM3dWZSO0QACiGK+obhBNwYw== + dependencies: + "@types/cookie" "^0.4.0" + "@types/cors" "^2.8.8" + "@types/node" ">=10.0.0" + accepts "~1.3.4" + base64id "~2.0.0" + debug "~4.3.1" + engine.io "~4.1.0" + socket.io-adapter "~2.1.0" + socket.io-parser "~4.0.3" + +source-map-js@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" + integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== + +source-map-js@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-loader@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.0.tgz#f2a04ee2808ad01c774dea6b7d2639839f3b3049" + integrity sha512-GKGWqWvYr04M7tn8dryIWvb0s8YM41z82iQv01yBtIylgxax0CwvSy6gc2Y02iuXwEfGWRlMicH0nvms9UZphw== + dependencies: + abab "^2.0.5" + iconv-lite "^0.6.2" + source-map-js "^0.6.2" + +source-map-support@0.5.20: + version "0.5.20" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@~0.7.2: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +streamroller@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.0.2.tgz#30418d0eee3d6c93ec897f892ed098e3a81e68b7" + integrity sha512-ur6y5S5dopOaRXBuRIZ1u6GC5bcEXHRZKgfBjfCglMhmIf+roVCECjvkEYzNQOXIN2/JPnkMPW/8B3CZoKaEPA== + dependencies: + date-format "^4.0.3" + debug "^4.1.1" + fs-extra "^10.0.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-loader@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.0.tgz#d66ea95fc50b22f8b79b69a9e414760fcf58d8d8" + integrity sha512-szANub7ksJtQioJYtpbWwh1hUl99uK15n5HDlikeCRil/zYMZgSxucHddyF/4A3qJMUiAjPhFowrrQuNMA7jwQ== + +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.1.3: + version "5.3.0" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz#21641326486ecf91d8054161c816e464435bae9f" + integrity sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ== + dependencies: + jest-worker "^27.4.1" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.2" + +terser@^5.7.2: + version "5.10.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" + integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.20" + +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== + +ua-parser-js@^0.7.28: + version "0.7.31" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" + integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +v8-compile-cache@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +vary@^1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= + +watchpack@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" + integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +webpack-cli@4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.0.tgz#dc43e6e0f80dd52e89cbf73d5294bcd7ad6eb343" + integrity sha512-n/jZZBMzVEl4PYIBs+auy2WI0WTQ74EnJDiyD98O2JZY6IVIHJNitkYp/uTXOviIOMfgzrNvC9foKv/8o8KSZw== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^1.1.0" + "@webpack-cli/info" "^1.4.0" + "@webpack-cli/serve" "^1.6.0" + colorette "^2.0.14" + commander "^7.0.0" + execa "^5.0.0" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^2.2.0" + rechoir "^0.7.0" + v8-compile-cache "^2.2.0" + webpack-merge "^5.7.3" + +webpack-merge@^4.1.5: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== + dependencies: + lodash "^4.17.15" + +webpack-merge@^5.7.3: + version "5.8.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^3.2.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@5.57.1: + version "5.57.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.57.1.tgz#ead5ace2c17ecef2ae8126f143bfeaa7f55eab44" + integrity sha512-kHszukYjTPVfCOEyrUthA3jqJwduY/P3eO8I0gMNOZGIQWKAwZftxmp5hq6paophvwo9NoUrcZOecs9ulOyyTg== + dependencies: + "@types/eslint-scope" "^3.7.0" + "@types/estree" "^0.0.50" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.8.3" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.4" + json-parse-better-errors "^1.0.2" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.2.0" + webpack-sources "^3.2.0" + +which@2.0.2, which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +which@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" + integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== + +workerpool@6.1.5: + version "6.1.5" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" + integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@~7.4.2: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0, yargs@^16.1.1: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -- 2.34.1 From 860763987666280bd5978c1f33ff27f3397a2652 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 26 Jan 2022 20:33:44 +0700 Subject: [PATCH 081/102] Change units --- benchmarks/build.gradle.kts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 3dc221bae..90ec5dfbe 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -101,8 +101,9 @@ benchmark { // Some extra precision warmups = 2 iterations = 10 - iterationTime = 2000 - iterationTimeUnit = "ms" + iterationTime = 10 + iterationTimeUnit = "s" + outputTimeUnit = "s" include("ExpressionsInterpretersBenchmark") } -- 2.34.1 From 7bb66f6a00c8fa045e60a333bc5aae3d9cf5dfbd Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 29 Jan 2022 15:02:46 +0300 Subject: [PATCH 082/102] Add TensorFlow prototype --- CHANGELOG.md | 1 + README.md | 29 ------ docs/templates/README-TEMPLATE.md | 29 ------ gradle.properties | 2 +- kmath-tensorflow/build.gradle.kts | 4 +- .../tensorflow/DoubleTensorFlowAlgebra.kt | 21 ++++- .../kmath/tensorflow/TensorFlowAlgebra.kt | 90 +++++++++++-------- .../kscience/kmath/tensorflow/tfOperations.kt | 23 +++++ .../kmath/tensorflow/DoubleTensorFlowOps.kt | 18 +++- 9 files changed, 114 insertions(+), 103 deletions(-) create mode 100644 kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 857ed060b..a19b1f467 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Integration between `MST` and Symja `IExpr` - Complex power - Separate methods for UInt, Int and Number powers. NaN safety. +- Tensorflow prototype ### Changed - Exponential operations merged with hyperbolic functions diff --git a/README.md b/README.md index 8604873ae..92260716e 100644 --- a/README.md +++ b/README.md @@ -50,35 +50,6 @@ module definitions below. The module stability could have the following levels: with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ## Modules
diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index e75d4c5ed..b0c418697 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -50,35 +50,6 @@ module definitions below. The module stability could have the following levels: with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ## Modules $modules diff --git a/gradle.properties b/gradle.properties index 130d294a2..7dd9e6d61 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,4 +12,4 @@ org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G -toolsVersion=0.10.9-kotlin-1.6.10 +toolsVersion=0.11.1-kotlin-1.6.10 diff --git a/kmath-tensorflow/build.gradle.kts b/kmath-tensorflow/build.gradle.kts index c8307f01f..9380a7308 100644 --- a/kmath-tensorflow/build.gradle.kts +++ b/kmath-tensorflow/build.gradle.kts @@ -6,8 +6,8 @@ description = "Google tensorflow connector" dependencies { api(project(":kmath-tensors")) - api("org.tensorflow:tensorflow-core-api:0.3.3") - testImplementation("org.tensorflow:tensorflow-core-platform:0.3.3") + api("org.tensorflow:tensorflow-core-api:0.4.0") + testImplementation("org.tensorflow:tensorflow-core-platform:0.4.0") } readme { 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 eb8245944..ecfd8d098 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 @@ -11,6 +11,7 @@ import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.PowerOperations public class DoubleTensorFlowOutput( graph: Graph, @@ -23,7 +24,7 @@ public class DoubleTensorFlowOutput( public class DoubleTensorFlowAlgebra internal constructor( graph: Graph, -) : TensorFlowAlgebra(graph) { +) : TensorFlowAlgebra(graph), PowerOperations> { override val elementAlgebra: DoubleField get() = DoubleField @@ -57,9 +58,22 @@ public class DoubleTensorFlowAlgebra internal constructor( override fun const(value: Double): Constant = ops.constant(value) + override fun divide( + left: StructureND, + right: StructureND, + ): TensorFlowOutput = left.operate(right) { l, r -> + ops.math.div(l, r) + } + override fun power(arg: StructureND, pow: Number): TensorFlowOutput = + arg.operate { ops.math.pow(it, const(pow.toDouble())) } } +/** + * Compute a tensor with TensorFlow in a single run. + * + * The resulting tensor is available outside of scope + */ public fun DoubleField.produceWithTF( block: DoubleTensorFlowAlgebra.() -> StructureND, ): StructureND = Graph().use { graph -> @@ -67,6 +81,11 @@ public fun DoubleField.produceWithTF( scope.export(scope.block()) } +/** + * Compute several outputs with TensorFlow in a single run. + * + * The resulting tensors are available outside of scope + */ public fun DoubleField.produceMapWithTF( block: DoubleTensorFlowAlgebra.() -> Map>, ): Map> = Graph().use { graph -> 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 7ad91c267..e2541a73e 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 @@ -12,6 +12,7 @@ import org.tensorflow.op.core.Max import org.tensorflow.op.core.Min import org.tensorflow.op.core.Sum 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.UnstableKMathAPI @@ -29,6 +30,9 @@ internal val NdArray.scalar: T get() = getObject() public sealed interface TensorFlowTensor : Tensor +/** + * Static (eager) in-memory TensorFlow tensor + */ @JvmInline public value class TensorFlowArray(public val tensor: NdArray) : Tensor { override val shape: Shape get() = tensor.shape().asArray().toIntArray() @@ -42,6 +46,11 @@ public value class TensorFlowArray(public val tensor: NdArray) : Tensor } } +/** + * Lazy graph-based TensorFlow tensor. The tensor is actualized on call. + * + * If the tensor is used for intermediate operations, actualizing it could impact performance. + */ public abstract class TensorFlowOutput( protected val graph: Graph, output: Output, @@ -72,11 +81,11 @@ public abstract class TensorFlowOutput( } -public abstract class TensorFlowAlgebra> internal constructor( +public abstract class TensorFlowAlgebra> internal constructor( protected val graph: Graph, ) : TensorAlgebra { - protected val ops: Ops by lazy { Ops.create(graph) } + public val ops: Ops by lazy { Ops.create(graph) } protected abstract fun StructureND.asTensorFlow(): TensorFlowOutput @@ -87,7 +96,10 @@ public abstract class TensorFlowAlgebra> internal con override fun StructureND.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) get(Shape(0)) else null - private inline fun StructureND.biOp( + /** + * Perform binary lazy operation on tensor. Both arguments are implicitly converted + */ + public fun StructureND.operate( other: StructureND, operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { @@ -96,7 +108,7 @@ public abstract class TensorFlowAlgebra> internal con return operation(left, right).asOutput().wrap() } - private inline fun T.biOp( + public fun T.operate( other: StructureND, operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { @@ -105,7 +117,7 @@ public abstract class TensorFlowAlgebra> internal con return operation(left, right).asOutput().wrap() } - private inline fun StructureND.biOp( + public fun StructureND.operate( value: T, operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { @@ -114,7 +126,7 @@ public abstract class TensorFlowAlgebra> internal con return operation(left, right).asOutput().wrap() } - private inline fun Tensor.inPlaceOp( + public fun Tensor.operateInPlace( other: StructureND, operation: (left: Operand, right: Operand) -> Operand, ): Unit { @@ -124,7 +136,7 @@ public abstract class TensorFlowAlgebra> internal con origin.output = operation(left, right).asOutput() } - private inline fun Tensor.inPlaceOp( + public fun Tensor.operateInPlace( value: T, operation: (left: Operand, right: Operand) -> Operand, ): Unit { @@ -134,61 +146,61 @@ public abstract class TensorFlowAlgebra> internal con origin.output = operation(left, right).asOutput() } - private inline fun StructureND.unOp(operation: (Operand) -> Operand): TensorFlowOutput = + public fun StructureND.operate(operation: (Operand) -> Operand): TensorFlowOutput = operation(asTensorFlow().output).asOutput().wrap() - override fun T.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) + override fun T.plus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::add) - override fun StructureND.plus(arg: T): TensorFlowOutput = biOp(arg, ops.math::add) + override fun StructureND.plus(arg: T): TensorFlowOutput = operate(arg, ops.math::add) - override fun StructureND.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) + override fun StructureND.plus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::add) - override fun Tensor.plusAssign(value: T): Unit = inPlaceOp(value, ops.math::add) + override fun Tensor.plusAssign(value: T): Unit = operateInPlace(value, ops.math::add) - override fun Tensor.plusAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::add) + override fun Tensor.plusAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::add) - override fun StructureND.minus(arg: T): TensorFlowOutput = biOp(arg, ops.math::sub) + override fun StructureND.minus(arg: T): TensorFlowOutput = operate(arg, ops.math::sub) - override fun StructureND.minus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::sub) + override fun StructureND.minus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::sub) - override fun T.minus(arg: StructureND): Tensor = biOp(arg, ops.math::sub) + override fun T.minus(arg: StructureND): Tensor = operate(arg, ops.math::sub) - override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) + override fun Tensor.minusAssign(value: T): Unit = operateInPlace(value, ops.math::sub) - override fun Tensor.minusAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::sub) + override fun Tensor.minusAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::sub) - override fun T.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) + override fun T.times(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::mul) - override fun StructureND.times(arg: T): TensorFlowOutput = biOp(arg, ops.math::mul) + override fun StructureND.times(arg: T): TensorFlowOutput = operate(arg, ops.math::mul) - override fun StructureND.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) + override fun StructureND.times(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::mul) - override fun Tensor.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul) + override fun Tensor.timesAssign(value: T): Unit = operateInPlace(value, ops.math::mul) - override fun Tensor.timesAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::mul) + override fun Tensor.timesAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::mul) - override fun StructureND.unaryMinus(): TensorFlowOutput = unOp(ops.math::neg) + override fun StructureND.unaryMinus(): TensorFlowOutput = operate(ops.math::neg) - override fun Tensor.get(i: Int): Tensor = unOp { + override fun Tensor.get(i: Int): Tensor = operate { TODO("Not yet implemented") } - override fun Tensor.transpose(i: Int, j: Int): Tensor = unOp { + override fun Tensor.transpose(i: Int, j: Int): Tensor = operate { ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) } - override fun Tensor.view(shape: IntArray): Tensor = unOp { + override fun Tensor.view(shape: IntArray): Tensor = operate { ops.reshape(it, ops.constant(shape)) } - override fun Tensor.viewAs(other: StructureND): Tensor = biOp(other) { l, r -> + override fun Tensor.viewAs(other: StructureND): Tensor = operate(other) { l, r -> ops.reshape(l, ops.shape(r)) } - override fun StructureND.dot(other: StructureND): TensorFlowOutput = biOp(other) { l, r -> + override fun StructureND.dot(other: StructureND): TensorFlowOutput = operate(other) { l, r -> ops.linalg.matMul( - if (l.asTensor().shape().numDimensions() == 1) ops.expandDims(l,ops.constant(0)) else l, - if (r.asTensor().shape().numDimensions() == 1) ops.expandDims(r,ops.constant(-1)) else r) + if (l.asTensor().shape().numDimensions() == 1) ops.expandDims(l, ops.constant(0)) else l, + if (r.asTensor().shape().numDimensions() == 1) ops.expandDims(r, ops.constant(-1)) else r) } override fun diagonalEmbedding( @@ -196,31 +208,31 @@ public abstract class TensorFlowAlgebra> internal con offset: Int, dim1: Int, dim2: Int, - ): TensorFlowOutput = diagonalEntries.unOp { - TODO() + ): TensorFlowOutput = diagonalEntries.operate { + TODO("Not yet implemented") } - override fun StructureND.sum(): T = unOp { + override fun StructureND.sum(): T = operate { ops.sum(it, ops.constant(intArrayOf())) }.value() - override fun StructureND.sum(dim: Int, keepDim: Boolean): TensorFlowOutput = unOp { + override fun StructureND.sum(dim: Int, keepDim: Boolean): TensorFlowOutput = operate { ops.sum(it, ops.constant(dim), Sum.keepDims(keepDim)) } - override fun StructureND.min(): T = unOp { + override fun StructureND.min(): T = operate { ops.min(it, ops.constant(intArrayOf())) }.value() - override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor = unOp { + override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor = operate { ops.min(it, ops.constant(dim), Min.keepDims(keepDim)) } - override fun StructureND.max(): T = unOp { + override fun StructureND.max(): T = operate { ops.max(it, ops.constant(intArrayOf())) }.value() - override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor = unOp { + override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor = operate { ops.max(it, ops.constant(dim), Max.keepDims(keepDim)) } diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt new file mode 100644 index 000000000..257d4d6ea --- /dev/null +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensorflow + +import org.tensorflow.types.family.TNumber +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.TrigonometricOperations + +// + +// TODO add other operations + +public fun TensorFlowAlgebra.sin( + arg: StructureND, +): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.sin(it) } + +public fun TensorFlowAlgebra.cos( + arg: StructureND, +): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.cos(it) } 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 b7a4b94b4..805ad7c66 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 @@ -1,9 +1,10 @@ package space.kscience.kmath.tensorflow import org.junit.jupiter.api.Test -import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.get import space.kscience.kmath.nd.structureND import space.kscience.kmath.operations.DoubleField +import kotlin.test.assertEquals class DoubleTensorFlowOps { @Test @@ -13,7 +14,20 @@ class DoubleTensorFlowOps { initial + (initial * 2.0) } - println(StructureND.toString(res)) + //println(StructureND.toString(res)) + assertEquals(3.0, res[0, 0]) } + @Test + fun extensionOps(){ + val res = DoubleField.produceWithTF { + val i = structureND(2, 2) { 0.5 } + + sin(i).pow(2) + cos(i).pow(2) + } + + assertEquals(1.0, res[0,0],0.01) + } + + } \ No newline at end of file -- 2.34.1 From d35516b9afc4bf7d213100b016920b8c92867083 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 2 Feb 2022 10:00:45 +0700 Subject: [PATCH 083/102] Fix theta --- .../commonMain/kotlin/space/kscience/kmath/complex/Complex.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d3c414838..77fe782a9 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 @@ -41,7 +41,7 @@ public val Complex.r: Double * An angle between vector represented by complex number and X axis. */ public val Complex.theta: Double - get() = atan(im / re) + get() = atan2(im, re) private val PI_DIV_2 = Complex(PI / 2, 0) -- 2.34.1 From e094f6e8ee9da6931eae1617d2276ce2329549b4 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 8 Feb 2022 11:43:50 +0700 Subject: [PATCH 084/102] Remove Algebra.evaluate(MST) by inlining in into interpret --- .../space/kscience/kmath/ast/TestParser.kt | 10 +- .../kmath/ast/TestParserPrecedence.kt | 18 +-- .../space/kscience/kmath/expressions/MST.kt | 113 ++++++++---------- 3 files changed, 65 insertions(+), 76 deletions(-) diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt index b838245e1..d0c3a789e 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.ast import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.ComplexField -import space.kscience.kmath.expressions.evaluate +import space.kscience.kmath.expressions.interpret import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField import kotlin.test.Test @@ -17,14 +17,14 @@ internal class TestParser { @Test fun evaluateParsedMst() { val mst = "2+2*(2+2)".parseMath() - val res = ComplexField.evaluate(mst) + val res = mst.interpret(ComplexField) assertEquals(Complex(10.0, 0.0), res) } @Test fun evaluateMstSymbol() { val mst = "i".parseMath() - val res = ComplexField.evaluate(mst) + val res = mst.interpret(ComplexField) assertEquals(ComplexField.i, res) } @@ -32,7 +32,7 @@ internal class TestParser { @Test fun evaluateMstUnary() { val mst = "sin(0)".parseMath() - val res = DoubleField.evaluate(mst) + val res = mst.interpret(DoubleField) assertEquals(0.0, res) } @@ -53,7 +53,7 @@ internal class TestParser { } val mst = "magic(a, b)".parseMath() - val res = magicalAlgebra.evaluate(mst) + val res = mst.interpret(magicalAlgebra) assertEquals("a ★ b", res) } } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt index bb6bb3ce1..42cf5ce58 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt @@ -5,35 +5,35 @@ package space.kscience.kmath.ast -import space.kscience.kmath.expressions.evaluate +import space.kscience.kmath.expressions.interpret import space.kscience.kmath.operations.DoubleField import kotlin.test.Test import kotlin.test.assertEquals internal class TestParserPrecedence { @Test - fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath())) + fun test1(): Unit = assertEquals(6.0, "2*2+2".parseMath().interpret(f)) @Test - fun test2(): Unit = assertEquals(6.0, f.evaluate("2+2*2".parseMath())) + fun test2(): Unit = assertEquals(6.0, "2+2*2".parseMath().interpret(f)) @Test - fun test3(): Unit = assertEquals(10.0, f.evaluate("2^3+2".parseMath())) + fun test3(): Unit = assertEquals(10.0, "2^3+2".parseMath().interpret(f)) @Test - fun test4(): Unit = assertEquals(10.0, f.evaluate("2+2^3".parseMath())) + fun test4(): Unit = assertEquals(10.0, "2+2^3".parseMath().interpret(f)) @Test - fun test5(): Unit = assertEquals(16.0, f.evaluate("2^3*2".parseMath())) + fun test5(): Unit = assertEquals(16.0, "2^3*2".parseMath().interpret(f)) @Test - fun test6(): Unit = assertEquals(16.0, f.evaluate("2*2^3".parseMath())) + fun test6(): Unit = assertEquals(16.0, "2*2^3".parseMath().interpret(f)) @Test - fun test7(): Unit = assertEquals(18.0, f.evaluate("2+2^3*2".parseMath())) + fun test7(): Unit = assertEquals(18.0, "2+2^3*2".parseMath().interpret(f)) @Test - fun test8(): Unit = assertEquals(18.0, f.evaluate("2*2^3+2".parseMath())) + fun test8(): Unit = assertEquals(18.0, "2*2^3+2".parseMath().interpret(f)) private companion object { private val f = DoubleField diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt index 7533024a1..24e96e845 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbol +import space.kscience.kmath.operations.bindSymbolOrNull /** * A Mathematical Syntax Tree (MST) node for mathematical expressions. @@ -43,66 +43,50 @@ public sealed interface MST { // TODO add a function with named arguments -/** - * Interprets the [MST] node with this [Algebra]. - * - * @receiver the algebra that provides operations. - * @param node the node to evaluate. - * @return the value of expression. - * @author Alexander Nozik - */ -public fun Algebra.evaluate(node: MST): T = when (node) { - is MST.Numeric -> (this as? NumericAlgebra)?.number(node.value) - ?: error("Numeric nodes are not supported by $this") - - is Symbol -> bindSymbol(node) - - is MST.Unary -> when { - this is NumericAlgebra && node.value is MST.Numeric -> unaryOperationFunction(node.operation)(number(node.value.value)) - else -> unaryOperationFunction(node.operation)(evaluate(node.value)) - } - - is MST.Binary -> when { - this is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> - binaryOperationFunction(node.operation)(number(node.left.value), number(node.right.value)) - - this is NumericAlgebra && node.left is MST.Numeric -> - leftSideNumberOperationFunction(node.operation)(node.left.value, evaluate(node.right)) - - this is NumericAlgebra && node.right is MST.Numeric -> - rightSideNumberOperationFunction(node.operation)(evaluate(node.left), node.right.value) - - else -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right)) - } -} - -internal class InnerAlgebra(val algebra: Algebra, val arguments: Map) : NumericAlgebra { - override fun bindSymbolOrNull(value: String): T? = algebra.bindSymbolOrNull(value) ?: arguments[StringSymbol(value)] - - override fun unaryOperation(operation: String, arg: T): T = - algebra.unaryOperation(operation, arg) - - override fun binaryOperation(operation: String, left: T, right: T): T = - algebra.binaryOperation(operation, left, right) - - override fun unaryOperationFunction(operation: String): (arg: T) -> T = - algebra.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = - algebra.binaryOperationFunction(operation) - - @Suppress("UNCHECKED_CAST") - override fun number(value: Number): T = if (algebra is NumericAlgebra<*>) - (algebra as NumericAlgebra).number(value) - else - error("Numeric nodes are not supported by $this") -} /** * Interprets the [MST] node with this [Algebra] and optional [arguments] */ -public fun MST.interpret(algebra: Algebra, arguments: Map): T = - InnerAlgebra(algebra, arguments).evaluate(this) +public fun MST.interpret(algebra: Algebra, arguments: Map): T = when (this) { + is MST.Numeric -> (algebra as NumericAlgebra?)?.number(value) + ?: error("Numeric nodes are not supported by $algebra") + + is Symbol -> algebra.bindSymbolOrNull(this) ?: arguments.getValue(this) + + is MST.Unary -> when { + algebra is NumericAlgebra && this.value is MST.Numeric -> algebra.unaryOperation( + this.operation, + algebra.number(this.value.value), + ) + else -> algebra.unaryOperationFunction(this.operation)(this.value.interpret(algebra, arguments)) + } + + is MST.Binary -> when { + algebra is NumericAlgebra && this.left is MST.Numeric && this.right is MST.Numeric -> algebra.binaryOperation( + this.operation, + algebra.number(this.left.value), + algebra.number(this.right.value), + ) + + algebra is NumericAlgebra && this.left is MST.Numeric -> algebra.leftSideNumberOperation( + this.operation, + this.left.value, + this.right.interpret(algebra, arguments), + ) + + algebra is NumericAlgebra && this.right is MST.Numeric -> algebra.rightSideNumberOperation( + this.operation, + left.interpret(algebra, arguments), + right.value, + ) + + else -> algebra.binaryOperation( + this.operation, + this.left.interpret(algebra, arguments), + this.right.interpret(algebra, arguments), + ) + } +} /** * Interprets the [MST] node with this [Algebra] and optional [arguments] @@ -111,12 +95,17 @@ public fun MST.interpret(algebra: Algebra, arguments: Map): T * @param algebra the algebra that provides operations. * @return the value of expression. */ -public fun MST.interpret(algebra: Algebra, vararg arguments: Pair): T = - interpret(algebra, mapOf(*arguments)) +public fun MST.interpret(algebra: Algebra, vararg arguments: Pair): T = interpret( + algebra, + when (arguments.size) { + 0 -> emptyMap() + 1 -> mapOf(arguments[0]) + else -> hashMapOf(*arguments) + }, +) /** * Interpret this [MST] as expression. */ -public fun MST.toExpression(algebra: Algebra): Expression = Expression { arguments -> - interpret(algebra, arguments) -} +public fun MST.toExpression(algebra: Algebra): Expression = + Expression { arguments -> interpret(algebra, arguments) } -- 2.34.1 From 745a7ad66ef125d3f0b00de455109f8e62f2fa58 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 5 Feb 2022 04:27:10 +0700 Subject: [PATCH 085/102] Add complete constant folding in kmath-ast by introducing TypedMst, some minor changes --- README.md | 6 + kmath-ast/README.md | 63 ++++--- kmath-ast/docs/README-TEMPLATE.md | 114 +++++++---- .../space/kscience/kmath/ast/TypedMst.kt | 177 ++++++++++++++++++ .../kscience/kmath/ast/evaluateConstants.kt | 93 +++++++++ .../space/kscience/kmath/ast/TestFolding.kt | 52 +++++ .../space/kscience/kmath/estree/estree.kt | 89 +++------ .../kmath/estree/internal/ESTreeBuilder.kt | 2 +- .../kmath/wasm/internal/WasmBuilder.kt | 67 +++---- .../kotlin/space/kscience/kmath/wasm/wasm.kt | 30 ++- .../kotlin/space/kscience/kmath/asm/asm.kt | 135 +++++++------ .../kmath/asm/internal/GenericAsmBuilder.kt | 8 +- .../kmath/asm/internal/PrimitiveAsmBuilder.kt | 82 +++----- .../kmath/asm/internal/codegenUtils.kt | 8 +- .../FunctionalExpressionAlgebra.kt | 4 +- .../space/kscience/kmath/expressions/MST.kt | 4 +- 16 files changed, 622 insertions(+), 312 deletions(-) create mode 100644 kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt create mode 100644 kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt create mode 100644 kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt diff --git a/README.md b/README.md index 92260716e..99dd6d00f 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,12 @@ One can still use generic algebras though. > **Maturity**: PROTOTYPE
+* ### [kmath-tensorflow](kmath-tensorflow) +> +> +> **Maturity**: PROTOTYPE +
+ * ### [kmath-tensors](kmath-tensors) > > diff --git a/kmath-ast/README.md b/kmath-ast/README.md index 5e3366881..bedf17486 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -1,6 +1,6 @@ # Module kmath-ast -Performance and visualization extensions to MST API. +Extensions to MST API: transformations, dynamic compilation and visualization. - [expression-language](src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser - [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler @@ -35,6 +35,26 @@ dependencies { } ``` +## Parsing expressions + +In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances. + +Supported literals: +1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`. +2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`—all parsed either as `kotlin.Long` or `kotlin.Double`. + +Supported binary operators (from the highest precedence to the lowest one): +1. `^` +2. `*`, `/` +3. `+`, `-` + +Supported unary operator: +1. `-`, e. g. `-x` + +Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples: +1. `sin(x)` +2. `add(x, y)` + ## Dynamic expression code generation ### On JVM @@ -42,48 +62,41 @@ dependencies { `kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a special implementation of `Expression` with implemented `invoke` function. -For example, the following builder: +For example, the following code: ```kotlin -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.* -import space.kscience.kmath.asm.* +import space.kscience.kmath.asm.compileToExpression +import space.kscience.kmath.complex.ComplexField -MstField { x + 2 }.compileToExpression(DoubleField) -``` +"x+2".parseMath().compileToExpression(ComplexField) +``` -... leads to generation of bytecode, which can be decompiled to the following Java class: +… leads to generation of bytecode, which can be decompiled to the following Java class: ```java -package space.kscience.kmath.asm.generated; - import java.util.Map; - import kotlin.jvm.functions.Function2; import space.kscience.kmath.asm.internal.MapIntrinsics; +import space.kscience.kmath.complex.Complex; import space.kscience.kmath.expressions.Expression; import space.kscience.kmath.expressions.Symbol; -public final class AsmCompiledExpression_45045_0 implements Expression { +public final class CompiledExpression_45045_0 implements Expression { private final Object[] constants; - public final Double invoke(Map arguments) { - return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2); - } - - public AsmCompiledExpression_45045_0(Object[] constants) { - this.constants = constants; + public Complex invoke(Map arguments) { + Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x"); + return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]); } } - ``` -#### Known issues +Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. -- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class - loading overhead. -- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. +#### Limitations + +- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead. +- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders. ### On JS @@ -129,7 +142,7 @@ An example of emitted Wasm IR in the form of WAT: ) ``` -#### Known issues +#### Limitations - ESTree expression compilation uses `eval` which can be unavailable in several environments. - WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/). diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md index 9494af63a..e9e22f4d4 100644 --- a/kmath-ast/docs/README-TEMPLATE.md +++ b/kmath-ast/docs/README-TEMPLATE.md @@ -1,11 +1,31 @@ # Module kmath-ast -Performance and visualization extensions to MST API. +Extensions to MST API: transformations, dynamic compilation and visualization. ${features} ${artifact} +## Parsing expressions + +In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances. + +Supported literals: +1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`. +2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`—all parsed either as `kotlin.Long` or `kotlin.Double`. + +Supported binary operators (from the highest precedence to the lowest one): +1. `^` +2. `*`, `/` +3. `+`, `-` + +Supported unary operator: +1. `-`, e. g. `-x` + +Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples: +1. `sin(x)` +2. `add(x, y)` + ## Dynamic expression code generation ### On JVM @@ -13,48 +33,66 @@ ${artifact} `kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a special implementation of `Expression` with implemented `invoke` function. -For example, the following builder: +For example, the following code: ```kotlin -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.* -import space.kscience.kmath.asm.* - -MstField { x + 2 }.compileToExpression(DoubleField) -``` - -... leads to generation of bytecode, which can be decompiled to the following Java class: - -```java -package space.kscience.kmath.asm.generated; - -import java.util.Map; - -import kotlin.jvm.functions.Function2; -import space.kscience.kmath.asm.internal.MapIntrinsics; -import space.kscience.kmath.expressions.Expression; -import space.kscience.kmath.expressions.Symbol; - -public final class AsmCompiledExpression_45045_0 implements Expression { - private final Object[] constants; - - public final Double invoke(Map arguments) { - return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2); - } - - public AsmCompiledExpression_45045_0(Object[] constants) { - this.constants = constants; - } -} +import space.kscience.kmath.asm.compileToExpression +import space.kscience.kmath.operations.DoubleField +"x^3-x+3".parseMath().compileToExpression(DoubleField) ``` -#### Known issues +… leads to generation of bytecode, which can be decompiled to the following Java class: -- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class - loading overhead. -- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. +```java +import java.util.*; +import kotlin.jvm.functions.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.complex.*; +import space.kscience.kmath.expressions.*; + +public final class CompiledExpression_45045_0 implements Expression { + private final Object[] constants; + + public Complex invoke(Map arguments) { + Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x"); + return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]); + } +} +``` + +For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: + +```java +import java.util.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.expressions.*; + +public final class CompiledExpression_-386104628_0 implements DoubleExpression { + private final SymbolIndexer indexer; + + public SymbolIndexer getIndexer() { + return this.indexer; + } + + public double invoke(double[] arguments) { + double var2 = arguments[0]; + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } + + public final Double invoke(Map arguments) { + double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } +} +``` + +Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. + +#### Limitations + +- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead. +- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders. ### On JS @@ -100,7 +138,7 @@ An example of emitted Wasm IR in the form of WAT: ) ``` -#### Known issues +#### Limitations - ESTree expression compilation uses `eval` which can be unavailable in several environments. - WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/). 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 new file mode 100644 index 000000000..8a8b8797d --- /dev/null +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt @@ -0,0 +1,177 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.ast + +import space.kscience.kmath.expressions.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 + +/** + * MST form where all values belong to the type [T]. It is optimal for constant folding, dynamic compilation, etc. + * + * @param T the type. + */ +@UnstableKMathAPI +public sealed interface TypedMst { + /** + * A node containing a unary operation. + * + * @param T the type. + * @property operation The identifier of operation. + * @property function The function implementing this operation. + * @property value The argument of this operation. + */ + public class Unary(public val operation: String, public val function: (T) -> T, public val value: TypedMst) : + TypedMst { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + other as Unary<*> + if (operation != other.operation) return false + if (value != other.value) return false + return true + } + + override fun hashCode(): Int { + var result = operation.hashCode() + result = 31 * result + value.hashCode() + return result + } + + override fun toString(): String = "Unary(operation=$operation, value=$value)" + } + + /** + * A node containing binary operation. + * + * @param T the type. + * @property operation The identifier of operation. + * @property function The binary function implementing this operation. + * @property left The left operand. + * @property right The right operand. + */ + public class Binary( + public val operation: String, + public val function: Function, + public val left: TypedMst, + public val right: TypedMst, + ) : TypedMst { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as Binary<*> + + if (operation != other.operation) return false + if (left != other.left) return false + if (right != other.right) return false + + return true + } + + override fun hashCode(): Int { + var result = operation.hashCode() + result = 31 * result + left.hashCode() + result = 31 * result + right.hashCode() + return result + } + + override fun toString(): String = "Binary(operation=$operation, left=$left, right=$right)" + } + + /** + * The non-numeric constant value. + * + * @param T the type. + * @property value The held value. + * @property number The number this value corresponds. + */ + public class Constant(public val value: T, public val number: Number?) : TypedMst { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + other as Constant<*> + if (value != other.value) return false + if (number != other.number) return false + return true + } + + override fun hashCode(): Int { + var result = value?.hashCode() ?: 0 + result = 31 * result + (number?.hashCode() ?: 0) + return result + } + + override fun toString(): String = "Constant(value=$value, number=$number)" + } + + /** + * The node containing a variable + * + * @param T the type. + * @property symbol The symbol of the variable. + */ + public class Variable(public val symbol: Symbol) : TypedMst { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + other as Variable<*> + if (symbol != other.symbol) return false + return true + } + + override fun hashCode(): Int = symbol.hashCode() + override fun toString(): String = "Variable(symbol=$symbol)" + } +} + +/** + * 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)) + + is TypedMst.Binary -> when { + algebra is NumericAlgebra && left is TypedMst.Constant && left.number != null -> + algebra.leftSideNumberOperation(operation, left.number, right.interpret(algebra, arguments)) + + algebra is NumericAlgebra && right is TypedMst.Constant && right.number != null -> + algebra.rightSideNumberOperation(operation, left.interpret(algebra, arguments), right.number) + + else -> algebra.binaryOperation( + operation, + left.interpret(algebra, arguments), + right.interpret(algebra, arguments), + ) + } + + is TypedMst.Constant -> value + is TypedMst.Variable -> arguments.getValue(symbol) +} + +/** + * Interprets the [TypedMst] node with this [Algebra] and optional [arguments]. + */ +@UnstableKMathAPI +public fun TypedMst.interpret(algebra: Algebra, vararg arguments: Pair): T = interpret( + algebra, + when (arguments.size) { + 0 -> emptyMap() + 1 -> mapOf(arguments[0]) + else -> hashMapOf(*arguments) + }, +) + +/** + * 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 new file mode 100644 index 000000000..71fb154c9 --- /dev/null +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt @@ -0,0 +1,93 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.ast + +import space.kscience.kmath.expressions.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 + +/** + * 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"), + value, + ) + + is MST.Unary -> when (val arg = value.evaluateConstants(algebra)) { + is TypedMst.Constant -> { + val value = algebra.unaryOperation( + operation, + arg.value, + ) + + TypedMst.Constant(value, if (value is Number) value else null) + } + + else -> TypedMst.Unary(operation, algebra.unaryOperationFunction(operation), arg) + } + + is MST.Binary -> { + val left = left.evaluateConstants(algebra) + val right = right.evaluateConstants(algebra) + + when { + left is TypedMst.Constant && right is TypedMst.Constant -> { + val value = when { + algebra is NumericAlgebra && left.number != null -> algebra.leftSideNumberOperation( + operation, + left.number, + right.value, + ) + + algebra is NumericAlgebra && right.number != null -> algebra.rightSideNumberOperation( + operation, + left.value, + right.number, + ) + + else -> algebra.binaryOperation( + operation, + left.value, + right.value, + ) + } + + TypedMst.Constant(value, if (value is Number) value else null) + } + + algebra is NumericAlgebra && left is TypedMst.Constant && left.number != null -> TypedMst.Binary( + operation, + algebra.leftSideNumberOperationFunction(operation), + left, + right, + ) + + algebra is NumericAlgebra && right is TypedMst.Constant && right.number != null -> TypedMst.Binary( + operation, + algebra.rightSideNumberOperationFunction(operation), + left, + right, + ) + + else -> TypedMst.Binary(operation, algebra.binaryOperationFunction(operation), left, right) + } + } + + is Symbol -> { + val boundSymbol = algebra.bindSymbolOrNull(this) + + if (boundSymbol != null) + TypedMst.Constant(boundSymbol, if (boundSymbol is Number) boundSymbol else null) + else + TypedMst.Variable(this) + } +} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt new file mode 100644 index 000000000..954a0f330 --- /dev/null +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.ast + +import space.kscience.kmath.operations.ByteRing +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.IntRing +import space.kscience.kmath.operations.pi +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.fail + +internal class TestFolding { + @Test + fun foldUnary() = assertEquals( + -1, + ("-(1)".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, + ) + + @Test + fun foldDeepUnary() = assertEquals( + 1, + ("-(-(1))".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, + ) + + @Test + fun foldBinary() = assertEquals( + 2, + ("1*2".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, + ) + + @Test + fun foldDeepBinary() = assertEquals( + 10, + ("1*2*5".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, + ) + + @Test + fun foldSymbol() = assertEquals( + DoubleField.pi, + ("pi".parseMath().evaluateConstants(DoubleField) as? TypedMst.Constant ?: fail()).value, + ) + + @Test + fun foldNumeric() = assertEquals( + 42.toByte(), + ("42".parseMath().evaluateConstants(ByteRing) as? TypedMst.Constant ?: fail()).value, + ) +} 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 a6b6e022b..a8b1aa2e1 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,87 +5,48 @@ package space.kscience.kmath.estree +import space.kscience.kmath.ast.TypedMst +import space.kscience.kmath.ast.evaluateConstants import space.kscience.kmath.estree.internal.ESTreeBuilder import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.MST -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 -import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbolOrNull - -@PublishedApi -internal fun MST.compileWith(algebra: Algebra): Expression { - fun ESTreeBuilder.visit(node: MST): BaseExpression = when (node) { - is Symbol -> { - val symbol = algebra.bindSymbolOrNull(node) - - if (symbol != null) - constant(symbol) - else - variable(node.identity) - } - - is Numeric -> constant( - (algebra as? NumericAlgebra)?.number(node.value) ?: error("Numeric nodes are not supported by $this") - ) - - is Unary -> when { - algebra is NumericAlgebra && node.value is Numeric -> constant( - algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)) - ) - - else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) - } - - is Binary -> when { - algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant( - algebra.binaryOperationFunction(node.operation).invoke( - algebra.number((node.left as Numeric).value), - algebra.number((node.right as Numeric).value) - ) - ) - - algebra is NumericAlgebra && node.left is Numeric -> call( - algebra.leftSideNumberOperationFunction(node.operation), - visit(node.left), - visit(node.right), - ) - - algebra is NumericAlgebra && node.right is Numeric -> call( - algebra.rightSideNumberOperationFunction(node.operation), - visit(node.left), - visit(node.right), - ) - - else -> call( - algebra.binaryOperationFunction(node.operation), - visit(node.left), - visit(node.right), - ) - } - } - - return ESTreeBuilder { visit(this@compileWith) }.instance -} /** * Create a compiled expression with given [MST] and given [algebra]. */ -public fun MST.compileToExpression(algebra: Algebra): Expression = compileWith(algebra) +@OptIn(UnstableKMathAPI::class) +public fun MST.compileToExpression(algebra: Algebra): Expression { + val typed = evaluateConstants(algebra) + if (typed is TypedMst.Constant) return Expression { typed.value } + fun ESTreeBuilder.visit(node: TypedMst): BaseExpression = when (node) { + is TypedMst.Constant -> constant(node.value) + is TypedMst.Variable -> variable(node.symbol) + is TypedMst.Unary -> call(node.function, visit(node.value)) + + is TypedMst.Binary -> call( + node.function, + visit(node.left), + visit(node.right), + ) + } + + return ESTreeBuilder { visit(typed) }.instance +} /** * Compile given MST to expression and evaluate it against [arguments] */ -public inline fun MST.compile(algebra: Algebra, arguments: Map): T = - compileToExpression(algebra).invoke(arguments) - +public fun MST.compile(algebra: Algebra, arguments: Map): T = + compileToExpression(algebra)(arguments) /** * Compile given MST to expression and evaluate it against [arguments] */ -public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = - compileToExpression(algebra).invoke(*arguments) +public fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = + compileToExpression(algebra)(*arguments) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt index 4907d8225..10a6c4a16 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -61,7 +61,7 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp } } - fun variable(name: String): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name)) + fun variable(name: Symbol): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name.identity)) fun call(function: Function, vararg args: BaseExpression): BaseExpression = SimpleCallExpression( optional = false, 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 96090a633..aacb62f36 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,8 +5,8 @@ package space.kscience.kmath.wasm.internal +import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.expressions.* -import space.kscience.kmath.expressions.MST.* import space.kscience.kmath.internal.binaryen.* import space.kscience.kmath.internal.webassembly.Instance import space.kscience.kmath.misc.UnstableKMathAPI @@ -16,11 +16,12 @@ import space.kscience.kmath.internal.webassembly.Module as WasmModule private val spreader = eval("(obj, args) => obj(...args)") +@OptIn(UnstableKMathAPI::class) @Suppress("UnsafeCastFromDynamic") internal sealed class WasmBuilder>( protected val binaryenType: Type, protected val algebra: Algebra, - protected val target: MST, + protected val target: TypedMst, ) { protected val keys: MutableList = mutableListOf() protected lateinit var ctx: BinaryenModule @@ -51,59 +52,41 @@ internal sealed class WasmBuilder>( Instance(c, js("{}")).exports.executable } - protected open fun visitSymbol(node: Symbol): ExpressionRef { - algebra.bindSymbolOrNull(node)?.let { return visitNumeric(Numeric(it)) } + protected abstract fun visitNumber(number: Number): ExpressionRef - var idx = keys.indexOf(node) + protected open fun visitVariable(node: TypedMst.Variable): ExpressionRef { + var idx = keys.indexOf(node.symbol) if (idx == -1) { - keys += node + keys += node.symbol idx = keys.lastIndex } return ctx.local.get(idx, binaryenType) } - protected abstract fun visitNumeric(node: Numeric): ExpressionRef - - protected open fun visitUnary(node: Unary): ExpressionRef = + protected open fun visitUnary(node: TypedMst.Unary): ExpressionRef = error("Unary operation ${node.operation} not defined in $this") - protected open fun visitBinary(mst: Binary): ExpressionRef = + protected open fun visitBinary(mst: TypedMst.Binary): ExpressionRef = error("Binary operation ${mst.operation} not defined in $this") protected open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()") - protected fun visit(node: MST): ExpressionRef = when (node) { - is Symbol -> visitSymbol(node) - is Numeric -> visitNumeric(node) + protected fun visit(node: TypedMst): ExpressionRef = when (node) { + is TypedMst.Constant -> visitNumber( + node.number ?: error("Object constants are not supported by pritimive ASM builder"), + ) - is Unary -> when { - algebra is NumericAlgebra && node.value is Numeric -> visitNumeric( - Numeric(algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) - ) - - else -> visitUnary(node) - } - - is Binary -> when { - algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> visitNumeric( - Numeric( - algebra.binaryOperationFunction(node.operation) - .invoke( - algebra.number((node.left as Numeric).value), - algebra.number((node.right as Numeric).value) - ) - ) - ) - - else -> visitBinary(node) - } + is TypedMst.Variable -> visitVariable(node) + is TypedMst.Unary -> visitUnary(node) + is TypedMst.Binary -> visitBinary(node) } } @UnstableKMathAPI -internal class DoubleWasmBuilder(target: MST) : WasmBuilder(f64, DoubleField, target) { +internal class DoubleWasmBuilder(target: TypedMst) : + WasmBuilder(f64, DoubleField, target) { override val instance by lazy { object : DoubleExpression { override val indexer = SimpleSymbolIndexer(keys) @@ -114,9 +97,9 @@ internal class DoubleWasmBuilder(target: MST) : WasmBuilder): ExpressionRef = when (node.operation) { GroupOps.MINUS_OPERATION -> ctx.f64.neg(visit(node.value)) GroupOps.PLUS_OPERATION -> visit(node.value) PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(node.value)) @@ -137,7 +120,7 @@ internal class DoubleWasmBuilder(target: MST) : WasmBuilder super.visitUnary(node) } - override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { + override fun visitBinary(mst: TypedMst.Binary): ExpressionRef = when (mst.operation) { GroupOps.PLUS_OPERATION -> ctx.f64.add(visit(mst.left), visit(mst.right)) GroupOps.MINUS_OPERATION -> ctx.f64.sub(visit(mst.left), visit(mst.right)) RingOps.TIMES_OPERATION -> ctx.f64.mul(visit(mst.left), visit(mst.right)) @@ -148,7 +131,7 @@ internal class DoubleWasmBuilder(target: MST) : WasmBuilder(i32, IntRing, target) { +internal class IntWasmBuilder(target: TypedMst) : WasmBuilder(i32, IntRing, target) { override val instance by lazy { object : IntExpression { override val indexer = SimpleSymbolIndexer(keys) @@ -157,15 +140,15 @@ internal class IntWasmBuilder(target: MST) : WasmBuilder(i32 } } - override fun visitNumeric(node: Numeric) = ctx.i32.const(node.value.toInt()) + override fun visitNumber(number: Number) = ctx.i32.const(number.toInt()) - override fun visitUnary(node: Unary): ExpressionRef = when (node.operation) { + override fun visitUnary(node: TypedMst.Unary): ExpressionRef = when (node.operation) { GroupOps.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(node.value)) GroupOps.PLUS_OPERATION -> visit(node.value) else -> super.visitUnary(node) } - override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { + override fun visitBinary(mst: TypedMst.Binary): ExpressionRef = when (mst.operation) { GroupOps.PLUS_OPERATION -> ctx.i32.add(visit(mst.left), visit(mst.right)) GroupOps.MINUS_OPERATION -> ctx.i32.sub(visit(mst.left), visit(mst.right)) RingOps.TIMES_OPERATION -> ctx.i32.mul(visit(mst.left), visit(mst.right)) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt index 12e6b41af..f9540f9db 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,7 +7,8 @@ package space.kscience.kmath.wasm -import space.kscience.kmath.estree.compileWith +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 @@ -21,8 +22,16 @@ import space.kscience.kmath.wasm.internal.IntWasmBuilder * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: IntRing): IntExpression = IntWasmBuilder(this).instance +public fun MST.compileToExpression(algebra: IntRing): IntExpression { + val typed = evaluateConstants(algebra) + return if (typed is TypedMst.Constant) object : IntExpression { + override val indexer = SimpleSymbolIndexer(emptyList()) + + override fun invoke(arguments: IntArray): Int = typed.value + } else + IntWasmBuilder(typed).instance +} /** * Compile given MST to expression and evaluate it against [arguments]. @@ -31,7 +40,7 @@ public fun MST.compileToExpression(algebra: IntRing): IntExpression = IntWasmBui */ @UnstableKMathAPI public fun MST.compile(algebra: IntRing, arguments: Map): Int = - compileToExpression(algebra).invoke(arguments) + compileToExpression(algebra)(arguments) /** @@ -49,7 +58,16 @@ public fun MST.compile(algebra: IntRing, vararg arguments: Pair): I * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: DoubleField): Expression = DoubleWasmBuilder(this).instance +public fun MST.compileToExpression(algebra: DoubleField): Expression { + val typed = evaluateConstants(algebra) + + return if (typed is TypedMst.Constant) object : DoubleExpression { + override val indexer = SimpleSymbolIndexer(emptyList()) + + override fun invoke(arguments: DoubleArray): Double = typed.value + } else + DoubleWasmBuilder(typed).instance +} /** @@ -59,7 +77,7 @@ public fun MST.compileToExpression(algebra: DoubleField): Expression = D */ @UnstableKMathAPI public fun MST.compile(algebra: DoubleField, arguments: Map): Double = - compileToExpression(algebra).invoke(arguments) + compileToExpression(algebra)(arguments) /** @@ -69,4 +87,4 @@ public fun MST.compile(algebra: DoubleField, arguments: Map): Do */ @UnstableKMathAPI public fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = - compileToExpression(algebra).invoke(*arguments) + compileToExpression(algebra)(*arguments) 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 8e426622d..73b9c97a7 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 @@ -8,10 +8,14 @@ package space.kscience.kmath.asm 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.expressions.MST.* import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Algebra +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.IntRing +import space.kscience.kmath.operations.LongRing /** * Compiles given MST to an Expression using AST compiler. @@ -21,102 +25,64 @@ import space.kscience.kmath.operations.* * @return the compiled expression. * @author Alexander Nozik */ +@OptIn(UnstableKMathAPI::class) @PublishedApi internal fun MST.compileWith(type: Class, algebra: Algebra): Expression { - fun GenericAsmBuilder.variablesVisitor(node: MST): Unit = when (node) { - is Symbol -> prepareVariable(node.identity) - is Unary -> variablesVisitor(node.value) + val typed = evaluateConstants(algebra) + if (typed is TypedMst.Constant) return Expression { typed.value } - is Binary -> { + fun GenericAsmBuilder.variablesVisitor(node: TypedMst): Unit = when (node) { + is TypedMst.Unary -> variablesVisitor(node.value) + + is TypedMst.Binary -> { variablesVisitor(node.left) variablesVisitor(node.right) } - else -> Unit + is TypedMst.Variable -> prepareVariable(node.symbol) + is TypedMst.Constant -> Unit } - fun GenericAsmBuilder.expressionVisitor(node: MST): Unit = when (node) { - is Symbol -> { - val symbol = algebra.bindSymbolOrNull(node) + fun GenericAsmBuilder.expressionVisitor(node: TypedMst): Unit = when (node) { + is TypedMst.Constant -> if (node.number != null) + loadNumberConstant(node.number) + else + loadObjectConstant(node.value) - if (symbol != null) - loadObjectConstant(symbol as Any) - else - loadVariable(node.identity) - } + is TypedMst.Variable -> loadVariable(node.symbol) + is TypedMst.Unary -> buildCall(node.function) { expressionVisitor(node.value) } - is Numeric -> if (algebra is NumericAlgebra) { - if (Number::class.java.isAssignableFrom(type)) - loadNumberConstant(algebra.number(node.value) as Number) - else - loadObjectConstant(algebra.number(node.value)) - } else - error("Numeric nodes are not supported by $this") - - is Unary -> when { - algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant( - algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)), - ) - - else -> buildCall(algebra.unaryOperationFunction(node.operation)) { expressionVisitor(node.value) } - } - - is Binary -> when { - algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant( - algebra.binaryOperationFunction(node.operation).invoke( - algebra.number((node.left as Numeric).value), - algebra.number((node.right as Numeric).value), - ) - ) - - algebra is NumericAlgebra && node.left is Numeric -> buildCall( - algebra.leftSideNumberOperationFunction(node.operation), - ) { - expressionVisitor(node.left) - expressionVisitor(node.right) - } - - algebra is NumericAlgebra && node.right is Numeric -> buildCall( - algebra.rightSideNumberOperationFunction(node.operation), - ) { - expressionVisitor(node.left) - expressionVisitor(node.right) - } - - else -> buildCall(algebra.binaryOperationFunction(node.operation)) { - expressionVisitor(node.left) - expressionVisitor(node.right) - } + is TypedMst.Binary -> buildCall(node.function) { + expressionVisitor(node.left) + expressionVisitor(node.right) } } return GenericAsmBuilder( type, - buildName(this), - { variablesVisitor(this@compileWith) }, - { expressionVisitor(this@compileWith) }, + buildName("${typed.hashCode()}_${type.simpleName}"), + { variablesVisitor(typed) }, + { expressionVisitor(typed) }, ).instance } - /** * Create a compiled expression with given [MST] and given [algebra]. */ public inline fun MST.compileToExpression(algebra: Algebra): Expression = compileWith(T::class.java, algebra) - /** * Compile given MST to expression and evaluate it against [arguments] */ public inline fun MST.compile(algebra: Algebra, arguments: Map): T = - compileToExpression(algebra).invoke(arguments) + compileToExpression(algebra)(arguments) /** * Compile given MST to expression and evaluate it against [arguments] */ public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = - compileToExpression(algebra).invoke(*arguments) + compileToExpression(algebra)(*arguments) /** @@ -125,7 +91,16 @@ public inline fun MST.compile(algebra: Algebra, vararg argu * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: IntRing): IntExpression = IntAsmBuilder(this).instance +public fun MST.compileToExpression(algebra: IntRing): IntExpression { + val typed = evaluateConstants(algebra) + + return if (typed is TypedMst.Constant) object : IntExpression { + override val indexer = SimpleSymbolIndexer(emptyList()) + + override fun invoke(arguments: IntArray): Int = typed.value + } else + IntAsmBuilder(typed).instance +} /** * Compile given MST to expression and evaluate it against [arguments]. @@ -134,7 +109,7 @@ public fun MST.compileToExpression(algebra: IntRing): IntExpression = IntAsmBuil */ @UnstableKMathAPI public fun MST.compile(algebra: IntRing, arguments: Map): Int = - compileToExpression(algebra).invoke(arguments) + compileToExpression(algebra)(arguments) /** * Compile given MST to expression and evaluate it against [arguments]. @@ -152,8 +127,16 @@ public fun MST.compile(algebra: IntRing, vararg arguments: Pair): I * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: LongRing): LongExpression = LongAsmBuilder(this).instance +public fun MST.compileToExpression(algebra: LongRing): LongExpression { + val typed = evaluateConstants(algebra) + return if (typed is TypedMst.Constant) object : LongExpression { + override val indexer = SimpleSymbolIndexer(emptyList()) + + override fun invoke(arguments: LongArray): Long = typed.value + } else + LongAsmBuilder(typed).instance +} /** * Compile given MST to expression and evaluate it against [arguments]. @@ -162,7 +145,7 @@ public fun MST.compileToExpression(algebra: LongRing): LongExpression = LongAsmB */ @UnstableKMathAPI public fun MST.compile(algebra: LongRing, arguments: Map): Long = - compileToExpression(algebra).invoke(arguments) + compileToExpression(algebra)(arguments) /** @@ -181,7 +164,17 @@ public fun MST.compile(algebra: LongRing, vararg arguments: Pair): * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: DoubleField): DoubleExpression = DoubleAsmBuilder(this).instance +public fun MST.compileToExpression(algebra: DoubleField): DoubleExpression { + val typed = evaluateConstants(algebra) + + return if (typed is TypedMst.Constant) object : DoubleExpression { + override val indexer = SimpleSymbolIndexer(emptyList()) + + override fun invoke(arguments: DoubleArray): Double = typed.value + } else + DoubleAsmBuilder(typed).instance +} + /** * Compile given MST to expression and evaluate it against [arguments]. @@ -190,7 +183,7 @@ public fun MST.compileToExpression(algebra: DoubleField): DoubleExpression = Dou */ @UnstableKMathAPI public fun MST.compile(algebra: DoubleField, arguments: Map): Double = - compileToExpression(algebra).invoke(arguments) + compileToExpression(algebra)(arguments) /** * Compile given MST to expression and evaluate it against [arguments]. @@ -199,4 +192,4 @@ public fun MST.compile(algebra: DoubleField, arguments: Map): Do */ @UnstableKMathAPI public fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = - compileToExpression(algebra).invoke(*arguments) + compileToExpression(algebra)(*arguments) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt index 5eb739956..6cf3d8721 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt @@ -56,7 +56,7 @@ internal class GenericAsmBuilder( /** * Local variables indices are indices of symbols in this list. */ - private val argumentsLocals = mutableListOf() + private val argumentsLocals = mutableListOf() /** * Subclasses, loads and instantiates [Expression] for given parameters. @@ -253,10 +253,10 @@ internal class GenericAsmBuilder( * Stores value variable [name] into a local. Should be called within [variablesPrepareCallback] before using * [loadVariable]. */ - fun prepareVariable(name: String): Unit = invokeMethodVisitor.run { + fun prepareVariable(name: Symbol): Unit = invokeMethodVisitor.run { if (name in argumentsLocals) return@run load(1, MAP_TYPE) - aconst(name) + aconst(name.identity) invokestatic( MAP_INTRINSICS_TYPE.internalName, @@ -280,7 +280,7 @@ internal class GenericAsmBuilder( * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored * with [prepareVariable] first. */ - fun loadVariable(name: String): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tType) + fun loadVariable(name: Symbol): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tType) inline fun buildCall(function: Function, parameters: GenericAsmBuilder.() -> Unit) { contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } 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 bf1f42395..01bad83e5 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,6 +11,7 @@ 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.ast.TypedMst import space.kscience.kmath.expressions.* import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* @@ -25,9 +26,9 @@ internal sealed class PrimitiveAsmBuilder>( classOfT: Class<*>, protected val classOfTPrimitive: Class<*>, expressionParent: Class, - protected val target: MST, + protected val target: TypedMst, ) : AsmBuilder() { - private val className: String = buildName(target) + private val className: String = buildName("${target.hashCode()}_${classOfT.simpleName}") /** * ASM type for [tType]. @@ -329,63 +330,39 @@ internal sealed class PrimitiveAsmBuilder>( } private fun visitVariables( - node: MST, + node: TypedMst, arrayMode: Boolean, alreadyLoaded: MutableList = mutableListOf() ): Unit = when (node) { - is Symbol -> when (node) { - !in alreadyLoaded -> { - alreadyLoaded += node - prepareVariable(node, arrayMode) - } - else -> { - } - } + is TypedMst.Variable -> if (node.symbol !in alreadyLoaded) { + alreadyLoaded += node.symbol + prepareVariable(node.symbol, arrayMode) + } else Unit - is MST.Unary -> visitVariables(node.value, arrayMode, alreadyLoaded) + is TypedMst.Unary -> visitVariables(node.value, arrayMode, alreadyLoaded) - is MST.Binary -> { + is TypedMst.Binary -> { visitVariables(node.left, arrayMode, alreadyLoaded) visitVariables(node.right, arrayMode, alreadyLoaded) } - else -> Unit + is TypedMst.Constant -> Unit } - private fun visitExpression(node: MST): Unit = when (node) { - is Symbol -> { - val symbol = algebra.bindSymbolOrNull(node) + private fun visitExpression(node: TypedMst): Unit = when (node) { + is TypedMst.Variable -> loadVariable(node.symbol) - if (symbol != null) - loadNumberConstant(symbol) - else - loadVariable(node) - } + is TypedMst.Constant -> loadNumberConstant( + node.number ?: error("Object constants are not supported by pritimive ASM builder"), + ) - is MST.Numeric -> loadNumberConstant(algebra.number(node.value)) - - is MST.Unary -> if (node.value is MST.Numeric) - loadNumberConstant( - algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as MST.Numeric).value)), - ) - else - visitUnary(node) - - is MST.Binary -> when { - node.left is MST.Numeric && node.right is MST.Numeric -> loadNumberConstant( - algebra.binaryOperationFunction(node.operation)( - algebra.number((node.left as MST.Numeric).value), - algebra.number((node.right as MST.Numeric).value), - ), - ) - - else -> visitBinary(node) - } + is TypedMst.Unary -> visitUnary(node) + is TypedMst.Binary -> visitBinary(node) } - protected open fun visitUnary(node: MST.Unary) = visitExpression(node.value) + protected open fun visitUnary(node: TypedMst.Unary) = visitExpression(node.value) - protected open fun visitBinary(node: MST.Binary) { + protected open fun visitBinary(node: TypedMst.Binary) { visitExpression(node.left) visitExpression(node.right) } @@ -404,14 +381,13 @@ internal sealed class PrimitiveAsmBuilder>( } @UnstableKMathAPI -internal class DoubleAsmBuilder(target: MST) : PrimitiveAsmBuilder( +internal class DoubleAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder( DoubleField, java.lang.Double::class.java, java.lang.Double.TYPE, DoubleExpression::class.java, target, ) { - private fun buildUnaryJavaMathCall(name: String) = invokeMethodVisitor.invokestatic( MATH_TYPE.internalName, name, @@ -434,7 +410,7 @@ internal class DoubleAsmBuilder(target: MST) : PrimitiveAsmBuilder) { super.visitUnary(node) when (node.operation) { @@ -459,7 +435,7 @@ internal class DoubleAsmBuilder(target: MST) : PrimitiveAsmBuilder) { super.visitBinary(node) when (node.operation) { @@ -479,7 +455,7 @@ internal class DoubleAsmBuilder(target: MST) : PrimitiveAsmBuilder) : PrimitiveAsmBuilder( IntRing, Integer::class.java, @@ -487,7 +463,7 @@ internal class IntAsmBuilder(target: MST) : IntExpression::class.java, target ) { - override fun visitUnary(node: MST.Unary) { + override fun visitUnary(node: TypedMst.Unary) { super.visitUnary(node) when (node.operation) { @@ -497,7 +473,7 @@ internal class IntAsmBuilder(target: MST) : } } - override fun visitBinary(node: MST.Binary) { + override fun visitBinary(node: TypedMst.Binary) { super.visitBinary(node) when (node.operation) { @@ -510,14 +486,14 @@ internal class IntAsmBuilder(target: MST) : } @UnstableKMathAPI -internal class LongAsmBuilder(target: MST) : PrimitiveAsmBuilder( +internal class LongAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder( LongRing, java.lang.Long::class.java, java.lang.Long.TYPE, LongExpression::class.java, target, ) { - override fun visitUnary(node: MST.Unary) { + override fun visitUnary(node: TypedMst.Unary) { super.visitUnary(node) when (node.operation) { @@ -527,7 +503,7 @@ internal class LongAsmBuilder(target: MST) : PrimitiveAsmBuilder) { super.visitBinary(node) when (node.operation) { diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt index 06e040e93..9e880f4fc 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt @@ -55,15 +55,15 @@ internal inline fun MethodVisitor.instructionAdapter(block: InstructionAdapter.( internal fun MethodVisitor.label(): Label = Label().also(::visitLabel) /** - * Creates a class name for [Expression] subclassed to implement [mst] provided. + * Creates a class name for [Expression] based with appending [marker] to reduce collisions. * * These methods help to avoid collisions of class name to prevent loading several classes with the same name. If there * is a colliding class, change [collision] parameter or leave it `0` to check existing classes recursively. * * @author Iaroslav Postovalov */ -internal tailrec fun buildName(mst: MST, collision: Int = 0): String { - val name = "space.kscience.kmath.asm.generated.CompiledExpression_${mst.hashCode()}_$collision" +internal tailrec fun buildName(marker: String, collision: Int = 0): String { + val name = "space.kscience.kmath.asm.generated.CompiledExpression_${marker}_$collision" try { Class.forName(name) @@ -71,7 +71,7 @@ internal tailrec fun buildName(mst: MST, collision: Int = 0): String { return name } - return buildName(mst, collision + 1) + return buildName(marker, collision + 1) } @Suppress("FunctionName") diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 5f194f2ea..880cf8421 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -34,12 +34,12 @@ public abstract class FunctionalExpressionAlgebra>( override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = { left, right -> Expression { arguments -> - algebra.binaryOperationFunction(operation)(left.invoke(arguments), right.invoke(arguments)) + algebra.binaryOperationFunction(operation)(left(arguments), right(arguments)) } } override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> - Expression { arguments -> algebra.unaryOperationFunction(operation)(arg.invoke(arguments)) } + Expression { arguments -> algebra.unaryOperation(operation, arg(arguments)) } } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt index 24e96e845..18226119b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt @@ -24,7 +24,7 @@ public sealed interface MST { public data class Numeric(val value: Number) : MST /** - * A node containing an unary operation. + * A node containing a unary operation. * * @property operation the identifier of operation. * @property value the argument of this operation. @@ -34,7 +34,7 @@ public sealed interface MST { /** * A node containing binary operation. * - * @property operation the identifier operation. + * @property operation the identifier of operation. * @property left the left operand. * @property right the right operand. */ -- 2.34.1 From 408443989c5858d555926b2cd6ab3e9edbb057ff Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 13 Feb 2022 17:48:04 +0300 Subject: [PATCH 086/102] Up version --- build.gradle.kts | 2 +- .../kmath/expressions/FunctionalExpressionAlgebra.kt | 2 -- .../space/kscience/kmath/expressions/SimpleAutoDiff.kt | 7 ++----- .../kscience/kmath/tensorflow/TensorFlowAlgebra.kt | 10 ++++++++++ .../space/kscience/kmath/tensorflow/tfOperations.kt | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1b2d9d7c0..a07bcd2c5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ allprojects { } group = "space.kscience" - version = "0.3.0-dev-17" + version = "0.3.0-dev-18" } subprojects { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 880cf8421..68cc8e791 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -164,8 +164,6 @@ public open class FunctionalExpressionExtendedField> override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) - - override fun bindSymbol(value: String): Expression = super.bindSymbol(value) } public inline fun > A.expressionInGroup( diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt index 96fc73249..ac8c44446 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 @@ -272,7 +272,7 @@ public fun > SimpleAutoDiffField.sqrt(x: Aut public fun > SimpleAutoDiffField.pow( x: AutoDiffValue, y: Double, -): AutoDiffValue = derive(const { x.value.pow(y)}) { z -> +): AutoDiffValue = derive(const { x.value.pow(y) }) { z -> x.d += z.d * y * x.value.pow(y - 1) } @@ -343,10 +343,7 @@ public fun > SimpleAutoDiffField.atanh(x: Au public class SimpleAutoDiffExtendedField>( context: F, bindings: Map, -) : ExtendedField>, ScaleOperations>, - SimpleAutoDiffField(context, bindings) { - - override fun bindSymbol(value: String): AutoDiffValue = super.bindSymbol(value) +) : ExtendedField>, ScaleOperations>, SimpleAutoDiffField(context, bindings) { override fun number(value: Number): AutoDiffValue = const { number(value) } 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 e2541a73e..e9e75543d 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 @@ -241,6 +241,16 @@ public abstract class TensorFlowAlgebra> internal c ops.math.argMax(asTensorFlow().output, ops.constant(dim), TInt32::class.java).output() ).actualTensor +// private val symbolCache = HashMap>() +// +// override fun bindSymbolOrNull(value: String): TensorFlowOutput? { +// return symbolCache.getOrPut(value){ops.var} +// } +// +// public fun StructureND.grad( +// +// )= operate { ops.gradients() } + @OptIn(UnstableKMathAPI::class) override fun export(arg: StructureND): StructureND = if (arg is TensorFlowOutput) arg.actualTensor else arg diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt index 257d4d6ea..f67c333ce 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt @@ -20,4 +20,4 @@ public fun TensorFlowAlgebra.sin( public fun TensorFlowAlgebra.cos( arg: StructureND, -): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.cos(it) } +): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.cos(it) } \ No newline at end of file -- 2.34.1 From a78e361b178eca4a9b89a25dc5067e3e0732dc33 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sun, 13 Feb 2022 16:01:05 +0300 Subject: [PATCH 087/102] Implement much faster dot product algorithm for tensors --- .../kscience/kmath/benchmarks/DotBenchmark.kt | 10 ++++++++++ .../kmath/tensors/core/DoubleTensorAlgebra.kt | 2 +- .../kmath/tensors/core/internal/linUtils.kt | 18 +++++++++++++----- .../tensors/core/TestDoubleTensorAlgebra.kt | 9 +++++++++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 63165baaa..53d7ee9b6 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -15,7 +15,9 @@ import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import kotlin.random.Random @State(Scope.Benchmark) @@ -32,6 +34,9 @@ internal class DotBenchmark { random.nextDouble() } + val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224) + val tensor2 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12225) + val cmMatrix1 = CMLinearSpace { matrix1.toCM() } val cmMatrix2 = CMLinearSpace { matrix2.toCM() } @@ -78,4 +83,9 @@ internal class DotBenchmark { fun doubleDot(blackhole: Blackhole) = with(DoubleField.linearSpace) { blackhole.consume(matrix1 dot matrix2) } + + @Benchmark + fun doubleTensorDot(blackhole: Blackhole) = DoubleTensorAlgebra.invoke { + blackhole.consume(tensor1 dot tensor2) + } } 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 50252ad31..a75e5a8e3 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 @@ -421,7 +421,7 @@ public open class DoubleTensorAlgebra : for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { val (a, b) = ab - dotTo(a.as2D(), b.as2D(), res.as2D(), l, m1, n) + dotTo(a, b, res, l, m1, n) } return if (penultimateDim) { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index 2fb5b949f..aba6167ce 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -54,18 +54,26 @@ internal val BufferedTensor.matrices: VirtualBuffer> internal fun BufferedTensor.matrixSequence(): Sequence> = matrices.asSequence() internal fun dotTo( - a: MutableStructure2D, - b: MutableStructure2D, - res: MutableStructure2D, + a: BufferedTensor, + b: BufferedTensor, + res: BufferedTensor, l: Int, m: Int, n: Int, ) { + val aStart = a.bufferStart + val bStart = b.bufferStart + val resStart = res.bufferStart + + val aBuffer = a.mutableBuffer + val bBuffer = b.mutableBuffer + val resBuffer = res.mutableBuffer + for (i in 0 until l) { for (j in 0 until n) { var curr = 0.0 for (k in 0 until m) { - curr += a[i, k] * b[k, j] + curr += aBuffer[aStart + i * m + k] * bBuffer[bStart + k * n + j] } - res[i, j] = curr + resBuffer[resStart + i * n + j] = curr } } } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 03357f1e1..205ae2fee 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -107,6 +107,8 @@ internal class TestDoubleTensorAlgebra { val tensor11 = fromArray(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor2 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor3 = fromArray(intArrayOf(1, 1, 3), doubleArrayOf(-1.0, -2.0, -3.0)) + val tensor4 = fromArray(intArrayOf(2, 3, 3), (1..18).map { it.toDouble() }.toDoubleArray()) + val tensor5 = fromArray(intArrayOf(2, 3, 3), (1..18).map { 1 + it.toDouble() }.toDoubleArray()) val res12 = tensor1.dot(tensor2) assertTrue(res12.mutableBuffer.array() contentEquals doubleArrayOf(140.0, 320.0)) @@ -123,6 +125,13 @@ internal class TestDoubleTensorAlgebra { val res11 = tensor1.dot(tensor11) assertTrue(res11.mutableBuffer.array() contentEquals doubleArrayOf(22.0, 28.0, 49.0, 64.0)) assertTrue(res11.shape contentEquals intArrayOf(2, 2)) + + val res45 = tensor4.dot(tensor5) + assertTrue(res45.mutableBuffer.array() contentEquals doubleArrayOf( + 36.0, 42.0, 48.0, 81.0, 96.0, 111.0, 126.0, 150.0, 174.0, + 468.0, 501.0, 534.0, 594.0, 636.0, 678.0, 720.0, 771.0, 822.0 + )) + assertTrue(res45.shape contentEquals intArrayOf(2, 3, 3)) } @Test -- 2.34.1 From ac3adfa644911b6def168c257cf8bee3a6018514 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 17 Feb 2022 22:46:17 +0300 Subject: [PATCH 088/102] Fix tf dot --- benchmarks/build.gradle.kts | 2 ++ .../kscience/kmath/benchmarks/DotBenchmark.kt | 22 ++++++++++++++----- build.gradle.kts | 2 +- .../real/{RealVector.kt => DoubleVector.kt} | 0 .../kmath/tensorflow/TensorFlowAlgebra.kt | 5 +++-- .../kmath/tensorflow/DoubleTensorFlowOps.kt | 16 ++++++++++++++ .../kmath/tensors/core/DoubleTensorAlgebra.kt | 1 + 7 files changed, 40 insertions(+), 8 deletions(-) rename kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/{RealVector.kt => DoubleVector.kt} (100%) diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 90ec5dfbe..e46f4a9b4 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -52,6 +52,8 @@ kotlin { implementation(project(":kmath-viktor")) implementation(project(":kmath-jafama")) implementation(project(":kmath-multik")) + implementation(projects.kmath.kmathTensorflow) + implementation("org.tensorflow:tensorflow-core-platform:0.4.0") implementation("org.nd4j:nd4j-native:1.0.0-M1") // uncomment if your system supports AVX2 // val os = System.getProperty("os.name") diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 53d7ee9b6..4a5cd4aa2 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -17,7 +17,9 @@ import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.tensorflow.produceWithTF import space.kscience.kmath.tensors.core.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.tensorAlgebra import kotlin.random.Random @State(Scope.Benchmark) @@ -44,6 +46,16 @@ internal class DotBenchmark { val ejmlMatrix2 = EjmlLinearSpaceDDRM { matrix2.toEjml() } } + + @Benchmark + fun tfDot(blackhole: Blackhole){ + blackhole.consume( + DoubleField.produceWithTF { + tensor1 dot tensor2 + } + ) + } + @Benchmark fun cmDotWithConversion(blackhole: Blackhole) = CMLinearSpace { blackhole.consume(matrix1 dot matrix2) @@ -64,13 +76,13 @@ internal class DotBenchmark { blackhole.consume(matrix1 dot matrix2) } -// @Benchmark -// fun tensorDot(blackhole: Blackhole) = with(Double.tensorAlgebra) { -// blackhole.consume(matrix1 dot matrix2) -// } + @Benchmark + fun tensorDot(blackhole: Blackhole) = with(DoubleField.tensorAlgebra) { + blackhole.consume(matrix1 dot matrix2) + } @Benchmark - fun multikDot(blackhole: Blackhole) = with(Double.multikAlgebra) { + fun multikDot(blackhole: Blackhole) = with(DoubleField.multikAlgebra) { blackhole.consume(matrix1 dot matrix2) } diff --git a/build.gradle.kts b/build.gradle.kts index a07bcd2c5..3b48c7328 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ allprojects { } group = "space.kscience" - version = "0.3.0-dev-18" + version = "0.3.0-dev-19" } subprojects { diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt similarity index 100% rename from kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt rename to kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt 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 e9e75543d..b40739ee0 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 @@ -199,8 +199,9 @@ public abstract class TensorFlowAlgebra> internal c override fun StructureND.dot(other: StructureND): TensorFlowOutput = operate(other) { l, r -> ops.linalg.matMul( - if (l.asTensor().shape().numDimensions() == 1) ops.expandDims(l, ops.constant(0)) else l, - if (r.asTensor().shape().numDimensions() == 1) ops.expandDims(r, ops.constant(-1)) else r) + if (l.shape().numDimensions() == 1) ops.expandDims(l, ops.constant(0)) else l, + if (r.shape().numDimensions() == 1) ops.expandDims(r, ops.constant(-1)) else r + ) } override fun diagonalEmbedding( 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 805ad7c66..3d118d980 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 @@ -4,6 +4,9 @@ import org.junit.jupiter.api.Test import space.kscience.kmath.nd.get import space.kscience.kmath.nd.structureND import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.sum +import kotlin.random.Random import kotlin.test.assertEquals class DoubleTensorFlowOps { @@ -18,6 +21,19 @@ class DoubleTensorFlowOps { assertEquals(3.0, res[0, 0]) } + @Test + fun dot(){ + val random = Random(12224) + val dim = 1000 + + val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224) + val tensor2 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12225) + + DoubleField.produceWithTF { + tensor1 dot tensor2 + }.sum() + } + @Test fun extensionOps(){ val res = DoubleField.produceWithTF { 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 a75e5a8e3..ebe7a10b6 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 @@ -997,5 +997,6 @@ public open class DoubleTensorAlgebra : } public val Double.Companion.tensorAlgebra: DoubleTensorAlgebra.Companion get() = DoubleTensorAlgebra +public val DoubleField.tensorAlgebra: DoubleTensorAlgebra.Companion get() = DoubleTensorAlgebra -- 2.34.1 From 7a72a0b979e04ba928c31e01058ff561cebcc69f Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sun, 13 Feb 2022 13:16:35 +0300 Subject: [PATCH 089/102] Implement Jacobi algorithm to find eigenvalues --- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 98 ++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) 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 ebe7a10b6..418cf16b9 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 @@ -895,7 +895,7 @@ public open class DoubleTensorAlgebra : * and when the cosine approaches 1 in the SVD algorithm. * @return a pair `eigenvalues to eigenvectors`. */ - public fun StructureND.symEig(epsilon: Double): Pair { + public fun StructureND.symEigSvd(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) fun MutableStructure2D.cleanSym(n: Int) { @@ -922,6 +922,102 @@ public open class DoubleTensorAlgebra : return eig to v } + // TODO + // 1. Cyclic method + // 2. Sort eigenvalues + public fun StructureND.symEig(epsilon: Double): Pair { + checkSymmetric(tensor, epsilon) + + val ii = tensor.minusIndex(-2) + val jj = tensor.minusIndex(-1) + val n = tensor.numElements + + val size = this.dimension + val commonShape = this.shape.sliceArray(0 until size - 2) + intArrayOf(1, 1) + + var d = this.copy() + var s = diagonalEmbedding(ones(this.shape.sliceArray(0 until size - 1))) + + do { + // 1. Find max element by abs value that is not on diagonal + val buffer = MutableBuffer.boxing(commonShape.reduce(Int::times)) { Triple(0.0, 0, 0) } + val maxOffDiagonalElements = BufferedTensor(commonShape, buffer, 0) + for (offset in 0 until n) { + val multiIndex = d.linearStructure.index(offset) + if (multiIndex[ii] != multiIndex[jj]) { + val value = d.mutableBuffer.array()[offset] + + val commonIndex = multiIndex.sliceArray(0 until size - 2) + intArrayOf(0, 0) + if (abs(value) > maxOffDiagonalElements[commonIndex].first) { + maxOffDiagonalElements[commonIndex] = Triple(abs(value), multiIndex[ii], multiIndex[jj]) + } + } + } + + // 2. Evaluate "rotation" angle + val angles = zeros(commonShape) + for (offset in 0 until maxOffDiagonalElements.numElements) { + val (_, i, j) = maxOffDiagonalElements.mutableBuffer[offset] + val multiIndex = maxOffDiagonalElements.linearStructure.index(offset) + + val dIJ = d.mutableBuffer[d.linearStructure.offset(multiIndex.also { it[ii] = i; it[jj] = j })] + val dII = d.mutableBuffer[d.linearStructure.offset(multiIndex.also { it[ii] = i; it[jj] = i })] + val dJJ = d.mutableBuffer[d.linearStructure.offset(multiIndex.also { it[ii] = j; it[jj] = j })] + + angles.mutableBuffer.array()[offset] = if (dII == dJJ) { + if (dIJ > 0) PI / 4 else -PI / 4 + } else { + 0.5 * atan(2 * dIJ / (dJJ - dII)) + } + } + + // 3. Build rotation tensor `s1` + val s1 = diagonalEmbedding(ones(this.shape.sliceArray(0 until size - 1))) + for (offset in 0 until n) { + val multiIndex = d.linearStructure.index(offset) + + val commonIndex = multiIndex.sliceArray(0 until size - 2) + intArrayOf(0, 0) + val (_, i, j) = maxOffDiagonalElements[commonIndex] + val angleValue = angles[commonIndex] + s1.mutableBuffer.array()[offset] = when { + multiIndex[ii] == i && multiIndex[jj] == i || multiIndex[ii] == j && multiIndex[jj] == j -> cos(angleValue) + multiIndex[ii] == i && multiIndex[jj] == j -> sin(angleValue) + multiIndex[ii] == j && multiIndex[jj] == i -> -sin(angleValue) + else -> s1.mutableBuffer.array()[offset] + } + } + + // 4. Evaluate new tensor + d = (s1.transpose() dot d) dot s1 + s = s dot s1 + if (d.isDiagonal(epsilon)) break + } while(true) + + val eigenvalues = zeros(d.shape.sliceArray(0 until size - 1)) + for (offset in 0 until n) { + val multiIndex = d.linearStructure.index(offset) + if (multiIndex[ii] == multiIndex[jj]) { + eigenvalues[multiIndex.sliceArray(0 until size - 1)] = d.mutableBuffer.array()[offset] + } + } + + return eigenvalues to s + } + + public fun StructureND.isDiagonal(epsilon: Double = 1e-9): Boolean { + val ii = tensor.minusIndex(-2) + val jj = tensor.minusIndex(-1) + + for (offset in 0 until tensor.numElements) { + val multiIndex = tensor.linearStructure.index(offset) + if (multiIndex[ii] != multiIndex[jj] && abs(tensor.mutableBuffer.array()[offset]) > epsilon) { + return false + } + } + + return true + } + /** * Computes the determinant of a square matrix input, or of each square matrix in a batched input * using LU factorization algorithm. -- 2.34.1 From 7aff774bc166d537c40a7958418ac9a40403d74e Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sun, 13 Feb 2022 21:49:06 +0300 Subject: [PATCH 090/102] Improve Jacobi algorithm readability by extracting some logic into helper fun --- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 128 +++++++++--------- 1 file changed, 66 insertions(+), 62 deletions(-) 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 418cf16b9..7fa6e885d 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 @@ -10,6 +10,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.MutableStructure2D +import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D @@ -885,7 +886,7 @@ public open class DoubleTensorAlgebra : return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) } - override fun StructureND.symEig(): Pair = symEig(epsilon = 1e-15) + override fun StructureND.symEig(): Pair = symEigJacobi(epsilon = 1e-10) /** * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, @@ -922,96 +923,99 @@ public open class DoubleTensorAlgebra : return eig to v } - // TODO - // 1. Cyclic method - // 2. Sort eigenvalues - public fun StructureND.symEig(epsilon: Double): Pair { + public fun StructureND.symEigJacobi(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) - val ii = tensor.minusIndex(-2) - val jj = tensor.minusIndex(-1) - val n = tensor.numElements - val size = this.dimension - val commonShape = this.shape.sliceArray(0 until size - 2) + intArrayOf(1, 1) + val s = zeros(this.shape) + val eigenvalues = zeros(this.shape.sliceArray(0 until size - 1)) - var d = this.copy() - var s = diagonalEmbedding(ones(this.shape.sliceArray(0 until size - 1))) + var eigenvalueStart = 0 + var eigenvectorStart = 0 + for (matrix in tensor.matrixSequence()) { + matrix.as2D().jacobiHelper(eigenvalues, s, eigenvalueStart, eigenvectorStart, epsilon) + eigenvalueStart += this.shape.last() + eigenvectorStart += this.shape.last() * this.shape.last() + } + // TODO sort eigenvalues + return eigenvalues to s + } + + private fun MutableStructure2D.jacobiHelper( + eigenvalues: DoubleTensor, + eigenvectors: DoubleTensor, + eigenvalueStart: Int, + eigenvectorStart: Int, + epsilon: Double + ) { + var d = this + var s = eye(this.shape[0]) + + // TODO implement cyclic method do { // 1. Find max element by abs value that is not on diagonal - val buffer = MutableBuffer.boxing(commonShape.reduce(Int::times)) { Triple(0.0, 0, 0) } - val maxOffDiagonalElements = BufferedTensor(commonShape, buffer, 0) - for (offset in 0 until n) { - val multiIndex = d.linearStructure.index(offset) - if (multiIndex[ii] != multiIndex[jj]) { - val value = d.mutableBuffer.array()[offset] - - val commonIndex = multiIndex.sliceArray(0 until size - 2) + intArrayOf(0, 0) - if (abs(value) > maxOffDiagonalElements[commonIndex].first) { - maxOffDiagonalElements[commonIndex] = Triple(abs(value), multiIndex[ii], multiIndex[jj]) + var maxOffDiagonalElement = 0.0 + var maxElementIndex = Pair(0, 0) + for (i in 0 until this.rowNum) { + for (j in 0 until this.colNum) { + if (i == j) continue + if (abs(d[i, j]) > maxOffDiagonalElement) { + maxOffDiagonalElement = abs(d[i, j]) + maxElementIndex = i to j } } } // 2. Evaluate "rotation" angle - val angles = zeros(commonShape) - for (offset in 0 until maxOffDiagonalElements.numElements) { - val (_, i, j) = maxOffDiagonalElements.mutableBuffer[offset] - val multiIndex = maxOffDiagonalElements.linearStructure.index(offset) + val dIJ = d[maxElementIndex.first, maxElementIndex.second] + val dII = d[maxElementIndex.first, maxElementIndex.first] + val dJJ = d[maxElementIndex.second, maxElementIndex.second] - val dIJ = d.mutableBuffer[d.linearStructure.offset(multiIndex.also { it[ii] = i; it[jj] = j })] - val dII = d.mutableBuffer[d.linearStructure.offset(multiIndex.also { it[ii] = i; it[jj] = i })] - val dJJ = d.mutableBuffer[d.linearStructure.offset(multiIndex.also { it[ii] = j; it[jj] = j })] - - angles.mutableBuffer.array()[offset] = if (dII == dJJ) { - if (dIJ > 0) PI / 4 else -PI / 4 - } else { - 0.5 * atan(2 * dIJ / (dJJ - dII)) - } + val angle = if (dII == dJJ) { + if (dIJ > 0) PI / 4 else -PI / 4 + } else { + 0.5 * atan(2 * dIJ / (dJJ - dII)) } // 3. Build rotation tensor `s1` - val s1 = diagonalEmbedding(ones(this.shape.sliceArray(0 until size - 1))) - for (offset in 0 until n) { - val multiIndex = d.linearStructure.index(offset) - - val commonIndex = multiIndex.sliceArray(0 until size - 2) + intArrayOf(0, 0) - val (_, i, j) = maxOffDiagonalElements[commonIndex] - val angleValue = angles[commonIndex] - s1.mutableBuffer.array()[offset] = when { - multiIndex[ii] == i && multiIndex[jj] == i || multiIndex[ii] == j && multiIndex[jj] == j -> cos(angleValue) - multiIndex[ii] == i && multiIndex[jj] == j -> sin(angleValue) - multiIndex[ii] == j && multiIndex[jj] == i -> -sin(angleValue) - else -> s1.mutableBuffer.array()[offset] + val s1 = eye(this.rowNum) + for (i in 0 until this.rowNum) { + for (j in 0 until this.colNum) { + s1.mutableBuffer.array()[i * this.rowNum + j] = when { + maxElementIndex.first == i && maxElementIndex.first == j -> cos(angle) + maxElementIndex.second == i && maxElementIndex.second == j -> cos(angle) + maxElementIndex.first == i && maxElementIndex.second == j -> sin(angle) + maxElementIndex.first == j && maxElementIndex.second == i -> -sin(angle) + else -> s1.mutableBuffer.array()[i * this.rowNum + j] + } } } // 4. Evaluate new tensor - d = (s1.transpose() dot d) dot s1 + d = ((s1.transpose() dot d) dot s1).as2D() s = s dot s1 if (d.isDiagonal(epsilon)) break } while(true) - val eigenvalues = zeros(d.shape.sliceArray(0 until size - 1)) - for (offset in 0 until n) { - val multiIndex = d.linearStructure.index(offset) - if (multiIndex[ii] == multiIndex[jj]) { - eigenvalues[multiIndex.sliceArray(0 until size - 1)] = d.mutableBuffer.array()[offset] + // 5. Copy result + for (i in 0 until this.rowNum) { + for (j in 0 until this.colNum) { + eigenvectors.mutableBuffer.array()[eigenvectorStart + i * this.rowNum + j] = s.mutableBuffer.array()[i * this.rowNum + j] } } - return eigenvalues to s + for (i in 0 until this.rowNum) { + eigenvalues.mutableBuffer.array()[eigenvalueStart + i] = d[i, i] + } } - public fun StructureND.isDiagonal(epsilon: Double = 1e-9): Boolean { - val ii = tensor.minusIndex(-2) - val jj = tensor.minusIndex(-1) - - for (offset in 0 until tensor.numElements) { - val multiIndex = tensor.linearStructure.index(offset) - if (multiIndex[ii] != multiIndex[jj] && abs(tensor.mutableBuffer.array()[offset]) > epsilon) { - return false + public fun Structure2D.isDiagonal(epsilon: Double = 1e-9): Boolean { + for (i in 0 until this.rowNum) { + for (j in 0 until this.colNum) { + if (i != j && abs(this[i, j]) > epsilon) { + return false + } } } -- 2.34.1 From b13765ec1928e0f2b2eb6165a8a5a0e1a057b08f Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sun, 20 Feb 2022 02:21:52 +0300 Subject: [PATCH 091/102] Implement much faster Jacobi algorithm --- benchmarks/build.gradle.kts | 5 + .../benchmarks/TensorAlgebraBenchmark.kt | 37 ++++ .../kmath/tensors/core/DoubleTensorAlgebra.kt | 182 ++++++++++-------- 3 files changed, 149 insertions(+), 75 deletions(-) create mode 100644 benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index e46f4a9b4..f8d39b9c5 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -124,6 +124,11 @@ benchmark { include("JafamaBenchmark") } + configurations.register("tensorAlgebra") { + commonConfiguration() + include("TensorAlgebraBenchmark") + } + configurations.register("viktor") { commonConfiguration() include("ViktorBenchmark") diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt new file mode 100644 index 000000000..38e064e53 --- /dev/null +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State +import space.kscience.kmath.linear.linearSpace +import space.kscience.kmath.linear.matrix +import space.kscience.kmath.linear.symmetric +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.tensors.core.tensorAlgebra +import kotlin.random.Random + +@State(Scope.Benchmark) +internal class TensorAlgebraBenchmark { + companion object { + private val random = Random(12224) + private const val dim = 30 + + private val matrix = DoubleField.linearSpace.matrix(dim, dim).symmetric { _, _ -> random.nextDouble() } + } + + @Benchmark + fun tensorSymEigSvd(blackhole: Blackhole) = with(Double.tensorAlgebra) { + blackhole.consume(matrix.symEigSvd(1e-10)) + } + + @Benchmark + fun tensorSymEigJacobi(blackhole: Blackhole) = with(Double.tensorAlgebra) { + blackhole.consume(matrix.symEigJacobi(50, 1e-10)) + } +} \ No newline at end of file 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 7fa6e885d..675ff4191 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 @@ -9,11 +9,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.MutableStructure2D -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.nd.as2D +import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.indices @@ -886,7 +882,7 @@ public open class DoubleTensorAlgebra : return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) } - override fun StructureND.symEig(): Pair = symEigJacobi(epsilon = 1e-10) + override fun StructureND.symEig(): Pair = symEigJacobi(maxIteration = 50, epsilon = 1e-15) /** * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, @@ -923,103 +919,139 @@ public open class DoubleTensorAlgebra : return eig to v } - public fun StructureND.symEigJacobi(epsilon: Double): Pair { + public fun StructureND.symEigJacobi(maxIteration: Int, epsilon: Double): Pair { checkSymmetric(tensor, epsilon) val size = this.dimension - val s = zeros(this.shape) + val eigenvectors = zeros(this.shape) val eigenvalues = zeros(this.shape.sliceArray(0 until size - 1)) var eigenvalueStart = 0 var eigenvectorStart = 0 for (matrix in tensor.matrixSequence()) { - matrix.as2D().jacobiHelper(eigenvalues, s, eigenvalueStart, eigenvectorStart, epsilon) + val matrix2D = matrix.as2D() + val (d, v) = matrix2D.jacobiHelper(maxIteration, epsilon) + + for (i in 0 until matrix2D.rowNum) { + for (j in 0 until matrix2D.colNum) { + eigenvectors.mutableBuffer.array()[eigenvectorStart + i * matrix2D.rowNum + j] = v[i, j] + } + } + + for (i in 0 until matrix2D.rowNum) { + eigenvalues.mutableBuffer.array()[eigenvalueStart + i] = d[i] + } + eigenvalueStart += this.shape.last() eigenvectorStart += this.shape.last() * this.shape.last() } - // TODO sort eigenvalues - return eigenvalues to s + return eigenvalues to eigenvectors } private fun MutableStructure2D.jacobiHelper( - eigenvalues: DoubleTensor, - eigenvectors: DoubleTensor, - eigenvalueStart: Int, - eigenvectorStart: Int, + maxIteration: Int, epsilon: Double - ) { - var d = this - var s = eye(this.shape[0]) + ): Pair, Structure2D> { + val A_ = this.copy().as2D() + val V = eye(this.shape[0]).as2D() + val D = DoubleTensor(intArrayOf(this.shape[0]), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() + val B = DoubleTensor(intArrayOf(this.shape[0]), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() + val Z = zeros(intArrayOf(this.shape[0])).as1D() - // TODO implement cyclic method - do { - // 1. Find max element by abs value that is not on diagonal + fun maxOffDiagonal(matrix: MutableStructure2D): Double { var maxOffDiagonalElement = 0.0 - var maxElementIndex = Pair(0, 0) - for (i in 0 until this.rowNum) { - for (j in 0 until this.colNum) { - if (i == j) continue - if (abs(d[i, j]) > maxOffDiagonalElement) { - maxOffDiagonalElement = abs(d[i, j]) - maxElementIndex = i to j + for (i in 0 until matrix.rowNum - 1) { + for (j in i + 1 until matrix.colNum) { + maxOffDiagonalElement = max(maxOffDiagonalElement, abs(matrix[i, j])) + } + } + return maxOffDiagonalElement + } + + fun rotate(a: MutableStructure2D, s: Double, tau: Double, i: Int, j: Int, k: Int, l: Int) { + val g = a[i, j] + val h = a[k, l] + a[i, j] = g - s * (h + g * tau) + a[k, l] = h + s * (g - h * tau) + } + + fun jacobiIteration( + a: MutableStructure2D, + v: MutableStructure2D, + d: MutableStructure1D, + z: MutableStructure1D, + ) { + for (ip in 0 until a.rowNum - 1) { + for (iq in ip + 1 until a.colNum) { + val g = 100.0 * abs(a[ip, iq]) + + if (g <= epsilon * abs(d[ip]) && g <= epsilon * abs(d[iq])) { + a[ip, iq] = 0.0 + continue + } + + var h = d[iq] - d[ip] + val t = when { + g <= epsilon * abs(h) -> (a[ip, iq]) / h + else -> { + val theta = 0.5 * h / (a[ip, iq]) + val denominator = abs(theta) + sqrt(1.0 + theta * theta) + if (theta < 0.0) -1.0 / denominator else 1.0 / denominator + } + } + + val c = 1.0 / sqrt(1 + t * t) + val s = t * c + val tau = s / (1.0 + c) + h = t * a[ip, iq] + z[ip] -= h + z[iq] += h + d[ip] -= h + d[iq] += h + a[ip, iq] = 0.0 + + for (j in 0 until ip) { + rotate(a, s, tau, j, ip, j, iq) + } + for (j in (ip + 1) until iq) { + rotate(a, s, tau, ip, j, j, iq) + } + for (j in (iq + 1) until a.rowNum) { + rotate(a, s, tau, ip, j, iq, j) + } + for (j in 0 until a.rowNum) { + rotate(v, s, tau, j, ip, j, iq) } } } + } - // 2. Evaluate "rotation" angle - val dIJ = d[maxElementIndex.first, maxElementIndex.second] - val dII = d[maxElementIndex.first, maxElementIndex.first] - val dJJ = d[maxElementIndex.second, maxElementIndex.second] - - val angle = if (dII == dJJ) { - if (dIJ > 0) PI / 4 else -PI / 4 - } else { - 0.5 * atan(2 * dIJ / (dJJ - dII)) - } - - // 3. Build rotation tensor `s1` - val s1 = eye(this.rowNum) - for (i in 0 until this.rowNum) { - for (j in 0 until this.colNum) { - s1.mutableBuffer.array()[i * this.rowNum + j] = when { - maxElementIndex.first == i && maxElementIndex.first == j -> cos(angle) - maxElementIndex.second == i && maxElementIndex.second == j -> cos(angle) - maxElementIndex.first == i && maxElementIndex.second == j -> sin(angle) - maxElementIndex.first == j && maxElementIndex.second == i -> -sin(angle) - else -> s1.mutableBuffer.array()[i * this.rowNum + j] - } - } - } - - // 4. Evaluate new tensor - d = ((s1.transpose() dot d) dot s1).as2D() - s = s dot s1 - if (d.isDiagonal(epsilon)) break - } while(true) - - // 5. Copy result - for (i in 0 until this.rowNum) { - for (j in 0 until this.colNum) { - eigenvectors.mutableBuffer.array()[eigenvectorStart + i * this.rowNum + j] = s.mutableBuffer.array()[i * this.rowNum + j] + fun updateDiagonal( + d: MutableStructure1D, + z: MutableStructure1D, + b: MutableStructure1D, + ) { + for (ip in 0 until d.size) { + b[ip] += z[ip] + d[ip] = b[ip] + z[ip] = 0.0 } } - for (i in 0 until this.rowNum) { - eigenvalues.mutableBuffer.array()[eigenvalueStart + i] = d[i, i] - } - } - - public fun Structure2D.isDiagonal(epsilon: Double = 1e-9): Boolean { - for (i in 0 until this.rowNum) { - for (j in 0 until this.colNum) { - if (i != j && abs(this[i, j]) > epsilon) { - return false - } + var sm = maxOffDiagonal(A_) + for (iteration in 0 until maxIteration) { + if (sm < epsilon) { + break } + + jacobiIteration(A_, V, D, Z) + updateDiagonal(D, Z, B) + sm = maxOffDiagonal(A_) } - return true + // TODO sort eigenvalues + return D to V } /** -- 2.34.1 From dda6602ed4c2b8b9d7eea017b2786697e6b02ec8 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sun, 20 Feb 2022 02:44:27 +0300 Subject: [PATCH 092/102] Replace complex access to tensor with faster access to buffer in Jacobi algorithm --- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) 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 675ff4191..e9dc34748 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 @@ -953,23 +953,33 @@ public open class DoubleTensorAlgebra : maxIteration: Int, epsilon: Double ): Pair, Structure2D> { - val A_ = this.copy().as2D() - val V = eye(this.shape[0]).as2D() - val D = DoubleTensor(intArrayOf(this.shape[0]), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() - val B = DoubleTensor(intArrayOf(this.shape[0]), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() - val Z = zeros(intArrayOf(this.shape[0])).as1D() + val n = this.shape[0] + val A_ = this.copy() + val V = eye(n) + val D = DoubleTensor(intArrayOf(n), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() + val B = DoubleTensor(intArrayOf(n), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() + val Z = zeros(intArrayOf(n)).as1D() - fun maxOffDiagonal(matrix: MutableStructure2D): Double { + // assume that buffered tensor is square matrix + operator fun BufferedTensor.get(i: Int, j: Int): Double { + return this.mutableBuffer.array()[bufferStart + i * this.shape[0] + j] + } + + operator fun BufferedTensor.set(i: Int, j: Int, value: Double) { + this.mutableBuffer.array()[bufferStart + i * this.shape[0] + j] = value + } + + fun maxOffDiagonal(matrix: BufferedTensor): Double { var maxOffDiagonalElement = 0.0 - for (i in 0 until matrix.rowNum - 1) { - for (j in i + 1 until matrix.colNum) { + for (i in 0 until n - 1) { + for (j in i + 1 until n) { maxOffDiagonalElement = max(maxOffDiagonalElement, abs(matrix[i, j])) } } return maxOffDiagonalElement } - fun rotate(a: MutableStructure2D, s: Double, tau: Double, i: Int, j: Int, k: Int, l: Int) { + fun rotate(a: BufferedTensor, s: Double, tau: Double, i: Int, j: Int, k: Int, l: Int) { val g = a[i, j] val h = a[k, l] a[i, j] = g - s * (h + g * tau) @@ -977,13 +987,13 @@ public open class DoubleTensorAlgebra : } fun jacobiIteration( - a: MutableStructure2D, - v: MutableStructure2D, + a: BufferedTensor, + v: BufferedTensor, d: MutableStructure1D, z: MutableStructure1D, ) { - for (ip in 0 until a.rowNum - 1) { - for (iq in ip + 1 until a.colNum) { + for (ip in 0 until n - 1) { + for (iq in ip + 1 until n) { val g = 100.0 * abs(a[ip, iq]) if (g <= epsilon * abs(d[ip]) && g <= epsilon * abs(d[iq])) { @@ -1017,10 +1027,10 @@ public open class DoubleTensorAlgebra : for (j in (ip + 1) until iq) { rotate(a, s, tau, ip, j, j, iq) } - for (j in (iq + 1) until a.rowNum) { + for (j in (iq + 1) until n) { rotate(a, s, tau, ip, j, iq, j) } - for (j in 0 until a.rowNum) { + for (j in 0 until n) { rotate(v, s, tau, j, ip, j, iq) } } @@ -1051,7 +1061,7 @@ public open class DoubleTensorAlgebra : } // TODO sort eigenvalues - return D to V + return D to V.as2D() } /** -- 2.34.1 From a621dd7c5b97fa3753ec3fe7f55b238b914fd544 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sun, 20 Feb 2022 02:55:37 +0300 Subject: [PATCH 093/102] Drop duplicate test from `DorBenchmark` --- .../kscience/kmath/benchmarks/DotBenchmark.kt | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 4a5cd4aa2..16fd544a8 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -15,10 +15,8 @@ import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer import space.kscience.kmath.tensorflow.produceWithTF -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.tensorAlgebra import kotlin.random.Random @@ -36,9 +34,6 @@ internal class DotBenchmark { random.nextDouble() } - val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224) - val tensor2 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12225) - val cmMatrix1 = CMLinearSpace { matrix1.toCM() } val cmMatrix2 = CMLinearSpace { matrix2.toCM() } @@ -48,10 +43,10 @@ internal class DotBenchmark { @Benchmark - fun tfDot(blackhole: Blackhole){ + fun tfDot(blackhole: Blackhole) { blackhole.consume( DoubleField.produceWithTF { - tensor1 dot tensor2 + matrix1 dot matrix1 } ) } @@ -95,9 +90,4 @@ internal class DotBenchmark { fun doubleDot(blackhole: Blackhole) = with(DoubleField.linearSpace) { blackhole.consume(matrix1 dot matrix2) } - - @Benchmark - fun doubleTensorDot(blackhole: Blackhole) = DoubleTensorAlgebra.invoke { - blackhole.consume(tensor1 dot tensor2) - } } -- 2.34.1 From 4575ab2b797ff5dfea99ea72e0470b977eb9ee48 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 7 Mar 2022 10:39:59 +0300 Subject: [PATCH 094/102] Update interpolation API to agree with other conventions. --- .../kscience/kmath/benchmarks/DotBenchmark.kt | 7 +++++ .../kmath/functions/interpolateSquare.kt | 4 +-- .../kmath/integration/SplineIntegrator.kt | 3 ++ .../kmath/interpolation/Interpolator.kt | 31 +++++++++++++++++++ .../kmath/interpolation/LinearInterpolator.kt | 4 +++ .../kmath/interpolation/SplineInterpolator.kt | 16 ++++++---- .../interpolation/LinearInterpolatorTest.kt | 6 ++-- .../interpolation/SplineInterpolatorTest.kt | 7 ++--- .../kscience/kmath/multik/MultikNDTest.kt | 25 +++++++++++++++ .../kmath/tensorflow/DoubleTensorFlowOps.kt | 2 -- 10 files changed, 87 insertions(+), 18 deletions(-) diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 16fd544a8..7d5ae310b 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -15,8 +15,10 @@ import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer import space.kscience.kmath.tensorflow.produceWithTF +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.tensorAlgebra import kotlin.random.Random @@ -90,4 +92,9 @@ internal class DotBenchmark { fun doubleDot(blackhole: Blackhole) = with(DoubleField.linearSpace) { blackhole.consume(matrix1 dot matrix2) } + + @Benchmark + fun doubleTensorDot(blackhole: Blackhole) = DoubleTensorAlgebra.invoke { + blackhole.consume(matrix1 dot matrix2) + } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt index 091242829..feefedece 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials +import space.kscience.kmath.interpolation.splineInterpolator import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.real.map import space.kscience.kmath.real.step @@ -28,7 +28,7 @@ fun main() { val xs = 0.0..100.0 step 0.5 val ys = xs.map(function) - val polynomial: PiecewisePolynomial = SplineInterpolator.double.interpolatePolynomials(xs, ys) + val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(xs, ys) val polyFunction = polynomial.asFunction(DoubleField, 0.0) 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 15d548641..eb88d9ae0 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 @@ -28,6 +28,8 @@ public fun > PiecewisePolynomial.integrate(algebra: Field> PiecewisePolynomial.integrate( @@ -98,6 +100,7 @@ public object DoubleSplineIntegrator : UnivariateIntegrator { } } +@Suppress("unused") @UnstableKMathAPI public inline val DoubleField.splineIntegrator: UnivariateIntegrator get() = DoubleSplineIntegrator \ No newline at end of file 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 b13adefa5..2266092a3 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 @@ -9,6 +9,7 @@ package space.kscience.kmath.interpolation 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 @@ -59,3 +60,33 @@ public fun > PolynomialInterpolator.interpolatePolynomials( val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) return interpolatePolynomials(pointSet) } + +public fun > PolynomialInterpolator.interpolate( + x: Buffer, + y: Buffer, +): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) + +public fun > PolynomialInterpolator.interpolate( + data: Map, +): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) + +public fun > PolynomialInterpolator.interpolate( + data: List>, +): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) + + +public fun > PolynomialInterpolator.interpolate( + x: Buffer, + y: Buffer, + defaultValue: T, +): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) + +public fun > PolynomialInterpolator.interpolate( + data: Map, + defaultValue: T, +): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) + +public fun > PolynomialInterpolator.interpolate( + data: List>, + defaultValue: T, +): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file 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 edd0e6b0a..34d7bcf41 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 @@ -22,6 +22,7 @@ internal fun > insureSorted(points: XYColumnarData<*, T, *>) { * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java */ public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { + @OptIn(UnstableKMathAPI::class) override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { require(points.size > 0) { "Point array should not be empty" } @@ -37,3 +38,6 @@ public class LinearInterpolator>(override val algebra: Field> Field.linearInterpolator: LinearInterpolator + get() = LinearInterpolator(this) 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 39c33ee69..afcb33bd4 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 @@ -63,8 +63,8 @@ public class SplineInterpolator>( //Shift coefficients to represent absolute polynomial instead of one with an offset val polynomial = Polynomial( a - b * x0 + c * x02 - d * x03, - b - 2*c*x0 + 3*d*x02, - c - 3*d*x0, + b - 2 * c * x0 + 3 * d * x02, + c - 3 * d * x0, d ) cOld = c @@ -72,8 +72,12 @@ public class SplineInterpolator>( } } } - - public companion object { - public val double: SplineInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) - } } + + +public fun > Field.splineInterpolator( + bufferFactory: MutableBufferFactory, +): SplineInterpolator = SplineInterpolator(this, bufferFactory) + +public val DoubleField.splineInterpolator: SplineInterpolator + get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt index bec678bae..1143036d4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt @@ -5,8 +5,6 @@ package space.kscience.kmath.interpolation -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction import space.kscience.kmath.operations.DoubleField import kotlin.test.Test import kotlin.test.assertEquals @@ -21,8 +19,8 @@ internal class LinearInterpolatorTest { 3.0 to 4.0 ) - val polynomial: PiecewisePolynomial = LinearInterpolator(DoubleField).interpolatePolynomials(data) - val function = polynomial.asFunction(DoubleField) + //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) + val function = DoubleField.linearInterpolator.interpolate(data) assertEquals(null, function(-1.0)) assertEquals(0.5, function(0.5)) assertEquals(2.0, function(1.5)) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt index 3adaab2d1..4c7d816d4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -5,8 +5,6 @@ package space.kscience.kmath.interpolation -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction import space.kscience.kmath.operations.DoubleField import kotlin.math.PI import kotlin.math.sin @@ -21,9 +19,10 @@ internal class SplineInterpolatorTest { x to sin(x) } - val polynomial: PiecewisePolynomial = SplineInterpolator.double.interpolatePolynomials(data) + //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) + + val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) - val function = polynomial.asFunction(DoubleField, Double.NaN) assertEquals(Double.NaN, function(-1.0)) assertEquals(sin(0.5), function(0.5), 0.1) assertEquals(sin(1.5), function(1.5), 0.1) diff --git a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt index 404541776..72c43d8e6 100644 --- a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt +++ b/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt @@ -6,13 +6,38 @@ package space.kscience.kmath.multik import org.junit.jupiter.api.Test +import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.one import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.tensorAlgebra +import kotlin.test.assertTrue internal class MultikNDTest { @Test fun basicAlgebra(): Unit = DoubleField.multikAlgebra{ one(2,2) + 1.0 } + + @Test + fun dotResult(){ + val dim = 100 + + val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224) + val tensor2 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12225) + + val multikResult = with(DoubleField.multikAlgebra){ + tensor1 dot tensor2 + } + + val defaultResult = with(DoubleField.tensorAlgebra){ + tensor1 dot tensor2 + } + + assertTrue { + StructureND.contentEquals(multikResult, defaultResult) + } + + } } \ No newline at end of file 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 3d118d980..308469eed 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,6 @@ import space.kscience.kmath.nd.structureND import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.sum -import kotlin.random.Random import kotlin.test.assertEquals class DoubleTensorFlowOps { @@ -23,7 +22,6 @@ class DoubleTensorFlowOps { @Test fun dot(){ - val random = Random(12224) val dim = 1000 val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224) -- 2.34.1 From 8518f333e3a1897af304b344062dbbd9328f44c7 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 8 Mar 2022 01:31:31 +0700 Subject: [PATCH 095/102] Delete yarn.lock --- .gitignore | 1 + kotlin-js-store/yarn.lock | 2059 ------------------------------------- 2 files changed, 1 insertion(+), 2059 deletions(-) delete mode 100644 kotlin-js-store/yarn.lock diff --git a/.gitignore b/.gitignore index 79f3238e1..5ddd846a8 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ out/ !/.idea/copyright/ !/.idea/scopes/ +/kotlin-js-store/yarn.lock diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock deleted file mode 100644 index e21abe604..000000000 --- a/kotlin-js-store/yarn.lock +++ /dev/null @@ -1,2059 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@discoveryjs/json-ext@^0.5.0": - version "0.5.6" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz#d5e0706cf8c6acd8c6032f8d54070af261bbbb2f" - integrity sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA== - -"@types/component-emitter@^1.2.10": - version "1.2.11" - resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506" - integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ== - -"@types/cookie@^0.4.0": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" - integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== - -"@types/cors@^2.8.8": - version "2.8.12" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" - integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== - -"@types/eslint-scope@^3.7.0": - version "3.7.3" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" - integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.1.tgz#c48251553e8759db9e656de3efc846954ac32304" - integrity sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*", "@types/estree@^0.0.50": - version "0.0.50" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" - integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== - -"@types/json-schema@*", "@types/json-schema@^7.0.8": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== - -"@types/node@*", "@types/node@>=10.0.0": - version "17.0.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.12.tgz#f7aa331b27f08244888c47b7df126184bc2339c5" - integrity sha512-4YpbAsnJXWYK/fpTVFlMIcUIho2AYCi4wg5aNPrG1ng7fn/1/RZfCIpRCiBX+12RVa34RluilnvCqD+g3KiSiA== - -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - -"@webassemblyjs/ast@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" - integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== - dependencies: - "@webassemblyjs/helper-numbers" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - -"@webassemblyjs/floating-point-hex-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" - integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== - -"@webassemblyjs/helper-api-error@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" - integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== - -"@webassemblyjs/helper-buffer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" - integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== - -"@webassemblyjs/helper-numbers@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" - integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/helper-wasm-bytecode@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" - integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== - -"@webassemblyjs/helper-wasm-section@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" - integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - -"@webassemblyjs/ieee754@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" - integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" - integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" - integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== - -"@webassemblyjs/wasm-edit@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" - integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/helper-wasm-section" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-opt" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - "@webassemblyjs/wast-printer" "1.11.1" - -"@webassemblyjs/wasm-gen@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" - integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" - -"@webassemblyjs/wasm-opt@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" - integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - -"@webassemblyjs/wasm-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" - integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" - -"@webassemblyjs/wast-printer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" - integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@xtuc/long" "4.2.2" - -"@webpack-cli/configtest@^1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356" - integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg== - -"@webpack-cli/info@^1.4.0": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea" - integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA== - dependencies: - envinfo "^7.7.3" - -"@webpack-cli/serve@^1.6.0": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe" - integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw== - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - -abab@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" - integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== - -accepts@~1.3.4: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -acorn-import-assertions@^1.7.6: - version "1.8.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" - integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== - -acorn@^8.4.1: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== - -ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv@^6.12.5: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -astring@1.7.5: - version "1.7.5" - resolved "https://registry.yarnpkg.com/astring/-/astring-1.7.5.tgz#a7d47fceaf32b052d33a3d07c511efeec67447ca" - integrity sha512-lobf6RWXb8c4uZ7Mdq0U12efYmpD1UFnyOWVJPTa3ukqZrMopav+2hdNu0hgBF0JIBFK9QgrBDfwYvh3DFJDAA== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-arraybuffer@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812" - integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI= - -base64id@2.0.0, base64id@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" - integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== - -benchmark@*: - version "2.1.4" - resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629" - integrity sha1-CfPeMckWQl1JjMLuVloOvzwqVik= - dependencies: - lodash "^4.17.4" - platform "^1.3.3" - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -binaryen@101.0.0: - version "101.0.0" - resolved "https://registry.yarnpkg.com/binaryen/-/binaryen-101.0.0.tgz#42a9e4cc7a22e2c1d75a31d28005a9b518b2c555" - integrity sha512-FRmVxvrR8jtcf0qcukNAPZDM3dZ2sc9GmA/hKxBI7k3fFzREKh1cAs+ruQi+ITTKz7u/AuFMuVnbJwTh0ef/HQ== - -body-parser@^1.19.0: - version "1.19.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" - integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== - dependencies: - bytes "3.1.1" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.8.1" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.9.6" - raw-body "2.4.2" - type-is "~1.6.18" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - -browserslist@^4.14.5: - version "4.19.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" - integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== - dependencies: - caniuse-lite "^1.0.30001286" - electron-to-chromium "^1.4.17" - escalade "^3.1.1" - node-releases "^2.0.1" - picocolors "^1.0.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -bytes@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" - integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== - -camelcase@^6.0.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caniuse-lite@^1.0.30001286: - version "1.0.30001301" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz#ebc9086026534cab0dab99425d9c3b4425e5f450" - integrity sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA== - -chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chokidar@3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chokidar@^3.5.1: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -clone-deep@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colorette@^2.0.14: - version "2.0.16" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" - integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== - -colors@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - -component-emitter@~1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -connect@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" - integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== - dependencies: - debug "2.6.9" - finalhandler "1.1.2" - parseurl "~1.3.3" - utils-merge "1.0.1" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -cookie@~0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" - integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== - -cors@~2.8.5: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - -cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -css-loader@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.3.0.tgz#334d3500ff0a0c14cfbd4b0670088dbb5b5c1530" - integrity sha512-9NGvHOR+L6ps13Ilw/b216++Q8q+5RpJcVufCdW9S/9iCzs4KBDNa8qnA/n3FK/sSfWmH35PAIK/cfPi7LOSUg== - dependencies: - icss-utils "^5.1.0" - postcss "^8.2.15" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.1.0" - semver "^7.3.5" - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -custom-event@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" - integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU= - -date-format@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.3.tgz#f63de5dc08dc02efd8ef32bf2a6918e486f35873" - integrity sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ== - -debug@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - -debug@^4.1.1, debug@^4.3.3, debug@~4.3.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -di@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" - integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= - -diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - -dom-serialize@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" - integrity sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs= - dependencies: - custom-event "~1.0.0" - ent "~2.2.0" - extend "^3.0.0" - void-elements "^2.0.0" - -dukat@0.5.8-rc.4: - version "0.5.8-rc.4" - resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21" - integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA== - dependencies: - google-protobuf "3.12.2" - typescript "3.9.5" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -electron-to-chromium@^1.4.17: - version "1.4.52" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.52.tgz#ce44c6d6cc449e7688a4356b8c261cfeafa26833" - integrity sha512-JGkh8HEh5PnVrhU4HbpyyO0O791dVY6k7AdqfDeqbcRMeoGxtNHWT77deR2nhvbLe4dKpxjlDEvdEwrvRLGu2Q== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -engine.io-parser@~4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-4.0.3.tgz#83d3a17acfd4226f19e721bb22a1ee8f7662d2f6" - integrity sha512-xEAAY0msNnESNPc00e19y5heTPX4y/TJ36gr8t1voOaNmTojP9b3oK3BbJLFufW2XFPQaaijpFewm2g2Um3uqA== - dependencies: - base64-arraybuffer "0.1.4" - -engine.io@~4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-4.1.2.tgz#f96ceb56d4b39cc7ca5bd29a20e9c99c1ad1a765" - integrity sha512-t5z6zjXuVLhXDMiFJPYsPOWEER8B0tIsD3ETgw19S1yg9zryvUfY3Vhtk3Gf4sihw/bQGIqQ//gjvVlu+Ca0bQ== - dependencies: - accepts "~1.3.4" - base64id "2.0.0" - cookie "~0.4.1" - cors "~2.8.5" - debug "~4.3.1" - engine.io-parser "~4.0.0" - ws "~7.4.2" - -enhanced-resolve@^5.8.3: - version "5.8.3" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" - integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -ent@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" - integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= - -envinfo@^7.7.3: - version "7.8.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" - integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== - -es-module-lexer@^0.9.0: - version "0.9.3" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" - integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-scope@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -eventemitter3@^4.0.0: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -events@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fastest-levenshtein@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" - integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-up@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -find-up@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -flatted@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" - integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== - -follow-redirects@^1.0.0: - version "1.14.7" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" - integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== - -format-util@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" - integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== - -fs-extra@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" - integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - -glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.3, glob@^7.1.7: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -google-protobuf@3.12.2: - version "3.12.2" - resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" - integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== - -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -http-errors@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.1" - -http-proxy@^1.18.1: - version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" - integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -icss-utils@^5.0.0, icss-utils@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" - integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== - -import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -interpret@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" - integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-core-module@^2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" - integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== - dependencies: - has "^1.0.3" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -isbinaryfile@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf" - integrity sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -jest-worker@^27.4.1: - version "27.4.6" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.6.tgz#5d2d93db419566cb680752ca0792780e71b3273e" - integrity sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -js-base64@3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.6.1.tgz#555aae398b74694b4037af1f8a5a6209d170efbe" - integrity sha512-Frdq2+tRRGLQUIQOgsIGSCd1VePCS2fsddTG5dTCqR0JHgltXWfsxnY0gIXPoMeRmdom6Oyq+UMOFg5suduOjQ== - -js-yaml@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -karma-chrome-launcher@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz#805a586799a4d05f4e54f72a204979f3f3066738" - integrity sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg== - dependencies: - which "^1.2.1" - -karma-mocha@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d" - integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ== - dependencies: - minimist "^1.2.3" - -karma-sourcemap-loader@0.3.8: - version "0.3.8" - resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.8.tgz#d4bae72fb7a8397328a62b75013d2df937bdcf9c" - integrity sha512-zorxyAakYZuBcHRJE+vbrK2o2JXLFWK8VVjiT/6P+ltLBUGUvqTEkUiQ119MGdOrK7mrmxXHZF1/pfT6GgIZ6g== - dependencies: - graceful-fs "^4.1.2" - -karma-webpack@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.0.tgz#2a2c7b80163fe7ffd1010f83f5507f95ef39f840" - integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA== - dependencies: - glob "^7.1.3" - minimatch "^3.0.4" - webpack-merge "^4.1.5" - -karma@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/karma/-/karma-6.3.4.tgz#359899d3aab3d6b918ea0f57046fd2a6b68565e6" - integrity sha512-hbhRogUYIulfkBTZT7xoPrCYhRBnBoqbbL4fszWD0ReFGUxU+LYBr3dwKdAluaDQ/ynT9/7C+Lf7pPNW4gSx4Q== - dependencies: - body-parser "^1.19.0" - braces "^3.0.2" - chokidar "^3.5.1" - colors "^1.4.0" - connect "^3.7.0" - di "^0.0.1" - dom-serialize "^2.2.1" - glob "^7.1.7" - graceful-fs "^4.2.6" - http-proxy "^1.18.1" - isbinaryfile "^4.0.8" - lodash "^4.17.21" - log4js "^6.3.0" - mime "^2.5.2" - minimatch "^3.0.4" - qjobs "^1.2.0" - range-parser "^1.2.1" - rimraf "^3.0.2" - socket.io "^3.1.0" - source-map "^0.6.1" - tmp "^0.2.1" - ua-parser-js "^0.7.28" - yargs "^16.1.1" - -kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -loader-runner@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" - integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -log4js@^6.3.0: - version "6.4.1" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.4.1.tgz#9d3a8bf2c31c1e213fe3fc398a6053f7a2bc53e8" - integrity sha512-iUiYnXqAmNKiIZ1XSAitQ4TmNs8CdZYTAWINARF3LjnsLN8tY5m0vRwd6uuWj/yNY0YHxeZodnbmxKFUOM2rMg== - dependencies: - date-format "^4.0.3" - debug "^4.3.3" - flatted "^3.2.4" - rfdc "^1.3.0" - streamroller "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -mime-db@1.51.0: - version "1.51.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== - -mime-types@^2.1.27, mime-types@~2.1.24: - version "2.1.34" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== - dependencies: - mime-db "1.51.0" - -mime@^2.5.2: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.3: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mocha@9.1.2: - version "9.1.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.1.2.tgz#93f53175b0f0dc4014bd2d612218fccfcf3534d3" - integrity sha512-ta3LtJ+63RIBP03VBjMGtSqbe6cWXRejF9SyM9Zyli1CKZJZ+vfCTj3oW24V7wAphMJdpOFLoMI3hjJ1LWbs0w== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.2" - debug "4.3.2" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.1.7" - growl "1.10.5" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "3.0.4" - ms "2.1.3" - nanoid "3.1.25" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - workerpool "6.1.5" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nanoid@3.1.25: - version "3.1.25" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" - integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== - -nanoid@^3.1.30: - version "3.2.0" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" - integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== - -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -node-releases@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" - integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -object-assign@^4: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -platform@^1.3.3: - version "1.3.6" - resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" - integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== - -postcss-modules-extract-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== - -postcss-modules-local-by-default@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" - integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== - dependencies: - icss-utils "^5.0.0" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - -postcss-modules-scope@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" - integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== - dependencies: - postcss-selector-parser "^6.0.4" - -postcss-modules-values@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" - integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== - dependencies: - icss-utils "^5.0.0" - -postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: - version "6.0.9" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" - integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-value-parser@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== - -postcss@^8.2.15: - version "8.4.5" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" - integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== - dependencies: - nanoid "^3.1.30" - picocolors "^1.0.0" - source-map-js "^1.0.1" - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -qjobs@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" - integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== - -qs@6.9.6: - version "6.9.6" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" - integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -range-parser@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" - integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== - dependencies: - bytes "3.1.1" - http-errors "1.8.1" - iconv-lite "0.4.24" - unpipe "1.0.0" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -rechoir@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" - integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== - dependencies: - resolve "^1.9.0" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve@^1.9.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== - dependencies: - is-core-module "^2.8.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - -rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -safe-buffer@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -schema-utils@^3.1.0, schema-utils@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -serialize-javascript@6.0.0, serialize-javascript@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== - dependencies: - randombytes "^2.1.0" - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.3: - version "3.0.6" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" - integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== - -socket.io-adapter@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.1.0.tgz#edc5dc36602f2985918d631c1399215e97a1b527" - integrity sha512-+vDov/aTsLjViYTwS9fPy5pEtTkrbEKsw2M+oVSoFGw6OD1IpvlV1VPhUzNbofCQ8oyMbdYJqDtGdmHQK6TdPg== - -socket.io-parser@~4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.4.tgz#9ea21b0d61508d18196ef04a2c6b9ab630f4c2b0" - integrity sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g== - dependencies: - "@types/component-emitter" "^1.2.10" - component-emitter "~1.3.0" - debug "~4.3.1" - -socket.io@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-3.1.2.tgz#06e27caa1c4fc9617547acfbb5da9bc1747da39a" - integrity sha512-JubKZnTQ4Z8G4IZWtaAZSiRP3I/inpy8c/Bsx2jrwGrTbKeVU5xd6qkKMHpChYeM3dWZSO0QACiGK+obhBNwYw== - dependencies: - "@types/cookie" "^0.4.0" - "@types/cors" "^2.8.8" - "@types/node" ">=10.0.0" - accepts "~1.3.4" - base64id "~2.0.0" - debug "~4.3.1" - engine.io "~4.1.0" - socket.io-adapter "~2.1.0" - socket.io-parser "~4.0.3" - -source-map-js@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" - integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== - -source-map-js@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - -source-map-loader@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.0.tgz#f2a04ee2808ad01c774dea6b7d2639839f3b3049" - integrity sha512-GKGWqWvYr04M7tn8dryIWvb0s8YM41z82iQv01yBtIylgxax0CwvSy6gc2Y02iuXwEfGWRlMicH0nvms9UZphw== - dependencies: - abab "^2.0.5" - iconv-lite "^0.6.2" - source-map-js "^0.6.2" - -source-map-support@0.5.20: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -"statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -streamroller@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.0.2.tgz#30418d0eee3d6c93ec897f892ed098e3a81e68b7" - integrity sha512-ur6y5S5dopOaRXBuRIZ1u6GC5bcEXHRZKgfBjfCglMhmIf+roVCECjvkEYzNQOXIN2/JPnkMPW/8B3CZoKaEPA== - dependencies: - date-format "^4.0.3" - debug "^4.1.1" - fs-extra "^10.0.0" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -style-loader@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.0.tgz#d66ea95fc50b22f8b79b69a9e414760fcf58d8d8" - integrity sha512-szANub7ksJtQioJYtpbWwh1hUl99uK15n5HDlikeCRil/zYMZgSxucHddyF/4A3qJMUiAjPhFowrrQuNMA7jwQ== - -supports-color@8.1.1, supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -tapable@^2.1.1, tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - -terser-webpack-plugin@^5.1.3: - version "5.3.0" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz#21641326486ecf91d8054161c816e464435bae9f" - integrity sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ== - dependencies: - jest-worker "^27.4.1" - schema-utils "^3.1.1" - serialize-javascript "^6.0.0" - source-map "^0.6.1" - terser "^5.7.2" - -terser@^5.7.2: - version "5.10.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" - integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.20" - -tmp@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typescript@3.9.5: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== - -ua-parser-js@^0.7.28: - version "0.7.31" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" - integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -util-deprecate@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -v8-compile-cache@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -vary@^1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -void-elements@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" - integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= - -watchpack@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" - integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - -webpack-cli@4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.0.tgz#dc43e6e0f80dd52e89cbf73d5294bcd7ad6eb343" - integrity sha512-n/jZZBMzVEl4PYIBs+auy2WI0WTQ74EnJDiyD98O2JZY6IVIHJNitkYp/uTXOviIOMfgzrNvC9foKv/8o8KSZw== - dependencies: - "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^1.1.0" - "@webpack-cli/info" "^1.4.0" - "@webpack-cli/serve" "^1.6.0" - colorette "^2.0.14" - commander "^7.0.0" - execa "^5.0.0" - fastest-levenshtein "^1.0.12" - import-local "^3.0.2" - interpret "^2.2.0" - rechoir "^0.7.0" - v8-compile-cache "^2.2.0" - webpack-merge "^5.7.3" - -webpack-merge@^4.1.5: - version "4.2.2" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" - integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== - dependencies: - lodash "^4.17.15" - -webpack-merge@^5.7.3: - version "5.8.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" - integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== - dependencies: - clone-deep "^4.0.1" - wildcard "^2.0.0" - -webpack-sources@^3.2.0: - version "3.2.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack@5.57.1: - version "5.57.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.57.1.tgz#ead5ace2c17ecef2ae8126f143bfeaa7f55eab44" - integrity sha512-kHszukYjTPVfCOEyrUthA3jqJwduY/P3eO8I0gMNOZGIQWKAwZftxmp5hq6paophvwo9NoUrcZOecs9ulOyyTg== - dependencies: - "@types/eslint-scope" "^3.7.0" - "@types/estree" "^0.0.50" - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/wasm-edit" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - acorn "^8.4.1" - acorn-import-assertions "^1.7.6" - browserslist "^4.14.5" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.8.3" - es-module-lexer "^0.9.0" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.4" - json-parse-better-errors "^1.0.2" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.1.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.1.3" - watchpack "^2.2.0" - webpack-sources "^3.2.0" - -which@2.0.2, which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -which@^1.2.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -wildcard@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" - integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== - -workerpool@6.1.5: - version "6.1.5" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" - integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -ws@~7.4.2: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-unparser@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - -yargs@16.2.0, yargs@^16.1.1: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -- 2.34.1 From 0b2e8ff25ee572c5561d5d5aaa392a7e66332fa1 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 8 Mar 2022 23:15:48 +0300 Subject: [PATCH 096/102] Build fixes --- build.gradle.kts | 5 +++-- buildSrc/build.gradle.kts | 3 ++- buildSrc/gradle.properties | 8 +------- buildSrc/settings.gradle.kts | 5 +++-- gradle.properties | 3 +-- settings.gradle.kts | 16 ---------------- 6 files changed, 10 insertions(+), 30 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3b48c7328..3372d505d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,16 +1,17 @@ plugins { id("ru.mipt.npm.gradle.project") - id("org.jetbrains.kotlinx.kover") version "0.5.0-RC" + id("org.jetbrains.kotlinx.kover") version "0.5.0" } allprojects { repositories { + maven("https://repo.kotlin.link") maven("https://oss.sonatype.org/content/repositories/snapshots") mavenCentral() } group = "space.kscience" - version = "0.3.0-dev-19" + version = "0.3.0-dev-20" } subprojects { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index ceb220bd5..b69ebe6cd 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -7,6 +7,7 @@ plugins { java.targetCompatibility = JavaVersion.VERSION_11 repositories { + mavenLocal() maven("https://repo.kotlin.link") mavenCentral() gradlePluginPortal() @@ -14,7 +15,7 @@ repositories { val toolsVersion: String by extra val kotlinVersion = npmlibs.versions.kotlin.asProvider().get() -val benchmarksVersion = "0.4.2" +val benchmarksVersion = npmlibs.versions.kotlinx.benchmark.get() dependencies { api("ru.mipt.npm:gradle-tools:$toolsVersion") diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties index 6678f24a8..05486d4f6 100644 --- a/buildSrc/gradle.properties +++ b/buildSrc/gradle.properties @@ -4,11 +4,5 @@ # kotlin.code.style=official -kotlin.mpp.stability.nowarn=true -kotlin.jupyter.add.scanner=false - -org.gradle.configureondemand=true -org.gradle.parallel=true - -toolsVersion=0.10.9-kotlin-1.6.10 +toolsVersion=0.11.1-kotlin-1.6.10 diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index 87ff205f6..9c5550602 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -3,7 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ - enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") enableFeaturePreview("VERSION_CATALOGS") @@ -12,8 +11,10 @@ dependencyResolutionManagement { val toolsVersion: String by extra repositories { + mavenLocal() maven("https://repo.kotlin.link") mavenCentral() + gradlePluginPortal() } versionCatalogs { @@ -21,4 +22,4 @@ dependencyResolutionManagement { from("ru.mipt.npm:version-catalog:$toolsVersion") } } -} +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 7dd9e6d61..7d9628621 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,11 +5,10 @@ kotlin.code.style=official kotlin.mpp.stability.nowarn=true +kotlin.native.ignoreDisabledTargets=true kotlin.jupyter.add.scanner=false org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G - -toolsVersion=0.11.1-kotlin-1.6.10 diff --git a/settings.gradle.kts b/settings.gradle.kts index 3001d000c..a8b473fee 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,22 +3,6 @@ rootProject.name = "kmath" enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") enableFeaturePreview("VERSION_CATALOGS") -dependencyResolutionManagement { - - val toolsVersion: String by extra - - repositories { - maven("https://repo.kotlin.link") - mavenCentral() - } - - versionCatalogs { - create("npmlibs") { - from("ru.mipt.npm:version-catalog:$toolsVersion") - } - } -} - include( ":kmath-memory", ":kmath-complex", -- 2.34.1 From 92cffd78d935e8d834ec14887680ccffdaf89586 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 1 Apr 2022 02:23:34 +0700 Subject: [PATCH 097/102] Upgrade gradle tools --- .github/workflows/build.yml | 11 ++-- .github/workflows/pages.yml | 7 +- .github/workflows/publish.yml | 17 ++--- README.md | 80 ++++++++--------------- benchmarks/README.md | 4 ++ buildSrc/gradle.properties | 3 +- buildSrc/settings.gradle.kts | 3 +- docs/templates/README-TEMPLATE.md | 2 +- examples/README.md | 4 ++ gradle.properties | 7 +- gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 59821 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- kmath-ast/README.md | 55 +++++++++++----- kmath-commons/README.md | 32 +++++++++ kmath-complex/README.md | 10 +-- kmath-core/README.md | 10 +-- kmath-coroutines/README.md | 32 +++++++++ kmath-dimensions/README.md | 32 +++++++++ kmath-ejml/README.md | 10 +-- kmath-for-real/README.md | 10 +-- kmath-functions/README.md | 10 +-- kmath-geometry/README.md | 32 +++++++++ kmath-histograms/README.md | 32 +++++++++ kmath-jafama/README.md | 10 +-- kmath-jupyter/README.md | 32 +++++++++ kmath-kotlingrad/README.md | 10 +-- kmath-memory/README.md | 32 +++++++++ kmath-multik/README.md | 32 +++++++++ kmath-nd4j/README.md | 10 +-- kmath-optimization/README.md | 32 +++++++++ kmath-stat/README.md | 32 +++++++++ kmath-symja/README.md | 32 +++++++++ kmath-tensorflow/README.md | 32 +++++++++ kmath-tensors/README.md | 10 +-- kmath-viktor/README.md | 32 +++++++++ settings.gradle.kts | 2 - 36 files changed, 556 insertions(+), 147 deletions(-) create mode 100644 benchmarks/README.md create mode 100644 examples/README.md create mode 100644 kmath-commons/README.md create mode 100644 kmath-coroutines/README.md create mode 100644 kmath-dimensions/README.md create mode 100644 kmath-geometry/README.md create mode 100644 kmath-histograms/README.md create mode 100644 kmath-jupyter/README.md create mode 100644 kmath-memory/README.md create mode 100644 kmath-multik/README.md create mode 100644 kmath-optimization/README.md create mode 100644 kmath-stat/README.md create mode 100644 kmath-symja/README.md create mode 100644 kmath-tensorflow/README.md create mode 100644 kmath-viktor/README.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f2c76a354..455e0dd2d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,14 +13,11 @@ jobs: runs-on: ${{matrix.os}} timeout-minutes: 40 steps: - - name: Checkout the repo - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: DeLaGuardo/setup-graalvm@4.0 + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2.5.0 with: - graalvm: 21.2.0 - java: java11 - arch: amd64 + java-version: 11 + distribution: liberica - name: Cache gradle uses: actions/cache@v2 with: diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 23ed54357..e7f5300c7 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -10,11 +10,10 @@ jobs: timeout-minutes: 40 steps: - uses: actions/checkout@v2 - - uses: DeLaGuardo/setup-graalvm@4.0 + - uses: actions/setup-java@v2.5.0 with: - graalvm: 21.2.0 - java: java11 - arch: amd64 + java-version: 11 + distribution: liberica - uses: actions/cache@v2 with: path: ~/.gradle/caches diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index fa3cb700c..17adc5655 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,14 +14,11 @@ jobs: os: [ macOS-latest, windows-latest ] runs-on: ${{matrix.os}} steps: - - name: Checkout the repo - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: DeLaGuardo/setup-graalvm@4.0 + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2.5.0 with: - graalvm: 21.2.0 - java: java11 - arch: amd64 + java-version: 11 + distribution: liberica - name: Cache gradle uses: actions/cache@v2 with: @@ -44,12 +41,12 @@ jobs: if: matrix.os == 'windows-latest' shell: cmd run: > - ./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true + ./gradlew releaseAll --no-daemon --build-cache -Ppublishing.enabled=true -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} - name: Publish Mac Artifacts if: matrix.os == 'macOS-latest' run: > - ./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true -Ppublishing.platform=macosX64 - -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} + ./gradlew releaseMacosX64 releaseIosArm64 releaseIosX64 release --no-daemon --build-cache + -Ppublishing.enabled=true -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} diff --git a/README.md b/README.md index 99dd6d00f..aea94f529 100644 --- a/README.md +++ b/README.md @@ -52,21 +52,18 @@ module definitions below. The module stability could have the following levels: ## Modules -
-* ### [benchmarks](benchmarks) +### [benchmarks](benchmarks) > > > **Maturity**: EXPERIMENTAL -
-* ### [examples](examples) +### [examples](examples) > > > **Maturity**: EXPERIMENTAL -
-* ### [kmath-ast](kmath-ast) +### [kmath-ast](kmath-ast) > > > **Maturity**: EXPERIMENTAL @@ -77,15 +74,13 @@ module definitions below. The module stability could have the following levels: > - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler > - [rendering](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering -
-* ### [kmath-commons](kmath-commons) +### [kmath-commons](kmath-commons) > > > **Maturity**: EXPERIMENTAL -
-* ### [kmath-complex](kmath-complex) +### [kmath-complex](kmath-complex) > Complex numbers and quaternions. > > **Maturity**: PROTOTYPE @@ -94,9 +89,8 @@ module definitions below. The module stability could have the following levels: > - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers > - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions -
-* ### [kmath-core](kmath-core) +### [kmath-core](kmath-core) > Core classes, algebra definitions, basic linear algebra > > **Maturity**: DEVELOPMENT @@ -112,21 +106,18 @@ performance calculations to code generation. > - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains > - [autodiff](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation -
-* ### [kmath-coroutines](kmath-coroutines) +### [kmath-coroutines](kmath-coroutines) > > > **Maturity**: EXPERIMENTAL -
-* ### [kmath-dimensions](kmath-dimensions) +### [kmath-dimensions](kmath-dimensions) > > > **Maturity**: PROTOTYPE -
-* ### [kmath-ejml](kmath-ejml) +### [kmath-ejml](kmath-ejml) > > > **Maturity**: PROTOTYPE @@ -136,9 +127,8 @@ performance calculations to code generation. > - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : Matrix implementation. > - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : LinearSpace implementations. -
-* ### [kmath-for-real](kmath-for-real) +### [kmath-for-real](kmath-for-real) > Extension module that should be used to achieve numpy-like behavior. All operations are specialized to work with `Double` numbers without declaring algebraic contexts. One can still use generic algebras though. @@ -150,9 +140,8 @@ One can still use generic algebras though. > - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures > - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators -
-* ### [kmath-functions](kmath-functions) +### [kmath-functions](kmath-functions) > > > **Maturity**: EXPERIMENTAL @@ -164,21 +153,18 @@ One can still use generic algebras though. > - [spline interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator. > - [integration](kmath-functions/#) : Univariate and multivariate quadratures -
-* ### [kmath-geometry](kmath-geometry) +### [kmath-geometry](kmath-geometry) > > > **Maturity**: PROTOTYPE -
-* ### [kmath-histograms](kmath-histograms) +### [kmath-histograms](kmath-histograms) > > > **Maturity**: PROTOTYPE -
-* ### [kmath-jafama](kmath-jafama) +### [kmath-jafama](kmath-jafama) > > > **Maturity**: PROTOTYPE @@ -186,15 +172,13 @@ One can still use generic algebras though. > **Features:** > - [jafama-double](kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama -
-* ### [kmath-jupyter](kmath-jupyter) +### [kmath-jupyter](kmath-jupyter) > > > **Maturity**: PROTOTYPE -
-* ### [kmath-kotlingrad](kmath-kotlingrad) +### [kmath-kotlingrad](kmath-kotlingrad) > > > **Maturity**: EXPERIMENTAL @@ -203,21 +187,18 @@ One can still use generic algebras though. > - [differentiable-mst-expression](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression. > - [scalars-adapters](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST -
-* ### [kmath-memory](kmath-memory) +### [kmath-memory](kmath-memory) > An API and basic implementation for arranging objects in a continuous memory block. > > **Maturity**: DEVELOPMENT -
-* ### [kmath-multik](kmath-multik) +### [kmath-multik](kmath-multik) > > > **Maturity**: PROTOTYPE -
-* ### [kmath-nd4j](kmath-nd4j) +### [kmath-nd4j](kmath-nd4j) > > > **Maturity**: EXPERIMENTAL @@ -227,33 +208,28 @@ One can still use generic algebras though. > - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long > - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double -
-* ### [kmath-optimization](kmath-optimization) +### [kmath-optimization](kmath-optimization) > > > **Maturity**: EXPERIMENTAL -
-* ### [kmath-stat](kmath-stat) +### [kmath-stat](kmath-stat) > > > **Maturity**: EXPERIMENTAL -
-* ### [kmath-symja](kmath-symja) +### [kmath-symja](kmath-symja) > > > **Maturity**: PROTOTYPE -
-* ### [kmath-tensorflow](kmath-tensorflow) +### [kmath-tensorflow](kmath-tensorflow) > > > **Maturity**: PROTOTYPE -
-* ### [kmath-tensors](kmath-tensors) +### [kmath-tensors](kmath-tensors) > > > **Maturity**: PROTOTYPE @@ -263,13 +239,11 @@ One can still use generic algebras though. > - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. > - [linear algebra operations](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. -
-* ### [kmath-viktor](kmath-viktor) +### [kmath-viktor](kmath-viktor) > > > **Maturity**: DEVELOPMENT -
## Multi-platform support @@ -308,8 +282,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:0.3.0-dev-17") - // api("space.kscience:kmath-core-jvm:0.3.0-dev-17") for jvm-specific version + api("space.kscience:kmath-core:$version") + // api("space.kscience:kmath-core-jvm:$version") for jvm-specific version } ``` diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 000000000..cd8fbafd3 --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,4 @@ +# Module benchmarks + + + diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties index 05486d4f6..a0b05e812 100644 --- a/buildSrc/gradle.properties +++ b/buildSrc/gradle.properties @@ -4,5 +4,4 @@ # kotlin.code.style=official - -toolsVersion=0.11.1-kotlin-1.6.10 +toolsVersion=0.11.2-kotlin-1.6.10 diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index 9c5550602..bc530ac03 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -7,7 +7,6 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") enableFeaturePreview("VERSION_CATALOGS") dependencyResolutionManagement { - val toolsVersion: String by extra repositories { @@ -22,4 +21,4 @@ dependencyResolutionManagement { from("ru.mipt.npm:version-catalog:$toolsVersion") } } -} \ No newline at end of file +} diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index b0c418697..4ffa9e75f 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -52,7 +52,7 @@ module definitions below. The module stability could have the following levels: ## Modules -$modules +${modules} ## Multi-platform support diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 000000000..d4e1c5289 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,4 @@ +# Module examples + + + diff --git a/gradle.properties b/gradle.properties index 7d9628621..a7cd2f876 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,13 +2,10 @@ # Copyright 2018-2021 KMath contributors. # Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. # - kotlin.code.style=official +kotlin.jupyter.add.scanner=false kotlin.mpp.stability.nowarn=true kotlin.native.ignoreDisabledTargets=true - -kotlin.jupyter.add.scanner=false - org.gradle.configureondemand=true -org.gradle.parallel=true org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G +org.gradle.parallel=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..41d9927a4d4fb3f96a785543079b8df6723c946b 100644 GIT binary patch delta 8958 zcmY+KWl$VIlZIh&f(Hri?gR<$?iyT!TL`X;1^2~W7YVSq1qtqM!JWlDxLm%}UESUM zndj}Uny%^UnjhVhFb!8V3s(a#fIy>`VW15{5nuy;_V&a5O#0S&!a4dSkUMz_VHu3S zGA@p9Q$T|Sj}tYGWdjH;Mpp8m&yu&YURcrt{K;R|kM~(*{v%QwrBJIUF+K1kX5ZmF zty3i{d`y0;DgE+de>vN@yYqFPe1Ud{!&G*Q?iUc^V=|H%4~2|N zW+DM)W!`b&V2mQ0Y4u_)uB=P@-2`v|Wm{>CxER1P^ z>c}ZPZ)xxdOCDu59{X^~2id7+6l6x)U}C4Em?H~F`uOxS1?}xMxTV|5@}PlN%Cg$( zwY6c}r60=z5ZA1L zTMe;84rLtYvcm?M(H~ZqU;6F7Evo{P7!LGcdwO|qf1w+)MsnvK5^c@Uzj<{ zUoej1>95tuSvDJ|5K6k%&UF*uE6kBn47QJw^yE&#G;u^Z9oYWrK(+oL97hBsUMc_^ z;-lmxebwlB`Er_kXp2$`&o+rPJAN<`WX3ws2K{q@qUp}XTfV{t%KrsZ5vM!Q#4{V& zq>iO$MCiLq#%wXj%`W$_%FRg_WR*quv65TdHhdpV&jlq<=K^K`&!Kl5mA6p4n~p3u zWE{20^hYpn1M}}VmSHBXl1*-)2MP=0_k)EPr#>EoZukiXFDz?Di1I>2@Z^P$pvaF+ zN+qUy63jek2m59;YG)`r^F3-O)0RDIXPhf)XOOdkmu`3SMMSW(g+`Ajt{=h1dt~ks ztrhhP|L4G%5x79N#kwAHh5N){@{fzE7n&%dnisCm65Za<8r_hKvfx4Bg*`%-*-Mvn zFvn~)VP@}1sAyD+B{{8l{EjD10Av&Mz9^Xff*t`lU=q=S#(|>ls520;n3<}X#pyh& z*{CJf7$*&~!9jMnw_D~ikUKJ2+UnXmN6qak{xx%W;BKuXt7@ky!LPI1qk?gDwG@@o zkY+BkIie>{{q==5)kXw(*t#I?__Kwi>`=+s?Gq6X+vtSsaAO&Tf+Bl$vKnzc&%BHM z=loWOQq~n}>l=EL(5&6((ESsQC3^@4jlO5Od{qN#sWV)vqXw}aA>*uvwZopNN(|-T zRTF%5Y_k1R$;(d-)n;hWex{;7b6KgdAVE@&0pd(*qDzBO#YZV%kh%pYt1`hnQ(Fa& zYiDrOTDqk5M7hzp9kI2h!PxNnuJ&xl*zF8sx6!67bA49R1bmUF5bpK&&{eI0U~cH}PM z3aW1$lRb|ItkG5~_eBNu$|I|vYIdAA9a!pVq<+UTx*M}fG`23zxXp&E=FfnY- zEzKj;Cu_s4v>leO7M2-mE(UzKHL4c$c`3dS*19OpLV^4NI*hWWnJQ9lvzP4c;c?do zqrcsKT*i~eIHl0D3r4N{)+RsB6XhrC^;sp2cf_Eq#6*CV;t8v=V!ISe>>9kPgh}NI z=1UZutslxcT$Ad;_P^;Oouoa(cs!Ctpvi>%aQ+Zp=1d|h{W9Wmf7JWxa(~<#tSZ?C%wu4_5F!fc!<@PIBeJ)Nr^$bB6!_Gic_7}c3J{QI~Gg5g5jTp9}V6KYgrgaX>pJt}7$!wOht&KO|+z{Iw@YL|@~D zMww}+lG}rm2^peNx>58ME||ZQxFQeVSX8iogHLq_vXb`>RnoEKaTWBF-$JD#Q4BMv zt2(2Qb*x-?ur1Y(NsW8AdtX0#rDB?O(Vs4_xA(u-o!-tBG03OI!pQD+2UytbL5>lG z*(F)KacHqMa4?dxa(Vcrw>IIAeB$3cx#;;5r2X;HE8|}eYdAgCw#tpXNy7C3w1q`9 zGxZ6;@1G%8shz9e+!K2MO*{_RjO}Jo6eL3{TSZ>nY7)Qs`Dhi5><@oh0r)gT7H-?3 zLDsd^@m%JvrS8sta5`QiZNs^*GT}Hiy^zjK2^Ni%`Z|ma)D2 zuyumbvw$M8$haCTI~6M%d4+P)uX%u{Sfg4Al+F7c6;O-*)DKI7E8izSOKB#FcV{M+ zEvY0FBkq!$J0EW$Cxl}3{JwV^ki-T?q6C30Y5e&p@8Rd?$ST-Ghn*-`tB{k54W<>F z5I)TFpUC!E9298=sk>m#FI4sUDy_!8?51FqqW!9LN1(zuDnB3$!pEUjL>N>RNgAG~-9Xm|1lqHseW(%v&6K(DZ3Pano(1-Qe?3%J&>0`~w^Q-p&@ zg@HjvhJk?*hpF7$9P|gkzz`zBz_5Z!C4_-%fCcAgiSilzFQef!@amHDrW!YZS@?7C zs2Y9~>yqO+rkih?kXztzvnB^6W=f52*iyuZPv$c42$WK7>PHb z6%MYIr5D32KPdwL1hJf{_#jn?`k(taW?mwmZVvrr=y~fNcV$`}v(8};o9AjOJumS4 z`889O91^pkF+|@$d9wVoZ3;^j;^sUs&Ubo_qD&MTL%O z&*SE0ujG~zm;?x)8TLC&ft))nyI zcg44@*Q{cYT+qGrA=In_X{NNCD+B0w#;@g)jvBU;_8od6U>;7HIo@F*=g8CQUo(u^ z3r4FJ7#<@)MXO&5+DgKE&^>^`r!loe7CWE*1k0*0wLFzSOV8jvlX~WOQ?$1v zk$Or}!;ix0g78^6W;+<=J>z@CBs!<<)HvF(Ls-&`matpesJ5kkjC)6nGB@b{ii6-Uoho$BT%iJgugTOeZ$5Xo4D7Pd< zC*LJh5V@2#5%aBZCgzlQi3@<_!VfiL07ywc)ZbwKPfcR|ElQoS(8x|a7#IR}7#Io= zwg4$8S{egr-NffD)Fg&X9bJSoM25pF&%hf>(T&9bI}=#dPQyNYz;ZZ7EZ=u1n701SWKkZ9n(-qU ztN`sdWL1uxQ1mKS@x11;O|@^AD9!NeoPx}?EKIr!2>1Qq4gjfGU)tr6?Z5l7JAS3j zZeq{vG{rb%DFE4%$szK}d2UzB{4>L?Tv+NAlE*&Nq6g+XauaSI+N2Y8PJLw+aNg1p zbxr|hI8wcMP&&+(Cu|%+Jq|r>+BHk@{AvfBXKiVldN)@}TBS0LdIpnANCVE26WL-} zV}HJ^?m&$Rkq;Zf*i-hoasnpJVyTH__dbGWrB_R55d*>pTyl6(?$EO@>RCmTX1Hzr zT2)rOng?D4FfZ_C49hjMV*UonG2DlG$^+k=Y%|?Dqae4}JOU=8=fgY4Uh!pa9eEqf zFX&WLPu!jArN*^(>|H>dj~g`ONZhaaD%h_HHrHkk%d~TR_RrX{&eM#P@3x=S^%_6h zh=A)A{id16$zEFq@-D7La;kTuE!oopx^9{uA3y<}9 z^bQ@U<&pJV6kq7LRF47&!UAvgkBx=)KS_X!NY28^gQr27P=gKh0+E>$aCx&^vj2uc}ycsfSEP zedhTgUwPx%?;+dESs!g1z}5q9EC+fol}tAH9#fhZQ?q1GjyIaR@}lGCSpM-014T~l zEwriqt~ftwz=@2tn$xP&-rJt?nn5sy8sJ5Roy;pavj@O+tm}d_qmAlvhG(&k>(arz z;e|SiTr+0<&6(-An0*4{7akwUk~Yf4M!!YKj^swp9WOa%al`%R>V7mi z+5+UodFAaPdi4(8_FO&O!Ymb#@yxkuVMrog(7gkj$G@FLA#ENMxG)4f<}S%Fn?Up$+C%{02AgMKa^ z4SFGWp6U>{Q6VRJV}yjxXT*e`1XaX}(dW1F&RNhpTzvCtzuu;LMhMfJ2LBEy?{^GHG!OF!! zDvs64TG)?MX&9NCE#H3(M0K>O>`ca0WT2YR>PTe&tn?~0FV!MRtdb@v?MAUG&Ef7v zW%7>H(;Mm)RJkt18GXv!&np z?RUxOrCfs;m{fBz5MVlq59idhov21di5>WXWD-594L-X5;|@kyWi@N+(jLuh=o+5l zGGTi~)nflP_G}Yg5Pi%pl88U4+^*ihDoMP&zA*^xJE_X*Ah!jODrijCqQ^{=&hD7& z^)qv3;cu?olaT3pc{)Kcy9jA2E8I)#Kn8qO>70SQ5P8YSCN=_+_&)qg)OYBg|-k^d3*@jRAeB?;yd-O1A0wJ z?K*RDm|wE<(PBz~+C%2CTtzCTUohxP2*1kE8Of~{KRAvMrO_}NN&@P7SUO{;zx0iK z@or9R8ydYOFZf(cHASCAatL%;62IL27~SmASr(7F&NMr+#gNw@z1VM z_ALFwo3)SoANEwRerBdRV`>y`t72#aF2ConmWQp(Xy|msN9$yxhZ1jAQ67lq{vbC5 zujj|MlGo`6Bfn0TfKgi(k=gq0`K~W+X(@GzYlPI4g0M;owH3yG14rhK>lG8lS{`!K z+Nc@glT-DGz?Ym?v#Hq|_mEdPAlHH5jZuh*6glq!+>Lk$S%ED2@+ea6CE@&1-9a?s znglt|fmIK}fg<9@XgHe4*q!aO<-;Xj$T?IzB-{&2`#eA6rdtCi80mpP&vw(Uytxu$#YzNI_cB>LS zmim>ys;ir;*Dzbr22ZDxO2s;671&J0U<9(n1yj)J zHFNz=ufPcQVEG+ePjB<5C;=H0{>Mi*xD>hQq8`Vi7TjJ$V04$`h3EZGL|}a07oQdR z?{cR(z+d>arn^AUug&voOzzi$ZqaS)blz-z3zr;10x;oP2)|Cyb^WtN2*wNn`YX!Y z+$Pji<7|!XyMCEw4so}xXLU)p)BA~2fl>y2Tt}o9*BPm?AXA8UE8a;>rOgyCwZBFa zyl42y`bc3}+hiZL_|L_LY29vVerM+BVE@YxK>TGm@dHi@Uw*7AIq?QA9?THL603J% zIBJ4y3n8OFzsOI;NH%DZ!MDwMl<#$)d9eVVeqVl(5ZX$PPbt*p_(_9VSXhaUPa9Qu z7)q4vqYKX7ieVSjOmVEbLj4VYtnDpe*0Y&+>0dS^bJ<8s*eHq3tjRAw^+Mu4W^-E= z4;&namG4G;3pVDyPkUw#0kWEO1;HI6M51(1<0|*pa(I!sj}F^)avrE`ShVMKBz}nE zzKgOPMSEp6M>hJzyTHHcjV%W*;Tdb}1xJjCP#=iQuBk_Eho6yCRVp&e!}4IBJ&?ksVc&u#g3+G$oNlJ?mWfADjeBS-Ph3`DKk-~Z70XugH8sq2eba@4 zIC1H_J$`9b$K`J)sGX3d!&>OmC@@rx1TL~NinQOYy72Q_+^&Mg>Ku(fTgaXdr$p_V z#gav1o{k~c>#)u3r@~6v^o)Lf=C{rAlL@!s457pq)pO;Cojx7U{urO4cvXP|E>+dV zmr2?!-5)tk-&*ap^D^2x7NG6nOop2zNFQ9v8-EZ{WCz-h36C)<^|f{V#R_WE^@(T0+d-at5hXX{U?zak*ac-XnyINo+yBD~~3O1I=a z99|CI>502&s-Qi5bv>^2#cQ%ut<4d7KgQ^kE|=%6#VlGiY8$rdJUH{sra;P~cyb_i zeX(kS%w0C?mjhJl9TZp8RS;N~y3(EXEz13oPhOSE4WaTljGkVXWd~|#)vsG6_76I)Kb z8ro?;{j^lxNsaxE-cfP;g(e;mhh3)&ba}li?woV2#7ByioiD>s%L_D;?#;C#z;a(N z-_WY<=SH42m9bFQ>Nb z@4K$@4l8pD7AKxCR>t0%`Qoy9=hA?<<^Vcj8;-E+oBe3ReW1`el8np8E$k{LgFQ}2 z2t8a`wOXFdJ9!5$&mEfD1CnJ)TB+RJih88-Zos9@HZ# zL#{qfbF0ARTXkR@G{lwlOH~nnL)1jcyu!qv2`57S&%oKz0}r{~l9U_UHaJ5!8#nrs z?2FrL`mxnzu&{bweD&62)ilz*?pYIvt`T!XFVVA78})p1YEy7 z8fK#s?b~Yo$n7&_a?EBdXH-_W)Z44?!;DFx6pZ?~RArtBI*Qm4~6nX6Z_T*i$bQPE;Qz?DAPstpGSqr-AJ zo%m9cA`oDDm?&dTaoh_>@F>a?!y4qt_;NGN9Z<%SS;fX-cSu|>+Pba22`CRb#|HZa z;{)yHE>M-pc1C0mrnT~80!u&dvVTYFV8xTQ#g;6{c<9d!FDqU%TK5T6h*w*p980D~ zUyCb`y3{-?(mJFP)0*-Nt;mI$-gc4VQumh|rs&j_^R{sgTPF`1Xja2YWstsKFuQ(d zmZMxV$p$|qQUXchu&8%J(9|)B?`~rIx&)LqDS>ob5%gTeTP#Sbny#y*rnJ&?(l=!( zoV~}LJ1DPLnF8oyM(2ScrQ0{Q4m4-BWnS4wilgCW-~~;}pw=&<+HggRD_3c@3RQIr z9+-%!%}u_{`YS=&>h%kPO3ce}>y!d-zqiniNR-b5r97u;+K6HA2tS>Z#cV{+eFI`* zd8RMGAUtX1KWfPV;q<-5JAykS+2sY$2~UX+4461a(%{P#{rwFPu0xpIuYlbgD{C7C z=U{FUarVTYX6ZUq3wE@G^QT4H2Re;n$Fz9cJ>hABl)9T8pozqbA1)H-%1=WKm^QMu zjnUZ&Pu>q+X&6Co*y#@pxc-4waKMInEPGmE_>3@Ym3S*dedSradmc5mlJn`i0vMW6 zhBnGQD^Z;&S0lnS0curqDO@({J7kTtRE+Ra?nl^HP9<)W&C>~`!258f$XDbyQOQXG zP8hhySnarOpgu8xv8@WlXnm(Uk~)_3$Sg0vTbU3 z{W!5B(L3{Yy3K5PN<@jEarAtja`}@KYva&zFRF*s+_%jIXh$T(S=an8?=Ry3H*NRqWgsM`&!#|@kf1>=4q%bFw7^Rhz!z5I zyI^zU8_R1WN9`88Z=n>pIZQ`Ixr~_9G%Q}@A7rd#*%y7G zXl^Id=^ZL?Rx}}gWXCqzj9C6;x(~mAH|$JteXa1MH<6UQig@!Hf~t}B%tP0I|H&;y zO6N0}svOa1a^PyP9N5?4W6VF%=Bj{qHUgc8@siw4bafT=UPFSoQqKgyUX>sXTBZ=x zOh^Ad!{kOM9v{%5y}`-8u*T&C7Vq6mD%GR}UeU(*epO&qgC-CkD;%=l)ZuinSzHM` z{@`j&_vC6dDe{Yb9k@1zeV_K6!l(@=6ucoI=R^cH=6{i71%4W3$J-?<8Qn#$-DMtA z6Qqi)t?4ifrt%3jSA#6ji#{f(($KBL-iQh-xrC||3U3lq`9>r)>X%oLvtimuHW-)} zy}>9~|M>w4eES`g7;iBM%Se5-OP%1U6gNWp3AZqT8C6OlFFfQ$|7LL;tBV)(qlp4K zruar^K8FnJN3@_}B;G`a~H`t|3+6d>q3#`ctTkE-D^1#d9NalQ04lH*qUW2!V zhk7#z8OwHhSl8w14;KctfO8ubZJ4$dEdpXE78wABz=n5*=q9ex3S}`e7x~~V-jmHOhtX2*n+pBslo3uosdE7xABK=V#-t{1Hd~?i z{i~%Bw6NYF+F$aK$M`r#xe=NxhA5=p%i7!$);sd>Q}#`G?Q~fygrMXmZw?0#5#17W}6Tj+&kFexG{!mYl5FoA99}3G9l;3lVQ^ z48^~gsVppE*x91WheqI(A%F0Z#$#1UJP1R12Mj9r)y(A?a+iquX+d8WD4WAQJ_!oq z9rTISr7bPd(GTP57xm$}C}&kjMivi;zi^Y9g3&X0A;ovdJ?{%_wHgt%%9P&N4H z^XzV(uNA4 zAP`hgP6BEN5`YXh|DF~6Pud?~gWfhUKoPX4>z|}0aocC&K+AoV%|SX*N!wGq3|y< zg4lP(04XIPmt6}$N!dTk+pZv>u;MTB{L4hp9uXk7>aS!6jqM2lVr%{)H3$O127TSZ z0x9hi0k-P?nWFdQ0K`pykqUIT&jD~B0tHP{ffS(}fZ(aW$oBWTSfHO!A^><6vA?qar%tzN-5NQO zL&|F{nGiQyzNJ+bM$Y`n=Lx^3wTG^o2bGB@cwr1eb+6c-1tN=U+Db;bc~eJ!hwM{SbI=#g?$!PjDB+) zPgU_2EIxocr*EOJG52-~!gml&|D|C2OQ3Y(zAhL}iae4-Ut0F*!z!VEdfw8#`LAi# zhJ_EM*~;S|FMV6y%-SduHjPOI3cFM(GpH|HES<}*=vqY+64%dJYc|k?n6Br7)D#~# zEqO(xepfaf2F{>{E2`xb=AO%A<7RtUq6kU_Iu0m?@0K(+<}u3gVw5fy=Y4CC*{IE3 zLP3YBJ7x+U(os5=&NT%gKi23bbaZ`@;%ln)wp4GpDUT$J8NtFDHJzIe_-t}{!HAsh zJ4<^WovY};)9IKAskSebdQiXv$y5}THuJZ}ouoElIZRui=6lrupV|_Jz=9^&;@HwL;J#@23k?A;k`0Bgf;ioO>W`IQ+4? z7A)eKoY4%+g%=w;=Vm8}H>@U*=*AWNtPqgWRqib#5RTGA@Q=43FrQn3J`GkTUV5yp0U`EOTqjfp+-9;0F8!dMEwwcK%(6`8sDD^aR04 zd6O5vh|Xk?&3dy4f|1QK&Ulf{h6Iq;d-&*ti#Ck>wZFG;GHwc?b;X~eBITx49>2d8 z4HcK&1&DvEGT6kXdzAm4oO8%c}8OBt~8H956_;YP-ss*uMf==a+%w~F>Qkm7r)IAuxuoX}h92$gHqbFUun#8m zWHdy`Zrm#=Pa98x8cO0vd@Tgkr*lm0{dky+Gocr0P8y%HGEI#c3qLqIRc`Oq_C%*; zG+QTr(#Q|yHKv6R@!DmLlwJQ3FAB)Yor-I4zyDyqM4yp5n2TrQH>gRt*Zw0+WI-Sj`EgmYHh=t9! zF6lz^xpqGGpo6!5`sc0a^FVhy_Uxq|@~(1@IIzV)nTpY9sY`CV!?8e&bB8=M&sYEb z2i}fvKdhp9Hs68Y-!QJ<=wE(iQ5+49tqt;Rh|jhYrI5VW-mIz|UY{h8E=rC5sh#DU z?wGgk-Tn!I?+Zer7pHlF_Z^!Kd1qkS3&lv#%s6-<5Y%jQL${cge5=G5Ab?D&|9$Y~ zf%rJC2+=2vg;y0-SJb3<@3%}BO$T$C66q$L_H33a`VUbgW~N(4B=v5(<=My|#|J7q z*Ox4wL4kbJd_~EjLTABSu4U7Jk#`y(6O*U6(k6XxM}CtGZB(H@3~kh*zaGRXM}Iwp zQ%xFk2>@wiZrVCV_G4G~v;NebCQ%T7{SDyPpSv&dT@Cn)Mx@IK*IdNrj{*4pkV4wv z)y0J538h>cpB7iPSzA~x24T`{dzNkpvGIqvt1Dvdq@o-`B=$hkczX8$yFMhsWNK-X zxr$kR$tMD0@W)Vxe1^t9qVmsg&K^F@u84)(n2dttIEAZFN6VD$&tskpG%SI7whGL3 z)DeRiwe&?8m7U{G`oW8!SCi*dM>oYL%UKQnKxV_0RXAEBQg1kStExGEUVwLJ0orGGwb7uv+kPDl7_E2*iD|J*=8A@;XCvwq0aw5oJYN*Yh&o=l} z2z8YKb-fIAH5spql4eXqp*)o2*b>#1@DSt?zZi{GPj0gH&Nm+EI<3^z0w%YTEV4xw zI6$+=Faa|Y4o5i0zm5lOg|&tmnJ806DBovU@Ll6XsA;NRrTK~t*AAJIAS=v-UZ%Pr z$oddI@NRir&erzCwq|)ciJemr-E061j{0Vc@Ys7K(mW|JYj*$+i1Q8XlIK8T?TYS(AXu$`2U zQ@fHxc=AVHl_}cRZQ)w0anMEoqRKKIvS^`<-aMf*FM`NsG&Uowneo+Ji$7DUDYc7*Hjg;-&aHM%3 zXO6cz$$G};Uqh+iY7Wpme>PHG4cu(q;xyskNLs$^uRRMfEg?8Cj~aE-ajM%CXkx0F z>C?g3tIA#9sBQOpe`J+04{q7^TqhFk^F1jFtk4JDRO*`d-fx`GYHb=&(JiaM1b?Y^ zO3Kj3sj76ieol|N$;>j@t#tKj=@*gP+mv}KwlTcPYgR$+)2(gk)2JNE=jSauPq!$< z<|?Sb%W)wS)b>b6i{8!x!^!xIdU3{CJFVnTcw0j{M%DUCF=_>eYYEUWnA-|B(+KYL z_W_`JI&&u^@t0})@DH^1LDuT0s3dMpCHIbYBgOT4Zh_4yHbSqRbtIKndeT4Q*Jg91 z@>rO!^t-G~*AIW;FQ$3J=b;oGg8?CTa~qNCb>&cgp@e;?0AqA&paz~(%PYO+QBo4( zp?}ZdSMWx0iJm7HVNk9A#^9Osa#GPJ!_pYEW}($8>&2}fbr@&ygZ?${A7_9?X$(&5 z#~-hxdPQwCNEpf=^+WH-3`2LxrrBMTa}~qJC9S;VzhG!On^JLyW6WkF{8aAE$sM+( zxr8xLW(KIjI`Rm(24r3OJBk<3GF=G!uSP0-G&AY32mLm8q=#Xom&Pqv=1C{d3>1^ zAjsmV@XZ%BKq^eUfBpa8KvO8ob|F3hAjJv*yo2Bhl0)KUus{qA9m8jf)KnOGGTa6~4>3@J_VzkL|vYPl*uL+Ot*Q7W!f5rJw5+AsjP_IfL+-S*2p| zB7!FhjvkUTxQkGWGSg{X;h~dK>gAJivW?88Nu!3o>ySDaABn$rAYt086#27fbjPQS zhq>55ASvm*60qRdVOY9=bU^+{Pi#!OaZwENN;zy5?EztOHK-Q5;rCuiFl}BSc1YaQ zC-S{=KsGDz@Ji9O5W;XxE0xI|@3o6(2~i4b8Ii9VT;^G$*dRw(V?=br)D&q^XkeBX z+gl~+R@rVD-Hwv@7RHV?Bip5KMI)aV^&snt?H<$Nt=OPx#VxF&BGi?2A2+lNOYywNUGMeGL;|(=UjGDtLG0sN&LpGx;|U;xa13s z;W_|SPk^G}!M9_^pO zA3bt3-tca%^42sHeDtfcC0S3w3H1ny!Bxpa=*k?XRPpx9Bb-gx1J9Yvx)4J(8cG+q z(iCPZ9dsf3#QVyZgD_MW#G#qgV)olu$59&3(PzQfw@%4uZ~<5J=ABvdY43(Qnp{;G zHg3>@T#>DbTuhFl3)fb3TFqdh)V2aq7!;&JOHseTWukvA7}(iGUq;v-{2J0iHSNHq z;+)h!p6Ok^+Sp8-jgL($n6Qu47xyE`cFO5SdZR6;R!FET`tm#0D37z339Suxjpv+s z*=%2-N$N?X&0?x_uut3erF@aBGj;9$k9?3FlbDO{RQa1_qtxrh4!4#fjp4x~akvdTp@ zos?^Q&XE;3N93s4rHQGPrV7+au1$$aB6$hLy*Yz_kN$~dweb9PcB!eYVQTGjFuJP> zZCEwBtb>TIgIO^qAzq@Bv-qud_ZD-2W<_at&ml-gv`tPt$@DF5`HlA zM>DmmMkpv&Zm-8)Y#0bLQf4MpD4_-7M8eu6rh(tL8dq8onHs#R9J~dGd2IaXXMC~h z91pKhnQa%Fsn29nAA1;x(%oC zhca~qQDJaMf?wFrl-Pj;e$bZMYmMF!Y3Lv&Sb?Sjn#!NVx&NDyc^$b4uYyo2OmERa zRz;yDGd@JTykzFLe|Wk-y7#3x`6$wt$zR8r48mdUvfbeL+4D|Z``~7$PrE@qc7rZe zVsIoIbCwzjLZ@_M1*bD{HaYn();Z1-q*-I{tEnTZ(}Zmk&%MXSNBX>o| z-u*RNkAyKC-Srp7c-=@5f)xMWg>o2WWl}j6j9=8+D8;T z>0*0q#;qw8%U8i;6s0fu#I*%(g*@@a2Er@@nyI}{=@W{Z-;`=wN4N~>6Xrh&z#g}l zN1g5}0-#(nHUTv_rl2{yUZ;h#t&Fd?tY!7L%ClY)>uH-Ny2ET$lW$S)IQiN79H)D^ zb&0AXYkupy0~w8)*>Sj_p9}4L?lGTq%VG|2p`nWGhnM^!g|j-|O{%9Q%swOq63|*W zw$(N_laI}`ilB+o!a-wl?er~;;3+)$_akSQ!8YO_&-e*SI7n^(QQ;X0ZE`{4f!gAl z5$d+9CKVNonM!NO_frREICIAxOv)wm>}-k?iRisM`R7;=lyo|E_YR~FpS&PS`Lg0f zl-ON<0S%Uix8J%#yZdkCz4YNhcec<|7*P(JsM#>-L>+tYg_71q9~70FAc^6KW5jql zw!crdgVLH1G_eET=|SEc977;)ezVC|{PJZfra|}@rD;0s&@61mTEBJtILllg{%{vN zfhb&lq0yChaLhnJ-Qb62MB7`>M;|_ceHKZAeeh@#8tbrK!ArP6oXIhMK;dhEJTY`@ z0Tq>MIe0`7tGv)N*F0IGYSJv0vN?Az8g+4K9S!pW2~9F4W(_U_T=jCZrzuZ3*|__T zONp_UWmyePv8C~rckc?Xji;Z5OEqg zC*Um)i;Wh4TEwqReQdVVbUKT^2>Tpi6z_^-uF*adUFug4i@JhzpWT^Sk&E>CyP2?H zWf6x}ehuTs6wvzCnTU&gYzT029Nz19(In1WC z`(1IGmi!O%2AR|BjQa4Q0~u)kM%}?xQyjWuQ16^Gp++;`vr7!k--UZWM*~7Zl|ceO@I3`OpaRhD;YoCuo5IC0uHx>9 z478hu@H|e0Zlo)Zj@01#;8BDs@991xe~^9uG2}UXLM(m7fa}AMwX*tjioBeV&Q8Gx zSq$6wZFkRBK`cMI>R(@W@+lo2t)L+4q-negWRLWZBz*|%=W4v62JrmzNuOtA*x)QE z5L%=OH#@KMdB%Jp^r?0tE}5-*6oP`-lO7Sf)0)n*e<{HA=&qhLR)oD8-+V}Z4=md) z+k9lKf64DB2hAT)UaCP~di?-V3~JBH7itYyk~L6hrnxM%?RKntqd`=!b|e7eFnAcu z3*V;g{xr7TSTm$}DY%~SMpl>m{Sj!We+WfxSEor?YeiAxYUy25pn(?T()E>ByP^c@ zipwvWrhIK((R((VU+;@LmOnDu)ZXB3YArzzin!Z^0;PyJWnlfflo|q8(QY;o1*5CO z##hnkO{uynTMdk`~DOC#1 zdiYxQoy}=@7(ke#A8$YZZVtk4wo$8x28&I;cY3Ro-|kW=*yiiHgCLZeAr)UtVx>Tu z|LvL0hq|1-jC0I4x#>&QZCfrVB=zT!nR|~Uz`9%~2 znl{uZ{VEszW`Fad^q_HB!K9*|U-stK%?~;g?&&+12A}Rq$z($Bzuk^2X(Y=hF?-dQ ztc3DsQKI;qhWIV`99Q#R3xnU0AvY!i*BECj-z9l74|%O=V@nlv|qqC^r^-~C?E zGW%c|uYgnfJ(gjsTm_cIqcv*mYM{+i+&@F@+69ZQOK&u#v4oxUSQJ=tvqQ3W=*m;| z>SkBi8LYb-qRY7Sthh*0%3XAC%$z1rhOJzuX=PkTOa=DlocZUpE#KxVNH5)_4n=T( zGi3YrH7e~sPNYVBd~Grcq#CF~rN{p9Zza-Ntnwfma@TB)=3g36*0lSZg#ixEjFe%+ zX=&LDZ5zqculZ`=RYc^ln(~;nN|Qh6gN=!6f9-N2h+3NWbIxYud&;4SX*tWf5slk4 z{q@@l71UAZgj~*6edXb57fBUxvAS7s(RI=X868JM0+^DCn2yC>;v%S;qPOjB>YVsz(Zx9a>>BK&M zIQK>7_n)4ud0X5YM}^i*keH{ehLsiy9@NvOpsFeQjdI6anLGvVbBw_*fU1TzdVS$i z*4j7z!I5RF#rSz|8ibi$;qE{4`aqWYik7QB5U&F5C*;TO_x+gtzPGpzNt!7~nsBT7)Ckc(K~%uv&{{6A`mmBJVAk-{s~52Vu|HbCH7_W1~ZCX^RflOakGg=jo2Z z<*s;5-J+2@^LRDZ-7EV&Pq+FTErw@pfFqvx^i%E7Fx#^n(E`m2(c>K-O5`M`Yek9el zzTGs5qD6*G;y#~xu3>qWuO?-amKYtvRA}I9z#UspEeM;wOERYeot_n_EUMJf$4_u?E!6X~?q)tPoZb^_;8Y_Ox2h1m<+Le-fsRd|T8db<8#$bqez zua^Z|>h%zdnuU^ww$#-dZ9NTM`FN+!IlLkz*FqWb!x^Z|C{KyGjZ+>G;;7Mb@LY|H zc+Gp`L((Dw7pnDlHNm&;SfHedhx*kad$I^uGz{`0BYelq0yEUHpNKSkvj$|dpvY3{7*YGyhXA^LP0&wOw9oNoC=QoVx1<2Dne8qqZL zm>nFh5DX(-RnQwvHCZQwn^#Z=E!SPVlaRJ78Bo@}!!9dRt^qZy?-*`Pt4WSmgucJv zV1yFkcjlEM^uz-;b#Q7ZCP@Lk)m}uPX={R4B=56k7WNh11BN~0T*vr@!!ow^B0hOR zQ)4)&(e%>bNNL%bm<&8H{*l_L7s0$2GUgX2Vd;=4d9Dm2v3TaL+;L>{K7h7 zV#k?xDPm(NDE31$ z<}|X)pEY6myjK+^gaIMk&Yj2~F0rSKemNqlsVm4c|N7mp_C*L01s;GNx#D-*&gk!qQr}^?_r@q!8fuXw!)fA7xkd} zb>vHvdx~H$5qqAWrow7}+8zBM65-JOt5z za=T6f7MK`XJuQog8kIEboPdhcaVJeHy)5z7EBLK5NRr()E|#K0L0N^JD@pUA^Czb` zbUZ_558y+vqAGeyHCbrvOvLD67Ph}06959VzQ_|>RrXQAqE+AQ(-AaKdxoWaF8hdt z{O3W@b^*o#-f1VuU>YMV03ELF7zkCN4Q&b#prz%3Nne0lSbRo@@ z^ihv%oIl~Qyl6Q;a#$*jOC%x0_;eis*)J7=f@Ct*)xF5 zo}u~@-I}2|$b%5L7>@+Z?4o+1r&v6ceIy+vroK&jCQ<4q&45HP2wCol4hVm3pZtjf zHz1D7oyaSKJ~T{Gx}7ONLA)D5k(%%`WswrDyzX*rn}i}}TB4^y#@mAwPzoC)`?rYv zHgx|trUN#mu*VzUV~8TnJM2Qh*ZM5B{x&y>5An`(M7=Z*Q>TdiH@j*2=moNuOtvpz z+G`@~-`%~+AgPKgke@XiRPgndh@bp*-HRsh;HTtz@-y_uhb%7ylVOTqG0#u?Vn5c5 zEp*XRo|8hcgG^$#{$O9CJ&NE;TrfRpSnLmes&MO{m=N%zc`}gb!eQ7odl$oy1%PI} z#AIxx%oRVy&{O~9xnK4$EY>(eQj}!HKIV$Fz*H=-=Kn)N0D6u`(;iO|VraI4fu_W` z;b5{7;Lyx4za}DU#+U7}=H0dAS#YJJ&g2!P@Htu-AL&w=-)*%P9h2{wR|@?Ff9~)b z^+e_3Hetq7W%ls{!?<6&Y$Z;NNB41pvrv)|MET6AZXFXJeFqbFW5@i5WGzl?bP+~? z*&_puH;wKv2)9T_d+P`bLvJFqX#j&xa*-;0nGBbQf0DC>o~=J_Wmtf*2SZQr?{i~X z9-IbRH8{iy?<0v9Ir1?$66+igy|yDQ5J~A9sFX@Pe<*kCY8+MwH?I z`P}zfQ6l^AO8ehZ=l^ZR;R%uu4;BK*=?W9t|0{+-at(MQZ(CtG=EJFNaFMlKCMXu30(gJUqj5+ z`GM|!keqcj;FKTa_qq;{*dHRXAq157hlB@kL#8%yAm2AgfU|*rDKX@FLlp=HL8ddv zAWLCHe@DcDeB2}fl7#=0+#<05c3=VqM*O3bkr@9X4nO|)q0hU;Gye{L8ZN*NH8Id@mP-u;Fmb8YuorjLrW&ndip8CN%_qp982r w1WEnz9^$&s1hkp_3#lPJQ~!HI7WYYjA7>z!`?f%npAh2%rB@vD|Lau$2O)#1n*aa+ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e6e5897b..aa991fcea 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.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/kmath-ast/README.md b/kmath-ast/README.md index bedf17486..4872a3a26 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,17 +10,17 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-17' + implementation 'space.kscience:kmath-ast:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-17") + implementation("space.kscience:kmath-ast:0.3.0-dev-20") } ``` @@ -66,20 +66,19 @@ For example, the following code: ```kotlin import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.operations.DoubleField -"x+2".parseMath().compileToExpression(ComplexField) +"x^3-x+3".parseMath().compileToExpression(DoubleField) ``` … leads to generation of bytecode, which can be decompiled to the following Java class: ```java -import java.util.Map; -import kotlin.jvm.functions.Function2; -import space.kscience.kmath.asm.internal.MapIntrinsics; -import space.kscience.kmath.complex.Complex; -import space.kscience.kmath.expressions.Expression; -import space.kscience.kmath.expressions.Symbol; +import java.util.*; +import kotlin.jvm.functions.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.complex.*; +import space.kscience.kmath.expressions.*; public final class CompiledExpression_45045_0 implements Expression { private final Object[] constants; @@ -91,6 +90,32 @@ public final class CompiledExpression_45045_0 implements Expression { } ``` +For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: + +```java +import java.util.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.expressions.*; + +public final class CompiledExpression_-386104628_0 implements DoubleExpression { + private final SymbolIndexer indexer; + + public SymbolIndexer getIndexer() { + return this.indexer; + } + + public double invoke(double[] arguments) { + double var2 = arguments[0]; + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } + + public final Double invoke(Map arguments) { + double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } +} +``` + Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. #### Limitations @@ -134,9 +159,9 @@ MstField { x + 2 }.compileToExpression(DoubleField) An example of emitted Wasm IR in the form of WAT: ```lisp -(func $executable (param $0 f64) (result f64) +(func \$executable (param \$0 f64) (result f64) (f64.add - (local.get $0) + (local.get \$0) (f64.const 2) ) ) diff --git a/kmath-commons/README.md b/kmath-commons/README.md new file mode 100644 index 000000000..a17a39205 --- /dev/null +++ b/kmath-commons/README.md @@ -0,0 +1,32 @@ +# Module kmath-commons + +Commons math binding for kmath + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-commons:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-commons:0.3.0-dev-20") +} +``` diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 92f2435ba..b55ce0fea 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,17 +8,17 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-17' + implementation 'space.kscience:kmath-complex:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-17") + implementation("space.kscience:kmath-complex:0.3.0-dev-20") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index e765ad50c..31965ef92 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,17 +15,17 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-17' + implementation 'space.kscience:kmath-core:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-17") + implementation("space.kscience:kmath-core:0.3.0-dev-20") } ``` diff --git a/kmath-coroutines/README.md b/kmath-coroutines/README.md new file mode 100644 index 000000000..0d83a6c60 --- /dev/null +++ b/kmath-coroutines/README.md @@ -0,0 +1,32 @@ +# Module kmath-coroutines + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-coroutines:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-coroutines:0.3.0-dev-20") +} +``` diff --git a/kmath-dimensions/README.md b/kmath-dimensions/README.md new file mode 100644 index 000000000..52097cf40 --- /dev/null +++ b/kmath-dimensions/README.md @@ -0,0 +1,32 @@ +# Module kmath-dimensions + +A proof of concept module for adding type-safe dimensions to structures + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-dimensions:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-dimensions:0.3.0-dev-20") +} +``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index fcd092bf1..3fe6d9e1a 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,17 +9,17 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-17' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-17") + implementation("space.kscience:kmath-ejml:0.3.0-dev-20") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 938327612..197190dcd 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,17 +9,17 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-17' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0-dev-17") + implementation("space.kscience:kmath-for-real:0.3.0-dev-20") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 3d4beee47..6379ad0b5 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,17 +11,17 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-17' + implementation 'space.kscience:kmath-functions:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0-dev-17") + implementation("space.kscience:kmath-functions:0.3.0-dev-20") } ``` diff --git a/kmath-geometry/README.md b/kmath-geometry/README.md new file mode 100644 index 000000000..6b8fb25a0 --- /dev/null +++ b/kmath-geometry/README.md @@ -0,0 +1,32 @@ +# Module kmath-geometry + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-geometry:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-geometry:0.3.0-dev-20") +} +``` diff --git a/kmath-histograms/README.md b/kmath-histograms/README.md new file mode 100644 index 000000000..0b8a632d6 --- /dev/null +++ b/kmath-histograms/README.md @@ -0,0 +1,32 @@ +# Module kmath-histograms + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-histograms:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-histograms:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-histograms:0.3.0-dev-20") +} +``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index 760244751..a274b3d88 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,17 +7,17 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0-dev-17' + implementation 'space.kscience:kmath-jafama:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0-dev-17") + implementation("space.kscience:kmath-jafama:0.3.0-dev-20") } ``` diff --git a/kmath-jupyter/README.md b/kmath-jupyter/README.md new file mode 100644 index 000000000..8014b969d --- /dev/null +++ b/kmath-jupyter/README.md @@ -0,0 +1,32 @@ +# Module kmath-jupyter + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-jupyter:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-jupyter:0.3.0-dev-20") +} +``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 588ccb9b4..08c913090 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,17 +8,17 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-17' + implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-17") + implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-20") } ``` diff --git a/kmath-memory/README.md b/kmath-memory/README.md new file mode 100644 index 000000000..d37087a66 --- /dev/null +++ b/kmath-memory/README.md @@ -0,0 +1,32 @@ +# Module kmath-memory + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-memory:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-memory:0.3.0-dev-20") +} +``` diff --git a/kmath-multik/README.md b/kmath-multik/README.md new file mode 100644 index 000000000..167445f52 --- /dev/null +++ b/kmath-multik/README.md @@ -0,0 +1,32 @@ +# Module kmath-multik + +JetBrains Multik connector + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-multik:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-multik:0.3.0-dev-20") +} +``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 7ca9cd4fd..225de18e9 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,17 +9,17 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-17' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-17") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-20") } ``` diff --git a/kmath-optimization/README.md b/kmath-optimization/README.md new file mode 100644 index 000000000..137975c90 --- /dev/null +++ b/kmath-optimization/README.md @@ -0,0 +1,32 @@ +# Module kmath-optimization + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-optimization:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-optimization:0.3.0-dev-20") +} +``` diff --git a/kmath-stat/README.md b/kmath-stat/README.md new file mode 100644 index 000000000..762e61237 --- /dev/null +++ b/kmath-stat/README.md @@ -0,0 +1,32 @@ +# Module kmath-stat + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-stat:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-stat:0.3.0-dev-20") +} +``` diff --git a/kmath-symja/README.md b/kmath-symja/README.md new file mode 100644 index 000000000..e3c717cff --- /dev/null +++ b/kmath-symja/README.md @@ -0,0 +1,32 @@ +# Module kmath-symja + +Symja integration module + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-symja:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-symja:0.3.0-dev-20") +} +``` diff --git a/kmath-tensorflow/README.md b/kmath-tensorflow/README.md new file mode 100644 index 000000000..f1dfa0202 --- /dev/null +++ b/kmath-tensorflow/README.md @@ -0,0 +1,32 @@ +# Module kmath-tensorflow + +Google tensorflow connector + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-tensorflow:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-tensorflow:0.3.0-dev-20") +} +``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 42ce91336..3d7dfd1fb 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,17 +9,17 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-20`. -**Gradle:** -```gradle +**Gradle Groovy:** +```groovy repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-17' + implementation 'space.kscience:kmath-tensors:0.3.0-dev-20' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-17") + implementation("space.kscience:kmath-tensors:0.3.0-dev-20") } ``` diff --git a/kmath-viktor/README.md b/kmath-viktor/README.md new file mode 100644 index 000000000..229d4dcd4 --- /dev/null +++ b/kmath-viktor/README.md @@ -0,0 +1,32 @@ +# Module kmath-viktor + +Binding for https://github.com/JetBrains-Research/viktor + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-viktor:0.3.0-dev-20`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-viktor:0.3.0-dev-20' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-viktor:0.3.0-dev-20") +} +``` diff --git a/settings.gradle.kts b/settings.gradle.kts index a8b473fee..b3c275810 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,6 @@ rootProject.name = "kmath" enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -enableFeaturePreview("VERSION_CATALOGS") - include( ":kmath-memory", ":kmath-complex", -- 2.34.1 From 13fb49e48c84217dd07b7f3343ba2c0f08962081 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 1 Apr 2022 02:27:50 +0700 Subject: [PATCH 098/102] Rename version catalog --- buildSrc/build.gradle.kts | 8 ++++---- buildSrc/settings.gradle.kts | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b69ebe6cd..fa5142538 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,7 +1,7 @@ plugins { `kotlin-dsl` `version-catalog` - alias(npmlibs.plugins.kotlin.plugin.serialization) + alias(miptNpmLibs.plugins.kotlin.plugin.serialization) } java.targetCompatibility = JavaVersion.VERSION_11 @@ -14,8 +14,8 @@ repositories { } val toolsVersion: String by extra -val kotlinVersion = npmlibs.versions.kotlin.asProvider().get() -val benchmarksVersion = npmlibs.versions.kotlinx.benchmark.get() +val kotlinVersion = miptNpmLibs.versions.kotlin.asProvider().get() +val benchmarksVersion = miptNpmLibs.versions.kotlinx.benchmark.get() dependencies { api("ru.mipt.npm:gradle-tools:$toolsVersion") @@ -23,7 +23,7 @@ dependencies { api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion") api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") //to be used inside build-script only - implementation(npmlibs.kotlinx.serialization.json) + implementation(miptNpmLibs.kotlinx.serialization.json) } kotlin.sourceSets.all { diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index bc530ac03..7c1df133d 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -4,7 +4,6 @@ */ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -enableFeaturePreview("VERSION_CATALOGS") dependencyResolutionManagement { val toolsVersion: String by extra @@ -17,7 +16,7 @@ dependencyResolutionManagement { } versionCatalogs { - create("npmlibs") { + create("miptNpmLibs") { from("ru.mipt.npm:version-catalog:$toolsVersion") } } -- 2.34.1 From 38fd3e24c8261eb4da302d499c13d0d063d93712 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 1 Apr 2022 02:37:14 +0700 Subject: [PATCH 099/102] Use correct class name for kotlin JVM compilation --- benchmarks/build.gradle.kts | 2 +- examples/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index f8d39b9c5..22712816d 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -155,7 +155,7 @@ kotlin.sourceSets.all { } } -tasks.withType { +tasks.withType { kotlinOptions { jvmTarget = "11" freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xlambdas=indy" diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 36715cd78..60f8f5aed 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -58,7 +58,7 @@ kotlin.sourceSets.all { } } -tasks.withType { +tasks.withType { kotlinOptions { jvmTarget = "11" freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" -- 2.34.1 From 3277a99ed3bb3668160de14d3e4e23ad9b587600 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 1 Apr 2022 02:58:12 +0700 Subject: [PATCH 100/102] Never use GitHub Packages to publish project with --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3372d505d..445976853 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -56,7 +56,7 @@ subprojects { readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") ksciencePublish { - github("kmath") + github("kmath", addToRelease = false) space() sonatype() } -- 2.34.1 From bae465fe865b0b8288861b78b62c04f4b5eef8c3 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 1 Apr 2022 03:06:07 +0700 Subject: [PATCH 101/102] Update GitHub actions --- .github/workflows/build.yml | 8 ++++---- .github/workflows/pages.yml | 20 +++++++++++++++----- .github/workflows/publish.yml | 11 +++++------ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 455e0dd2d..0834c2656 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,13 +13,13 @@ jobs: runs-on: ${{matrix.os}} timeout-minutes: 40 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.5.0 + - uses: actions/checkout@v3.0.0 + - uses: actions/setup-java@v3.0.0 with: java-version: 11 distribution: liberica - name: Cache gradle - uses: actions/cache@v2 + uses: actions/cache@v3.0.1 with: path: | ~/.gradle/caches @@ -28,7 +28,7 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - name: Cache konan - uses: actions/cache@v2 + uses: actions/cache@v3.0.1 with: path: ~/.konan key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index e7f5300c7..0158c82ac 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -9,19 +9,29 @@ jobs: runs-on: ubuntu-20.04 timeout-minutes: 40 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.5.0 + - uses: actions/checkout@v3.0.0 + - uses: actions/setup-java@v3.0.0 with: java-version: 11 distribution: liberica - - uses: actions/cache@v2 + - name: Cache gradle + uses: actions/cache@v3.0.1 with: - path: ~/.gradle/caches + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache konan + uses: actions/cache@v3.0.1 + with: + path: ~/.konan key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- - run: ./gradlew dokkaHtmlMultiModule --build-cache --no-daemon --no-parallel --stacktrace - - uses: JamesIves/github-pages-deploy-action@4.1.0 + - uses: JamesIves/github-pages-deploy-action@4.2.5 with: branch: gh-pages folder: build/dokka/htmlMultiModule diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 17adc5655..83755793a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,13 +14,13 @@ jobs: os: [ macOS-latest, windows-latest ] runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.5.0 + - uses: actions/checkout@v3.0.0 + - uses: actions/setup-java@v3.0.0 with: java-version: 11 distribution: liberica - name: Cache gradle - uses: actions/cache@v2 + uses: actions/cache@v3.0.1 with: path: | ~/.gradle/caches @@ -29,14 +29,13 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - name: Cache konan - uses: actions/cache@v2 + uses: actions/cache@v3.0.1 with: path: ~/.konan key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- - - name: Gradle Wrapper Validation - uses: gradle/wrapper-validation-action@v1.0.4 + - uses: gradle/wrapper-validation-action@v1.0.4 - name: Publish Windows Artifacts if: matrix.os == 'windows-latest' shell: cmd -- 2.34.1 From 97a320c9ef8cd3cdbb73256499200a23be51b84d Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Fri, 1 Apr 2022 14:02:03 +0700 Subject: [PATCH 102/102] Use gradle-build-action --- .github/workflows/build.yml | 14 +++----------- .github/workflows/pages.yml | 13 +++---------- .github/workflows/publish.yml | 34 ++++++++++++++++------------------ 3 files changed, 22 insertions(+), 39 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0834c2656..cffef64b0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,15 +18,6 @@ jobs: with: java-version: 11 distribution: liberica - - name: Cache gradle - uses: actions/cache@v3.0.1 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} - restore-keys: | - ${{ runner.os }}-gradle- - name: Cache konan uses: actions/cache@v3.0.1 with: @@ -36,5 +27,6 @@ jobs: ${{ runner.os }}-gradle- - name: Gradle Wrapper Validation uses: gradle/wrapper-validation-action@v1.0.4 - - name: Build - run: ./gradlew build --build-cache --no-daemon --stacktrace + - uses: gradle/gradle-build-action@v2.1.5 + with: + arguments: build diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 0158c82ac..9b76fd16e 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -14,15 +14,6 @@ jobs: with: java-version: 11 distribution: liberica - - name: Cache gradle - uses: actions/cache@v3.0.1 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} - restore-keys: | - ${{ runner.os }}-gradle- - name: Cache konan uses: actions/cache@v3.0.1 with: @@ -30,7 +21,9 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- - - run: ./gradlew dokkaHtmlMultiModule --build-cache --no-daemon --no-parallel --stacktrace + - uses: gradle/gradle-build-action@v2.1.5 + with: + arguments: dokkaHtmlMultiModule --no-parallel - uses: JamesIves/github-pages-deploy-action@4.2.5 with: branch: gh-pages diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 83755793a..8e9b98dcb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,15 +19,6 @@ jobs: with: java-version: 11 distribution: liberica - - name: Cache gradle - uses: actions/cache@v3.0.1 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} - restore-keys: | - ${{ runner.os }}-gradle- - name: Cache konan uses: actions/cache@v3.0.1 with: @@ -38,14 +29,21 @@ jobs: - uses: gradle/wrapper-validation-action@v1.0.4 - name: Publish Windows Artifacts if: matrix.os == 'windows-latest' - shell: cmd - run: > - ./gradlew releaseAll --no-daemon --build-cache -Ppublishing.enabled=true - -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} - -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} + uses: gradle/gradle-build-action@v2.1.5 + with: + arguments: | + releaseAll + -Ppublishing.enabled=true + -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} + -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} - name: Publish Mac Artifacts if: matrix.os == 'macOS-latest' - run: > - ./gradlew releaseMacosX64 releaseIosArm64 releaseIosX64 release --no-daemon --build-cache - -Ppublishing.enabled=true -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} - -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} + uses: gradle/gradle-build-action@v2.1.5 + with: + arguments: | + releaseMacosX64 + releaseIosArm64 + releaseIosX64 + -Ppublishing.enabled=true + -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} + -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} -- 2.34.1