Compare commits

...

No commits in common. "dev" and "gh-pages" have entirely different histories.

4630 changed files with 587018 additions and 73111 deletions
.github
.gitignore
.idea
CHANGELOG.mdREADME.md
benchmarks
build.gradle.kts
docs
examples
gradle.properties
gradle
gradlewgradlew.bat
images

3
.github/CODEOWNERS vendored

@ -1,3 +0,0 @@
@altavir
/kmath-trajectory @ESchouten

@ -1,24 +0,0 @@
name: Gradle build
on:
push:
branches: [ dev, master ]
pull_request:
jobs:
build:
runs-on: windows-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3.5.1
with:
java-version: '17'
distribution: 'liberica'
cache: 'gradle'
- name: Gradle Wrapper Validation
uses: gradle/wrapper-validation-action@v1.0.4
- name: Gradle Build
uses: gradle/gradle-build-action@v2.4.2
with:
arguments: test jvmTest

@ -1,31 +0,0 @@
name: Dokka publication
on:
workflow_dispatch:
release:
types: [ created ]
jobs:
build:
runs-on: ubuntu-24.04
timeout-minutes: 40
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: 17
distribution: liberica
- name: Cache konan
uses: actions/cache@v3
with:
path: ~/.konan
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
restore-keys: |
${{ runner.os }}-gradle-
- uses: gradle/gradle-build-action@v3
with:
arguments: dokkaGenerate --no-parallel
- uses: JamesIves/github-pages-deploy-action@v4
with:
branch: gh-pages
folder: build/dokka/html

24
.gitignore vendored

@ -1,24 +0,0 @@
.gradle
build/
out/
.idea/
.vscode/
.fleet/
.kotlin/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Cache of project
.gradletasknamecache
# Generated by javac -h and runtime
*.class
*.log
!/.idea/copyright/
!/.idea/scopes/
/gradle/yarn.lock

@ -1,7 +0,0 @@
<component name="CopyrightManager">
<copyright>
<option name="allowReplaceRegexp" value="Copyright \d{4}-\d{4} KMath" />
<option name="notice" value="Copyright 2018-&amp;#36;today.year KMath contributors.&#10;Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file." />
<option name="myName" value="kmath" />
</copyright>
</component>

@ -1,21 +0,0 @@
<component name="CopyrightManager">
<settings>
<module2copyright>
<element module="Apply copyright" copyright="kmath" />
</module2copyright>
<LanguageOptions name="Groovy">
<option name="fileTypeOverride" value="1" />
</LanguageOptions>
<LanguageOptions name="HTML">
<option name="fileTypeOverride" value="1" />
<option name="prefixLines" value="false" />
</LanguageOptions>
<LanguageOptions name="Properties">
<option name="fileTypeOverride" value="1" />
</LanguageOptions>
<LanguageOptions name="XML">
<option name="fileTypeOverride" value="1" />
<option name="prefixLines" value="false" />
</LanguageOptions>
</settings>
</component>

@ -1,3 +0,0 @@
<component name="DependencyValidationManager">
<scope name="Apply copyright" pattern="!file[*]:*//testData//*&amp;&amp;!file[*]:testData//*&amp;&amp;!file[*]:*.gradle.kts&amp;&amp;!file[*]:*.gradle&amp;&amp;!file[group:kotlin-ultimate]:*/&amp;&amp;!file[kotlin.libraries]:stdlib/api//*" />
</component>

@ -1,302 +0,0 @@
# KMath
## Unreleased
### Added
- Fit accessors with Attribute
### Changed
- Upgrade tensorflow version to 1.0.0
### Deprecated
### Removed
### Fixed
### Security
## 0.4.2 - 2025-01-27
### Added
- Convenient matrix builders for rows, columns, vstacks and hstacks
- Sparse matrix builder
### Fixed
- Ojalgo conversion bug which made all converted matrices be zero.
## 0.4.1 - 2025-01-12
### Added
- Metropolis-Hastings sampler
- Ojalgo `LinearSpace` implementation.
### Changed
- attributes-kt moved to a separate project, and the version used is 0.3.0
- Kotlin 2.1. Now use cross-compilation to deploy macOS targets.
- Changed `origin` to `cmMatrix` in kmath-commons to avoid property name clash. Expose bidirectional conversion in `CMLinearSpace`
- (BREAKING CHANGE) Changed implementations in `kmath-ejml` to match CM and ojalgo style. Specifically, provide bidirectional conversion for library types.
### Fixed
- (BREAKING CHANGE) Fix EJML to properly treat vectors as columns
## 0.4.0 - 2024-02-18
### Added
- Reification. Explicit `SafeType` for algebras.
- Integer division algebras.
- Float32 geometries.
- New Attributes-kt module that could be used as stand-alone. It declares. type-safe attributes containers.
- Explicit `mutableStructureND` builders for mutable structures.
- `Buffer.asList()` zero-copy transformation.
- Wasm support.
- Parallel implementation of `LinearSpace` for Float64
- Parallel buffer factories
### Changed
- Buffer copy removed from API (added as an extension).
- Default naming for algebra and buffers now uses IntXX/FloatXX notation instead of Java types.
- Remove unnecessary inlines in basic algebras.
- QuaternionField -> QuaternionAlgebra and does not implement `Field` anymore since it is non-commutative
- kmath-geometry is split into `euclidean2d` and `euclidean3d`
- Features replaced with Attributes.
- Transposed refactored.
- Kmath-memory is moved on top of core.
### Deprecated
- ND4J engine
### Removed
- `asPolynomial` function due to scope pollution
- Codegend for ejml (450 lines of codegen for 1000 lines of code is too much)
### Fixed
- Median statistics
- Complex power of negative real numbers
- Add proper mutability for MutableBufferND rows and columns
- Generic Float32 and Float64 vectors are used in geometry algebras.
## 0.3.1 - 2023-04-09
### Added
- Wasm support for `memory`, `core`, `complex` and `functions` modules.
- Generic builders for `BufferND` and `MutableBufferND`
- `NamedMatrix` - matrix with symbol-based indexing
- `Expression` with default arguments
- Type-aliases for numbers like `Float64`
- Autodiff for generic algebra elements in core!
- Algebra now has an obligatory `bufferFactory` (#477).
### Changed
- Removed marker `Vector` type for geometry
- Geometry uses type-safe angles
- Tensor operations switched to prefix notation
- Row-wise and column-wise ND shapes in the core
- Shape is read-only
- Major refactor of tensors (only minor API changes)
- Kotlin 1.8.20
- `LazyStructure` `deffered` -> `async` to comply with coroutines code style
- Default `dot` operation in tensor algebra no longer support broadcasting. Instead `matmul` operation is added
to `DoubleTensorAlgebra`.
- Multik went MPP
### Removed
- Trajectory moved to https://github.com/SciProgCentre/maps-kt
- Polynomials moved to https://github.com/SciProgCentre/kmath-polynomial
## 0.3.0
### Added
- `ScaleOperations` interface
- `Field` extends `ScaleOperations`
- Basic integration API
- Basic MPP distributions and samplers
- `bindSymbolOrNull`
- Blocking chains and Statistics
- Multiplatform integration
- Integration for any Field element
- Extended operations for ND4J fields
- Jupyter Notebook integration module (kmath-jupyter)
- `@PerformancePitfall` annotation to mark possibly slow API
- 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
- Separate methods for UInt, Int and Number powers. NaN safety.
- Tensorflow prototype
- `ValueAndErrorField`
- MST compilation to WASM: #286
- Jafama integration: #176
- `contentEquals` with tolerance: #364
- Compilation to TeX for MST: #254
### Changed
- Annotations moved to `space.kscience.kmath`
- Exponential operations merged with hyperbolic functions
- Space is replaced by Group. Space is reserved for vector spaces.
- VectorSpace is now a vector space
- Buffer factories for primitives moved to MutableBuffer.Companion
- Rename `NDStructure` and `NDAlgebra` to `StructureND` and `AlgebraND` respectively
- `Real` -> `Double`
- DataSets are moved from functions to core
- Redesign advanced Chain API
- Redesign `MST`. Remove `MstExpression`.
- Move `MST` to core
- Separated benchmarks and examples
- Rewrite `kmath-ejml` without `ejml-simple` artifact, support sparse matrices
- Promote stability of kmath-ast and kmath-kotlingrad to EXPERIMENTAL.
- ColumnarData returns nullable column
- `MST` is made sealed interface
- Replace `MST.Symbolic` by `Symbol`, `Symbol` now implements MST
- 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`
- New discoverability pattern: `<Type>.algebra.<nd/etc>`
- 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.
- Tensor algebra takes read-only structures as input and inherits AlgebraND
- `UnivariateDistribution` renamed to `Distribution1D`
- Rework of histograms.
- `UnivariateFunction` -> `Function1D`, `MultivariateFunction` -> `FunctionND`
### Deprecated
- Specialized `DoubleBufferAlgebra`
### Removed
- Nearest in Domain. To be implemented in geometry package.
- Number multiplication and division in main Algebra chain
- `contentEquals` from Buffer. It moved to the companion.
- MSTExpression
- 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
- Univariate histogram filling
## 0.2.0
### Added
- `fun` annotation for SAM interfaces in library
- Explicit `public` visibility for all public APIs
- Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140)
- Automatic README generation for features (#139)
- Native support for `memory`, `core` and `dimensions`
- `kmath-ejml` to supply EJML SimpleMatrix wrapper (https://github.com/mipt-npm/kmath/pull/136)
- A separate `Symbol` entity, which is used for global unbound symbol.
- A `Symbol` indexing scope.
- Basic optimization API for Commons-math.
- Chi squared optimization for array-like data in CM
- `Fitting` utility object in prob/stat
- ND4J support module submitting `NDStructure` and `NDAlgebra` over `INDArray`
- Coroutine-deterministic Monte-Carlo scope with a random number generator
- Some minor utilities to `kmath-for-real`
- Generic operation result parameter to `MatrixContext`
- New `MatrixFeature` interfaces for matrix decompositions
- Basic Quaternion vector support in `kmath-complex`.
### Changed
- Package changed from `scientifik` to `space.kscience`
- Gradle version: 6.6 -> 6.8.2
- Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`)
- `Polynomial` secondary constructor made function
- Kotlin version: 1.3.72 -> 1.4.30
- `kmath-ast` doesn't depend on heavy `kotlin-reflect` library
- Full autodiff refactoring based on `Symbol`
- `kmath-prob` renamed to `kmath-stat`
- Grid generators moved to `kmath-for-real`
- Use `Point<Float64>` instead of specialized type in `kmath-for-real`
- Optimized dot product for buffer matrices moved to `kmath-for-real`
- EjmlMatrix context is an object
- Matrix LUP `inverse` renamed to `inverseWithLup`
- `NumericAlgebra` moved outside of regular algebra chain (`Ring` no longer implements it).
- Features moved to NDStructure and became transparent.
- Capitalization of LUP in many names changed to Lup.
- Refactored `NDStructure` algebra to be more simple, preferring under-the-hood conversion to explicit NDStructure types
- Refactor histograms. They are marked as prototype
- `Complex` and related features moved to a separate module `kmath-complex`
- Refactor AlgebraElement
- `symbol` method in `Algebra` renamed to `bindSymbol` to avoid ambiguity
- Add `out` projection to `Buffer` generic
### Removed
- `kmath-koma` module because it doesn't support Kotlin 1.4.
- Support of `legacy` JS backend (we will support only IR)
- `toGrid` method.
- Public visibility of `BufferAccessor2D`
- `Real` class
- StructureND identity and equals
### Fixed
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
## 0.1.4
### Added
- Functional Expressions API
- Mathematical Syntax Tree, its interpreter and API
- String to MST parser (https://github.com/mipt-npm/kmath/pull/120)
- MST to JVM bytecode translator (https://github.com/mipt-npm/kmath/pull/94)
- FloatBuffer (specialized MutableBuffer over FloatArray)
- FlaggedBuffer to associate primitive numbers buffer with flags (to mark values infinite or missing, etc.)
- Specialized builder functions for all primitive buffers
like `IntBuffer(25) { it + 1 }` (https://github.com/mipt-npm/kmath/pull/125)
- Interface `NumericAlgebra` where `number` operation is available to convert numbers to algebraic elements
- Inverse trigonometric functions support in
ExtendedField (`asin`, `acos`, `atan`) (https://github.com/mipt-npm/kmath/pull/114)
- New space extensions: `average` and `averageWith`
- Local coding conventions
- Geometric Domains API in `kmath-core`
- Blocking chains in `kmath-coroutines`
- Full hyperbolic functions support and default implementations within `ExtendedField`
- Norm support for `Complex`
### Changed
- `readAsMemory` now has `throws IOException` in JVM signature.
- Several functions taking functional types were made `inline`.
- Several functions taking functional types now have `callsInPlace` contracts.
- BigInteger and BigDecimal algebra: JBigDecimalField has companion object with default math context; minor
optimizations
- `power(T, Int)` extension function has preconditions and supports `Field<T>`
- Memory objects have more preconditions (overflow checking)
- `tg` function is renamed to `tan` (https://github.com/mipt-npm/kmath/pull/114)
- Gradle version: 6.3 -> 6.6
- Moved probability distributions to commons-rng and to `kmath-prob`
### Fixed
- Missing copy method in Memory implementation on JS (https://github.com/mipt-npm/kmath/pull/106)
- D3.dim value in `kmath-dimensions`
- Multiplication in integer rings in `kmath-core` (https://github.com/mipt-npm/kmath/pull/101)
- Commons RNG compatibility (https://github.com/mipt-npm/kmath/issues/93)
- Multiplication of BigInt by scalar

288
README.md

@ -1,288 +0,0 @@
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
![Gradle build](https://github.com/SciProgCentre/kmath/workflows/Gradle%20build/badge.svg)
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22)
# KMath
Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based
analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior
architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like
experience could be achieved with [kmath-for-real](/kmath-for-real) extension module.
[Documentation site](https://SciProgCentre.github.io/kmath/)
## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
* [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814)
* [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103)
* [A talk at KotlinConf 2019 about using kotlin for science](https://youtu.be/LI_5TZ7tnOE?si=4LknX41gl_YeUbIe)
* [A talk on architecture at Joker-2021 (in Russian)](https://youtu.be/1bZ2doHiRRM?si=9w953ro9yu98X_KJ)
* [The same talk in English](https://youtu.be/yP5DIc2fVwQ?si=louZzQ1dcXV6gP10)
* [A seminar on tensor API](https://youtu.be/0H99wUs0xTM?si=6c__04jrByFQtVpo)
# Goal
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS, Native and
Wasm).
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
* Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
## Non-goals
* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API.
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better
experience for those, who want to work with specific types.
## Features and stability
KMath is a modular library. Different modules provide different features with different API stability guarantees. All
core modules are released with the same version, but with different API change policy. The features are described in
module definitions below. The module stability could have the following levels:
* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could
break any moment. You can still use it, but be sure to fix the specific version.
* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked
with `@UnstableKMathAPI` or other stability warning annotations.
* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor
versions, but not in patch versions. API is protected
with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool.
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
## Modules
### [benchmarks](benchmarks)
>
> **Maturity**: EXPERIMENTAL
### [examples](examples)
>
> **Maturity**: EXPERIMENTAL
### [kmath-ast](kmath-ast)
>
> **Maturity**: EXPERIMENTAL
>
> **Features:**
> - [expression-language](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
> - [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)
> Commons math binding for kmath
>
> **Maturity**: EXPERIMENTAL
### [kmath-complex](kmath-complex)
> Complex numbers and quaternions.
>
> **Maturity**: PROTOTYPE
>
> **Features:**
> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex numbers operations
> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions and their composition
### [kmath-core](kmath-core)
> Core classes, algebra definitions, basic linear algebra
>
> **Maturity**: DEVELOPMENT
>
> **Features:**
> - [algebras](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
> - [nd](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
> - [linear](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
> - [buffers](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
> - [expressions](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
> - [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
> - [Parallel linear algebra](kmath-core/#) : Parallel implementation for `LinearAlgebra`
### [kmath-coroutines](kmath-coroutines)
>
> **Maturity**: EXPERIMENTAL
### [kmath-dimensions](kmath-dimensions)
> A proof of concept module for adding type-safe dimensions to structures
>
> **Maturity**: PROTOTYPE
### [kmath-ejml](kmath-ejml)
>
> **Maturity**: PROTOTYPE
>
> **Features:**
> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : Point implementations.
> - [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)
> 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.
>
> **Maturity**: EXPERIMENTAL
>
> **Features:**
> - [DoubleVector](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points
> - [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)
> Functions, integration and interpolation
>
> **Maturity**: EXPERIMENTAL
>
> **Features:**
> - [piecewise](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt) : Piecewise functions.
> - [polynomials](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Polynomial functions.
> - [linear interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt) : Linear XY interpolator.
> - [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)
>
> **Maturity**: PROTOTYPE
### [kmath-histograms](kmath-histograms)
>
> **Maturity**: PROTOTYPE
### [kmath-jupyter](kmath-jupyter)
>
> **Maturity**: PROTOTYPE
### [kmath-kotlingrad](kmath-kotlingrad)
> Kotlin∇ integration module
>
> **Maturity**: EXPERIMENTAL
>
> **Features:**
> - [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)
> An API and basic implementation for arranging objects in a continuous memory block.
>
> **Maturity**: DEVELOPMENT
### [kmath-multik](kmath-multik)
> JetBrains Multik connector
>
> **Maturity**: PROTOTYPE
### [kmath-nd4j](kmath-nd4j)
> ND4J NDStructure implementation and according NDAlgebra classes
>
> **Maturity**: DEPRECATED
>
> **Features:**
> - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
> - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long
> - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double
### [kmath-ojalgo](kmath-ojalgo)
> Ojalgo bindings for kmath
>
> **Maturity**: PROTOTYPE
### [kmath-optimization](kmath-optimization)
>
> **Maturity**: EXPERIMENTAL
### [kmath-stat](kmath-stat)
>
> **Maturity**: EXPERIMENTAL
### [kmath-symja](kmath-symja)
> Symja integration module
>
> **Maturity**: PROTOTYPE
### [kmath-tensorflow](kmath-tensorflow)
> Google tensorflow connector
>
> **Maturity**: PROTOTYPE
### [kmath-tensors](kmath-tensors)
>
> **Maturity**: PROTOTYPE
>
> **Features:**
> - [tensor algebra](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.)
> - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/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)
> Binding for https://github.com/JetBrains-Research/viktor
>
> **Maturity**: DEPRECATED
### [test-utils](test-utils)
>
> **Maturity**: EXPERIMENTAL
## Multi-platform support
KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the
[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features
are delegated to platform-specific implementations even if they could be provided in the common module for performance
reasons. Currently, Kotlin/JVM is the primary platform, however, Kotlin/Native and Kotlin/JS contributions and
feedback are also welcome.
## Performance
Calculation of performance is one of the major goals of KMath in the future, but in some cases it is impossible to
achieve both
performance and flexibility.
We expect to focus on creating a convenient universal API first and then work on increasing performance for specific
cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy.
## Requirements
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend using GraalVM-CE or
Oracle GraalVM for execution to get better performance.
### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/)
repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could
be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy:
```kotlin
repositories {
maven("https://repo.kotlin.link")
}
dependencies {
api("space.kscience:kmath-core:$version")
// api("space.kscience:kmath-core-jvm:$version") for jvm-specific version
}
```
## Contributing
The project requires a lot of additional work. The most important thing we need is feedback about what features are
required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues
marked
with [good first issue](hhttps://github.com/SciProgCentre/kmath/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
label.

@ -1,121 +0,0 @@
# BenchmarksResult
## Report for benchmark configuration <code>main</code>
* Run on OpenJDK 64-Bit Server VM (build 17.0.11+9) with Java process:
```
C:\Users\altavir\scoop\apps\gradle\current\.gradle\jdks\eclipse_adoptium-17-amd64-windows.2\bin\java.exe -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant
```
* JMH 1.21 was used in `thrpt` mode with 5 warmup iterations by 10 s and 5 measurement iterations by 10 s.
### [ArrayBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`benchmarkArrayRead`|3.9E+06 &plusmn; 3.4E+05 ops/s|
|`benchmarkBufferRead`|4.0E+06 &plusmn; 3.2E+05 ops/s|
|`nativeBufferRead`|3.9E+06 &plusmn; 2.0E+05 ops/s|
### [BigIntBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`jvmAdd`|3.1E+07 &plusmn; 1.8E+07 ops/s|
|`jvmAddLarge`|4.5E+04 &plusmn; 5.5E+03 ops/s|
|`jvmMultiply`|3.6E+07 &plusmn; 1.7E+07 ops/s|
|`jvmMultiplyLarge`|1.9E+02 &plusmn; 95 ops/s|
|`jvmParsing10`|4.0E+06 &plusmn; 8.8E+05 ops/s|
|`jvmParsing16`|3.6E+06 &plusmn; 6.5E+05 ops/s|
|`jvmPower`|25 &plusmn; 1.4 ops/s|
|`jvmSmallAdd`|5.7E+07 &plusmn; 9.7E+05 ops/s|
|`kmAdd`|2.6E+07 &plusmn; 8.8E+05 ops/s|
|`kmAddLarge`|2.3E+04 &plusmn; 1.2E+03 ops/s|
|`kmMultiply`|3.8E+07 &plusmn; 5.5E+06 ops/s|
|`kmMultiplyLarge`|36 &plusmn; 3.8 ops/s|
|`kmParsing10`|2.5E+06 &plusmn; 1.4E+05 ops/s|
|`kmParsing16`|3.7E+06 &plusmn; 4.7E+05 ops/s|
|`kmPower`|6.6 &plusmn; 1.0 ops/s|
|`kmSmallAdd`|2.0E+07 &plusmn; 1.7E+06 ops/s|
### [BufferBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`bufferViewReadWrite`|6.0E+06 &plusmn; 7.4E+05 ops/s|
|`bufferViewReadWriteSpecialized`|7.6E+05 &plusmn; 1.1E+04 ops/s|
|`complexBufferReadWrite`|2.4E+06 &plusmn; 2.7E+05 ops/s|
|`doubleArrayReadWrite`|7.3E+06 &plusmn; 4.3E+05 ops/s|
|`doubleBufferReadWrite`|7.3E+06 &plusmn; 3.4E+05 ops/s|
### [DotBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`bufferedDot`|1.3 &plusmn; 0.032 ops/s|
|`cmDot`|0.42 &plusmn; 0.20 ops/s|
|`cmDotWithConversion`|0.83 &plusmn; 0.12 ops/s|
|`ejmlDot`|2.6 &plusmn; 0.049 ops/s|
|`ejmlDotWithConversion`|2.5 &plusmn; 0.075 ops/s|
|`multikDot`|25 &plusmn; 0.52 ops/s|
|`ojalgoDot`|11 &plusmn; 1.3 ops/s|
|`parallelDot`|11 &plusmn; 0.17 ops/s|
|`tensorDot`|1.1 &plusmn; 0.028 ops/s|
|`tfDot`|4.7 &plusmn; 0.14 ops/s|
### [ExpressionsInterpretersBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`asmGenericExpression`|12 &plusmn; 0.099 ops/s|
|`asmPrimitiveExpression`|26 &plusmn; 0.57 ops/s|
|`asmPrimitiveExpressionArray`|74 &plusmn; 1.7 ops/s|
|`functionalExpression`|5.3 &plusmn; 0.015 ops/s|
|`justCalculate`|74 &plusmn; 0.85 ops/s|
|`mstExpression`|4.2 &plusmn; 0.10 ops/s|
|`rawExpression`|25 &plusmn; 0.74 ops/s|
### [IntegrationBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`complexIntegration`|2.6E+03 &plusmn; 46 ops/s|
|`doubleIntegration`|2.8E+03 &plusmn; 1.1E+02 ops/s|
### [MatrixInverseBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`cmLUPInversion`|2.1E+03 &plusmn; 35 ops/s|
|`ejmlInverse`|1.2E+03 &plusmn; 27 ops/s|
|`kmathLupInversion`|4.0E+02 &plusmn; 52 ops/s|
|`kmathParallelLupInversion`|4.0E+02 &plusmn; 9.6 ops/s|
|`ojalgoInverse`|2.1E+03 &plusmn; 3.3E+02 ops/s|
### [MinStatisticBenchmark.kt](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MinStatisticBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`kotlinArrayMin`| 1875.7 &plusmn; 401.5 ops/s |
|`minBlocking`| 1357.9 &plusmn; 72.0 ops/s |
### [NDFieldBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`boxingFieldAdd`|1.7 &plusmn; 0.11 ops/s|
|`multikAdd`|7.0 &plusmn; 0.41 ops/s|
|`multikInPlaceAdd`|34 &plusmn; 1.7 ops/s|
|`specializedFieldAdd`|7.2 &plusmn; 1.2 ops/s|
|`tensorAdd`|7.2 &plusmn; 1.6 ops/s|
|`tensorInPlaceAdd`|7.4 &plusmn; 4.9 ops/s|
|`viktorAdd`|5.8 &plusmn; 0.65 ops/s|
### [ViktorBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`doubleFieldAddition`|7.1 &plusmn; 2.0 ops/s|
|`rawViktor`|6.2 &plusmn; 1.0 ops/s|
|`viktorFieldAddition`|6.4 &plusmn; 0.29 ops/s|
### [ViktorLogBenchmark](src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt)
| Benchmark | Score |
|:---------:|:-----:|
|`rawViktorLog`|1.3 &plusmn; 0.016 ops/s|
|`realFieldLog`|1.3 &plusmn; 0.019 ops/s|
|`viktorFieldLog`|1.3 &plusmn; 0.020 ops/s|

@ -1,284 +0,0 @@
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import kotlinx.benchmark.gradle.BenchmarksExtension
import java.util.*
plugins {
kotlin("multiplatform")
alias(spclibs.plugins.kotlin.plugin.allopen)
alias(spclibs.plugins.kotlinx.benchmark)
}
allOpen.annotation("org.openjdk.jmh.annotations.State")
//sourceSets.register("benchmarks")
repositories {
mavenCentral()
}
kotlin {
jvmToolchain(17)
compilerOptions {
optIn.addAll(
"space.kscience.kmath.UnstableKMathAPI"
)
}
jvm()
js(IR) {
nodejs()
}
sourceSets {
all {
languageSettings {
progressiveMode = true
optIn("kotlin.contracts.ExperimentalContracts")
optIn("kotlin.ExperimentalUnsignedTypes")
optIn("space.kscience.kmath.UnstableKMathAPI")
}
}
val commonMain by getting {
dependencies {
implementation(project(":kmath-ast"))
implementation(project(":kmath-core"))
implementation(project(":kmath-coroutines"))
implementation(project(":kmath-complex"))
implementation(project(":kmath-stat"))
implementation(project(":kmath-dimensions"))
implementation(project(":kmath-for-real"))
implementation(project(":kmath-tensors"))
implementation(libs.multik.default)
implementation(spclibs.kotlinx.benchmark.runtime)
}
}
val jvmMain by getting {
dependencies {
implementation(projects.kmathCommons)
implementation(projects.kmathEjml)
implementation(projects.kmathKotlingrad)
implementation(projects.kmathViktor)
implementation(projects.kmathOjalgo)
implementation(projects.kmath.kmathTensorflow)
implementation(projects.kmathMultik)
implementation(libs.tensorflow.core.platform)
// implementation(projects.kmathNd4j)
// implementation(libs.nd4j.native.platform)
// uncomment if your system supports AVX2
// val os = System.getProperty("os.name")
//
// if (System.getProperty("os.arch") in arrayOf("x86_64", "amd64")) when {
// os.startsWith("Windows") -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:windows-x86_64-avx2")
// os == "Linux" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:linux-x86_64-avx2")
// os == "Mac OS X" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:macosx-x86_64-avx2")
// } else
// implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
}
}
}
}
// Configure benchmark
benchmark {
// Setup configurations
targets {
register("jvm")
register("js")
}
fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() {
warmups = 2
iterations = 5
iterationTime = 2000
iterationTimeUnit = "ms"
}
configurations.register("buffer") {
commonConfiguration()
include("BufferBenchmark")
}
configurations.register("minStatistic") {
commonConfiguration()
include("MinStatisticBenchmark")
}
configurations.register("nd") {
commonConfiguration()
include("NDFieldBenchmark")
}
configurations.register("dot") {
commonConfiguration()
include("DotBenchmark")
}
configurations.register("expressions") {
// Some extra precision
warmups = 2
iterations = 10
iterationTime = 10
iterationTimeUnit = "s"
outputTimeUnit = "s"
include("ExpressionsInterpretersBenchmark")
}
configurations.register("matrixInverse") {
commonConfiguration()
include("MatrixInverseBenchmark")
}
configurations.register("bigInt") {
commonConfiguration()
include("BigIntBenchmark")
}
configurations.register("jafamaDouble") {
commonConfiguration()
include("JafamaBenchmark")
}
configurations.register("tensorAlgebra") {
commonConfiguration()
include("TensorAlgebraBenchmark")
}
configurations.register("viktor") {
commonConfiguration()
include("ViktorBenchmark")
}
configurations.register("viktorLog") {
commonConfiguration()
include("ViktorLogBenchmark")
}
configurations.register("integration") {
commonConfiguration()
include("IntegrationBenchmark")
}
}
private data class JmhReport(
val jmhVersion: String,
val benchmark: String,
val mode: String,
val threads: Int,
val forks: Int,
val jvm: String,
val jvmArgs: List<String>,
val jdkVersion: String,
val vmName: String,
val vmVersion: String,
val warmupIterations: Int,
val warmupTime: String,
val warmupBatchSize: Int,
val measurementIterations: Int,
val measurementTime: String,
val measurementBatchSize: Int,
val params: Map<String, String> = emptyMap(),
val primaryMetric: PrimaryMetric,
val secondaryMetrics: Map<String, SecondaryMetric>,
) {
interface Metric {
val score: Double
val scoreError: Double
val scoreConfidence: List<Double>
val scorePercentiles: Map<Double, Double>
val scoreUnit: String
}
data class PrimaryMetric(
override val score: Double,
override val scoreError: Double,
override val scoreConfidence: List<Double>,
override val scorePercentiles: Map<Double, Double>,
override val scoreUnit: String,
val rawDataHistogram: List<List<List<List<Double>>>>? = null,
val rawData: List<List<Double>>? = null,
) : Metric
data class SecondaryMetric(
override val score: Double,
override val scoreError: Double,
override val scoreConfidence: List<Double>,
override val scorePercentiles: Map<Double, Double>,
override val scoreUnit: String,
val rawData: List<List<Double>>,
) : Metric
}
readme {
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
val jsonMapper = jacksonObjectMapper()
fun noun(number: Number, singular: String, plural: String) = if (number.toLong() == 1L) singular else plural
extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg ->
val propertyName =
"benchmark${cfg.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }}"
logger.info("Processing benchmark data from benchmark ${cfg.name} into readme property $propertyName")
val launches = layout.buildDirectory.dir("reports/benchmarks/${cfg.name}").get().asFile
if (!launches.exists()) return@forEach
property(propertyName) {
val resDirectory = launches.listFiles()?.maxByOrNull {
it.nameWithoutExtension
}
if (resDirectory == null || !(resDirectory.resolve("jvm.json")).exists()) {
"> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**."
} else {
val reports: List<JmhReport> =
jsonMapper.readValue<List<JmhReport>>(resDirectory.resolve("jvm.json"))
buildString {
appendLine("## Report for benchmark configuration <code>${cfg.name}</code>")
appendLine()
val first = reports.first()
appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:")
appendLine()
appendLine("```")
appendLine(
"${first.jvm} ${
first.jvmArgs.joinToString(" ")
}"
)
appendLine("```")
appendLine(
"* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${
noun(first.warmupIterations, "iteration", "iterations")
} by ${first.warmupTime} and ${first.measurementIterations} measurement ${
noun(first.measurementIterations, "iteration", "iterations")
} by ${first.measurementTime}."
)
reports.groupBy { it.benchmark.substringBeforeLast(".") }.forEach { (cl, compare) ->
appendLine("### [${cl.substringAfterLast(".")}](src/jvmMain/kotlin/${cl.replace(".","/")}.kt)")
appendLine()
appendLine("| Benchmark | Score |")
appendLine("|:---------:|:-----:|")
compare.forEach { report ->
val benchmarkName = report.benchmark.substringAfterLast(".")
val score = String.format("%.2G", report.primaryMetric.score)
val error = String.format("%.2G", report.primaryMetric.scoreError)
appendLine("|`$benchmarkName`|$score &plusmn; $error ${report.primaryMetric.scoreUnit}|")
}
}
}
}
}
}
}

@ -1,5 +0,0 @@
# BenchmarksResult
${benchmarkMain}

@ -1,108 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.expressions.*
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Float64
import kotlin.math.sin
import kotlin.random.Random
import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression
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<Float64>, blackhole: Blackhole) {
val random = Random(0)
var sum = 0.0
val m = HashMap<Symbol, Double>()
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 = Float64Field.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(Float64Field)
@OptIn(UnstableKMathAPI::class)
private val wasm = node.wasmCompileToExpression(Float64Field)
private val estree = node.estreeCompileToExpression(Float64Field)
private val raw = Expression<Float64> { args ->
val x = args.getValue(x)
x * 2.0 + 2.0 / x - 16.0 / sin(x)
}
}
}

@ -1,43 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import java.nio.IntBuffer
@State(Scope.Benchmark)
internal class ArrayBenchmark {
@Benchmark
fun benchmarkArrayRead(blackhole: Blackhole) {
var res = 0
for (i in 1..size) res += array[size - i]
blackhole.consume(res)
}
@Benchmark
fun benchmarkBufferRead(blackhole: Blackhole) {
var res = 0
for (i in 1..size) res += arrayBuffer[size - i]
blackhole.consume(res)
}
@Benchmark
fun nativeBufferRead(blackhole: Blackhole) {
var res = 0
for (i in 1..size) res += nativeBuffer[size - i]
blackhole.consume(res)
}
private companion object {
private const val size = 1000
private val array = IntArray(size) { it }
private val arrayBuffer = IntBuffer.wrap(array)
private val nativeBuffer = IntBuffer.allocate(size).also { for (i in 0 until size) it.put(i, i) }
}
}

@ -1,112 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Blackhole
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import space.kscience.kmath.UnstableKMathAPI
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
@UnstableKMathAPI
@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 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)
}
@Benchmark
fun jvmAdd(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume(jvmNumber + jvmNumber + jvmNumber)
}
@Benchmark
fun kmAddLarge(blackhole: Blackhole) = BigIntField {
blackhole.consume(kmLargeNumber + kmLargeNumber + kmLargeNumber)
}
@Benchmark
fun jvmAddLarge(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume(jvmLargeNumber + jvmLargeNumber + jvmLargeNumber)
}
@Benchmark
fun kmMultiply(blackhole: Blackhole) = BigIntField {
blackhole.consume(kmNumber * kmNumber * kmNumber)
}
@Benchmark
fun kmMultiplyLarge(blackhole: Blackhole) = BigIntField {
blackhole.consume(kmLargeNumber * kmLargeNumber)
}
@Benchmark
fun jvmMultiply(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume(jvmNumber * jvmNumber * jvmNumber)
}
@Benchmark
fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume(jvmLargeNumber * jvmLargeNumber)
}
@Benchmark
fun kmPower(blackhole: Blackhole) = BigIntField {
blackhole.consume(kmNumber.pow(bigExponent.toUInt()))
}
@Benchmark
fun jvmPower(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume(jvmNumber.pow(bigExponent))
}
@Benchmark
fun kmParsing16(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume("0x7f57ed8b89c29a3b9a85c7a5b84ca3929c7b7488593".parseBigInteger())
}
@Benchmark
fun kmParsing10(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume("236656783929183747565738292847574838922010".parseBigInteger())
}
@Benchmark
fun jvmParsing10(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume("236656783929183747565738292847574838922010".toBigInteger(10))
}
@Benchmark
fun jvmParsing16(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume("7f57ed8b89c29a3b9a85c7a5b84ca3929c7b7488593".toBigInteger(16))
}
}

@ -1,80 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.complex
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.Float64Buffer
import space.kscience.kmath.structures.getDouble
import space.kscience.kmath.structures.permute
@State(Scope.Benchmark)
internal class BufferBenchmark {
@Benchmark
fun doubleArrayReadWrite(blackhole: Blackhole) {
val buffer = DoubleArray(size) { it.toDouble() }
var res = 0.0
(0 until size).forEach {
res += buffer[it]
}
blackhole.consume(res)
}
@Benchmark
fun doubleBufferReadWrite(blackhole: Blackhole) {
val buffer = Float64Buffer(size) { it.toDouble() }
var res = 0.0
(0 until size).forEach {
res += buffer[it]
}
blackhole.consume(res)
}
@Benchmark
fun bufferViewReadWrite(blackhole: Blackhole) {
val buffer = Float64Buffer(size) { it.toDouble() }.permute(reversedIndices)
var res = 0.0
(0 until size).forEach {
res += buffer[it]
}
blackhole.consume(res)
}
@Benchmark
fun bufferViewReadWriteSpecialized(blackhole: Blackhole) {
val buffer = Float64Buffer(size) { it.toDouble() }.permute(reversedIndices)
var res = 0.0
(0 until size).forEach {
res += buffer.getDouble(it)
}
blackhole.consume(res)
}
@Benchmark
fun complexBufferReadWrite(blackhole: Blackhole) = ComplexField {
val buffer = Buffer.complex(size / 2) { Complex(it.toDouble(), -it.toDouble()) }
var res = zero
(0 until size / 2).forEach {
res += buffer[it]
}
blackhole.consume(res)
}
private companion object {
private const val size = 100
private val reversedIndices = IntArray(size) { it }.apply { reverse() }
}
}

@ -1,100 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
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.Float64ParallelLinearSpace
import space.kscience.kmath.linear.invoke
import space.kscience.kmath.linear.linearSpace
import space.kscience.kmath.ojalgo.Ojalgo
import space.kscience.kmath.ojalgo.linearSpace
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.tensorflow.produceWithTF
import space.kscience.kmath.tensors.core.tensorAlgebra
import kotlin.random.Random
@State(Scope.Benchmark)
internal class DotBenchmark {
companion object {
val random = Random(12224)
const val dim = 1000
//creating invertible matrix
val matrix1 = Float64Field.linearSpace.buildMatrix(dim, dim) { _, _ ->
random.nextDouble()
}
val matrix2 = Float64Field.linearSpace.buildMatrix(dim, dim) { _, _ ->
random.nextDouble()
}
val cmMatrix1 = CMLinearSpace { matrix1.toCM() }
val cmMatrix2 = CMLinearSpace { matrix2.toCM() }
val ejmlMatrix1 = EjmlLinearSpaceDDRM { matrix1.toEjml() }
val ejmlMatrix2 = EjmlLinearSpaceDDRM { matrix2.toEjml() }
}
@Benchmark
fun tfDot(blackhole: Blackhole) {
blackhole.consume(
Float64Field.produceWithTF {
matrix1 dot matrix1
}
)
}
@Benchmark
fun cmDotWithConversion(blackhole: Blackhole) = CMLinearSpace {
blackhole.consume(matrix1 dot matrix2)
}
@Benchmark
fun cmDot(blackhole: Blackhole): Unit = CMLinearSpace {
blackhole.consume(cmMatrix1.asMatrix() dot cmMatrix2.asMatrix())
}
@Benchmark
fun ejmlDot(blackhole: Blackhole): Unit = EjmlLinearSpaceDDRM {
blackhole.consume(ejmlMatrix1.asMatrix() dot ejmlMatrix2.asMatrix())
}
@Benchmark
fun ejmlDotWithConversion(blackhole: Blackhole) = EjmlLinearSpaceDDRM {
blackhole.consume(matrix1 dot matrix2)
}
@Benchmark
fun ojalgoDot(blackhole: Blackhole) = Ojalgo.R064.linearSpace {
blackhole.consume(matrix1 dot matrix2)
}
@Benchmark
fun multikDot(blackhole: Blackhole) = with(multikAlgebra) {
blackhole.consume(matrix1 dot matrix2)
}
@Benchmark
fun tensorDot(blackhole: Blackhole) = with(Float64Field.tensorAlgebra) {
blackhole.consume(matrix1 dot matrix2)
}
@Benchmark
fun bufferedDot(blackhole: Blackhole) = with(Float64Field.linearSpace) {
blackhole.consume(matrix1 dot matrix2)
}
@Benchmark
fun parallelDot(blackhole: Blackhole) = with(Float64ParallelLinearSpace) {
blackhole.consume(matrix1 dot matrix2)
}
}

@ -1,125 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
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.Float64Field
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Float64
import kotlin.math.sin
import kotlin.random.Random
@State(Scope.Benchmark)
internal class ExpressionsInterpretersBenchmark {
/**
* Benchmark case for [Expression] created with [expressionInExtendedField].
*/
@Benchmark
fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, blackhole)
/**
* Benchmark case for [Expression] created with [toExpression].
*/
@Benchmark
fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, blackhole)
/**
* Benchmark case for [Expression] created with [compileToExpression].
*/
@Benchmark
fun 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].
*/
@Benchmark
fun asmPrimitiveExpression(blackhole: Blackhole) = invokeAndSum(asmPrimitive, 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<Float64>, blackhole: Blackhole) {
val random = Random(0)
var sum = 0.0
val m = HashMap<Symbol, Double>()
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 = Float64Field.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(Float64Field)
private val asmPrimitive = node.compileToExpression(Float64Field)
private val xIdx = asmPrimitive.indexer.indexOf(x)
private val asmGeneric = node.compileToExpression(Float64Field as Algebra<Float64>)
private val raw = Expression<Float64> { args ->
val x = args[x]!!
x * 2.0 + 2.0 / x - 16.0 / sin(x)
}
}
}

@ -1,40 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import org.openjdk.jmh.infra.Blackhole
import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.algebra
import space.kscience.kmath.integration.gaussIntegrator
import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.value
import space.kscience.kmath.operations.algebra
@State(Scope.Benchmark)
internal class IntegrationBenchmark {
@Benchmark
fun doubleIntegration(blackhole: Blackhole) {
val res = Double.algebra.gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double ->
//sin(1 / x)
1 / x
}.value
blackhole.consume(res)
}
@Benchmark
fun complexIntegration(blackhole: Blackhole) = with(Complex.algebra) {
val res = gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double ->
// sin(1 / x) + i * cos(1 / x)
1 / x - i / x
}.value
blackhole.consume(res)
}
}

@ -1,60 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
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.lupSolver
import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
import space.kscience.kmath.linear.*
import space.kscience.kmath.ojalgo.Ojalgo
import space.kscience.kmath.ojalgo.linearSpace
import space.kscience.kmath.operations.algebra
import kotlin.random.Random
@State(Scope.Benchmark)
internal class MatrixInverseBenchmark {
private companion object {
private val random = Random(1224)
private const val dim = 100
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 }
private val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
private val matrix = space { l dot u }
}
@Benchmark
fun kmathLupInversion(blackhole: Blackhole) {
blackhole.consume(Double.algebra.linearSpace.lupSolver().inverse(matrix))
}
@Benchmark
fun kmathParallelLupInversion(blackhole: Blackhole) {
blackhole.consume(Double.algebra.linearSpace.parallel.lupSolver().inverse(matrix))
}
@Benchmark
fun cmLUPInversion(blackhole: Blackhole) = CMLinearSpace {
blackhole.consume(lupSolver().inverse(matrix))
}
@Benchmark
fun ejmlInverse(blackhole: Blackhole) = EjmlLinearSpaceDDRM {
blackhole.consume(matrix.inverted())
}
@Benchmark
fun ojalgoInverse(blackhole: Blackhole) = Ojalgo.R064.linearSpace {
blackhole.consume(matrix.getOrComputeAttribute(Inverted))
}
}

@ -1,44 +0,0 @@
/*
* Copyright 2018-2025 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 kotlinx.coroutines.runBlocking
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.stat.min
import space.kscience.kmath.structures.*
@State(Scope.Benchmark)
internal class MinStatisticBenchmark {
@Benchmark
fun kotlinArrayMin(blackhole: Blackhole) {
val array = DoubleArray(size) { it.toDouble() }
var res = 0.0
(0 until size).forEach {
res += array.min()
}
blackhole.consume(res)
}
@Benchmark
fun minBlocking(blackhole: Blackhole) {
val buffer = Float64Buffer(size) { it.toDouble() }
var res = 0.0
(0 until size).forEach {
res += Float64Field.min.evaluateBlocking(buffer)
}
blackhole.consume(res)
}
private companion object {
private const val size = 1000
}
}

@ -1,95 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
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.UnsafeKMathAPI
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.tensors.core.DoubleTensor
import space.kscience.kmath.tensors.core.one
import space.kscience.kmath.tensors.core.tensorAlgebra
import space.kscience.kmath.viktor.viktorAlgebra
@State(Scope.Benchmark)
internal class NDFieldBenchmark {
private companion object {
private const val dim = 1000
private const val n = 100
private val shape = ShapeND(dim, dim)
private val specializedField = Float64Field.ndAlgebra
private val genericField = BufferedFieldOpsND(Float64Field)
private val viktorField = Float64Field.viktorAlgebra
}
@Benchmark
fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) {
var res: StructureND<Float64> = one(shape)
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@Benchmark
fun boxingFieldAdd(blackhole: Blackhole) = with(genericField) {
var res: StructureND<Float64> = one(shape)
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@Benchmark
fun multikAdd(blackhole: Blackhole) = with(multikAlgebra) {
var res: StructureND<Float64> = one(shape)
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@Benchmark
fun viktorAdd(blackhole: Blackhole) = with(viktorField) {
var res: StructureND<Float64> = one(shape)
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@Benchmark
fun tensorAdd(blackhole: Blackhole) = with(Double.tensorAlgebra) {
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 = one(shape)
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@OptIn(UnsafeKMathAPI::class)
@Benchmark
fun multikInPlaceAdd(blackhole: Blackhole) = with(multikAlgebra) {
val res = Multik.ones<Double, DN>(shape.asArray(), DataType.DoubleDataType).wrap()
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
// @Benchmark
// fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) {
// var res: StructureND<Float64> = one(dim, dim)
// repeat(n) { res += 1.0 }
// blackhole.consume(res)
// }
}

@ -1,39 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.linear.MatrixBuilder
import space.kscience.kmath.linear.linearSpace
import space.kscience.kmath.linear.symmetric
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.tensors.core.symEigJacobi
import space.kscience.kmath.tensors.core.symEigSvd
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 = Float64Field.linearSpace.MatrixBuilder(dim, dim).symmetric { _, _ -> random.nextDouble() }
}
@Benchmark
fun tensorSymEigSvd(blackhole: Blackhole) = with(Double.tensorAlgebra) {
blackhole.consume(symEigSvd(matrix, 1e-10))
}
@Benchmark
fun tensorSymEigJacobi(blackhole: Blackhole) = with(Double.tensorAlgebra) {
blackhole.consume(symEigJacobi(matrix, 50, 1e-10))
}
}

@ -1,59 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.nd.one
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.viktor.ViktorFieldND
@State(Scope.Benchmark)
internal class ViktorBenchmark {
@Benchmark
fun doubleFieldAddition(blackhole: Blackhole) {
with(doubleField) {
var res: StructureND<Float64> = one(shape)
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
}
@Benchmark
fun viktorFieldAddition(blackhole: Blackhole) {
with(viktorField) {
var res = one(shape)
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
}
@Benchmark
fun rawViktor(blackhole: Blackhole) {
val one = F64Array.full(init = 1.0, shape = intArrayOf(dim, dim))
var res = one
repeat(n) { res = res + one }
blackhole.consume(res)
}
private companion object {
private const val dim = 1000
private const val n = 100
private val shape = ShapeND(dim, dim)
// automatically build context most suited for given type.
private val doubleField = Float64Field.ndAlgebra
private val viktorField = ViktorFieldND(dim, dim)
}
}

@ -1,58 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.nd.one
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.viktor.ViktorFieldND
@State(Scope.Benchmark)
internal class ViktorLogBenchmark {
@Benchmark
fun realFieldLog(blackhole: Blackhole) {
with(doubleField) {
val fortyTwo = structureND(shape) { 42.0 }
var res = one(shape)
repeat(n) { res = ln(fortyTwo) }
blackhole.consume(res)
}
}
@Benchmark
fun viktorFieldLog(blackhole: Blackhole) {
with(viktorField) {
val fortyTwo = structureND(shape) { 42.0 }
var res = one
repeat(n) { res = ln(fortyTwo) }
blackhole.consume(res)
}
}
@Benchmark
fun rawViktorLog(blackhole: Blackhole) {
val fortyTwo = F64Array.full(dim, dim, init = 42.0)
lateinit var res: F64Array
repeat(n) { res = fortyTwo.log() }
blackhole.consume(res)
}
private companion object {
private const val dim = 1000
private const val n = 100
private val shape = ShapeND(dim, dim)
// automatically build context most suited for given type.
private val doubleField = Float64Field.ndAlgebra
private val viktorField = ViktorFieldND(dim, dim)
}
}

@ -1,11 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.benchmarks
import org.jetbrains.kotlinx.multik.default.DefaultEngine
import space.kscience.kmath.multik.MultikDoubleAlgebra
val multikAlgebra = MultikDoubleAlgebra(DefaultEngine())

@ -1,90 +0,0 @@
import space.kscience.gradle.useApache2Licence
import space.kscience.gradle.useSPCTeam
plugins {
alias(spclibs.plugins.kscience.project)
alias(spclibs.plugins.kotlinx.kover)
}
allprojects {
repositories {
maven("https://repo.kotlin.link")
maven("https://oss.sonatype.org/content/repositories/snapshots")
mavenCentral()
}
group = "space.kscience"
version = "0.4.3-dev-1"
}
dependencies {
subprojects.forEach {
dokka(it)
}
}
dokka{
dokkaSourceSets.configureEach {
val readmeFile = projectDir.resolve("README.md")
if (readmeFile.exists()) includes.from(readmeFile)
}
}
subprojects {
if (name.startsWith("kmath")) apply<MavenPublishPlugin>()
plugins.withId("org.jetbrains.dokka") {
dokka {
dokkaSourceSets.configureEach {
val readmeFile = projectDir.resolve("README.md")
if (readmeFile.exists()) includes.from(readmeFile)
val kotlinDirPath = "src/$name/kotlin"
val kotlinDir = file(kotlinDirPath)
if (kotlinDir.exists()) sourceLink {
localDirectory.set(kotlinDir)
remoteUrl(
"https://github.com/SciProgCentre/kmath/tree/master/${name}/$kotlinDirPath"
)
}
fun externalDocumentationLink(url: String, packageListUrl: String? = null){
externalDocumentationLinks.register(url) {
url(url)
packageListUrl?.let {
packageListUrl(it)
}
}
}
externalDocumentationLink("https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/")
externalDocumentationLink("https://deeplearning4j.org/api/latest/")
externalDocumentationLink("https://axelclk.bitbucket.io/symja/javadoc/")
externalDocumentationLink(
"https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/",
"https://kotlin.github.io/kotlinx.coroutines/package-list",
)
externalDocumentationLink(
"https://breandan.net/kotlingrad/kotlingrad",
"https://breandan.net/kotlingrad/package-list",
)
}
}
}
}
readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md")
ksciencePublish {
pom("https://github.com/SciProgCentre/kmath") {
useApache2Licence()
useSPCTeam()
}
repository("spc", "https://maven.sciprog.center/kscience")
central()
}
apiValidation.nonPublicMarkers.add("space.kscience.kmath.UnstableKMathAPI")

@ -1,86 +0,0 @@
# Algebraic Structures and Algebraic Elements
The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an
operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up,
say `Group<T>`. Next one needs to run the actual operation in the context:
```kotlin
import space.kscience.kmath.operations.*
val a: T = ...
val b: T = ...
val group: Group<T> = ...
val c = group { a + b }
```
At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in
mathematics, one could draw up different operations on same objects. For example, one could use different types of
geometry for vectors.
## Algebraic Structures
Primary mathematical contexts have the following hierarchy:
`Field <: Ring <: Group <: Algebra`
These interfaces follow real algebraic structures:
- [Group](https://mathworld.wolfram.com/Group.html) defines addition, its identity element (i.e., 0) and additive
inverse (-x);
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its identity element (i.e., 1);
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`.
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
interface. Also, contexts may have operations, which produce elements outside the context. For example, `Matrix.dot`
operation produces a matrix with new dimensions, which can be incompatible with initial matrix in linear operations.
## Spaces and Fields
KMath introduces contexts for builtin algebraic structures:
```kotlin
import space.kscience.kmath.operations.*
val c1 = Complex(1.0, 2.0)
val c2 = ComplexField.i
val c3 = c1 + c2
// or
val c3 = ComplexField { c1 + c2 }
```
Also, `ComplexField` features special operations to mix complex and real numbers, for example:
```kotlin
import space.kscience.kmath.operations.*
val c1 = Complex(1.0, 2.0)
val c2 = ComplexField { c1 - 1.0 } // Returns: Complex(re=0.0, im=2.0)
val c3 = ComplexField { c1 - i * 2.0 }
```
**Note**: In theory it is possible to add behaviors directly to the context, but as for now Kotlin does not support
that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and
[KEEP-176](https://github.com/Kotlin/KEEP/pull/176) for updates.
## Nested fields
Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex
elements like so:
```kotlin
val element = NDElement.complex(shape = intArrayOf(2, 2)) { index: IntArray ->
Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble())
}
```
The `element` in this example is a member of the `Field` of 2D structures, each element of which is a member of its own
`ComplexField`. It is important one does not need to create a special n-d class to hold complex numbers and implement
operations on it, one just needs to provide a field for its elements.
**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts
like
`MemorySpec`.

@ -1,20 +0,0 @@
# Buffers
Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write (
with `MutableBuffer`). There are different types of buffers:
* Primitive buffers wrapping like `DoubleBuffer` which are wrapping primitive arrays.
* Boxing `ListBuffer` wrapping a list
* Functionally defined `VirtualBuffer` which does not hold a state itself, but provides a function to calculate value
* `MemoryBuffer` allows direct allocation of objects in continuous memory block.
Some kmath features require a `BufferFactory` class to operate properly. A general convention is to use functions
defined in
`Buffer` and `MutableBuffer` companion classes. For example factory `Buffer.Companion::auto` in most cases creates the
most suitable buffer for given reified type (for types with custom memory buffer it still better to use their
own `MemoryBuffer.create()` factory).
## Buffer performance
One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers
instead.

@ -1,35 +0,0 @@
# Coding Conventions
Generally, KMath code follows
general [Kotlin coding conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but with a number of
small changes and clarifications.
## Utility Class Naming
Filename should coincide with a name of one of the classes contained in the file or start with small letter and describe
its contents.
The code convention [here](https://kotlinlang.org/docs/reference/coding-conventions.html#source-file-names) says that
file names should start with a capital letter even if file does not contain classes. Yet starting utility classes and
aggregators with a small letter seems to be a good way to visually separate those files.
This convention could be changed in future in a non-breaking way.
## Private Variable Naming
Private variables' names may start with underscore `_` for of the private mutable variable is shadowed by the public
read-only value with the same meaning.
This rule does not permit underscores in names, but it is sometimes useful to "underscore" the fact that public and
private versions draw up the same entity. It is allowed only for private variables.
This convention could be changed in future in a non-breaking way.
## Functions and Properties One-liners
Use one-liners when they occupy single code window line both for functions and properties with getters like
`val b: String get() = "fff"`. The same should be performed with multiline expressions when they could be
cleanly separated.
There is no universal consensus whenever use `fun a() = ...` or `fun a() { return ... }`. Yet from reader outlook
one-lines seem to better show that the property or function is easily calculated.

@ -1,73 +0,0 @@
# Context-oriented mathematics
## The problem
A known problem for implementing mathematics in statically-typed languages (but not only in them) is that different sets
of mathematical operators can be defined on the same mathematical objects. Sometimes there is no single way to treat
some operations, including basic arithmetic operations, on a Java/Kotlin `Number`. Sometimes there are different ways to
define the same structure, such as Euclidean and elliptic geometry vector spaces over real vectors. Another problem
arises when one wants to add some kind of behavior to an existing entity. In dynamic languages those problems are
usually solved by adding dynamic context-specific behaviors at runtime, but this solution has a lot of drawbacks.
## Context-oriented approach
One possible solution to these problems is to divorce numerical representations from behaviors. For example in Kotlin
one can define a separate class representing some entity without any operations, ex. a complex number:
```kotlin
data class Complex(val re: Double, val im: Double)
```
And then to define a separate class or singleton, representing an operation on those complex numbers:
```kotlin
object ComplexOperations {
operator fun Complex.plus(other: Complex) = Complex(re + other.re, im + other.im)
operator fun Complex.minus(other: Complex) = Complex(re - other.re, im - other.im)
}
```
In Java, applying such external operations could be cumbersome, but Kotlin has a unique feature that allows us
implement this
naturally: [extensions with receivers](https://kotlinlang.org/docs/reference/extensions.html#extension-functions). In
Kotlin, an operation on complex number could be implemented as:
```kotlin
with(ComplexOperations) { c1 + c2 - c3 }
```
Kotlin also allows the creation of functions with receivers:
```kotlin
fun ComplexOperations.doSomethingWithComplex(c1: Complex, c2: Complex, c3: Complex) = c1 + c2 - c3
ComplexOperations.doComethingWithComplex(c1, c2, c3)
```
In fact, whole parts of a program may be run within a mathematical context or even multiple nested contexts.
In KMath, contexts are not only responsible for operations, but also for raw object creation and advanced features.
## Other possibilities
### Type classes
An obvious candidate to get more or less the same functionality is the type class, which allows one to bind a behavior
to a specific type without modifying the type itself. On the plus side, type classes do not require explicit context
declaration, so the code looks cleaner. On the minus side, if there are different sets of behaviors for the same types,
it is impossible to combine them into one module. Also, unlike type classes, context can have parameters or even state.
For example in KMath, sizes and strides for `NDElement` or `Matrix` could be moved to context to optimize performance in
case of a large amount of structures.
### Wildcard imports and importing-on-demand
Sometimes, one may wish to use a single context throughout a file. In this case, is possible to import all members from
a package or file, via `import context.complex.*`. Effectively, this is the same as enclosing an entire file with a
single context. However, when using multiple contexts, this technique can introduce operator ambiguity, due to namespace
pollution. If there are multiple scoped contexts that define the same operation, it is still possible to import
specific operations as needed, without using an explicit context with extension functions, for example:
```
import context.complex.op1
import context.quaternion.op2
```

File diff suppressed because it is too large Load Diff

@ -1,24 +0,0 @@
# Expressions
Expressions is a feature, which allows constructing lazily or immediately calculated parametric mathematical
expressions.
The potential use-cases for it (so far) are following:
* lazy evaluation (in general simple lambda is better, but there are some border cases);
* automatic differentiation in single-dimension and in multiple dimensions;
* generation of mathematical syntax trees with subsequent code generation for other languages;
* symbolic computations, especially differentiation (and some other actions with `kmath-symja` integration with
Symja's `IExpr`&mdash;integration, simplification, and more);
* visualization with `kmath-jupyter`.
The workhorse of this API is `Expression` interface, which exposes
single `operator fun invoke(arguments: Map<Symbol, T>): T`
method. `ExpressionAlgebra` is used to generate expressions and introduce variables.
Currently there are two implementations:
* Generic `ExpressionField` in `kmath-core` which allows construction of custom lazy expressions
* Auto-differentiation expression in `kmath-commons` module allows using full power of `DerivativeStructure`
from commons-math. **TODO: add example**

@ -1 +0,0 @@
**TODO**

File diff suppressed because one or more lines are too long

Before

(image error) Size: 249 KiB

File diff suppressed because one or more lines are too long

Before

(image error) Size: 19 KiB

File diff suppressed because one or more lines are too long

Before

(image error) Size: 278 KiB

File diff suppressed because one or more lines are too long

Before

(image error) Size: 118 KiB

@ -1,36 +0,0 @@
## Basic linear algebra layout
KMath support for linear algebra organized in a context-oriented way, which means that operations are in most cases
declared in context classes, and are not the members of classes that store data. This allows more flexible approach to
maintain multiple back-ends. The new operations added as extensions to contexts instead of being member functions of
data structures.
The main context for linear algebra over matrices and vectors is `LinearSpace`, which defines addition and dot products
of matrices and vectors:
```kotlin
import space.kscience.kmath.linear.*
LinearSpace.Companion.real {
val vec = buildVector(10) { i -> i.toDouble() }
val mat = buildMatrix(10, 10) { i, j -> i.toDouble() + j }
// Addition
vec + vec
mat + mat
// Multiplication by scalar
vec * 2.0
mat * 2.0
// Dot product
mat dot vec
mat dot mat
}
```
## Backends overview
### EJML
### Commons Math

@ -1,150 +0,0 @@
# ND-structure generation and operations
**TODO**
# Performance for n-dimensional structures operations
One of the most sought after features of mathematical libraries is the high-performance operations on n-dimensional
structures. In `kmath` performance depends on which particular context was used for operation.
Let us consider following contexts:
```kotlin
// automatically build context most suited for given type.
val autoField = NDField.auto(DoubleField, dim, dim)
// specialized nd-field for Double. It works as generic Double field as well.
val specializedField = NDField.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives.
val genericField = NDField.buffered(DoubleField, dim, dim)
```
Now let us perform several tests and see, which implementation is best suited for each case:
## Test case
To test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0`
to it `n = 1000` times.
## Specialized
The code to run this looks like:
```kotlin
specializedField.run {
var res: NDBuffer<Float64> = one
repeat(n) {
res += 1.0
}
}
```
The performance of this code is the best of all tests since it inlines all operations and is specialized for operation
with doubles. We will measure everything else relative to this one, so time for this test will be `1x` (real time
on my computer is about 4.5 seconds). The only problem with this approach is that it requires specifying type
from the beginning. Everyone does so anyway, so it is the recommended approach.
## Automatic
Let's do the same with automatic field inference:
```kotlin
autoField.run {
var res = one
repeat(n) {
res += 1.0
}
}
```
Ths speed of this operation is approximately the same as for specialized case since `NDField.auto` just
returns the same `RealNDField` in this case. Of course, it is usually better to use specialized method to be sure.
## Lazy
Lazy field does not produce a structure when asked, instead it generates an empty structure and fills it on-demand
using coroutines to parallelize computations.
When one calls
```kotlin
lazyField.run {
var res = one
repeat(n) {
res += 1.0
}
}
```
The result will be calculated almost immediately but the result will be empty. To get the full result
structure one needs to call all its elements. In this case computation overhead will be huge. So this field never
should be used if one expects to use the full result structure. Though if one wants only small fraction, it could
save a lot of time.
This field still could be used with reasonable performance if call code is changed:
```kotlin
lazyField.run {
val res = one.map {
var c = 0.0
repeat(n) {
c += 1.0
}
c
}
res.elements().forEach { it.second }
}
```
In this case it completes in about `4x-5x` time due to boxing.
## Boxing
The boxing field produced by
```kotlin
genericField.run {
var res: NDBuffer<Float64> = one
repeat(n) {
res += 1.0
}
}
```
is the slowest one, because it requires boxing and unboxing the `double` on each operation. It takes about
`15x` time (**TODO: there seems to be a problem here, it should be slow, but not that slow**). This field should
never be used for primitives.
## Element operation
Let us also check the speed for direct operations on elements:
```kotlin
var res = genericField.one
repeat(n) {
res += 1.0
}
```
One would expect to be at least as slow as field operation, but in fact, this one takes only `2x` time to complete.
It happens, because in this particular case it does not use actual `NDField` but instead calculated directly
via extension function.
## What about python?
Usually it is bad idea to compare the direct numerical operation performance in different languages, but it hard to
work completely without frame of reference. In this case, simple numpy code:
```python
import numpy as np
res = np.ones((1000,1000))
for i in range(1000):
res = res + 1.0
```
gives the completion time of about `1.1x`, which means that specialized kotlin code in fact is working faster (I think
it is
because better memory management). Of course if one writes `res += 1.0`, the performance will be different,
but it would be different case, because numpy overrides `+=` with in-place operations. In-place operations are
available in `kmath` with `MutableNDStructure` but there is no field for it (one can still work with mapping
functions).

@ -1,223 +0,0 @@
# Polynomials and Rational Functions
KMath provides a way to work with uni- and multivariate polynomials and rational functions. It includes full support of
arithmetic operations of integers, **constants** (elements of ring polynomials are build over), variables (for certain
multivariate implementations), polynomials and rational functions encapsulated in so-called **polynomial space** and *
*rational function space** and some other utilities such as algebraic differentiation and substitution.
## Concrete realizations
There are 3 approaches to represent polynomials:
1. For univariate polynomials one can represent and store polynomial as a list of coefficients for each power of the
variable. I.e. polynomial $a_0 + \dots + a_n x^n $ can be represented as a finite sequence $(a_0; \dots; a_n)$. (
Compare to sequential definition of polynomials.)
2. For multivariate polynomials one can represent and store polynomial as a matching (in programming it is called "map"
or "dictionary", in math it is
called [functional relation](https://en.wikipedia.org/wiki/Binary_relation#Special_types_of_binary_relations)) of
each "**term signature**" (that describes what variables and in what powers appear in the term) with corresponding
coefficient of the term. But there are 2 possible approaches of term signature representation:
1. One can number all the variables, so term signature can be represented as a sequence describing powers of the
variables. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural or zero $d_i $) can be
represented as a finite sequence $(d_0; \dots; d_n)$.
2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of
each appeared variable with its power in the term. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for
natural non-zero $d_i $) can be represented as a finite matching $(x_0 \to d_1; \dots; x_n \to d_n)$.
All that three approaches are implemented by "list", "numbered", and "labeled" versions of polynomials and polynomial
spaces respectively. Whereas all rational functions are represented as fractions with corresponding polynomial numerator
and denominator, and rational functions' spaces are implemented in the same way as usual field of rational numbers (or
more precisely, as any field of fractions over integral domain) should be implemented.
So here are a bit of details. Let `C` by type of constants. Then:
1. `ListPolynomial`, `ListPolynomialSpace`, `ListRationalFunction` and `ListRationalFunctionSpace` implement the first
scenario. `ListPolynomial` stores polynomial $a_0 + \dots + a_n x^n $ as a coefficients
list `listOf(a_0, ..., a_n)` (of type `List<C>`).
They also have variation `ScalableListPolynomialSpace` that replaces former polynomials and
implements `ScaleOperations`.
2. `NumberedPolynomial`, `NumberedPolynomialSpace`, `NumberedRationalFunction` and `NumberedRationalFunctionSpace`
implement second scenario. `NumberedPolynomial` stores polynomials as structures of type `Map<List<UInt>, C>`.
Signatures are stored as `List<UInt>`. To prevent ambiguity signatures should not end with zeros.
3. `LabeledPolynomial`, `LabeledPolynomialSpace`, `LabeledRationalFunction` and `LabeledRationalFunctionSpace` implement
third scenario using common `Symbol` as variable type. `LabeledPolynomial` stores polynomials as structures of
type `Map<Map<Symbol, UInt>, C>`. Signatures are stored as `Map<Symbol, UInt>`. To prevent ambiguity each signature
should not map any variable to zero.
### Example: `ListPolynomial`
For example, polynomial $2 - 3x + x^2 $ (with `Int` coefficients) is represented
```kotlin
val polynomial: ListPolynomial<Int> = ListPolynomial(listOf(2, -3, 1))
// or
val polynomial: ListPolynomial<Int> = ListPolynomial(2, -3, 1)
```
All algebraic operations can be used in corresponding space:
```kotlin
val computationResult = Int.algebra.listPolynomialSpace {
ListPolynomial(2, -3, 1) + ListPolynomial(0, 6) == ListPolynomial(2, 3, 1)
}
println(computationResult) // true
```
For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt).
### Example: `NumberedPolynomial`
For example, polynomial $3 + 5 x_1 - 7 x_0^2 x_2 $ (with `Int` coefficients) is represented
```kotlin
val polynomial: NumberedPolynomial<Int> = NumberedPolynomial(
mapOf(
listOf<UInt>() to 3,
listOf(0u, 1u) to 5,
listOf(2u, 0u, 1u) to -7,
)
)
// or
val polynomial: NumberedPolynomial<Int> = NumberedPolynomial(
listOf<UInt>() to 3,
listOf(0u, 1u) to 5,
listOf(2u, 0u, 1u) to -7,
)
```
All algebraic operations can be used in corresponding space:
```kotlin
val computationResult = Int.algebra.numberedPolynomialSpace {
NumberedPolynomial(
listOf<UInt>() to 3,
listOf(0u, 1u) to 5,
listOf(2u, 0u, 1u) to -7,
) + NumberedPolynomial(
listOf(0u, 1u) to -5,
listOf(0u, 0u, 0u, 4u) to 4,
) == NumberedPolynomial(
listOf<UInt>() to 3,
listOf(0u, 1u) to 0,
listOf(2u, 0u, 1u) to -7,
listOf(0u, 0u, 0u, 4u) to 4,
)
}
println(computationResult) // true
```
For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt).
### Example: `LabeledPolynomial`
For example, polynomial $3 + 5 y - 7 x^2 z $ (with `Int` coefficients) is represented
```kotlin
val polynomial: LabeledPolynomial<Int> = LabeledPolynomial(
mapOf(
mapOf<Symbol, UInt>() to 3,
mapOf(y to 1u) to 5,
mapOf(x to 2u, z to 1u) to -7,
)
)
// or
val polynomial: LabeledPolynomial<Int> = LabeledPolynomial(
mapOf<Symbol, UInt>() to 3,
mapOf(y to 1u) to 5,
mapOf(x to 2u, z to 1u) to -7,
)
```
All algebraic operations can be used in corresponding space:
```kotlin
val computationResult = Int.algebra.labeledPolynomialSpace {
LabeledPolynomial(
listOf<UInt>() to 3,
listOf(0u, 1u) to 5,
listOf(2u, 0u, 1u) to -7,
) + LabeledPolynomial(
listOf(0u, 1u) to -5,
listOf(0u, 0u, 0u, 4u) to 4,
) == LabeledPolynomial(
listOf<UInt>() to 3,
listOf(0u, 1u) to 0,
listOf(2u, 0u, 1u) to -7,
listOf(0u, 0u, 0u, 4u) to 4,
)
}
println(computationResult) // true
```
For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt).
## Abstract entities (interfaces and abstract classes)
```mermaid
classDiagram
Polynomial <|-- ListPolynomial
Polynomial <|-- NumberedPolynomial
Polynomial <|-- LabeledPolynomial
RationalFunction <|-- ListRationalFunction
RationalFunction <|-- NumberedRationalFunction
RationalFunction <|-- LabeledRationalFunction
Ring <|-- PolynomialSpace
PolynomialSpace <|-- MultivariatePolynomialSpace
PolynomialSpace <|-- PolynomialSpaceOverRing
Ring <|-- RationalFunctionSpace
RationalFunctionSpace <|-- MultivariateRationalFunctionSpace
RationalFunctionSpace <|-- RationalFunctionSpaceOverRing
RationalFunctionSpace <|-- RationalFunctionSpaceOverPolynomialSpace
RationalFunctionSpace <|-- PolynomialSpaceOfFractions
RationalFunctionSpaceOverPolynomialSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace
MultivariateRationalFunctionSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace
MultivariateRationalFunctionSpace <|-- MultivariatePolynomialSpaceOfFractions
PolynomialSpaceOfFractions <|-- MultivariatePolynomialSpaceOfFractions
```
There are implemented `Polynomial` and `RationalFunction` interfaces as abstractions of polynomials and rational
functions respectively (although, there is not a lot of logic in them) and `PolynomialSpace`
and `RationalFunctionSpace` (that implement `Ring` interface) as abstractions of polynomials' and rational functions'
spaces respectively. More precisely, that means they allow to declare common logic of interaction with such objects and
spaces:
- `Polynomial` does not provide any logic. It is marker interface.
- `RationalFunction` provides numerator and denominator of rational function and destructuring declaration for them.
- `PolynomialSpace` provides all possible arithmetic interactions of integers, constants (of type `C`), and
polynomials (of type `P`) like addition, subtraction, multiplication, and some others and common properties like
degree of polynomial.
- `RationalFunctionSpace` provides the same as `PolynomialSpace` but also for rational functions: all possible
arithmetic interactions of integers, constants (of type `C`), polynomials (of type `P`), and rational functions (of
type `R`) like addition, subtraction, multiplication, division (in some cases), and some others and common properties
like degree of polynomial.
Then to add abstraction of similar behaviour with variables (in multivariate case) there are
implemented `MultivariatePolynomialSpace` and `MultivariateRationalFunctionSpace`. They just include variables (of
type `V`) in the interactions of the entities.
Also, to remove boilerplates there were provided helping subinterfaces and abstract subclasses:
- `PolynomialSpaceOverRing` allows to replace implementation of interactions of integers and constants with
implementations from provided ring over constants (of type `A: Ring<C>`).
- `RationalFunctionSpaceOverRing` &mdash; the same but for `RationalFunctionSpace`.
- `RationalFunctionSpaceOverPolynomialSpace` &mdash; the same but "the inheritance" includes interactions with
polynomials from provided `PolynomialSpace`.
- `PolynomialSpaceOfFractions` is actually abstract subclass of `RationalFunctionSpace` that implements all fractions
boilerplates with provided (`protected`) constructor of rational functions by polynomial numerator and denominator.
- `MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace` and `MultivariatePolynomialSpaceOfFractions`
&mdash; the same stories of operators inheritance and fractions boilerplates respectively but in multivariate case.
## Utilities
For all kinds of polynomials there are provided (implementation details depend on kind of polynomials) such common
utilities as:
1. differentiation and anti-differentiation,
2. substitution, invocation and functional representation.

@ -1,16 +0,0 @@
# Documentation
* [Algebra](algebra.md): [context-based](contexts.md) operations on different primitives and structures.
* [NDStructures](nd-structure.md)
* [Linear algebra](linear.md): matrices, operations and linear equations solving. To be moved to separate module.
Currently, supports basic API and multiple library back-ends.
* [Histograms](histograms.md): multidimensional histogram calculation and operations.
* [Expressions](expressions.md)
* [Statistics](statistics.md): statistical functions on data [Buffers](buffers.md)
* Commons math integration

@ -1,34 +0,0 @@
# Statistics
Mathematically speaking, a statistic is a measurable numerical function of sample data.
In KMath, a statistic is a function that operates on a [Buffer](buffers.md) and is implemented as the `evaluate` method
of the `Statistic` interface.
There are two subinterfaces of the `Statistic` interface:
* `BlockingStatistic` A statistic that is computed in a synchronous blocking mode
* `ComposableStatistic` A statistic tha could be computed separately on different blocks of data and then composed
## Common statistics and Implementation Status
| Category | Statistic | Description | Implementation Status |
|------------------|-------------------|-------------------------------------|--------------------------------|
| **Basic** | Min | Minimum value | ✅ `ComposableStatistic` |
| | Max | Maximum value | ✅ `ComposableStatistic` |
| | Mean | Arithmetic mean | ✅ `ComposableStatistic` |
| | Sum | Sum of all values | 🚧 Not yet implemented |
| | Product | Product of all values | 🚧 Not yet implemented |
| **Distribution** | Median | Median (50th percentile) | ✅ `BlockingStatistic` |
| | Quantile | Arbitrary percentile (e.g., Q1, Q3) | 🚧 Not yet implemented |
| | Variance | Unbiased sample variance | ✅ `BlockingStatistic` |
| | StandardDeviation | Population standard deviation (σ) | ✅ `BlockingStatistic` |
| | Skewness | Measure of distribution asymmetry | 🚧 *(Requires `ThirdMoment`)* |
| | Kurtosis | Measure of distribution tailedness | 🚧 *(Requires `FourthMoment`)* |
| **Advanced** | GeometricMean | Nth root of product of values | ✅ `ComposableStatistic` |
| | SumOfLogs | Sum of natural logarithms | Does not planned |
| | SumOfSquares | Sum of squared values | 🚧 *(Blocks `Variance`)* |
| **Moments** | FirstMoment | Mean (same as `Mean`) | ✅ *(Alias for `Mean`)* |
| | SecondMoment | Variance (same as `Variance`) | ✅ *(Alias for `Variance`)* |
| | ThirdMoment | Used in skewness calculation | 🚧 Not yet implemented |
| | FourthMoment | Used in kurtosis calculation | 🚧 Not yet implemented |
| **Risk Metrics** | SemiVariance | Downside variance | 🚧 *(Depends on `Variance`)* |

@ -1,16 +0,0 @@
## Artifact:
The Maven coordinates of this project are `${group}:${name}:${version}`.
**Gradle:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
mavenCentral()
}
dependencies {
implementation("${group}:${name}:${version}")
}
```

@ -1,109 +0,0 @@
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
![Gradle build](https://github.com/SciProgCentre/kmath/workflows/Gradle%20build/badge.svg)
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22)
[![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
# KMath
Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based
analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior
architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like
experience could be achieved with [kmath-for-real](/kmath-for-real) extension module.
[Documentation site](https://SciProgCentre.github.io/kmath/)
## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
* [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814)
* [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103)
* [A talk at KotlinConf 2019 about using kotlin for science](https://youtu.be/LI_5TZ7tnOE?si=4LknX41gl_YeUbIe)
* [A talk on architecture at Joker-2021 (in Russian)](https://youtu.be/1bZ2doHiRRM?si=9w953ro9yu98X_KJ)
* [The same talk in English](https://youtu.be/yP5DIc2fVwQ?si=louZzQ1dcXV6gP10)
* [A seminar on tensor API](https://youtu.be/0H99wUs0xTM?si=6c__04jrByFQtVpo)
# Goal
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS, Native and
Wasm).
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
* Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
## Non-goals
* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API.
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better
experience for those, who want to work with specific types.
## Features and stability
KMath is a modular library. Different modules provide different features with different API stability guarantees. All
core modules are released with the same version, but with different API change policy. The features are described in
module definitions below. The module stability could have the following levels:
* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could
break any moment. You can still use it, but be sure to fix the specific version.
* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked
with `@UnstableKMathAPI` or other stability warning annotations.
* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor
versions, but not in patch versions. API is protected
with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool.
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
## Modules
${modules}
## Multi-platform support
KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the
[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features
are delegated to platform-specific implementations even if they could be provided in the common module for performance
reasons. Currently, Kotlin/JVM is the primary platform, however, Kotlin/Native and Kotlin/JS contributions and
feedback are also welcome.
## Performance
Calculation of performance is one of the major goals of KMath in the future, but in some cases it is impossible to
achieve both
performance and flexibility.
We expect to focus on creating a convenient universal API first and then work on increasing performance for specific
cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy.
## Requirements
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend using GraalVM-CE or
Oracle GraalVM for execution to get better performance.
### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/)
repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could
be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy:
```kotlin
repositories {
maven("https://repo.kotlin.link")
}
dependencies {
api("${group}:kmath-core:$version")
// api("${group}:kmath-core-jvm:$version") for jvm-specific version
}
```
## Contributing
The project requires a lot of additional work. The most important thing we need is feedback about what features are
required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues
marked
with [good first issue](hhttps://github.com/SciProgCentre/kmath/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
label.

@ -1,4 +0,0 @@
# Module examples

@ -1,73 +0,0 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
plugins {
kotlin("jvm")
}
repositories {
mavenCentral()
maven("https://repo.kotlin.link")
maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers")
}
dependencies {
implementation(project(":kmath-ast"))
implementation(project(":kmath-kotlingrad"))
implementation(project(":kmath-core"))
implementation(project(":kmath-coroutines"))
implementation(project(":kmath-commons"))
implementation(project(":kmath-complex"))
implementation(project(":kmath-functions"))
implementation(project(":kmath-optimization"))
implementation(project(":kmath-stat"))
implementation(project(":kmath-viktor"))
implementation(project(":kmath-dimensions"))
implementation(project(":kmath-ejml"))
implementation(project(":kmath-tensors"))
implementation(project(":kmath-symja"))
implementation(project(":kmath-for-real"))
//multik
implementation(project(":kmath-multik"))
implementation(libs.multik.default)
//datetime
implementation(spclibs.kotlinx.datetime)
// implementation(project(":kmath-nd4j"))
// implementation("org.nd4j:nd4j-native:1.0.0-beta7")
// uncomment if your system supports AVX2
// val os = System.getProperty("os.name")
//
// if (System.getProperty("os.arch") in arrayOf("x86_64", "amd64")) when {
// os.startsWith("Windows") -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:windows-x86_64-avx2")
// os == "Linux" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:linux-x86_64-avx2")
// os == "Mac OS X" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:macosx-x86_64-avx2")
// } else
// implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
implementation("org.slf4j:slf4j-simple:1.7.32")
// plotting
implementation("space.kscience:plotlykt-server:0.7.0")
}
kotlin {
jvmToolchain(17)
sourceSets.all {
languageSettings {
optIn("kotlin.contracts.ExperimentalContracts")
optIn("kotlin.ExperimentalUnsignedTypes")
optIn("space.kscience.kmath.UnstableKMathAPI")
}
}
}
tasks.withType<KotlinJvmCompile> {
compilerOptions {
freeCompilerArgs.addAll("-Xjvm-default=all", "-Xopt-in=kotlin.RequiresOptIn", "-Xlambdas=indy")
}
}
readme {
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
}

@ -1,418 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"source": [
"%use kmath(0.3.1-dev-5)\n",
"%use plotly(0.5.0)\n",
"@file:DependsOn(\"space.kscience:kmath-commons:0.3.1-dev-5\")"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "lQbSB87rNAn9lV6poArVWW",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "code",
"source": [
"//Uncomment to work in Jupyter classic or DataLore\n",
"//Plotly.jupyter.notebook()"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "0UP158hfccGgjQtHz0wAi6",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "markdown",
"source": [
"# The model\n",
"\n",
"Defining the input data format, the statistic abstraction and the statistic implementation based on a weighted sum of elements."
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"source": [
"class XYValues(val xValues: DoubleArray, val yValues: DoubleArray) {\n",
" init {\n",
" require(xValues.size == yValues.size)\n",
" }\n",
"}\n",
"\n",
"fun interface XYStatistic {\n",
" operator fun invoke(values: XYValues): Double\n",
"}\n",
"\n",
"class ConvolutionalXYStatistic(val weights: DoubleArray) : XYStatistic {\n",
" override fun invoke(values: XYValues): Double {\n",
" require(weights.size == values.yValues.size)\n",
" val norm = values.yValues.sum()\n",
" return values.yValues.zip(weights) { value, weight -> value * weight }.sum()/norm\n",
" }\n",
"}"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "Zhgz1Ui91PWz0meJiQpHol",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "markdown",
"source": [
"# Generator\n",
"Generate sample data for parabolas and hyperbolas"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [
"fun generateParabolas(xValues: DoubleArray, a: Double, b: Double, c: Double): XYValues {\n",
" val yValues = xValues.map { x -> a * x * x + b * x + c }.toDoubleArray()\n",
" return XYValues(xValues, yValues)\n",
"}\n",
"\n",
"fun generateHyperbols(xValues: DoubleArray, gamma: Double, x0: Double, y0: Double): XYValues {\n",
" val yValues = xValues.map { x -> y0 + gamma / (x - x0) }.toDoubleArray()\n",
" return XYValues(xValues, yValues)\n",
"}"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"source": [
"val xValues = (1.0..10.0).step(1.0).toDoubleArray()\n",
"\n",
"val xy = generateHyperbols(xValues, 1.0, 0.0, 0.0)\n",
"\n",
"Plotly.plot {\n",
" scatter {\n",
" this.x.doubles = xValues\n",
" this.y.doubles = xy.yValues\n",
" }\n",
"}"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "ZE2atNvFzQsCvpAF8KK4ch",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "markdown",
"source": [
"Create a default statistic with uniform weights"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"source": [
"val statistic = ConvolutionalXYStatistic(DoubleArray(xValues.size){1.0})\n",
"statistic(xy)"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "EA5HaydTddRKYrtAUwd29h",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "code",
"source": [
"import kotlin.random.Random\n",
"\n",
"val random = Random(1288)\n",
"\n",
"val parabolas = buildList{\n",
" repeat(500){\n",
" add(\n",
" generateParabolas(\n",
" xValues, \n",
" random.nextDouble(), \n",
" random.nextDouble(), \n",
" random.nextDouble()\n",
" )\n",
" )\n",
" }\n",
"}\n",
"\n",
"val hyperbolas: List<XYValues> = buildList{\n",
" repeat(500){\n",
" add(\n",
" generateHyperbols(\n",
" xValues, \n",
" random.nextDouble()*10, \n",
" random.nextDouble(), \n",
" random.nextDouble()\n",
" )\n",
" )\n",
" }\n",
"}"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "t5t6IYmD7Q1ykeo9uijFfQ",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "code",
"source": [
"Plotly.plot { \n",
" scatter { \n",
" x.doubles = xValues\n",
" y.doubles = parabolas[257].yValues\n",
" }\n",
" scatter { \n",
" x.doubles = xValues\n",
" y.doubles = hyperbolas[252].yValues\n",
" }\n",
" }"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "oXB8lmju7YVYjMRXITKnhO",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "code",
"source": [
"Plotly.plot { \n",
" histogram { \n",
" name = \"parabolae\"\n",
" x.numbers = parabolas.map { statistic(it) }\n",
" }\n",
" histogram { \n",
" name = \"hyperbolae\"\n",
" x.numbers = hyperbolas.map { statistic(it) }\n",
" }\n",
"}"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "8EIIecUZrt2NNrOkhxG5P0",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "code",
"source": [
"val lossFunction: (XYStatistic) -> Double = { statistic ->\n",
" - abs(parabolas.sumOf { statistic(it) } - hyperbolas.sumOf { statistic(it) })\n",
"}"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "h7UmglJW5zXkAfKHK40oIL",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "markdown",
"source": [
"Using commons-math optimizer to optimize weights"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"source": [
"import org.apache.commons.math3.optim.*\n",
"import org.apache.commons.math3.optim.nonlinear.scalar.*\n",
"import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.*\n",
"\n",
"val optimizer = SimplexOptimizer(1e-1, Double.MAX_VALUE)\n",
"\n",
"val result = optimizer.optimize(\n",
" ObjectiveFunction { point ->\n",
" lossFunction(ConvolutionalXYStatistic(point))\n",
" },\n",
" NelderMeadSimplex(xValues.size),\n",
" InitialGuess(DoubleArray(xValues.size){ 1.0 }),\n",
" GoalType.MINIMIZE,\n",
" MaxEval(100000)\n",
")"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "0EG3K4aCUciMlgGQKPvJ57",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "markdown",
"source": [
"Print resulting weights of optimization"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"source": [
"result.point"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "LelUlY0ZSlJEO9yC6SLk5B",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "code",
"source": [
"Plotly.plot { \n",
" scatter { \n",
" y.doubles = result.point\n",
" }\n",
"}"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "AuFOq5t9KpOIkGrOLsVXNf",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "markdown",
"source": [
"# The resulting statistic distribution"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"source": [
"val resultStatistic = ConvolutionalXYStatistic(result.point)\n",
"Plotly.plot { \n",
" histogram { \n",
" name = \"parabolae\"\n",
" x.numbers = parabolas.map { resultStatistic(it) }\n",
" }\n",
" histogram { \n",
" name = \"hyperbolae\"\n",
" x.numbers = hyperbolas.map { resultStatistic(it) }\n",
" }\n",
"}"
],
"execution_count": null,
"outputs": [],
"metadata": {
"datalore": {
"node_id": "zvmq42DRdM5mZ3SpzviHwI",
"type": "CODE",
"hide_input_from_viewers": false,
"hide_output_from_viewers": false
}
}
},
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [],
"metadata": {
"collapsed": false
}
}
],
"metadata": {
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"datalore": {
"version": 1,
"computation_mode": "JUPYTER",
"package_manager": "pip",
"base_environment": "default",
"packages": []
}
},
"nbformat": 4,
"nbformat_minor": 4
}

@ -1,26 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast
import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess
import space.kscience.kmath.ast.rendering.LatexSyntaxRenderer
import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer
import space.kscience.kmath.ast.rendering.renderWithStringBuilder
fun main() {
val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
println("MathSyntax:")
println(syntax)
println()
val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
println("LaTeX:")
println(latex)
println()
val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax)
println("MathML:")
println(mathML)
}

@ -1,26 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast
import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.Symbol.Companion.x
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.invoke
fun main() {
val expr = MstExtendedField {
x * 2.0 + number(2.0) / x - number(16.0) + asinh(x) / sin(x)
}.compileToExpression(Float64Field)
val m = DoubleArray(expr.indexer.symbols.size)
val xIdx = expr.indexer.indexOf(x)
repeat(10000000) {
m[xIdx] = 1.0
expr(m)
}
}

@ -1,27 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast
import space.kscience.kmath.expressions.Symbol.Companion.x
import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.toExpression
import space.kscience.kmath.kotlingrad.toKotlingradExpression
import space.kscience.kmath.operations.Float64Field
/**
* In this example, *x<sup>2</sup> &minus; 4 x &minus; 44* function is differentiated with Kotlin, and the
* derivation result is compared with valid derivative in a certain point.
*/
fun main() {
val actualDerivative = "x^2-4*x-44"
.parseMath()
.toKotlingradExpression(Float64Field)
.derivative(x)
val expectedDerivative = "2*x-4".parseMath().toExpression(Float64Field)
check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0))
}

@ -1,27 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast
import space.kscience.kmath.expressions.Symbol.Companion.x
import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.toExpression
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.symja.toSymjaExpression
/**
* In this example, *x<sup>2</sup> &minus; 4 x &minus; 44* function is differentiated with Symja, and the
* derivation result is compared with valid derivative in a certain point.
*/
fun main() {
val actualDerivative = "x^2-4*x-44"
.parseMath()
.toSymjaExpression(Float64Field)
.derivative(x)
val expectedDerivative = "2*x-4".parseMath().toExpression(Float64Field)
check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0))
}

@ -1,92 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.expressions
import space.kscience.kmath.UnstableKMathAPI
// Only kmath-core is needed.
// Let's declare some variables
val x by symbol
val y by symbol
val z by symbol
@OptIn(UnstableKMathAPI::class)
fun main() {
// Let's define some random expression.
val someExpression = Double.autodiff.differentiate {
// We bind variables `x` and `y` to the builder scope,
val x = bindSymbol(x)
val y = bindSymbol(y)
// Then we use the bindings to define expression `xy + x + y - 1`
x * y + x + y - 1
}
// Then we can evaluate it at any point ((-1, -1) in the case):
println(someExpression(x to -1.0, y to -1.0))
// >>> -2.0
// We can also construct its partial derivatives:
val dxExpression = someExpression.derivative(x) // ∂/∂x. Must be `y+1`
val dyExpression = someExpression.derivative(y) // ∂/∂y. Must be `x+1`
val dxdxExpression = someExpression.derivative(x, x) // ∂^2/∂x^2. Must be `0`
// We can evaluate them as well
println(dxExpression(x to 57.0, y to 6.0))
// >>> 7.0
println(dyExpression(x to -1.0, y to 179.0))
// >>> 0.0
println(dxdxExpression(x to 239.0, y to 30.0))
// >>> 0.0
// You can also provide extra arguments that obviously won't affect the result:
println(dxExpression(x to 57.0, y to 6.0, z to 42.0))
// >>> 7.0
println(dyExpression(x to -1.0, y to 179.0, z to 0.0))
// >>> 0.0
println(dxdxExpression(x to 239.0, y to 30.0, z to 100_000.0))
// >>> 0.0
// But in case you forgot to specify bound symbol's value, exception is thrown:
println(runCatching { someExpression(z to 4.0) })
// >>> Failure(java.lang.IllegalStateException: Symbol 'x' is not supported in ...)
// The reason is that the expression is evaluated lazily,
// and each `bindSymbol` operation actually substitutes the provided symbol with the corresponding value.
// For example, let there be an expression
val simpleExpression = Double.autodiff.differentiate {
val x = bindSymbol(x)
x pow 2
}
// When you evaluate it via
simpleExpression(x to 1.0, y to 57.0, z to 179.0)
// lambda above has the context of map `{x: 1.0, y: 57.0, z: 179.0}`.
// When x is bound, you can think of it as substitution `x -> 1.0`.
// Other values are unused which does not make any problem to us.
// But in the case the corresponding value is not provided,
// we cannot bind the variable. Thus, exception is thrown.
// There is also a function `bindSymbolOrNull` that fixes the problem:
val fixedExpression = Double.autodiff.differentiate {
val x = bindSymbolOrNull(x) ?: const(8.0)
x pow -2
}
println(fixedExpression())
// >>> 0.015625
// It works!
// The expression provides a bunch of operations:
// 1. Constant bindings (via `const` and `number`).
// 2. Variable bindings (via `bindVariable`, `bindVariableOrNull`).
// 3. Arithmetic operations (via `+`, `-`, `*`, and `-`).
// 4. Exponentiation (via `pow` or `power`).
// 5. `exp` and `ln`.
// 6. Trigonometrical functions (`sin`, `cos`, `tan`, `cot`).
// 7. Inverse trigonometrical functions (`asin`, `acos`, `atan`, `acot`).
// 8. Hyperbolic functions and inverse hyperbolic functions.
}

@ -1,119 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.fit
import kotlinx.html.br
import kotlinx.html.h3
import space.kscience.kmath.commons.optimization.CMOptimizer
import space.kscience.kmath.distributions.NormalDistribution
import space.kscience.kmath.expressions.DifferentiableExpression
import space.kscience.kmath.expressions.autodiff
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.operations.asIterable
import space.kscience.kmath.operations.toList
import space.kscience.kmath.optimization.minimize
import space.kscience.kmath.optimization.optimizeWith
import space.kscience.kmath.optimization.result
import space.kscience.kmath.optimization.resultValue
import space.kscience.kmath.random.RandomGenerator
import space.kscience.kmath.real.DoubleVector
import space.kscience.kmath.real.map
import space.kscience.kmath.real.step
import space.kscience.kmath.stat.chiSquaredExpression
import space.kscience.kmath.structures.Float64
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.models.TraceValues
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
/**
* Shortcut to use buffers in plotly
*/
operator fun TraceValues.invoke(vector: DoubleVector) {
numbers = vector.asIterable()
}
/**
* 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 + 1
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(it) }//RealVector.same(x.size, sigma)
// compute differentiable chi^2 sum for given model ax^2 + bx + c
val chi2: DifferentiableExpression<Float64> = Double.autodiff.chiSquaredExpression(x, y, yErr) { arg ->
//bind variables to autodiff context
val a = bindSymbol(a)
val b = bindSymbol(b)
//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
}
//minimize the chi^2 in given starting point. Derivatives are not required, they are already included.
val result = chi2.optimizeWith(
CMOptimizer,
mapOf(a to 1.5, b to 0.9, c to 1.0),
attributesBuilder = {
minimize()
}
)
//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.result[a]!! * it.pow(2) + result.result[b]!! * it + 1 })
name = "fit"
}
}
br()
h3 {
+"Fit result: $result"
}
h3 {
+"Chi2/dof = ${result.resultValue / (x.size - 3)}"
}
}
page.makeFile()
}

@ -1,113 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.fit
import kotlinx.html.br
import kotlinx.html.h3
import space.kscience.kmath.data.XYErrorColumnarData
import space.kscience.kmath.distributions.NormalDistribution
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.autodiff
import space.kscience.kmath.expressions.binding
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.operations.asIterable
import space.kscience.kmath.operations.toList
import space.kscience.kmath.optimization.*
import space.kscience.kmath.random.RandomGenerator
import space.kscience.kmath.real.map
import space.kscience.kmath.real.step
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
private val d by symbol
private val e 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 + 1
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,
Double.autodiff,
mapOf(a to 0.9, b to 1.2, c to 2.0, e to 1.0, d to 1.0, e to 0.0),
attributesBuilder = {
freeParameters(a, b, c, d)
},
) { arg ->
//bind variables to autodiff context
val a by binding
val b by binding
//Include default value for c if it is not provided as a parameter
val c = bindSymbolOrNull(c) ?: one
val d by binding
val e by binding
a * arg.pow(2) + b * arg + c + d * arg.pow(3) + e / arg
}
println("Resulting chi2/dof: ${result.chiSquaredOrNull}/${result.dof}")
//display a page with plot and numerical results
val page = Plotly.page {
plot {
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.startPoint + result.result + (Symbol.x to it)) })
name = "fit"
}
}
br()
h3 {
+"Fit result: ${result.result}"
}
h3 {
+"Chi2/dof = ${result.chiSquaredOrNull!! / result.dof}"
}
}
page.makeFile()
}

@ -1,37 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.ComplexField.div
import space.kscience.kmath.complex.ComplexField.minus
import space.kscience.kmath.complex.algebra
import space.kscience.kmath.integration.gaussIntegrator
import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.value
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.structures.Float64
import kotlin.math.pow
fun main() {
//Define a function
val function: Function1D<Float64> = { x -> 3 * x.pow(2) + 2 * x + 1 }
//get the result of the integration
val result = Float64Field.gaussIntegrator.integrate(0.0..10.0, function = function)
//the value is nullable because in some cases the integration could not succeed
println(result.value)
repeat(100000) {
Complex.algebra.gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double ->
// sin(1 / x) + i * cos(1 / x)
1 / x - ComplexField.i / x
}.value
}
}

@ -1,52 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.interpolation.SplineInterpolator
import space.kscience.kmath.interpolation.interpolatePolynomials
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.structures.Float64
import space.kscience.plotly.Plotly
import space.kscience.plotly.UnstablePlotlyAPI
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.functionXY
import space.kscience.plotly.scatter
import kotlin.math.PI
import kotlin.math.sin
@OptIn(UnstablePlotlyAPI::class)
fun main() {
val data = (0..10).map {
val x = it.toDouble() / 5 * PI
x to sin(x)
}
val polynomial: PiecewisePolynomial<Float64> = SplineInterpolator(Float64Field).interpolatePolynomials(data)
val function = polynomial.asFunction(Float64Field, 0.0)
val cmInterpolate = org.apache.commons.math3.analysis.interpolation.SplineInterpolator().interpolate(
data.map { it.first }.toDoubleArray(),
data.map { it.second }.toDoubleArray()
)
Plotly.plot {
scatter {
name = "interpolated"
x.numbers = data.map { it.first }
y.numbers = x.doubles.map { function(it) }
}
scatter {
name = "original"
functionXY(0.0..(2 * PI), 0.1) { sin(it) }
}
scatter {
name = "cm"
x.numbers = data.map { it.first }
y.numbers = x.doubles.map { cmInterpolate.value(it) }
}
}.makeFile()
}

@ -1,46 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.interpolation.interpolatePolynomials
import space.kscience.kmath.interpolation.splineInterpolator
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.real.map
import space.kscience.kmath.real.step
import space.kscience.kmath.structures.Float64
import space.kscience.plotly.Plotly
import space.kscience.plotly.UnstablePlotlyAPI
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.functionXY
import space.kscience.plotly.scatter
@OptIn(UnstablePlotlyAPI::class)
fun main() {
val function: Function1D<Float64> = { x ->
if (x in 30.0..50.0) {
1.0
} else {
0.0
}
}
val xs = 0.0..100.0 step 0.5
val ys = xs.map(function)
val polynomial: PiecewisePolynomial<Float64> = Float64Field.splineInterpolator.interpolatePolynomials(xs, ys)
val polyFunction = polynomial.asFunction(Float64Field, 0.0)
Plotly.plot {
scatter {
name = "interpolated"
functionXY(25.0..55.0, 0.1) { polyFunction(it) }
}
scatter {
name = "original"
functionXY(25.0..55.0, 0.1) { function(it) }
}
}.makeFile()
}

@ -1,33 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
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.structureND
import space.kscience.kmath.nd.withNdAlgebra
import space.kscience.kmath.operations.algebra
import space.kscience.kmath.structures.Float64
import kotlin.math.pow
fun main(): Unit = Double.algebra.withNdAlgebra(2, 2) {
//Produce a diagonal StructureND
fun diagonal(v: Double) = structureND { (i, j) ->
if (i == j) v else 0.0
}
//Define a function in a nd space
val function: (Double) -> StructureND<Float64> = { x: Double -> 3 * x.pow(2) + 2 * diagonal(x) + 1 }
//get the result of the integration
val result = gaussIntegrator.integrate(0.0..10.0, function = function)
//the value is nullable because in some cases the integration could not succeed
println(result.value)
}

@ -1,31 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.linear
import kotlin.random.Random
import kotlin.time.measureTime
fun main() = with(Float64ParallelLinearSpace) {
val random = Random(12224)
val dim = 1000
//creating invertible matrix
val matrix1 = buildMatrix(dim, dim) { i, j ->
if (i <= j) random.nextDouble() else 0.0
}
val matrix2 = buildMatrix(dim, dim) { i, j ->
if (i <= j) random.nextDouble() else 0.0
}
val time = measureTime {
repeat(30) {
matrix1 dot matrix2
}
}
println(time)
}

@ -1,42 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.linear
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.commons.linear.CMLinearSpace
import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.algebra
import space.kscience.kmath.structures.Float64
import kotlin.random.Random
@OptIn(PerformancePitfall::class)
fun main() {
val dim = 46
val random = Random(123)
val u = Float64.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
listOf(CMLinearSpace, EjmlLinearSpaceDDRM).forEach { algebra ->
with(algebra) {
//create a symmetric matrix
val matrix = buildMatrix(dim, dim) { row, col ->
if (row >= col) u[row, col] else u[col, row]
}
val eigen = matrix.getOrComputeAttribute(EIG) ?: error("Failed to compute eigenvalue decomposition")
check(
StructureND.contentEquals(
matrix,
eigen.v dot eigen.d dot eigen.v.transposed(),
1e-4
)
) { "$algebra decomposition failed" }
println("$algebra eigenvalue decomposition complete and checked" )
}
}
}

@ -1,34 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.linear
import space.kscience.kmath.real.*
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.structures.Float64Buffer
fun main() {
val x0 = DoubleVector(0.0, 0.0, 0.0)
val sigma = DoubleVector(1.0, 1.0, 1.0)
val gaussian: (Point<Float64>) -> Double = { x ->
require(x.size == x0.size)
kotlin.math.exp(-((x - x0) / sigma).square().sum())
}
fun ((Point<Float64>) -> Double).grad(x: Point<Float64>): Point<Float64> {
require(x.size == x0.size)
return Float64Buffer(x.size) { i ->
val h = sigma[i] / 5
val dVector = Float64Buffer(x.size) { if (it == i) h else 0.0 }
val f1 = this(x + dVector / 2)
val f0 = this(x - dVector / 2)
(f1 - f0) / h
}
}
println(gaussian.grad(x0))
}

@ -1,27 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.linear
import kotlin.random.Random
import kotlin.time.measureTime
fun main(): Unit = with(Float64LinearSpace) {
val random = Random(1224)
val dim = 500
//creating invertible matrix
val u = buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
val l = buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
val matrix = l dot u
val time = measureTime {
repeat(20) {
lupSolver().inverse(matrix)
}
}
println(time)
}

@ -1,11 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.operations
fun main() {
val res = BigIntField { number(1) * 2 }
println("bigint:$res")
}

@ -1,40 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.operations
import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.algebra
import space.kscience.kmath.complex.ndAlgebra
import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.structureND
fun main() = Complex.algebra {
val complex = 2 + 2 * i
println(complex * 8 - 5 * i)
//flat buffer
val buffer = with(bufferAlgebra) {
buffer(8) { Complex(it, -it) }.map { Complex(it.im, it.re) }
}
println(buffer)
// 2d element
val element: BufferND<Complex> = ndAlgebra.structureND(2, 2) { (i, j) ->
Complex(i - j, i + j)
}
println(element)
// 1d element operation
val result: StructureND<Complex> = ndAlgebra {
val a = structureND(8) { (it) -> i * it - it.toDouble() }
val b = 3
val c = Complex(1.0, 1.0)
(a pow b) + c
}
println(result)
}

@ -1,30 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.operations
import space.kscience.kmath.commons.linear.CMLinearSpace
import space.kscience.kmath.linear.MatrixBuilder
import space.kscience.kmath.linear.fill
import space.kscience.kmath.nd.Float64BufferND
import space.kscience.kmath.nd.Structure2D
import space.kscience.kmath.nd.mutableStructureND
import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.viktor.viktorAlgebra
fun main() {
val viktorStructure = Float64Field.viktorAlgebra.mutableStructureND(2, 2) { (i, j) ->
if (i == j) 2.0 else 0.0
}
val cmMatrix: Structure2D<Float64> = CMLinearSpace.MatrixBuilder(2, 2).fill(0.0, 1.0, 0.0, 3.0)
val res: Float64BufferND = Float64Field.ndAlgebra {
exp(viktorStructure) + 2.0 * cmMatrix
}
println(res)
}

@ -1,17 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.series
import kotlinx.datetime.Instant
import space.kscience.kmath.operations.algebra
import space.kscience.kmath.operations.bufferAlgebra
import kotlin.time.Duration
fun SeriesAlgebra.Companion.time(zero: Instant, step: Duration) = MonotonicSeriesAlgebra(
bufferAlgebra = Double.algebra.bufferAlgebra,
offsetToLabel = { zero + step * it },
labelToOffset = { (it - zero) / step }
)

@ -1,65 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.series
import kotlinx.html.h1
import kotlinx.html.p
import space.kscience.kmath.operations.algebra
import space.kscience.kmath.operations.bufferAlgebra
import space.kscience.kmath.operations.toList
import space.kscience.kmath.stat.KMComparisonResult
import space.kscience.kmath.stat.ksComparisonStatistic
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.structures.slice
import space.kscience.plotly.*
import kotlin.math.PI
fun Double.Companion.seriesAlgebra() = Double.algebra.bufferAlgebra.seriesAlgebra()
fun main() = with(Double.seriesAlgebra()) {
fun Plot.plotSeries(name: String, buffer: Buffer<Float64>) {
scatter {
this.name = name
x.numbers = buffer.labels
y.numbers = buffer.toList()
}
}
val s1 = series(100) { sin(2 * PI * it / 100) + 1.0 }
val s2 = s1.slice(20..50).moveTo(40)
val s3: Buffer<Float64> = s1.zip(s2) { l, r -> l + r } //s1 + s2
val s4 = s3.map { ln(it) }
val kmTest: KMComparisonResult<Float64> = ksComparisonStatistic(s1, s2)
Plotly.page {
h1 { +"This is my plot" }
p {
+"Kolmogorov-smirnov test for s1 and s2: ${kmTest.value}"
}
plot {
plotSeries("s1", s1)
plotSeries("s2", s2)
plotSeries("s3", s3)
plotSeries("s4", s4)
layout {
xaxis {
range(0.0..100.0)
}
}
}
}.makeFile()
}

@ -1,47 +0,0 @@
/*
* Copyright 2018-2023 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.series
import space.kscience.kmath.structures.*
import space.kscience.plotly.*
import space.kscience.plotly.models.Scatter
import space.kscience.plotly.models.ScatterMode
import kotlin.random.Random
fun main(): Unit = with(Double.seriesAlgebra()) {
val random = Random(1234)
val arrayOfRandoms = DoubleArray(20) { random.nextDouble() }
val series1: Float64Buffer = arrayOfRandoms.asBuffer()
val series2: Series<Float64> = series1.moveBy(3)
val res = series2 - series1
println(res.size)
println(res)
fun Plot.series(name: String, buffer: Buffer<Float64>, block: Scatter.() -> Unit = {}) {
scatter {
this.name = name
x.numbers = buffer.offsetIndices
y.doubles = buffer.toDoubleArray()
block()
}
}
Plotly.plot {
series("series1", series1)
series("series2", series2)
series("dif", res) {
mode = ScatterMode.lines
line.color("magenta")
}
}.makeFile(resourceLocation = ResourceLocation.REMOTE)
}

@ -1,94 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.stat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.apache.commons.rng.sampling.distribution.BoxMullerNormalizedGaussianSampler
import org.apache.commons.rng.simple.RandomSource
import space.kscience.kmath.random.RandomGenerator
import space.kscience.kmath.samplers.GaussianSampler
import java.time.Duration
import java.time.Instant
import org.apache.commons.rng.sampling.distribution.GaussianSampler as CMGaussianSampler
private suspend fun runKMathChained(): Duration {
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
val normal = GaussianSampler(7.0, 2.0)
val chain = normal.sample(generator)
val startTime = Instant.now()
var sum = 0.0
repeat(10000001) { counter ->
sum += chain.next()
if (counter % 100000 == 0) {
val duration = Duration.between(startTime, Instant.now())
val meanValue = sum / counter
println("Chain sampler completed $counter elements in $duration: $meanValue")
}
}
return Duration.between(startTime, Instant.now())
}
private fun runKMathBlocking(): Duration {
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
val normal = GaussianSampler(7.0, 2.0)
val chain = normal.sample(generator)
val startTime = Instant.now()
var sum = 0.0
repeat(10000001) { counter ->
sum += chain.nextBlocking()
if (counter % 100000 == 0) {
val duration = Duration.between(startTime, Instant.now())
val meanValue = sum / counter
println("Chain sampler completed $counter elements in $duration: $meanValue")
}
}
return Duration.between(startTime, Instant.now())
}
private fun runCMDirect(): Duration {
val rng = RandomSource.MT.create(123L)
val sampler = CMGaussianSampler.of(
BoxMullerNormalizedGaussianSampler.of(rng),
7.0,
2.0
)
val startTime = Instant.now()
var sum = 0.0
repeat(10000001) { counter ->
sum += sampler.sample()
if (counter % 100000 == 0) {
val duration = Duration.between(startTime, Instant.now())
val meanValue = sum / counter
println("Direct sampler completed $counter elements in $duration: $meanValue")
}
}
return Duration.between(startTime, Instant.now())
}
/**
* Comparing chain sampling performance with direct sampling performance
*/
fun main(): Unit = runBlocking(Dispatchers.Default) {
val directJob = async { runCMDirect() }
val chainJob = async { runKMathChained() }
val blockingJob = async { runKMathBlocking() }
println("KMath Chained: ${chainJob.await()}")
println("KMath Blocking: ${blockingJob.await()}")
println("Apache Direct: ${directJob.await()}")
}

@ -1,40 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.stat
import kotlinx.coroutines.runBlocking
import space.kscience.kmath.chains.Chain
import space.kscience.kmath.chains.combineWithState
import space.kscience.kmath.distributions.NormalDistribution
import space.kscience.kmath.random.RandomGenerator
import space.kscience.kmath.structures.Float64
private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
/**
* Averaging.
*/
private fun Chain<Float64>.mean(): Chain<Float64> = combineWithState(AveragingChainState(), { it.copy() }) { chain ->
val next = chain.next()
num++
value += next
return@combineWithState value / num
}
fun main() {
val normal = NormalDistribution(0.0, 2.0)
val chain = normal.sample(RandomGenerator.default).mean()
runBlocking {
repeat(10001) { counter ->
val mean = chain.next()
if (counter % 1000 == 0) {
println("[$counter] Average value is $mean")
}
}
}
}

@ -1,66 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("unused")
package space.kscience.kmath.structures
import space.kscience.kmath.complex.*
import space.kscience.kmath.linear.transposed
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.nd.structureND
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.invoke
import kotlin.system.measureTimeMillis
fun main() {
val dim = 1000
val n = 1000
val realField = Float64Field.ndAlgebra(dim, dim)
val complexField: ComplexFieldND = ComplexField.ndAlgebra(dim, dim)
val realTime = measureTimeMillis {
realField {
var res: StructureND<Float64> = one
repeat(n) {
res += 1.0
}
}
}
println("Real addition completed in $realTime millis")
val complexTime = measureTimeMillis {
complexField {
var res: StructureND<Complex> = one
repeat(n) {
res += 1.0
}
}
}
println("Complex addition completed in $complexTime millis")
}
fun complexExample() {
//Create a context for 2-d structure with complex values
ComplexField {
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)
//a structure generator specific to this context
val matrix = structureND { (k, l) -> k + l * i }
//Perform sum
val sum = matrix + x + 1.0
//Represent the sum as 2d-structure and transpose
sum.as2D().transposed()
}
}
}

@ -1,80 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.structures
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.viktor.ViktorFieldND
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.system.measureTimeMillis
internal inline fun measureAndPrint(title: String, block: () -> Unit) {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
val time = measureTimeMillis(block)
println("$title completed in $time millis")
}
@OptIn(DelicateCoroutinesApi::class)
fun main() {
// initializing Nd4j
val dim = 1000
val n = 1000
val shape = ShapeND(dim, dim)
// specialized nd-field for Double. It works as generic Double field as well.
val doubleField = Float64Field.ndAlgebra
//A generic field. It should be used for objects, not primitives.
val genericField = BufferedFieldOpsND(Float64Field)
//viktor field
val viktorField = ViktorFieldND(dim, dim)
//parallel processing based on Java Streams
val parallelField = Float64Field.ndStreaming(dim, dim)
measureAndPrint("Boxing addition") {
genericField {
var res: StructureND<Float64> = one(shape)
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Specialized addition") {
doubleField {
var res: StructureND<Float64> = one(shape)
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Viktor addition") {
viktorField {
var res: StructureND<Float64> = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Parallel stream addition") {
parallelField {
var res: StructureND<Float64> = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Lazy addition") {
val res = doubleField.one(shape).mapAsync(GlobalScope) {
var c = 0.0
repeat(n) {
c += 1.0
}
c
}
res.elements().forEach { it.second }
}
}

@ -1,127 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.structures
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.NumbersAddOps
import java.util.*
import java.util.stream.IntStream
/**
* A demonstration implementation of NDField over Real using Java [java.util.stream.DoubleStream] for parallel
* execution.
*/
class StreamDoubleFieldND(override val shape: ShapeND) : FieldND<Double, Float64Field>,
NumbersAddOps<StructureND<Float64>>,
ExtendedField<StructureND<Float64>> {
private val strides = ColumnStrides(shape)
override val elementAlgebra: Float64Field get() = Float64Field
override val zero: BufferND<Float64> by lazy { structureND(shape) { zero } }
override val one: BufferND<Float64> by lazy { structureND(shape) { one } }
override fun number(value: Number): BufferND<Float64> {
val d = value.toDouble() // minimize conversions
return structureND(shape) { d }
}
@OptIn(PerformancePitfall::class)
private val StructureND<Float64>.buffer: Float64Buffer
get() = when {
shape != this@StreamDoubleFieldND.shape -> throw ShapeMismatchException(
this@StreamDoubleFieldND.shape,
shape
)
this is BufferND && indices == this@StreamDoubleFieldND.strides -> this.buffer as Float64Buffer
else -> Float64Buffer(strides.linearSize) { offset -> get(strides.index(offset)) }
}
override fun structureND(shape: ShapeND, initializer: Float64Field.(IntArray) -> Double): BufferND<Float64> {
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
val index = strides.index(offset)
Float64Field.initializer(index)
}.toArray()
return BufferND(strides, array.asBuffer())
}
override fun mutableStructureND(
shape: ShapeND,
initializer: DoubleField.(IntArray) -> Double,
): MutableBufferND<Float64> {
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
val index = strides.index(offset)
DoubleField.initializer(index)
}.toArray()
return MutableBufferND(strides, array.asBuffer())
}
@OptIn(PerformancePitfall::class)
override fun StructureND<Float64>.map(
transform: Float64Field.(Double) -> Double,
): BufferND<Float64> {
val array = Arrays.stream(buffer.array).parallel().map { Float64Field.transform(it) }.toArray()
return BufferND(strides, array.asBuffer())
}
@OptIn(PerformancePitfall::class)
override fun StructureND<Float64>.mapIndexed(
transform: Float64Field.(index: IntArray, Double) -> Double,
): BufferND<Float64> {
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
Float64Field.transform(
strides.index(offset),
buffer.array[offset]
)
}.toArray()
return BufferND(strides, array.asBuffer())
}
@OptIn(PerformancePitfall::class)
override fun zip(
left: StructureND<Float64>,
right: StructureND<Float64>,
transform: Float64Field.(Double, Double) -> Double,
): BufferND<Float64> {
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
Float64Field.transform(left.buffer.array[offset], right.buffer.array[offset])
}.toArray()
return BufferND(strides, array.asBuffer())
}
override fun StructureND<Float64>.unaryMinus(): StructureND<Float64> = map { -it }
override fun scale(a: StructureND<Float64>, value: Double): StructureND<Float64> = a.map { it * value }
override fun power(arg: StructureND<Float64>, pow: Number): BufferND<Float64> = arg.map { power(it, pow) }
override fun exp(arg: StructureND<Float64>): BufferND<Float64> = arg.map { exp(it) }
override fun ln(arg: StructureND<Float64>): BufferND<Float64> = arg.map { ln(it) }
override fun sin(arg: StructureND<Float64>): BufferND<Float64> = arg.map { sin(it) }
override fun cos(arg: StructureND<Float64>): BufferND<Float64> = arg.map { cos(it) }
override fun tan(arg: StructureND<Float64>): BufferND<Float64> = arg.map { tan(it) }
override fun asin(arg: StructureND<Float64>): BufferND<Float64> = arg.map { asin(it) }
override fun acos(arg: StructureND<Float64>): BufferND<Float64> = arg.map { acos(it) }
override fun atan(arg: StructureND<Float64>): BufferND<Float64> = arg.map { atan(it) }
override fun sinh(arg: StructureND<Float64>): BufferND<Float64> = arg.map { sinh(it) }
override fun cosh(arg: StructureND<Float64>): BufferND<Float64> = arg.map { cosh(it) }
override fun tanh(arg: StructureND<Float64>): BufferND<Float64> = arg.map { tanh(it) }
override fun asinh(arg: StructureND<Float64>): BufferND<Float64> = arg.map { asinh(it) }
override fun acosh(arg: StructureND<Float64>): BufferND<Float64> = arg.map { acosh(it) }
override fun atanh(arg: StructureND<Float64>): BufferND<Float64> = arg.map { atanh(it) }
}
fun Float64Field.ndStreaming(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(ShapeND(shape))

@ -1,45 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.structures
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.ColumnStrides
import space.kscience.kmath.nd.ShapeND
import kotlin.system.measureTimeMillis
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
@OptIn(PerformancePitfall::class)
fun main() {
val n = 6000
val array = DoubleArray(n * n) { 1.0 }
val buffer = Float64Buffer(array)
val strides = ColumnStrides(ShapeND(n, n))
val structure = BufferND(strides, buffer)
measureTimeMillis {
var res = 0.0
strides.asSequence().forEach { res = structure[it] }
} // warmup
val time1 = measureTimeMillis {
var res = 0.0
strides.asSequence().forEach { res = structure[it] }
}
println("Structure reading finished in $time1 millis")
val time2 = measureTimeMillis {
var res = 0.0
strides.asSequence().forEach { res = buffer[strides.offset(it)] }
}
println("Buffer reading finished in $time2 millis")
val time3 = measureTimeMillis {
var res = 0.0
strides.asSequence().forEach { res = array[strides.offset(it)] }
}
println("Array reading finished in $time3 millis")
}

@ -1,42 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.structures
import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.operations.mapToBuffer
import kotlin.system.measureTimeMillis
private inline fun <T, reified R : Any> BufferND<T>.mapToBufferND(
bufferFactory: BufferFactory<R> = BufferFactory(),
crossinline block: (T) -> R,
): BufferND<R> = BufferND(indices, buffer.mapToBuffer(bufferFactory, block))
@Suppress("UNUSED_VARIABLE")
fun main() {
val n = 6000
val structure = BufferND(n, n) { 1.0 }
structure.mapToBufferND { it + 1 } // warm-up
val time1 = measureTimeMillis { val res = structure.mapToBufferND { it + 1 } }
println("Structure mapping finished in $time1 millis")
val array = DoubleArray(n * n) { 1.0 }
val time2 = measureTimeMillis {
val target = DoubleArray(n * n)
val res = array.forEachIndexed { index, value -> target[index] = value + 1 }
}
println("Array mapping finished in $time2 millis")
val buffer = Float64Buffer(DoubleArray(n * n) { 1.0 })
val time3 = measureTimeMillis {
val target = Float64Buffer(DoubleArray(n * n))
val res = array.forEachIndexed { index, value ->
target[index] = value + 1
}
}
println("Buffer mapping finished in $time3 millis")
}

@ -1,23 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.structures
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.buffer
import space.kscience.kmath.operations.bufferAlgebra
import space.kscience.kmath.operations.withSize
inline fun <reified R : Any> MutableBuffer.Companion.same(
n: Int,
value: R,
): MutableBuffer<R> = MutableBuffer(n) { value }
fun main() {
with(Float64Field.bufferAlgebra.withSize(5)) {
println(number(2.0) + buffer(1, 2, 3, 4, 5))
}
}

@ -1,26 +0,0 @@
/*
* Copyright 2018-2023 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.structures
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.algebra
@OptIn(PerformancePitfall::class)
fun main(): Unit = with(Double.algebra.ndAlgebra) {
val structure: MutableStructure2D<Float64> = mutableStructureND(ShapeND(2, 2)) { (i, j) ->
i.toDouble() + j.toDouble()
}.as2D()
structure[0, 1] = -2.0
val structure2 = mutableStructureND(2, 2) { (i, j) -> i.toDouble() + j.toDouble() }.as2D()
structure2[0, 1] = 2.0
println(structure + structure2)
}

@ -1,35 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.structures
import space.kscience.kmath.dimensions.D2
import space.kscience.kmath.dimensions.D3
import space.kscience.kmath.dimensions.DMatrixContext
import space.kscience.kmath.dimensions.Dimension
private fun DMatrixContext<Double, *>.simple() {
val m1 = produce<D2, D3> { i, j -> (i + j).toDouble() }
val m2 = produce<D3, D2> { i, j -> (i + j).toDouble() }
//Dimension-safe addition
m1.transposed() + m2
}
private object D5 : Dimension {
override val dim: Int = 5
}
private fun DMatrixContext<Double, *>.custom() {
val m1 = produce<D2, D5> { i, j -> (i + j).toDouble() }
val m2 = produce<D5, D2> { i, j -> (i - j).toDouble() }
val m3 = produce<D2, D2> { i, j -> (i - j).toDouble() }
(m1 dot m2) + m3
}
fun main(): Unit = with(DMatrixContext.real) {
simple()
custom()
}

@ -1,92 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors.LevenbergMarquardt.StaticLm
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.component1
import space.kscience.kmath.tensors.LevenbergMarquardt.funcDifficultForLm
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.div
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.LMInput
import space.kscience.kmath.tensors.core.levenbergMarquardt
import kotlin.math.roundToInt
fun main() {
val NData = 200
var t_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(NData, 1))).as2D()
for (i in 0 until NData) {
t_example[i, 0] = t_example[i, 0] * (i + 1) - 104
}
val Nparams = 15
var p_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1))).as2D()
for (i in 0 until Nparams) {
p_example[i, 0] = p_example[i, 0] + i - 25
}
val exampleNumber = 1
var y_hat = funcDifficultForLm(t_example, p_example, exampleNumber)
var p_init = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(Nparams, 1))).as2D()
for (i in 0 until Nparams) {
p_init[i, 0] = (p_example[i, 0] + 0.9)
}
var t = t_example
val y_dat = y_hat
val weight = 1.0 / Nparams * 1.0 - 0.085
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
var p_min = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
p_min = p_min.div(1.0 / -50.0)
val p_max = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
p_min = p_min.div(1.0 / 50.0)
val opts = doubleArrayOf(3.0, 10000.0, 1e-6, 1e-6, 1e-6, 1e-6, 1e-2, 11.0, 9.0, 1.0)
// val opts = doubleArrayOf(3.0, 10000.0, 1e-6, 1e-6, 1e-6, 1e-6, 1e-3, 11.0, 9.0, 1.0)
val inputData = LMInput(
::funcDifficultForLm,
p_init.as2D(),
t,
y_dat,
weight,
dp,
p_min.as2D(),
p_max.as2D(),
opts[1].toInt(),
doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
doubleArrayOf(opts[6], opts[7], opts[8]),
opts[9].toInt(),
10,
1
)
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
println("Parameters:")
for (i in 0 until result.resultParameters.shape.component1()) {
val x = (result.resultParameters[i, 0] * 10000).roundToInt() / 10000.0
print("$x ")
}
println()
println("Y true and y received:")
var y_hat_after = funcDifficultForLm(t_example, result.resultParameters, exampleNumber)
for (i in 0 until y_hat.shape.component1()) {
val x = (y_hat[i, 0] * 10000).roundToInt() / 10000.0
val y = (y_hat_after[i, 0] * 10000).roundToInt() / 10000.0
println("$x $y")
}
println("Сhi_sq:")
println(result.resultChiSq)
println("Number of iterations:")
println(result.iterations)
}

@ -1,59 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors.LevenbergMarquardt.StaticLm
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.component1
import space.kscience.kmath.tensors.LevenbergMarquardt.funcDifficultForLm
import space.kscience.kmath.tensors.LevenbergMarquardt.funcEasyForLm
import space.kscience.kmath.tensors.LevenbergMarquardt.getStartDataForFuncEasy
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.LMInput
import space.kscience.kmath.tensors.core.levenbergMarquardt
import kotlin.math.roundToInt
fun main() {
val startedData = getStartDataForFuncEasy()
val inputData = LMInput(
::funcEasyForLm,
DoubleTensorAlgebra.ones(ShapeND(intArrayOf(4, 1))).as2D(),
startedData.t,
startedData.y_dat,
startedData.weight,
startedData.dp,
startedData.p_min,
startedData.p_max,
startedData.opts[1].toInt(),
doubleArrayOf(startedData.opts[2], startedData.opts[3], startedData.opts[4], startedData.opts[5]),
doubleArrayOf(startedData.opts[6], startedData.opts[7], startedData.opts[8]),
startedData.opts[9].toInt(),
10,
startedData.example_number
)
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
println("Parameters:")
for (i in 0 until result.resultParameters.shape.component1()) {
val x = (result.resultParameters[i, 0] * 10000).roundToInt() / 10000.0
print("$x ")
}
println()
println("Y true and y received:")
var y_hat_after = funcDifficultForLm(startedData.t, result.resultParameters, startedData.example_number)
for (i in 0 until startedData.y_dat.shape.component1()) {
val x = (startedData.y_dat[i, 0] * 10000).roundToInt() / 10000.0
val y = (y_hat_after[i, 0] * 10000).roundToInt() / 10000.0
println("$x $y")
}
println("Сhi_sq:")
println(result.resultChiSq)
println("Number of iterations:")
println(result.iterations)
}

@ -1,91 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors.LevenbergMarquardt.StaticLm
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.component1
import space.kscience.kmath.tensors.LevenbergMarquardt.funcMiddleForLm
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.div
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.LMInput
import space.kscience.kmath.tensors.core.levenbergMarquardt
import kotlin.math.roundToInt
fun main() {
val NData = 100
var t_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(NData, 1))).as2D()
for (i in 0 until NData) {
t_example[i, 0] = t_example[i, 0] * (i + 1)
}
val Nparams = 20
var p_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1))).as2D()
for (i in 0 until Nparams) {
p_example[i, 0] = p_example[i, 0] + i - 25
}
val exampleNumber = 1
var y_hat = funcMiddleForLm(t_example, p_example, exampleNumber)
var p_init = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(Nparams, 1))).as2D()
for (i in 0 until Nparams) {
p_init[i, 0] = (p_example[i, 0] + 0.9)
}
var t = t_example
val y_dat = y_hat
val weight = 1.0
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
var p_min = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
p_min = p_min.div(1.0 / -50.0)
val p_max = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
p_min = p_min.div(1.0 / 50.0)
val opts = doubleArrayOf(3.0, 7000.0, 1e-5, 1e-5, 1e-5, 1e-5, 1e-5, 11.0, 9.0, 1.0)
val inputData = LMInput(
::funcMiddleForLm,
p_init.as2D(),
t,
y_dat,
weight,
dp,
p_min.as2D(),
p_max.as2D(),
opts[1].toInt(),
doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
doubleArrayOf(opts[6], opts[7], opts[8]),
opts[9].toInt(),
10,
1
)
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
println("Parameters:")
for (i in 0 until result.resultParameters.shape.component1()) {
val x = (result.resultParameters[i, 0] * 10000).roundToInt() / 10000.0
print("$x ")
}
println()
var y_hat_after = funcMiddleForLm(t_example, result.resultParameters, exampleNumber)
for (i in 0 until y_hat.shape.component1()) {
val x = (y_hat[i, 0] * 10000).roundToInt() / 10000.0
val y = (y_hat_after[i, 0] * 10000).roundToInt() / 10000.0
println("$x $y")
}
println("Сhi_sq:")
println(result.resultChiSq)
println("Number of iterations:")
println(result.iterations)
}

@ -1,76 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors.LevenbergMarquardt.StreamingLm
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import space.kscience.kmath.nd.MutableStructure2D
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.component1
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.tensors.LevenbergMarquardt.StartDataLm
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.zeros
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.LMInput
import space.kscience.kmath.tensors.core.levenbergMarquardt
import kotlin.random.Random
fun streamLm(
lm_func: (MutableStructure2D<Float64>, MutableStructure2D<Float64>, Int) -> (MutableStructure2D<Float64>),
startData: StartDataLm, launchFrequencyInMs: Long, numberOfLaunches: Int,
): Flow<MutableStructure2D<Float64>> = flow {
var example_number = startData.example_number
var p_init = startData.p_init
var t = startData.t
var y_dat = startData.y_dat
val weight = startData.weight
val dp = startData.dp
val p_min = startData.p_min
val p_max = startData.p_max
val opts = startData.opts
var steps = numberOfLaunches
val isEndless = (steps <= 0)
val inputData = LMInput(
lm_func,
p_init,
t,
y_dat,
weight,
dp,
p_min,
p_max,
opts[1].toInt(),
doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
doubleArrayOf(opts[6], opts[7], opts[8]),
opts[9].toInt(),
10,
example_number
)
while (isEndless || steps > 0) {
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
emit(result.resultParameters)
delay(launchFrequencyInMs)
inputData.realValues = generateNewYDat(y_dat, 0.1)
inputData.startParameters = result.resultParameters
if (!isEndless) steps -= 1
}
}
fun generateNewYDat(y_dat: MutableStructure2D<Float64>, delta: Double): MutableStructure2D<Float64> {
val n = y_dat.shape.component1()
val y_dat_new = zeros(ShapeND(intArrayOf(n, 1))).as2D()
for (i in 0 until n) {
val randomEps = Random.nextDouble(delta + delta) - delta
y_dat_new[i, 0] = y_dat[i, 0] + randomEps
}
return y_dat_new
}

@ -1,33 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors.LevenbergMarquardt.StreamingLm
import space.kscience.kmath.nd.component1
import space.kscience.kmath.tensors.LevenbergMarquardt.funcDifficultForLm
import space.kscience.kmath.tensors.LevenbergMarquardt.getStartDataForFuncDifficult
import kotlin.math.roundToInt
suspend fun main() {
val startData = getStartDataForFuncDifficult()
// Создание потока:
val lmFlow = streamLm(::funcDifficultForLm, startData, 0, 100)
var initialTime = System.currentTimeMillis()
var lastTime: Long
val launches = mutableListOf<Long>()
// Запуск потока
lmFlow.collect { parameters ->
lastTime = System.currentTimeMillis()
launches.add(lastTime - initialTime)
initialTime = lastTime
for (i in 0 until parameters.shape.component1()) {
val x = (parameters[i, 0] * 10000).roundToInt() / 10000.0
print("$x ")
if (i == parameters.shape.component1() - 1) println()
}
}
println("Average without first is: ${launches.subList(1, launches.size - 1).average()}")
}

@ -1,233 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors.LevenbergMarquardt
import space.kscience.kmath.nd.MutableStructure2D
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.component1
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.div
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.max
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.plus
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.pow
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.times
import space.kscience.kmath.tensors.core.asDoubleTensor
public data class StartDataLm(
var lm_matx_y_dat: MutableStructure2D<Float64>,
var example_number: Int,
var p_init: MutableStructure2D<Float64>,
var t: MutableStructure2D<Float64>,
var y_dat: MutableStructure2D<Float64>,
var weight: Double,
var dp: MutableStructure2D<Float64>,
var p_min: MutableStructure2D<Float64>,
var p_max: MutableStructure2D<Float64>,
var consts: MutableStructure2D<Float64>,
var opts: DoubleArray,
)
fun funcEasyForLm(
t: MutableStructure2D<Float64>,
p: MutableStructure2D<Float64>,
exampleNumber: Int,
): MutableStructure2D<Float64> {
val m = t.shape.component1()
var y_hat = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(m, 1)))
if (exampleNumber == 1) {
y_hat = DoubleTensorAlgebra.exp((t.times(-1.0 / p[1, 0]))).times(p[0, 0]) + t.times(p[2, 0]).times(
DoubleTensorAlgebra.exp((t.times(-1.0 / p[3, 0])))
)
} else if (exampleNumber == 2) {
val mt = t.max()
y_hat = (t.times(1.0 / mt)).times(p[0, 0]) +
(t.times(1.0 / mt)).pow(2).times(p[1, 0]) +
(t.times(1.0 / mt)).pow(3).times(p[2, 0]) +
(t.times(1.0 / mt)).pow(4).times(p[3, 0])
} else if (exampleNumber == 3) {
y_hat = DoubleTensorAlgebra.exp((t.times(-1.0 / p[1, 0])))
.times(p[0, 0]) + DoubleTensorAlgebra.sin((t.times(1.0 / p[3, 0]))).times(p[2, 0])
}
return y_hat.as2D()
}
fun funcMiddleForLm(
t: MutableStructure2D<Float64>,
p: MutableStructure2D<Float64>,
exampleNumber: Int,
): MutableStructure2D<Float64> {
val m = t.shape.component1()
var y_hat = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(m, 1)))
val mt = t.max()
for (i in 0 until p.shape.component1()) {
y_hat += (t.times(1.0 / mt)).times(p[i, 0])
}
for (i in 0 until 5) {
y_hat = funcEasyForLm(y_hat.as2D(), p, exampleNumber).asDoubleTensor()
}
return y_hat.as2D()
}
fun funcDifficultForLm(
t: MutableStructure2D<Float64>,
p: MutableStructure2D<Float64>,
exampleNumber: Int,
): MutableStructure2D<Float64> {
val m = t.shape.component1()
var y_hat = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(m, 1)))
val mt = t.max()
for (i in 0 until p.shape.component1()) {
y_hat = y_hat.plus((t.times(1.0 / mt)).times(p[i, 0]))
}
for (i in 0 until 4) {
y_hat = funcEasyForLm((y_hat.as2D() + t).as2D(), p, exampleNumber).asDoubleTensor()
}
return y_hat.as2D()
}
fun getStartDataForFuncDifficult(): StartDataLm {
val NData = 200
var t_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(NData, 1))).as2D()
for (i in 0 until NData) {
t_example[i, 0] = t_example[i, 0] * (i + 1) - 104
}
val Nparams = 15
var p_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1))).as2D()
for (i in 0 until Nparams) {
p_example[i, 0] = p_example[i, 0] + i - 25
}
val exampleNumber = 1
var y_hat = funcDifficultForLm(t_example, p_example, exampleNumber)
var p_init = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(Nparams, 1))).as2D()
for (i in 0 until Nparams) {
p_init[i, 0] = (p_example[i, 0] + 0.9)
}
var t = t_example
val y_dat = y_hat
val weight = 1.0 / Nparams * 1.0 - 0.085
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
var p_min = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
p_min = p_min.div(1.0 / -50.0)
val p_max = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
p_min = p_min.div(1.0 / 50.0)
val consts = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), doubleArrayOf(0.0)
).as2D()
val opts = doubleArrayOf(3.0, 10000.0, 1e-2, 1e-3, 1e-2, 1e-2, 1e-2, 11.0, 9.0, 1.0)
return StartDataLm(y_dat, 1, p_init, t, y_dat, weight, dp, p_min.as2D(), p_max.as2D(), consts, opts)
}
fun getStartDataForFuncMiddle(): StartDataLm {
val NData = 100
var t_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(NData, 1))).as2D()
for (i in 0 until NData) {
t_example[i, 0] = t_example[i, 0] * (i + 1)
}
val Nparams = 20
var p_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1))).as2D()
for (i in 0 until Nparams) {
p_example[i, 0] = p_example[i, 0] + i - 25
}
val exampleNumber = 1
var y_hat = funcMiddleForLm(t_example, p_example, exampleNumber)
var p_init = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(Nparams, 1))).as2D()
for (i in 0 until Nparams) {
p_init[i, 0] = (p_example[i, 0] + 10.0)
}
var t = t_example
val y_dat = y_hat
val weight = 1.0
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
var p_min = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
p_min = p_min.div(1.0 / -50.0)
val p_max = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
p_min = p_min.div(1.0 / 50.0)
val consts = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), doubleArrayOf(0.0)
).as2D()
val opts = doubleArrayOf(3.0, 10000.0, 1e-5, 1e-5, 1e-5, 1e-5, 1e-5, 11.0, 9.0, 1.0)
var example_number = 1
return StartDataLm(y_dat, example_number, p_init, t, y_dat, weight, dp, p_min.as2D(), p_max.as2D(), consts, opts)
}
fun getStartDataForFuncEasy(): StartDataLm {
val lm_matx_y_dat = doubleArrayOf(
19.6594, 18.6096, 17.6792, 17.2747, 16.3065, 17.1458, 16.0467, 16.7023, 15.7809, 15.9807,
14.7620, 15.1128, 16.0973, 15.1934, 15.8636, 15.4763, 15.6860, 15.1895, 15.3495, 16.6054,
16.2247, 15.9854, 16.1421, 17.0960, 16.7769, 17.1997, 17.2767, 17.5882, 17.5378, 16.7894,
17.7648, 18.2512, 18.1581, 16.7037, 17.8475, 17.9081, 18.3067, 17.9632, 18.2817, 19.1427,
18.8130, 18.5658, 18.0056, 18.4607, 18.5918, 18.2544, 18.3731, 18.7511, 19.3181, 17.3066,
17.9632, 19.0513, 18.7528, 18.2928, 18.5967, 17.8567, 17.7859, 18.4016, 18.9423, 18.4959,
17.8000, 18.4251, 17.7829, 17.4645, 17.5221, 17.3517, 17.4637, 17.7563, 16.8471, 17.4558,
17.7447, 17.1487, 17.3183, 16.8312, 17.7551, 17.0942, 15.6093, 16.4163, 15.3755, 16.6725,
16.2332, 16.2316, 16.2236, 16.5361, 15.3721, 15.3347, 15.5815, 15.6319, 14.4538, 14.6044,
14.7665, 13.3718, 15.0587, 13.8320, 14.7873, 13.6824, 14.2579, 14.2154, 13.5818, 13.8157
)
var example_number = 1
val p_init = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(4, 1)), doubleArrayOf(5.0, 2.0, 0.2, 10.0)
).as2D()
var t = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(100, 1))).as2D()
for (i in 0 until 100) {
t[i, 0] = t[i, 0] * (i + 1)
}
val y_dat = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(100, 1)), lm_matx_y_dat
).as2D()
val weight = 4.0
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
val p_min = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(4, 1)), doubleArrayOf(-50.0, -20.0, -2.0, -100.0)
).as2D()
val p_max = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(4, 1)), doubleArrayOf(50.0, 20.0, 2.0, 100.0)
).as2D()
val consts = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), doubleArrayOf(0.0)
).as2D()
val opts = doubleArrayOf(3.0, 100.0, 1e-3, 1e-3, 1e-1, 1e-1, 1e-2, 11.0, 9.0, 1.0)
return StartDataLm(y_dat, example_number, p_init, t, y_dat, weight, dp, p_min, p_max, consts, opts)
}

@ -1,72 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.tensors.core.DoubleTensor
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.randomNormal
import space.kscience.kmath.tensors.core.randomNormalLike
import kotlin.math.abs
// OLS estimator using SVD
fun main() {
//seed for random
val randSeed = 100500L
// work in context with linear operations
DoubleTensorAlgebra {
// take coefficient vector from normal distribution
val alpha = randomNormal(
ShapeND(5),
randSeed
) + fromArray(
ShapeND(5),
doubleArrayOf(1.0, 2.5, 3.4, 5.0, 10.1)
)
println("Real alpha:\n$alpha")
// also take sample of size 20 from normal distribution for x
val x = randomNormal(
ShapeND(20, 5),
randSeed
)
// calculate y and add gaussian noise (N(0, 0.05))
val y = x dot alpha
y += randomNormalLike(y, randSeed) * 0.05
// now restore the coefficient vector with OSL estimator with SVD
val (u, singValues, v) = svd(x)
// we have to make sure the singular values of the matrix are not close to zero
println("Singular values:\n$singValues")
// inverse Sigma matrix can be restored from singular values with diagonalEmbedding function
val sigma = diagonalEmbedding(singValues.map { if (abs(it) < 1e-3) 0.0 else 1.0 / it })
val alphaOLS = v dot sigma dot u.transposed() dot y
println(
"Estimated alpha:\n" +
"$alphaOLS"
)
// figure out MSE of approximation
fun mse(yTrue: DoubleTensor, yPred: DoubleTensor): Double {
require(yTrue.shape.size == 1)
require(yTrue.shape == yPred.shape)
val diff = yTrue - yPred
return sqrt(diff.dot(diff)).value()
}
println("MSE: ${mse(alpha, alphaOLS)}")
}
}

@ -1,74 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.tensors.core.*
// simple PCA
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(
ShapeND(10),
DoubleArray(10) { it.toDouble() }
)
// take y dependent on x with noise
val y = 2.0 * x + (3.0 + randomNormalLike(x, seed) * 1.5)
println("x:\n$x")
println("y:\n$y")
// stack them into single dataset
val dataset = stack(listOf(x, y)).transposed()
// normalize both x and y
val xMean = mean(x)
val yMean = mean(y)
val xStd = std(x)
val yStd = std(y)
val xScaled: DoubleTensor = (x - xMean) / xStd
val yScaled: DoubleTensor = (y - yMean) / yStd
// save means ans standard deviations for further recovery
val mean = fromArray(
ShapeND(2),
doubleArrayOf(xMean, yMean)
)
println("Means:\n$mean")
val std = fromArray(
ShapeND(2),
doubleArrayOf(xStd, yStd)
)
println("Standard deviations:\n$std")
// calculate the covariance matrix of scaled x and y
val covMatrix = covariance(listOf(xScaled.asDoubleTensor1D(), yScaled.asDoubleTensor1D()))
println("Covariance matrix:\n$covMatrix")
// and find out eigenvector of it
val (_, evecs) = symEig(covMatrix)
val v = evecs.getTensor(0)
println("Eigenvector:\n$v")
// reduce dimension of dataset
val datasetReduced = v dot stack(listOf(xScaled, yScaled))
println("Reduced data:\n$datasetReduced")
// we can restore original data from reduced data;
// for example, find 7th element of dataset.
val n = 7
val restored = (datasetReduced.getTensor(n) dot v.view(ShapeND(1, 2))) * std + mean
println("Original value:\n${dataset.getTensor(n)}")
println("Restored value:\n$restored")
}

@ -1,44 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.tensors.core.randomNormal
import space.kscience.kmath.tensors.core.tensorAlgebra
import space.kscience.kmath.tensors.core.withBroadcast
// Dataset normalization
fun main() = Double.tensorAlgebra.withBroadcast { // work in context with broadcast methods
// take dataset of 5-element vectors from normal distribution
val dataset = randomNormal(ShapeND(100, 5)) * 1.5 // all elements from N(0, 1.5)
dataset += fromArray(
ShapeND(5),
doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // row means
)
// find out mean and standard deviation of each column
val mean = mean(dataset, 0, false)
val std = std(dataset, 0, false)
println("Mean:\n$mean")
println("Standard deviation:\n$std")
// also, we can calculate other statistic as minimum and maximum of rows
println("Minimum:\n${dataset.min(0, false)}")
println("Maximum:\n${dataset.max(0, false)}")
// now we can scale dataset with mean normalization
val datasetScaled = (dataset - mean) / std
// find out mean and standardDiviation of scaled dataset
println("Mean of scaled:\n${mean(datasetScaled, 0, false)}")
println("Mean of scaled:\n${std(datasetScaled, 0, false)}")
}

@ -1,94 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.ShapeND
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() = Double.tensorAlgebra.withBroadcast {// work in context with linear operations
// set true value of x
val trueX = fromArray(
ShapeND(4),
doubleArrayOf(-2.0, 1.5, 6.8, -2.4)
)
// and A matrix
val a = fromArray(
ShapeND(4, 4),
doubleArrayOf(
0.5, 10.5, 4.5, 1.0,
8.5, 0.9, 12.8, 0.1,
5.56, 9.19, 7.62, 5.45,
1.0, 2.0, -3.0, -2.5
)
)
// calculate y value
val b = a dot trueX
// check out A and b
println("A:\n$a")
println("b:\n$b")
// solve `Ax = b` system using LUP decomposition
// get P, L, U such that PA = LU
val (p, l, u) = lu(a)
// check P is permutation matrix
println("P:\n$p")
// L is lower triangular matrix and U is upper triangular matrix
println("L:\n$l")
println("U:\n$u")
// and PA = LU
println("PA:\n${p dot a}")
println("LU:\n${l dot u}")
/* Ax = b;
PAx = Pb;
LUx = Pb;
let y = Ux, then
Ly = Pb -- this system can be easily solved, since the matrix L is lower triangular;
Ux = y can be solved the same way, since the matrix L is upper triangular
*/
// this function returns solution x of a system lx = b, l should be lower triangular
fun solveLT(l: DoubleTensor, b: DoubleTensor): DoubleTensor {
val n = l.shape[0]
val x = zeros(ShapeND(n))
for (i in 0 until n) {
x[intArrayOf(i)] = (b[intArrayOf(i)] - l.getTensor(i).dot(x).value()) / l[intArrayOf(i, i)]
}
return x
}
val y = solveLT(l, p dot b)
// solveLT(l, b) function can be easily adapted for upper triangular matrix by the permutation matrix revMat
// create it by placing ones on side diagonal
val revMat = zeroesLike(u)
val n = revMat.shape[0]
for (i in 0 until n) {
revMat[intArrayOf(i, n - 1 - i)] = 1.0
}
// solution of system ux = b, u should be upper triangular
fun solveUT(u: DoubleTensor, b: DoubleTensor): DoubleTensor = revMat dot solveLT(
revMat dot u dot revMat, revMat dot b
)
val x = solveUT(u, y)
println("True x:\n$trueX")
println("x founded with LU method:\n$x")
}

@ -1,22 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors
import org.jetbrains.kotlinx.multik.api.Multik
import org.jetbrains.kotlinx.multik.api.ndarray
import org.jetbrains.kotlinx.multik.default.DefaultEngine
import space.kscience.kmath.multik.MultikDoubleAlgebra
import space.kscience.kmath.nd.one
import space.kscience.kmath.structures.Float64
val multikAlgebra = MultikDoubleAlgebra(DefaultEngine())
fun main(): Unit = with(multikAlgebra) {
val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType<Float64>().wrap()
val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)).wrap()
one(a.shape) - a + b * 3.0
}

@ -1,236 +0,0 @@
/*
* Copyright 2018-2024 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.operations.asIterable
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.tensors.core.*
import kotlin.math.sqrt
const val seed = 100500L
// Simple feedforward neural network with backpropagation training
// interface of network layer
interface Layer {
fun forward(input: DoubleTensor): DoubleTensor
fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor
}
// activation layer
open class Activation(
val activation: (DoubleTensor) -> DoubleTensor,
val activationDer: (DoubleTensor) -> DoubleTensor,
) : Layer {
override fun forward(input: DoubleTensor): DoubleTensor {
return activation(input)
}
override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor {
return DoubleTensorAlgebra { outputError * activationDer(input) }
}
}
fun relu(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
x.map { if (it > 0) it else 0.0 }
}
fun reluDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
x.map { if (it > 0) 1.0 else 0.0 }
}
// activation layer with relu activator
class ReLU : Activation(::relu, ::reluDer)
fun sigmoid(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
1.0 / (1.0 + exp((-x)))
}
fun sigmoidDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
sigmoid(x) * (1.0 - sigmoid(x))
}
// activation layer with sigmoid activator
class Sigmoid : Activation(::sigmoid, ::sigmoidDer)
// dense layer
class Dense(
private val inputUnits: Int,
private val outputUnits: Int,
private val learningRate: Double = 0.1,
) : Layer {
private val weights: DoubleTensor = DoubleTensorAlgebra {
randomNormal(
ShapeND(inputUnits, outputUnits),
seed
) * sqrt(2.0 / (inputUnits + outputUnits))
}
private val bias: DoubleTensor = DoubleTensorAlgebra { zeros(ShapeND(outputUnits)) }
override fun forward(input: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra {
(input dot weights) + bias
}
override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
val gradInput = outputError dot weights.transposed()
val gradW = input.transposed() dot outputError
val gradBias = mean(structureND = outputError, dim = 0, keepDim = false) * input.shape[0].toDouble()
weights -= learningRate * gradW
bias -= learningRate * gradBias
gradInput
}
}
// simple accuracy equal to the proportion of correct answers
fun accuracy(yPred: DoubleTensor, yTrue: DoubleTensor): Double {
check(yPred.shape == yTrue.shape)
val n = yPred.shape[0]
var correctCnt = 0
for (i in 0 until n) {
if (yPred[intArrayOf(i, 0)] == yTrue[intArrayOf(i, 0)]) {
correctCnt += 1
}
}
return correctCnt.toDouble() / n.toDouble()
}
// neural network class
class NeuralNetwork(private val layers: List<Layer>) {
private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra {
val onesForAnswers = zeroesLike(yPred)
yTrue.source.asIterable().forEachIndexed { index, labelDouble ->
val label = labelDouble.toInt()
onesForAnswers[intArrayOf(index, label)] = 1.0
}
val softmaxValue = exp(yPred) / exp(yPred).sum(dim = 1, keepDim = true)
(-onesForAnswers + softmaxValue) / (yPred.shape[0].toDouble())
}
private fun forward(x: DoubleTensor): List<DoubleTensor> {
var input = x
return buildList {
layers.forEach { layer ->
val output = layer.forward(input)
add(output)
input = output
}
}
}
private fun train(xTrain: DoubleTensor, yTrain: DoubleTensor) {
val layerInputs = buildList {
add(xTrain)
addAll(forward(xTrain))
}
var lossGrad = softMaxLoss(layerInputs.last(), yTrain)
layers.zip(layerInputs).reversed().forEach { (layer, input) ->
lossGrad = layer.backward(input, lossGrad)
}
}
fun fit(xTrain: DoubleTensor, yTrain: DoubleTensor, batchSize: Int, epochs: Int) = DoubleTensorAlgebra {
fun iterBatch(x: DoubleTensor, y: DoubleTensor): Sequence<Pair<DoubleTensor, DoubleTensor>> = sequence {
val n = x.shape[0]
val shuffledIndices = (0 until n).shuffled()
for (i in 0 until n step batchSize) {
val excerptIndices = shuffledIndices.drop(i).take(batchSize).toIntArray()
val batch = x.rowsByIndices(excerptIndices) to y.rowsByIndices(excerptIndices)
yield(batch)
}
}
for (epoch in 0 until epochs) {
println("Epoch ${epoch + 1}/$epochs")
for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) {
train(xBatch, yBatch)
}
println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true).toDoubleTensor())}")
}
}
fun predict(x: DoubleTensor): DoubleTensor {
return forward(x).last()
}
}
fun main() = BroadcastDoubleTensorAlgebra {
val features = 5
val sampleSize = 250
val trainSize = 180
//val testSize = sampleSize - trainSize
// take sample of features from normal distribution
val x = randomNormal(ShapeND(sampleSize, features), seed) * 2.5
x += fromArray(
ShapeND(5),
doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // row means
)
// define class like '1' if the sum of features > 0 and '0' otherwise
val y = fromArray(
ShapeND(sampleSize, 1),
DoubleArray(sampleSize) { i ->
if (x.getTensor(i).sum() > 0.0) {
1.0
} else {
0.0
}
}
)
// split train ans test
val trainIndices = (0 until trainSize).toList().toIntArray()
val testIndices = (trainSize until sampleSize).toList().toIntArray()
val xTrain = x.rowsByIndices(trainIndices)
val yTrain = y.rowsByIndices(trainIndices)
val xTest = x.rowsByIndices(testIndices)
val yTest = y.rowsByIndices(testIndices)
// build model
val layers = buildList {
add(Dense(features, 64))
add(ReLU())
add(Dense(64, 16))
add(ReLU())
add(Dense(16, 2))
add(Sigmoid())
}
val model = NeuralNetwork(layers)
// fit it with train data
model.fit(xTrain, yTrain, batchSize = 20, epochs = 10)
// make prediction
val prediction = model.predict(xTest)
// process raw prediction via argMax
val predictionLabels = prediction.argMax(1, true).toDoubleTensor()
// find out accuracy
val acc = accuracy(yTest, predictionLabels)
println("Test accuracy:$acc")
}

@ -1,16 +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.
#
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx4096m
org.gradle.parallel=true
org.gradle.workers.max=4
kotlin.code.style=official
kotlin.mpp.stability.nowarn=true
kotlin.native.ignoreDisabledTargets=true
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
kotlin.native.enableKlibsCrossCompilation=true
toolsVersion=0.16.1-kotlin-2.1.0

@ -1,28 +0,0 @@
[versions]
commons-rng = "1.6"
multik = "0.2.3"
nd4j = "1.0.0-M2.1"
tensorflow = "1.0.0"
[libraries]
attributes = "space.kscience:attributes-kt:0.3.0"
commons-math = "org.apache.commons:commons-math3:3.6.1"
commons-rng-simple = { module = "org.apache.commons:commons-rng-simple", version.ref = "commons-rng" }
commons-rng-sampling = { module = "org.apache.commons:commons-rng-sampling", version.ref = "commons-rng" }
multik-core = { module = "org.jetbrains.kotlinx:multik-core", version.ref = "multik" }
multik-default = { module = "org.jetbrains.kotlinx:multik-default", version.ref = "multik" }
nd4j-api = { module = "org.nd4j:nd4j-api", version.ref = "nd4j" }
nd4j-native-platform = { module = "org.nd4j:nd4j-native-platform", version.ref = "nd4j" }
ojalgo = "org.ojalgo:ojalgo:55.1.0"
tensorflow-core-api = {module = "org.tensorflow:tensorflow-core-api", version.ref="tensorflow"}
tensorflow-core-platform = {module = "org.tensorflow:tensorflow-core-platform", version.ref="tensorflow"}
[plugins]

Binary file not shown.

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

234
gradlew vendored

@ -1,234 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# 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
#
# https://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.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
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
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
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
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 ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
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
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
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
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
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
# 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.
# 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" "$@"

89
gradlew.bat vendored

@ -1,89 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.2496 5.3C20.3496 4.5 19.2496 4 18.0496 4C16.8496 4 15.6496 4.5 14.8496 5.3L10.3496 9.8L11.7496 11.2L16.2496 6.7C17.2496 5.7 18.8496 5.7 19.8496 6.7C20.8496 7.7 20.8496 9.3 19.8496 10.3L15.3496 14.8L16.7496 16.2L21.2496 11.7C22.1496 10.8 22.5496 9.7 22.5496 8.5C22.5496 7.3 22.1496 6.2 21.2496 5.3Z" fill="#637282"/>
<path d="M8.35 16.7998C7.35 17.7998 5.75 17.7998 4.75 16.7998C3.75 15.7998 3.75 14.1998 4.75 13.1998L9.25 8.6998L7.85 7.2998L3.35 11.7998C1.55 13.5998 1.55 16.3998 3.35 18.1998C4.25 19.0998 5.35 19.4998 6.55 19.4998C7.75 19.4998 8.85 19.0998 9.75 18.1998L14.25 13.6998L12.85 12.2998L8.35 16.7998Z" fill="#637282"/>
</svg>

After

(image error) Size: 754 B

3
images/arrow_down.svg Normal file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="-5 -3 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 9l-6 5.25V3.75z" fill="currentColor"/>
</svg>

After

(image error) Size: 160 B

3
images/copy-icon.svg Normal file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 4H15V16H5V4ZM17 7H19V18V20H17H8V18H17V7Z" fill="black"/>
</svg>

After

(image error) Size: 215 B

Some files were not shown because too many files have changed in this diff Show More