Compare commits

...

9 Commits

Author SHA1 Message Date
fd9da63ef9 Prepare for 0.4.0 release 2024-02-18 15:05:56 +03:00
024e2a1a4f Add .kotlin to gitignore 2024-02-18 14:26:47 +03:00
41a325d428 fix dot bug introduced in the last refactor. Add test for parallel linear algebra. 2024-02-18 14:22:20 +03:00
79642a869d LUP cleanup 2024-02-18 14:00:38 +03:00
fbee95ab8b LUP cleanup 2024-02-18 13:32:22 +03:00
10739e0d04 Performance fixes 2024-02-18 12:27:46 +03:00
f8e91c2402 Finishing fixes 2024-02-17 21:32:26 +03:00
7d88fb0166 Merge branch 'dev' into dev-0.4
# Conflicts:
#	kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt
2024-02-16 18:57:57 +03:00
ca9df8a167 Add more corner cases for complex power 2024-02-08 18:06:06 +03:00
131 changed files with 2743 additions and 2210 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ out/
.idea/ .idea/
.vscode/ .vscode/
.fleet/ .fleet/
.kotlin/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)

View File

@ -3,14 +3,33 @@
## Unreleased ## Unreleased
### Added ### Added
### Changed
### Deprecated
### Removed
### Fixed
### Security
## 0.4.0-dev-3 - 2024-02-18
### Added
- Reification. Explicit `SafeType` for algebras and buffers. - Reification. Explicit `SafeType` for algebras and buffers.
- Integer division algebras. - Integer division algebras.
- Float32 geometries. - Float32 geometries.
- New Attributes-kt module that could be used as stand-alone. It declares. type-safe attributes containers. - New Attributes-kt module that could be used as stand-alone. It declares. type-safe attributes containers.
- Explicit `mutableStructureND` builders for mutable structures. - Explicit `mutableStructureND` builders for mutable structures.
- `Buffer.asList()` zero-copy transformation. - `Buffer.asList()` zero-copy transformation.
- Wasm support.
- Parallel implementation of `LinearSpace` for Float64
- Parallel buffer factories
### Changed ### Changed
- Default naming for algebra and buffers now uses IntXX/FloatXX notation instead of Java types. - Default naming for algebra and buffers now uses IntXX/FloatXX notation instead of Java types.
- Remove unnecessary inlines in basic algebras. - Remove unnecessary inlines in basic algebras.
- QuaternionField -> QuaternionAlgebra and does not implement `Field` anymore since it is non-commutative - QuaternionField -> QuaternionAlgebra and does not implement `Field` anymore since it is non-commutative
@ -21,18 +40,23 @@
### Deprecated ### Deprecated
- ND4J engine
### Removed ### Removed
- `asPolynomial` function due to scope pollution - `asPolynomial` function due to scope pollution
- Codegend for ejml (450 lines of codegen for 1000 lines of code is too much)
### Fixed ### Fixed
- Median statistics - Median statistics
- Complex power of negative real numbers - Complex power of negative real numbers
- Add proper mutability for MutableBufferND rows and columns
### Security
## 0.3.1 - 2023-04-09 ## 0.3.1 - 2023-04-09
### Added ### Added
- Wasm support for `memory`, `core`, `complex` and `functions` modules. - Wasm support for `memory`, `core`, `complex` and `functions` modules.
- Generic builders for `BufferND` and `MutableBufferND` - Generic builders for `BufferND` and `MutableBufferND`
- `NamedMatrix` - matrix with symbol-based indexing - `NamedMatrix` - matrix with symbol-based indexing
@ -42,6 +66,7 @@
- Algebra now has an obligatory `bufferFactory` (#477). - Algebra now has an obligatory `bufferFactory` (#477).
### Changed ### Changed
- Removed marker `Vector` type for geometry - Removed marker `Vector` type for geometry
- Geometry uses type-safe angles - Geometry uses type-safe angles
- Tensor operations switched to prefix notation - Tensor operations switched to prefix notation
@ -54,12 +79,14 @@
- Multik went MPP - Multik went MPP
### Removed ### Removed
- Trajectory moved to https://github.com/SciProgCentre/maps-kt - Trajectory moved to https://github.com/SciProgCentre/maps-kt
- Polynomials moved to https://github.com/SciProgCentre/kmath-polynomial - Polynomials moved to https://github.com/SciProgCentre/kmath-polynomial
## 0.3.0 ## 0.3.0
### Added ### Added
- `ScaleOperations` interface - `ScaleOperations` interface
- `Field` extends `ScaleOperations` - `Field` extends `ScaleOperations`
- Basic integration API - Basic integration API
@ -84,6 +111,7 @@
- Compilation to TeX for MST: #254 - Compilation to TeX for MST: #254
### Changed ### Changed
- Annotations moved to `space.kscience.kmath` - Annotations moved to `space.kscience.kmath`
- Exponential operations merged with hyperbolic functions - Exponential operations merged with hyperbolic functions
- Space is replaced by Group. Space is reserved for vector spaces. - Space is replaced by Group. Space is reserved for vector spaces.
@ -117,9 +145,11 @@
- `UnivariateFunction` -> `Function1D`, `MultivariateFunction` -> `FunctionND` - `UnivariateFunction` -> `Function1D`, `MultivariateFunction` -> `FunctionND`
### Deprecated ### Deprecated
- Specialized `DoubleBufferAlgebra` - Specialized `DoubleBufferAlgebra`
### Removed ### Removed
- Nearest in Domain. To be implemented in geometry package. - Nearest in Domain. To be implemented in geometry package.
- Number multiplication and division in main Algebra chain - Number multiplication and division in main Algebra chain
- `contentEquals` from Buffer. It moved to the companion. - `contentEquals` from Buffer. It moved to the companion.
@ -130,12 +160,14 @@
- Algebra elements are completely removed. Use algebra contexts instead. - Algebra elements are completely removed. Use algebra contexts instead.
### Fixed ### Fixed
- Ring inherits RingOperations, not GroupOperations - Ring inherits RingOperations, not GroupOperations
- Univariate histogram filling - Univariate histogram filling
## 0.2.0 ## 0.2.0
### Added ### Added
- `fun` annotation for SAM interfaces in library - `fun` annotation for SAM interfaces in library
- Explicit `public` visibility for all public APIs - Explicit `public` visibility for all public APIs
- Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140) - Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140)
@ -155,6 +187,7 @@
- Basic Quaternion vector support in `kmath-complex`. - Basic Quaternion vector support in `kmath-complex`.
### Changed ### Changed
- Package changed from `scientifik` to `space.kscience` - Package changed from `scientifik` to `space.kscience`
- Gradle version: 6.6 -> 6.8.2 - Gradle version: 6.6 -> 6.8.2
- Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`) - Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`)
@ -179,6 +212,7 @@
- Add `out` projection to `Buffer` generic - Add `out` projection to `Buffer` generic
### Removed ### Removed
- `kmath-koma` module because it doesn't support Kotlin 1.4. - `kmath-koma` module because it doesn't support Kotlin 1.4.
- Support of `legacy` JS backend (we will support only IR) - Support of `legacy` JS backend (we will support only IR)
- `toGrid` method. - `toGrid` method.
@ -187,11 +221,13 @@
- StructureND identity and equals - StructureND identity and equals
### Fixed ### Fixed
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140) - `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
## 0.1.4 ## 0.1.4
### Added ### Added
- Functional Expressions API - Functional Expressions API
- Mathematical Syntax Tree, its interpreter and API - Mathematical Syntax Tree, its interpreter and API
- String to MST parser (https://github.com/mipt-npm/kmath/pull/120) - String to MST parser (https://github.com/mipt-npm/kmath/pull/120)
@ -209,6 +245,7 @@
- Norm support for `Complex` - Norm support for `Complex`
### Changed ### Changed
- `readAsMemory` now has `throws IOException` in JVM signature. - `readAsMemory` now has `throws IOException` in JVM signature.
- Several functions taking functional types were made `inline`. - Several functions taking functional types were made `inline`.
- Several functions taking functional types now have `callsInPlace` contracts. - Several functions taking functional types now have `callsInPlace` contracts.
@ -220,6 +257,7 @@
- Moved probability distributions to commons-rng and to `kmath-prob` - Moved probability distributions to commons-rng and to `kmath-prob`
### Fixed ### Fixed
- Missing copy method in Memory implementation on JS (https://github.com/mipt-npm/kmath/pull/106) - Missing copy method in Memory implementation on JS (https://github.com/mipt-npm/kmath/pull/106)
- D3.dim value in `kmath-dimensions` - D3.dim value in `kmath-dimensions`
- Multiplication in integer rings in `kmath-core` (https://github.com/mipt-npm/kmath/pull/101) - Multiplication in integer rings in `kmath-core` (https://github.com/mipt-npm/kmath/pull/101)

View File

@ -2,7 +2,7 @@
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) [![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) ![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) [![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/spc/p/sci/maven/space/kscience/) [![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
# KMath # KMath
@ -11,18 +11,21 @@ analog to Python's NumPy library. Later we found that kotlin is much more flexib
architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like 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. experience could be achieved with [kmath-for-real](/kmath-for-real) extension module.
[Documentation site (**WIP**)](https://SciProgCentre.github.io/kmath/) [Documentation site](https://SciProgCentre.github.io/kmath/)
## Publications and talks ## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2) * [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) * [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) * [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 # Goal
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native) * Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS, Native and Wasm).
.
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
* Provide bindings and wrappers with those abstractions for popular optimized platform libraries. * Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
@ -53,19 +56,21 @@ module definitions below. The module stability could have the following levels:
## Modules ## Modules
### [benchmarks](benchmarks) ### [attributes-kt](attributes-kt)
> An API and basic implementation for arranging objects in a continuous memory block.
> >
> **Maturity**: DEVELOPMENT
### [benchmarks](benchmarks)
> >
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
### [examples](examples) ### [examples](examples)
> >
>
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
### [kmath-ast](kmath-ast) ### [kmath-ast](kmath-ast)
> >
>
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
> >
> **Features:** > **Features:**
@ -76,7 +81,7 @@ module definitions below. The module stability could have the following levels:
### [kmath-commons](kmath-commons) ### [kmath-commons](kmath-commons)
> > Commons math binding for kmath
> >
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
@ -109,17 +114,15 @@ performance calculations to code generation.
### [kmath-coroutines](kmath-coroutines) ### [kmath-coroutines](kmath-coroutines)
> >
>
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
### [kmath-dimensions](kmath-dimensions) ### [kmath-dimensions](kmath-dimensions)
> > A proof of concept module for adding type-safe dimensions to structures
> >
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
### [kmath-ejml](kmath-ejml) ### [kmath-ejml](kmath-ejml)
> >
>
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
> >
> **Features:** > **Features:**
@ -142,7 +145,7 @@ One can still use generic algebras though.
### [kmath-functions](kmath-functions) ### [kmath-functions](kmath-functions)
> > Functions, integration and interpolation
> >
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
> >
@ -156,18 +159,16 @@ One can still use generic algebras though.
### [kmath-geometry](kmath-geometry) ### [kmath-geometry](kmath-geometry)
> >
>
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
### [kmath-histograms](kmath-histograms) ### [kmath-histograms](kmath-histograms)
> >
>
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
### [kmath-jafama](kmath-jafama) ### [kmath-jafama](kmath-jafama)
> Jafama integration module
> >
> > **Maturity**: DEPRECATED
> **Maturity**: PROTOTYPE
> >
> **Features:** > **Features:**
> - [jafama-double](kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama > - [jafama-double](kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama
@ -175,11 +176,10 @@ One can still use generic algebras though.
### [kmath-jupyter](kmath-jupyter) ### [kmath-jupyter](kmath-jupyter)
> >
>
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
### [kmath-kotlingrad](kmath-kotlingrad) ### [kmath-kotlingrad](kmath-kotlingrad)
> > Kotlin∇ integration module
> >
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
> >
@ -194,14 +194,14 @@ One can still use generic algebras though.
> **Maturity**: DEVELOPMENT > **Maturity**: DEVELOPMENT
### [kmath-multik](kmath-multik) ### [kmath-multik](kmath-multik)
> > JetBrains Multik connector
> >
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
### [kmath-nd4j](kmath-nd4j) ### [kmath-nd4j](kmath-nd4j)
> ND4J NDStructure implementation and according NDAlgebra classes
> >
> > **Maturity**: DEPRECATED
> **Maturity**: EXPERIMENTAL
> >
> **Features:** > **Features:**
> - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray > - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
@ -211,27 +211,24 @@ One can still use generic algebras though.
### [kmath-optimization](kmath-optimization) ### [kmath-optimization](kmath-optimization)
> >
>
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
### [kmath-stat](kmath-stat) ### [kmath-stat](kmath-stat)
> >
>
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
### [kmath-symja](kmath-symja) ### [kmath-symja](kmath-symja)
> > Symja integration module
> >
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
### [kmath-tensorflow](kmath-tensorflow) ### [kmath-tensorflow](kmath-tensorflow)
> > Google tensorflow connector
> >
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
### [kmath-tensors](kmath-tensors) ### [kmath-tensors](kmath-tensors)
> >
>
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
> >
> **Features:** > **Features:**
@ -241,13 +238,12 @@ One can still use generic algebras though.
### [kmath-viktor](kmath-viktor) ### [kmath-viktor](kmath-viktor)
> > Binding for https://github.com/JetBrains-Research/viktor
> >
> **Maturity**: DEVELOPMENT > **Maturity**: DEVELOPMENT
### [test-utils](test-utils) ### [test-utils](test-utils)
> >
>
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
@ -256,22 +252,21 @@ One can still use generic algebras though.
KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the 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 [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 are delegated to platform-specific implementations even if they could be provided in the common module for performance
reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and reasons. Currently, Kotlin/JVM is the primary platform, however, Kotlin/Native and Kotlin/JS contributions and
feedback are also welcome. feedback are also welcome.
## Performance ## Performance
Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both 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. performance and flexibility.
We expect to focus on creating convenient universal API first and then work on increasing performance for specific 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 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. native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy.
## Requirements ## Requirements
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for 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.
execution to get better performance.
### Repositories ### Repositories
@ -291,10 +286,7 @@ dependencies {
} }
``` ```
Gradle `6.0+` is required for multiplatform artifacts.
## Contributing ## Contributing
The project requires a lot of additional work. The most important thing we need is a feedback about what features are 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 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.
marked with [waiting for a hero](https://github.com/SciProgCentre/kmath/labels/waiting%20for%20a%20hero) label.

4
attributes-kt/README.md Normal file
View File

@ -0,0 +1,4 @@
# Module attributes-kt

View File

@ -0,0 +1,97 @@
public abstract interface class space/kscience/attributes/Attribute {
}
public abstract interface class space/kscience/attributes/AttributeContainer {
public abstract fun getAttributes ()Lspace/kscience/attributes/Attributes;
}
public abstract interface class space/kscience/attributes/AttributeScope {
}
public abstract interface class space/kscience/attributes/AttributeWithDefault : space/kscience/attributes/Attribute {
public abstract fun getDefault ()Ljava/lang/Object;
}
public abstract interface class space/kscience/attributes/Attributes {
public static final field Companion Lspace/kscience/attributes/Attributes$Companion;
public fun get (Lspace/kscience/attributes/Attribute;)Ljava/lang/Object;
public abstract fun getContent ()Ljava/util/Map;
public fun getKeys ()Ljava/util/Set;
}
public final class space/kscience/attributes/Attributes$Companion {
public final fun getEMPTY ()Lspace/kscience/attributes/Attributes;
}
public final class space/kscience/attributes/AttributesBuilder : space/kscience/attributes/Attributes {
public fun <init> ()V
public final fun add (Lspace/kscience/attributes/SetAttribute;Ljava/lang/Object;)V
public final fun build ()Lspace/kscience/attributes/Attributes;
public final fun from (Lspace/kscience/attributes/Attributes;)V
public fun getContent ()Ljava/util/Map;
public final fun invoke (Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)V
public final fun remove (Lspace/kscience/attributes/SetAttribute;Ljava/lang/Object;)V
public final fun set (Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)V
}
public final class space/kscience/attributes/AttributesBuilderKt {
public static final fun Attributes (Lkotlin/jvm/functions/Function1;)Lspace/kscience/attributes/Attributes;
}
public final class space/kscience/attributes/AttributesKt {
public static final fun Attributes (Lspace/kscience/attributes/Attribute;)Lspace/kscience/attributes/Attributes;
public static final fun Attributes (Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)Lspace/kscience/attributes/Attributes;
public static final fun getOrDefault (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/AttributeWithDefault;)Ljava/lang/Object;
public static final fun isEmpty (Lspace/kscience/attributes/Attributes;)Z
public static final fun modify (Lspace/kscience/attributes/Attributes;Lkotlin/jvm/functions/Function1;)Lspace/kscience/attributes/Attributes;
public static final fun plus (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/Attributes;)Lspace/kscience/attributes/Attributes;
public static final fun withAttribute (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/Attribute;)Lspace/kscience/attributes/Attributes;
public static final fun withAttribute (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)Lspace/kscience/attributes/Attributes;
public static final fun withAttributeElement (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/SetAttribute;Ljava/lang/Object;)Lspace/kscience/attributes/Attributes;
public static final fun withoutAttribute (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/Attribute;)Lspace/kscience/attributes/Attributes;
public static final fun withoutAttributeElement (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/SetAttribute;Ljava/lang/Object;)Lspace/kscience/attributes/Attributes;
}
public abstract interface class space/kscience/attributes/FlagAttribute : space/kscience/attributes/Attribute {
}
public abstract class space/kscience/attributes/PolymorphicAttribute : space/kscience/attributes/Attribute {
public synthetic fun <init> (Lkotlin/reflect/KType;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getType-V0oMfBY ()Lkotlin/reflect/KType;
public fun hashCode ()I
}
public final class space/kscience/attributes/PolymorphicAttributeKt {
public static final fun get (Lspace/kscience/attributes/Attributes;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
public static final fun set (Lspace/kscience/attributes/AttributesBuilder;Lkotlin/jvm/functions/Function0;Ljava/lang/Object;)V
}
public final class space/kscience/attributes/SafeType {
public static final synthetic fun box-impl (Lkotlin/reflect/KType;)Lspace/kscience/attributes/SafeType;
public static fun constructor-impl (Lkotlin/reflect/KType;)Lkotlin/reflect/KType;
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (Lkotlin/reflect/KType;Ljava/lang/Object;)Z
public static final fun equals-impl0 (Lkotlin/reflect/KType;Lkotlin/reflect/KType;)Z
public final fun getKType ()Lkotlin/reflect/KType;
public fun hashCode ()I
public static fun hashCode-impl (Lkotlin/reflect/KType;)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (Lkotlin/reflect/KType;)Ljava/lang/String;
public final synthetic fun unbox-impl ()Lkotlin/reflect/KType;
}
public final class space/kscience/attributes/SafeTypeKt {
public static final fun getKClass-X0YbwmU (Lkotlin/reflect/KType;)Lkotlin/reflect/KClass;
}
public abstract interface class space/kscience/attributes/SetAttribute : space/kscience/attributes/Attribute {
}
public abstract interface annotation class space/kscience/attributes/UnstableAttributesAPI : java/lang/annotation/Annotation {
}
public abstract interface class space/kscience/attributes/WithType {
public abstract fun getType-V0oMfBY ()Lkotlin/reflect/KType;
}

View File

@ -2,6 +2,8 @@ plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.mpp")
} }
version = "0.1.0"
kscience { kscience {
jvm() jvm()
js() js()

View File

@ -5,6 +5,9 @@
package space.kscience.attributes package space.kscience.attributes
/**
* A marker interface for an attribute. Attributes are used as keys to access contents of type [T] in the container.
*/
public interface Attribute<T> public interface Attribute<T>
/** /**

View File

@ -13,7 +13,8 @@ public interface AttributeContainer {
} }
/** /**
* A scope, where attribute keys could be resolved * A scope, where attribute keys could be resolved.
* [O] is used only to resolve types in compile-time.
*/ */
public interface AttributeScope<O> public interface AttributeScope<O>

View File

@ -11,10 +11,19 @@ import kotlin.jvm.JvmInline
* A set of attributes. The implementation must guarantee that [content] keys correspond to its value types. * A set of attributes. The implementation must guarantee that [content] keys correspond to its value types.
*/ */
public interface Attributes { public interface Attributes {
/**
* Raw content for this [Attributes]
*/
public val content: Map<out Attribute<*>, Any?> public val content: Map<out Attribute<*>, Any?>
/**
* Attribute keys contained in this [Attributes]
*/
public val keys: Set<Attribute<*>> get() = content.keys public val keys: Set<Attribute<*>> get() = content.keys
/**
* Provide an attribute value. Return null if attribute is not present or if its value is null.
*/
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public operator fun <T> get(attribute: Attribute<T>): T? = content[attribute] as? T public operator fun <T> get(attribute: Attribute<T>): T? = content[attribute] as? T

View File

@ -99,7 +99,7 @@ class ExpressionsInterpretersBenchmark {
private val estree = node.estreeCompileToExpression(Float64Field) private val estree = node.estreeCompileToExpression(Float64Field)
private val raw = Expression<Double> { args -> private val raw = Expression<Double> { args ->
val x = args[x]!! val x = args.getValue(x)
x * 2.0 + 2.0 / x - 16.0 / sin(x) x * 2.0 + 2.0 / x - 16.0 / sin(x)
} }
} }

View File

@ -11,12 +11,11 @@ import kotlinx.benchmark.Scope
import kotlinx.benchmark.State import kotlinx.benchmark.State
import space.kscience.kmath.commons.linear.CMLinearSpace import space.kscience.kmath.commons.linear.CMLinearSpace
import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
import space.kscience.kmath.linear.Float64ParallelLinearSpace
import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.invoke
import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.linearSpace
import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.tensorflow.produceWithTF import space.kscience.kmath.tensorflow.produceWithTF
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.tensorAlgebra import space.kscience.kmath.tensors.core.tensorAlgebra
import kotlin.random.Random import kotlin.random.Random
@ -72,12 +71,12 @@ internal class DotBenchmark {
} }
@Benchmark @Benchmark
fun tensorDot(blackhole: Blackhole) = with(Float64Field.tensorAlgebra) { fun multikDot(blackhole: Blackhole) = with(multikAlgebra) {
blackhole.consume(matrix1 dot matrix2) blackhole.consume(matrix1 dot matrix2)
} }
@Benchmark @Benchmark
fun multikDot(blackhole: Blackhole) = with(multikAlgebra) { fun tensorDot(blackhole: Blackhole) = with(Float64Field.tensorAlgebra) {
blackhole.consume(matrix1 dot matrix2) blackhole.consume(matrix1 dot matrix2)
} }
@ -87,12 +86,8 @@ internal class DotBenchmark {
} }
@Benchmark @Benchmark
fun doubleDot(blackhole: Blackhole) = with(Float64Field.linearSpace) { fun parallelDot(blackhole: Blackhole) = with(Float64ParallelLinearSpace) {
blackhole.consume(matrix1 dot matrix2) blackhole.consume(matrix1 dot matrix2)
} }
@Benchmark
fun doubleTensorDot(blackhole: Blackhole) = DoubleTensorAlgebra.invoke {
blackhole.consume(matrix1 dot matrix2)
}
} }

View File

@ -15,6 +15,7 @@ import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.invoke
import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.linearSpace
import space.kscience.kmath.linear.lupSolver import space.kscience.kmath.linear.lupSolver
import space.kscience.kmath.linear.parallel
import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.algebra
import kotlin.random.Random import kotlin.random.Random
@ -38,16 +39,19 @@ internal class MatrixInverseBenchmark {
} }
@Benchmark @Benchmark
fun cmLUPInversion(blackhole: Blackhole) { fun kmathParallelLupInversion(blackhole: Blackhole) {
CMLinearSpace { blackhole.consume(Double.algebra.linearSpace.parallel.lupSolver().inverse(matrix))
blackhole.consume(lupSolver().inverse(matrix))
}
} }
@Benchmark @Benchmark
fun ejmlInverse(blackhole: Blackhole) { fun cmLUPInversion(blackhole: Blackhole) = CMLinearSpace {
EjmlLinearSpaceDDRM { blackhole.consume(lupSolver().inverse(matrix))
}
@Benchmark
fun ejmlInverse(blackhole: Blackhole) = EjmlLinearSpaceDDRM {
blackhole.consume(matrix.toEjml().inverted()) blackhole.consume(matrix.toEjml().inverted())
} }
}
} }

View File

@ -3,7 +3,7 @@ import space.kscience.gradle.useSPCTeam
plugins { plugins {
id("space.kscience.gradle.project") id("space.kscience.gradle.project")
id("org.jetbrains.kotlinx.kover") version "0.6.0" id("org.jetbrains.kotlinx.kover") version "0.7.6"
} }
allprojects { allprojects {
@ -14,7 +14,7 @@ allprojects {
} }
group = "space.kscience" group = "space.kscience"
version = "0.4.0-dev-3" version = "0.4.0"
} }
subprojects { subprojects {
@ -34,7 +34,7 @@ subprojects {
localDirectory.set(kotlinDir) localDirectory.set(kotlinDir)
remoteUrl.set( remoteUrl.set(
java.net.URL("https://github.com/SciProgCentre/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath") uri("https://github.com/SciProgCentre/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath").toURL()
) )
} }

View File

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

View File

@ -1,443 +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("KDocUnresolvedReference")
package space.kscience.kmath.ejml.codegen
import org.intellij.lang.annotations.Language
import java.io.File
private fun Appendable.appendEjmlVector(type: String, ejmlMatrixType: String) {
@Language("kotlin") val text = """/**
* [EjmlVector] specialization for [$type].
*/
public class Ejml${type}Vector<out M : $ejmlMatrixType>(override val origin: M) : EjmlVector<$type, M>(origin) {
init {
require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" }
}
override val type: SafeType<${type}> get() = safeTypeOf()
override operator fun get(index: Int): $type = origin[0, index]
}"""
appendLine(text)
appendLine()
}
private fun Appendable.appendEjmlMatrix(type: String, ejmlMatrixType: String) {
val text = """/**
* [EjmlMatrix] specialization for [$type].
*/
public class Ejml${type}Matrix<out M : $ejmlMatrixType>(override val origin: M) : EjmlMatrix<$type, M>(origin) {
override val type: SafeType<${type}> get() = safeTypeOf()
override operator fun get(i: Int, j: Int): $type = origin[i, j]
}"""
appendLine(text)
appendLine()
}
private fun Appendable.appendEjmlLinearSpace(
type: String,
kmathAlgebra: String,
ejmlMatrixParentTypeMatrix: String,
ejmlMatrixType: String,
ejmlMatrixDenseType: String,
ops: String,
denseOps: String,
isDense: Boolean,
) {
@Language("kotlin") val text = """
/**
* [EjmlLinearSpace] implementation based on [CommonOps_$ops], [DecompositionFactory_${ops}] operations and
* [${ejmlMatrixType}] matrices.
*/
public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, $ejmlMatrixType>() {
/**
* The [${kmathAlgebra}] reference.
*/
override val elementAlgebra: $kmathAlgebra get() = $kmathAlgebra
override val type: SafeType<${type}> get() = safeTypeOf()
@Suppress("UNCHECKED_CAST")
override fun Matrix<${type}>.toEjml(): Ejml${type}Matrix<${ejmlMatrixType}> = when {
this is Ejml${type}Matrix<*> && origin is $ejmlMatrixType -> this as Ejml${type}Matrix<${ejmlMatrixType}>
else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) }
}
@Suppress("UNCHECKED_CAST")
override fun Point<${type}>.toEjml(): Ejml${type}Vector<${ejmlMatrixType}> = when {
this is Ejml${type}Vector<*> && origin is $ejmlMatrixType -> this as Ejml${type}Vector<${ejmlMatrixType}>
else -> Ejml${type}Vector(${ejmlMatrixType}(size, 1).also {
(0 until it.numRows).forEach { row -> it[row, 0] = get(row) }
})
}
override fun buildMatrix(
rows: Int,
columns: Int,
initializer: ${kmathAlgebra}.(i: Int, j: Int) -> ${type},
): Ejml${type}Matrix<${ejmlMatrixType}> = ${ejmlMatrixType}(rows, columns).also {
(0 until rows).forEach { row ->
(0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) }
}
}.wrapMatrix()
override fun buildVector(
size: Int,
initializer: ${kmathAlgebra}.(Int) -> ${type},
): Ejml${type}Vector<${ejmlMatrixType}> = Ejml${type}Vector(${ejmlMatrixType}(size, 1).also {
(0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) }
})
private fun <T : ${ejmlMatrixParentTypeMatrix}> T.wrapMatrix() = Ejml${type}Matrix(this)
private fun <T : ${ejmlMatrixParentTypeMatrix}> T.wrapVector() = Ejml${type}Vector(this)
override fun Matrix<${type}>.unaryMinus(): Matrix<${type}> = this * elementAlgebra { -one }
override fun Matrix<${type}>.dot(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
val out = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.mult(toEjml().origin, other.toEjml().origin, out)
return out.wrapMatrix()
}
override fun Matrix<${type}>.dot(vector: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> {
val out = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.mult(toEjml().origin, vector.toEjml().origin, out)
return out.wrapVector()
}
override operator fun Matrix<${type}>.minus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
val out = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.add(
elementAlgebra.one,
toEjml().origin,
elementAlgebra { -one },
other.toEjml().origin,
out,${
if (isDense) "" else
"""
null,
null,"""
}
)
return out.wrapMatrix()
}
override operator fun Matrix<${type}>.times(value: ${type}): Ejml${type}Matrix<${ejmlMatrixType}> {
val res = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.scale(value, toEjml().origin, res)
return res.wrapMatrix()
}
override fun Point<${type}>.unaryMinus(): Ejml${type}Vector<${ejmlMatrixType}> {
val res = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.changeSign(toEjml().origin, res)
return res.wrapVector()
}
override fun Matrix<${type}>.plus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
val out = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.add(
elementAlgebra.one,
toEjml().origin,
elementAlgebra.one,
other.toEjml().origin,
out,${
if (isDense) "" else
"""
null,
null,"""
}
)
return out.wrapMatrix()
}
override fun Point<${type}>.plus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> {
val out = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.add(
elementAlgebra.one,
toEjml().origin,
elementAlgebra.one,
other.toEjml().origin,
out,${
if (isDense) "" else
"""
null,
null,"""
}
)
return out.wrapVector()
}
override fun Point<${type}>.minus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> {
val out = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.add(
elementAlgebra.one,
toEjml().origin,
elementAlgebra { -one },
other.toEjml().origin,
out,${
if (isDense) "" else
"""
null,
null,"""
}
)
return out.wrapVector()
}
override fun ${type}.times(m: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> = m * this
override fun Point<${type}>.times(value: ${type}): Ejml${type}Vector<${ejmlMatrixType}> {
val res = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.scale(value, toEjml().origin, res)
return res.wrapVector()
}
override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this
@UnstableKMathAPI
override fun <F : StructureFeature> computeFeature(structure: Matrix<${type}>, type: KClass<out F>): F? {
structure.getFeature(type)?.let { return it }
val origin = structure.toEjml().origin
return when (type) {
${
if (isDense)
""" InverseMatrixFeature::class -> object : InverseMatrixFeature<${type}> {
override val inverse: Matrix<${type}> by lazy {
val res = origin.copy()
CommonOps_${ops}.invert(res)
res.wrapMatrix()
}
}
DeterminantFeature::class -> object : DeterminantFeature<${type}> {
override val determinant: $type by lazy { CommonOps_${ops}.det(origin) }
}
SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<${type}> {
private val svd by lazy {
DecompositionFactory_${ops}.svd(origin.numRows, origin.numCols, true, true, false)
.apply { decompose(origin.copy()) }
}
override val u: Matrix<${type}> by lazy { svd.getU(null, false).wrapMatrix() }
override val s: Matrix<${type}> by lazy { svd.getW(null).wrapMatrix() }
override val v: Matrix<${type}> by lazy { svd.getV(null, false).wrapMatrix() }
override val singularValues: Point<${type}> by lazy { ${type}Buffer(svd.singularValues) }
}
QRDecompositionFeature::class -> object : QRDecompositionFeature<${type}> {
private val qr by lazy {
DecompositionFactory_${ops}.qr().apply { decompose(origin.copy()) }
}
override val q: Matrix<${type}> by lazy {
qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
}
override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
}
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> {
override val l: Matrix<${type}> by lazy {
val cholesky =
DecompositionFactory_${ops}.chol(structure.rowNum, true).apply { decompose(origin.copy()) }
cholesky.getT(null).wrapMatrix().withFeature(LFeature)
}
}
LupDecompositionFeature::class -> object : LupDecompositionFeature<${type}> {
private val lup by lazy {
DecompositionFactory_${ops}.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) }
}
override val l: Matrix<${type}> by lazy {
lup.getLower(null).wrapMatrix().withFeature(LFeature)
}
override val u: Matrix<${type}> by lazy {
lup.getUpper(null).wrapMatrix().withFeature(UFeature)
}
override val p: Matrix<${type}> by lazy { lup.getRowPivot(null).wrapMatrix() }
}""" else """ QRDecompositionFeature::class -> object : QRDecompositionFeature<$type> {
private val qr by lazy {
DecompositionFactory_${ops}.qr(FillReducing.NONE).apply { decompose(origin.copy()) }
}
override val q: Matrix<${type}> by lazy {
qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
}
override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
}
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> {
override val l: Matrix<${type}> by lazy {
val cholesky =
DecompositionFactory_${ops}.cholesky().apply { decompose(origin.copy()) }
(cholesky.getT(null) as ${ejmlMatrixParentTypeMatrix}).wrapMatrix().withFeature(LFeature)
}
}
LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object :
LUDecompositionFeature<${type}>, DeterminantFeature<${type}>, InverseMatrixFeature<${type}> {
private val lu by lazy {
DecompositionFactory_${ops}.lu(FillReducing.NONE).apply { decompose(origin.copy()) }
}
override val l: Matrix<${type}> by lazy {
lu.getLower(null).wrapMatrix().withFeature(LFeature)
}
override val u: Matrix<${type}> by lazy {
lu.getUpper(null).wrapMatrix().withFeature(UFeature)
}
override val inverse: Matrix<${type}> by lazy {
var a = origin
val inverse = ${ejmlMatrixDenseType}(1, 1)
val solver = LinearSolverFactory_${ops}.lu(FillReducing.NONE)
if (solver.modifiesA()) a = a.copy()
val i = CommonOps_${denseOps}.identity(a.numRows)
solver.solve(i, inverse)
inverse.wrapMatrix()
}
override val determinant: $type by lazy { elementAlgebra.number(lu.computeDeterminant().real) }
}"""
}
else -> null
}?.let{
type.cast(it)
}
}
/**
* Solves for *x* in the following equation: *x = [a] <sup>-1</sup> &middot; [b]*.
*
* @param a the base matrix.
* @param b n by p matrix.
* @return the solution for *x* that is n by p.
*/
public fun solve(a: Matrix<${type}>, b: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
val res = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.solve(${ejmlMatrixType}(a.toEjml().origin), ${ejmlMatrixType}(b.toEjml().origin), res)
return res.wrapMatrix()
}
/**
* Solves for *x* in the following equation: *x = [a] <sup>-1</sup> &middot; [b]*.
*
* @param a the base matrix.
* @param b n by p vector.
* @return the solution for *x* that is n by p.
*/
public fun solve(a: Matrix<${type}>, b: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> {
val res = ${ejmlMatrixType}(1, 1)
CommonOps_${ops}.solve(${ejmlMatrixType}(a.toEjml().origin), ${ejmlMatrixType}(b.toEjml().origin), res)
return Ejml${type}Vector(res)
}
}"""
appendLine(text)
appendLine()
}
/**
* Generates routine EJML classes.
*/
fun ejmlCodegen(outputFile: String): Unit = File(outputFile).run {
parentFile.mkdirs()
writer().use {
it.appendLine("/*")
it.appendLine(" * Copyright 2018-2024 KMath contributors.")
it.appendLine(" * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.")
it.appendLine(" */")
it.appendLine()
it.appendLine("/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */")
it.appendLine()
it.appendLine("package space.kscience.kmath.ejml")
it.appendLine()
it.appendLine("""import org.ejml.data.*
import org.ejml.dense.row.CommonOps_DDRM
import org.ejml.dense.row.CommonOps_FDRM
import org.ejml.dense.row.factory.DecompositionFactory_DDRM
import org.ejml.dense.row.factory.DecompositionFactory_FDRM
import org.ejml.sparse.FillReducing
import org.ejml.sparse.csc.CommonOps_DSCC
import org.ejml.sparse.csc.CommonOps_FSCC
import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC
import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC
import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC
import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.linear.*
import space.kscience.kmath.linear.Matrix
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.StructureFeature
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.structures.Float32
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.Float32Field
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.FloatField
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Float64Buffer
import space.kscience.kmath.structures.Float32Buffer
import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.FloatBuffer
import kotlin.reflect.KClass
import kotlin.reflect.cast""")
it.appendLine()
it.appendEjmlVector("Double", "DMatrix")
it.appendEjmlVector("Float", "FMatrix")
it.appendEjmlMatrix("Double", "DMatrix")
it.appendEjmlMatrix("Float", "FMatrix")
it.appendEjmlLinearSpace("Double", "Float64Field", "DMatrix", "DMatrixRMaj", "DMatrixRMaj", "DDRM", "DDRM", true)
it.appendEjmlLinearSpace("Float", "Float32Field", "FMatrix", "FMatrixRMaj", "FMatrixRMaj", "FDRM", "FDRM", true)
it.appendEjmlLinearSpace(
type = "Double",
kmathAlgebra = "Float64Field",
ejmlMatrixParentTypeMatrix = "DMatrix",
ejmlMatrixType = "DMatrixSparseCSC",
ejmlMatrixDenseType = "DMatrixRMaj",
ops = "DSCC",
denseOps = "DDRM",
isDense = false,
)
it.appendEjmlLinearSpace(
type = "Float",
kmathAlgebra = "Float32Field",
ejmlMatrixParentTypeMatrix = "FMatrix",
ejmlMatrixType = "FMatrixSparseCSC",
ejmlMatrixDenseType = "FMatrixRMaj",
ops = "FSCC",
denseOps = "FDRM",
isDense = false,
)
}
}

View File

@ -3,25 +3,10 @@
The Maven coordinates of this project are `${group}:${name}:${version}`. The Maven coordinates of this project are `${group}:${name}:${version}`.
**Gradle:** **Gradle:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
// development and snapshot versions
maven { url 'https://maven.pkg.jetbrains.space/spc/p/sci/dev' }
}
dependencies {
implementation '${group}:${name}:${version}'
}
```
**Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
maven("https://repo.kotlin.link") maven("https://repo.kotlin.link")
mavenCentral() mavenCentral()
// development and snapshot versions
maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
} }
dependencies { dependencies {

View File

@ -11,18 +11,21 @@ analog to Python's NumPy library. Later we found that kotlin is much more flexib
architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like 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. experience could be achieved with [kmath-for-real](/kmath-for-real) extension module.
[Documentation site (**WIP**)](https://SciProgCentre.github.io/kmath/) [Documentation site](https://SciProgCentre.github.io/kmath/)
## Publications and talks ## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2) * [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) * [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) * [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 # Goal
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native) * Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS, Native and Wasm).
.
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
* Provide bindings and wrappers with those abstractions for popular optimized platform libraries. * Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
@ -73,7 +76,7 @@ native/SciPy (mostly due to boxing operations on primitive numbers). The best pe
## Requirements ## Requirements
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend using GraalVM-CE 11/17 for execution to get better performance. 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 ### Repositories
@ -95,7 +98,5 @@ dependencies {
## Contributing ## Contributing
The project requires a lot of additional work. The most important thing we need is a feedback about what features are 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 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.
marked with
[good first issue](hhttps://github.com/SciProgCentre/kmath/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label.

View File

@ -13,10 +13,7 @@ import space.kscience.kmath.expressions.autodiff
import space.kscience.kmath.expressions.symbol import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.operations.asIterable import space.kscience.kmath.operations.asIterable
import space.kscience.kmath.operations.toList import space.kscience.kmath.operations.toList
import space.kscience.kmath.optimization.FunctionOptimizationTarget import space.kscience.kmath.optimization.*
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.random.RandomGenerator
import space.kscience.kmath.real.DoubleVector import space.kscience.kmath.real.DoubleVector
import space.kscience.kmath.real.map import space.kscience.kmath.real.map
@ -80,8 +77,9 @@ suspend fun main() {
val result = chi2.optimizeWith( val result = chi2.optimizeWith(
CMOptimizer, CMOptimizer,
mapOf(a to 1.5, b to 0.9, c to 1.0), mapOf(a to 1.5, b to 0.9, c to 1.0),
FunctionOptimizationTarget.MINIMIZE ){
) FunctionOptimizationTarget(OptimizationDirection.MINIMIZE)
}
//display a page with plot and numerical results //display a page with plot and numerical results
val page = Plotly.page { val page = Plotly.page {

View File

@ -7,6 +7,7 @@ package space.kscience.kmath.fit
import kotlinx.html.br import kotlinx.html.br
import kotlinx.html.h3 import kotlinx.html.h3
import space.kscience.attributes.Attributes
import space.kscience.kmath.data.XYErrorColumnarData import space.kscience.kmath.data.XYErrorColumnarData
import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.distributions.NormalDistribution
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol
@ -64,7 +65,7 @@ suspend fun main() {
QowOptimizer, QowOptimizer,
Double.autodiff, 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), mapOf(a to 0.9, b to 1.2, c to 2.0, e to 1.0, d to 1.0, e to 0.0),
OptimizationParameters(a, b, c, d) attributes = Attributes(OptimizationParameters, listOf(a, b, c, d))
) { arg -> ) { arg ->
//bind variables to autodiff context //bind variables to autodiff context
val a by binding val a by binding

View File

@ -8,7 +8,6 @@ package space.kscience.kmath.functions
import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.SplineInterpolator
import space.kscience.kmath.interpolation.interpolatePolynomials import space.kscience.kmath.interpolation.interpolatePolynomials
import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.structures.Float64Buffer
import space.kscience.plotly.Plotly import space.kscience.plotly.Plotly
import space.kscience.plotly.UnstablePlotlyAPI import space.kscience.plotly.UnstablePlotlyAPI
import space.kscience.plotly.makeFile import space.kscience.plotly.makeFile
@ -24,9 +23,7 @@ fun main() {
x to sin(x) x to sin(x)
} }
val polynomial: PiecewisePolynomial<Double> = SplineInterpolator( val polynomial: PiecewisePolynomial<Double> = SplineInterpolator(Float64Field).interpolatePolynomials(data)
Float64Field, ::Float64Buffer
).interpolatePolynomials(data)
val function = polynomial.asFunction(Float64Field, 0.0) val function = polynomial.asFunction(Float64Field, 0.0)

View File

@ -5,31 +5,26 @@
package space.kscience.kmath.linear package space.kscience.kmath.linear
import space.kscience.kmath.operations.algebra
import kotlin.random.Random import kotlin.random.Random
import kotlin.time.ExperimentalTime
import kotlin.time.measureTime import kotlin.time.measureTime
@OptIn(ExperimentalTime::class) fun main() = with(Float64ParallelLinearSpace) {
fun main() {
val random = Random(12224) val random = Random(12224)
val dim = 1000 val dim = 1000
//creating invertible matrix //creating invertible matrix
val matrix1 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> val matrix1 = buildMatrix(dim, dim) { i, j ->
if (i <= j) random.nextDouble() else 0.0 if (i <= j) random.nextDouble() else 0.0
} }
val matrix2 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> val matrix2 = buildMatrix(dim, dim) { i, j ->
if (i <= j) random.nextDouble() else 0.0 if (i <= j) random.nextDouble() else 0.0
} }
val time = measureTime { val time = measureTime {
with(Double.algebra.linearSpace) { repeat(30) {
repeat(10) {
matrix1 dot matrix2 matrix1 dot matrix2
} }
} }
}
println(time) println(time)

View File

@ -0,0 +1,27 @@
/*
* 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)
}

View File

@ -7,7 +7,7 @@ package space.kscience.kmath.series
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.Float64Buffer
import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.asBuffer
import space.kscience.kmath.structures.toDoubleArray import space.kscience.kmath.structures.toDoubleArray
import space.kscience.plotly.* import space.kscience.plotly.*
@ -21,7 +21,7 @@ fun main(): Unit = with(Double.seriesAlgebra()) {
val arrayOfRandoms = DoubleArray(20) { random.nextDouble() } val arrayOfRandoms = DoubleArray(20) { random.nextDouble() }
val series1: DoubleBuffer = arrayOfRandoms.asBuffer() val series1: Float64Buffer = arrayOfRandoms.asBuffer()
val series2: Series<Double> = series1.moveBy(3) val series2: Series<Double> = series1.moveBy(3)
val res = series2 - series1 val res = series2 - series1
@ -42,7 +42,7 @@ fun main(): Unit = with(Double.seriesAlgebra()) {
Plotly.plot { Plotly.plot {
series("series1", series1) series("series1", series1)
series("series2", series2) series("series2", series2)
series("dif", res){ series("dif", res) {
mode = ScatterMode.lines mode = ScatterMode.lines
line.color("magenta") line.color("magenta")
} }

View File

@ -8,7 +8,7 @@
package space.kscience.kmath.structures package space.kscience.kmath.structures
import space.kscience.kmath.complex.* import space.kscience.kmath.complex.*
import space.kscience.kmath.linear.transpose import space.kscience.kmath.linear.transposed
import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd.ndAlgebra
@ -60,7 +60,7 @@ fun complexExample() {
val sum = matrix + x + 1.0 val sum = matrix + x + 1.0
//Represent the sum as 2d-structure and transpose //Represent the sum as 2d-structure and transpose
sum.as2D().transpose() sum.as2D().transposed()
} }
} }
} }

View File

@ -7,6 +7,7 @@ package space.kscience.kmath.structures
import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.nd.* import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.NumbersAddOps

View File

@ -6,20 +6,18 @@
package space.kscience.kmath.structures package space.kscience.kmath.structures
import space.kscience.kmath.nd.BufferND import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.mapToBuffer import space.kscience.kmath.operations.mapToBuffer
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
private inline fun <T, reified R : Any> BufferND<T>.mapToBufferND( private inline fun <T, reified R : Any> BufferND<T>.mapToBufferND(
bufferFactory: BufferFactory<R> = BufferFactory.auto(), bufferFactory: BufferFactory<R> = BufferFactory(),
crossinline block: (T) -> R, crossinline block: (T) -> R,
): BufferND<R> = BufferND(indices, buffer.mapToBuffer(bufferFactory, block)) ): BufferND<R> = BufferND(indices, buffer.mapToBuffer(bufferFactory, block))
@Suppress("UNUSED_VARIABLE") @Suppress("UNUSED_VARIABLE")
fun main() { fun main() {
val n = 6000 val n = 6000
val structure = StructureND.buffered(ShapeND(n, n), Buffer.Companion::auto) { 1.0 } val structure = BufferND(n, n) { 1.0 }
structure.mapToBufferND { it + 1 } // warm-up structure.mapToBufferND { it + 1 } // warm-up
val time1 = measureTimeMillis { val res = structure.mapToBufferND { it + 1 } } val time1 = measureTimeMillis { val res = structure.mapToBufferND { it + 1 } }
println("Structure mapping finished in $time1 millis") println("Structure mapping finished in $time1 millis")

View File

@ -13,7 +13,7 @@ import space.kscience.kmath.operations.withSize
inline fun <reified R : Any> MutableBuffer.Companion.same( inline fun <reified R : Any> MutableBuffer.Companion.same(
n: Int, n: Int,
value: R value: R
): MutableBuffer<R> = auto(n) { value } ): MutableBuffer<R> = MutableBuffer(n) { value }
fun main() { fun main() {

View File

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

View File

@ -10,19 +10,8 @@ Extensions to MST API: transformations, dynamic compilation and visualization.
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-ast:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-ast:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-ast:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -31,7 +20,7 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-ast:0.4.0-dev-1") implementation("space.kscience:kmath-ast:0.4.0-dev-3")
} }
``` ```

View File

@ -6,19 +6,8 @@ Commons math binding for kmath
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-commons:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-commons:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-commons:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -27,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-commons:0.4.0-dev-1") implementation("space.kscience:kmath-commons:0.4.0-dev-3")
} }
``` ```

View File

@ -7,16 +7,20 @@ package space.kscience.kmath.commons.linear
import org.apache.commons.math3.linear.* import org.apache.commons.math3.linear.*
import org.apache.commons.math3.linear.LUDecomposition import org.apache.commons.math3.linear.LUDecomposition
import org.apache.commons.math3.linear.SingularValueDecomposition
import space.kscience.attributes.SafeType import space.kscience.attributes.SafeType
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.linear.* import space.kscience.kmath.linear.*
import space.kscience.kmath.linear.CholeskyDecomposition
import space.kscience.kmath.linear.QRDecomposition
import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.nd.Structure2D
import space.kscience.kmath.nd.StructureAttribute import space.kscience.kmath.nd.StructureAttribute
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.Float64
import kotlin.reflect.cast import space.kscience.kmath.structures.IntBuffer
import space.kscience.kmath.structures.asBuffer
public class CMMatrix(public val origin: RealMatrix) : Matrix<Double> { public class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
override val type: SafeType<Double> get() = DoubleField.type override val type: SafeType<Double> get() = DoubleField.type
@ -109,45 +113,44 @@ public object CMLinearSpace : LinearSpace<Double, Float64Field> {
val origin = structure.toCM().origin val origin = structure.toCM().origin
return when (attribute) { val raw: Any? = when (attribute) {
IsDiagonal -> if (origin is DiagonalMatrix) IsDiagonal else null IsDiagonal -> if (origin is DiagonalMatrix) Unit else null
Determinant -> LUDecomposition(origin).determinant Determinant -> LUDecomposition(origin).determinant
LUP -> GenericLupDecomposition {
private val lup by lazy { LUDecomposition(origin) } LUP -> object : LupDecomposition<Float64> {
override val determinant: Double by lazy { lup.determinant } val lup by lazy { LUDecomposition(origin) }
override val l: Matrix<Double> by lazy<Matrix<Double>> { CMMatrix(lup.l).withAttribute(LowerTriangular) } override val pivot: IntBuffer get() = lup.pivot.asBuffer()
override val u: Matrix<Double> by lazy<Matrix<Double>> { CMMatrix(lup.u).withAttribute(UpperTriangular) } override val l: Matrix<Float64> get() = lup.l.wrap()
override val p: Matrix<Double> by lazy { CMMatrix(lup.p) } override val u: Matrix<Float64> get() = lup.u.wrap()
} }
CholeskyDecompositionAttribute -> object : CholeskyDecompositionAttribute<Double> { Cholesky -> object : CholeskyDecomposition<Float64> {
override val l: Matrix<Double> by lazy<Matrix<Double>> { val cmCholesky by lazy { org.apache.commons.math3.linear.CholeskyDecomposition(origin) }
val cholesky = CholeskyDecomposition(origin) override val l: Matrix<Double> get() = cmCholesky.l.wrap()
CMMatrix(cholesky.l).withAttribute(LowerTriangular)
}
} }
QRDecompositionAttribute -> object : QRDecompositionAttribute<Double> { QR -> object : QRDecomposition<Float64> {
private val qr by lazy { QRDecomposition(origin) } val cmQr by lazy { org.apache.commons.math3.linear.QRDecomposition(origin) }
override val q: Matrix<Double> by lazy<Matrix<Double>> { override val q: Matrix<Float64> get() = cmQr.q.wrap().withAttribute(OrthogonalAttribute)
CMMatrix(qr.q).withAttribute( override val r: Matrix<Float64> get() = cmQr.r.wrap().withAttribute(UpperTriangular)
OrthogonalAttribute
)
}
override val r: Matrix<Double> by lazy<Matrix<Double>> { CMMatrix(qr.r).withAttribute(UpperTriangular) }
} }
SVDAttribute -> object : SVDAttribute<Double> { SVD -> object : space.kscience.kmath.linear.SingularValueDecomposition<Float64> {
private val sv by lazy { SingularValueDecomposition(origin) } val cmSvd by lazy { SingularValueDecomposition(origin) }
override val u: Matrix<Double> by lazy { CMMatrix(sv.u) }
override val s: Matrix<Double> by lazy { CMMatrix(sv.s) } override val u: Matrix<Float64> get() = cmSvd.u.wrap()
override val v: Matrix<Double> by lazy { CMMatrix(sv.v) } override val s: Matrix<Float64> get() = cmSvd.s.wrap()
override val singularValues: Point<Double> by lazy { Float64Buffer(sv.singularValues) } override val v: Matrix<Float64> get() = cmSvd.v.wrap()
override val singularValues: Point<Float64> get() = cmSvd.singularValues.asBuffer()
} }
else -> null else -> null
}?.let(type::cast)
} }
@Suppress("UNCHECKED_CAST")
return raw as V?
}
} }
public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix = CMMatrix(origin.add(other.origin)) public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix = CMMatrix(origin.add(other.origin))

View File

@ -3,6 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:OptIn(UnstableKMathAPI::class) @file:OptIn(UnstableKMathAPI::class)
package space.kscience.kmath.commons.optimization package space.kscience.kmath.commons.optimization
import org.apache.commons.math3.optim.* import org.apache.commons.math3.optim.*
@ -20,7 +21,6 @@ import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.SymbolIndexer import space.kscience.kmath.expressions.SymbolIndexer
import space.kscience.kmath.expressions.derivative import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.expressions.withSymbols import space.kscience.kmath.expressions.withSymbols
import space.kscience.kmath.misc.log
import space.kscience.kmath.optimization.* import space.kscience.kmath.optimization.*
import kotlin.collections.set import kotlin.collections.set
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -28,7 +28,7 @@ import kotlin.reflect.KClass
public operator fun PointValuePair.component1(): DoubleArray = point public operator fun PointValuePair.component1(): DoubleArray = point
public operator fun PointValuePair.component2(): Double = value public operator fun PointValuePair.component2(): Double = value
public object CMOptimizerEngine: OptimizationAttribute<() -> MultivariateOptimizer> public object CMOptimizerEngine : OptimizationAttribute<() -> MultivariateOptimizer>
/** /**
* Specify a Commons-maths optimization engine * Specify a Commons-maths optimization engine
@ -37,7 +37,7 @@ public fun AttributesBuilder<FunctionOptimization<Double>>.cmEngine(optimizerBui
set(CMOptimizerEngine, optimizerBuilder) set(CMOptimizerEngine, optimizerBuilder)
} }
public object CMOptimizerData: SetAttribute<SymbolIndexer.() -> OptimizationData> public object CMOptimizerData : SetAttribute<SymbolIndexer.() -> OptimizationData>
/** /**
* Specify Commons-maths optimization data. * Specify Commons-maths optimization data.
@ -118,21 +118,24 @@ public object CMOptimizer : Optimizer<Double, FunctionOptimization<Double>> {
val logger = problem.attributes[OptimizationLog] val logger = problem.attributes[OptimizationLog]
for (feature in problem.attributes) { problem.attributes[CMOptimizerData]?.let { builders: Set<SymbolIndexer.() -> OptimizationData> ->
when (feature) { builders.forEach { dataBuilder ->
is CMOptimizerData -> feature.data.forEach { dataBuilder ->
addOptimizationData(dataBuilder()) addOptimizationData(dataBuilder())
} }
is FunctionOptimizationTarget -> when (feature) {
FunctionOptimizationTarget.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE)
FunctionOptimizationTarget.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE)
} }
else -> logger?.log { "The feature $feature is unused in optimization" }
problem.attributes[FunctionOptimizationTarget]?.let { direction: OptimizationDirection ->
when (direction) {
OptimizationDirection.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE)
OptimizationDirection.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE)
} }
} }
val (point, value) = cmOptimizer.optimize(*optimizationData.values.toTypedArray()) val (point, value) = cmOptimizer.optimize(*optimizationData.values.toTypedArray())
return problem.withAttributes(OptimizationResult(point.toMap()), OptimizationValue(value)) return problem.withAttributes {
result(point.toMap())
value(value)
}
} }
} }
} }

View File

@ -7,6 +7,8 @@ package space.kscience.kmath.commons.integration
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.integration.IntegrandAbsoluteAccuracy
import space.kscience.kmath.integration.IntegrandRelativeAccuracy
import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.value import space.kscience.kmath.integration.value
import space.kscience.kmath.operations.Float64Field.sin import space.kscience.kmath.operations.Float64Field.sin
@ -27,8 +29,8 @@ internal class IntegrationTest {
@Test @Test
fun customSimpson() { fun customSimpson() {
val res = CMIntegrator.simpson().integrate(0.0..PI, { val res = CMIntegrator.simpson().integrate(0.0..PI, {
targetRelativeAccuracy = 1e-4 IntegrandRelativeAccuracy(1e-4)
targetAbsoluteAccuracy = 1e-4 IntegrandAbsoluteAccuracy(1e-4)
}, function).value }, function).value
assertTrue { abs(res - 2) < 1e-3 } assertTrue { abs(res - 2) < 1e-3 }
assertTrue { abs(res - 2) > 1e-12 } assertTrue { abs(res - 2) > 1e-12 }

View File

@ -73,8 +73,9 @@ internal class OptimizeTest {
val result: FunctionOptimization<Double> = chi2.optimizeWith( val result: FunctionOptimization<Double> = chi2.optimizeWith(
CMOptimizer, CMOptimizer,
mapOf(a to 1.5, b to 0.9, c to 1.0), mapOf(a to 1.5, b to 0.9, c to 1.0),
FunctionOptimizationTarget.MINIMIZE ){
) FunctionOptimizationTarget(OptimizationDirection.MINIMIZE)
}
println(result) println(result)
println("Chi2/dof = ${result.resultValue / (x.size - 3)}") println("Chi2/dof = ${result.resultValue / (x.size - 3)}")
} }

View File

@ -8,19 +8,8 @@ Complex and hypercomplex number systems in KMath.
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-complex:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-complex:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-complex:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -29,6 +18,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-complex:0.4.0-dev-1") implementation("space.kscience:kmath-complex:0.4.0-dev-3")
} }
``` ```

View File

@ -144,12 +144,19 @@ public object ComplexField :
zero zero
} }
} }
} else { } else {
exp(pow * ln(arg)) exp(pow * ln(arg))
} }
public fun power(arg: Complex, pow: Complex): Complex = exp(pow * ln(arg)) public fun power(arg: Complex, pow: Complex): Complex = if(arg == zero || arg == (-0.0).toComplex()){
if(pow == zero){
one
} else {
zero
}
} else {
exp(pow * ln(arg))
}
public fun Complex.pow(power: Complex): Complex = power(this, power) public fun Complex.pow(power: Complex): Complex = power(this, power)

View File

@ -71,6 +71,11 @@ internal class ComplexFieldTest {
(i * 8).let { it.im.toInt() to it.re.toInt() }, (i * 8).let { it.im.toInt() to it.re.toInt() },
(Complex(2, 2) pow 2).let { it.im.toInt() to it.re.toInt() }) (Complex(2, 2) pow 2).let { it.im.toInt() to it.re.toInt() })
assertEquals(1.0, Complex(0.0).pow(Complex(0.0)).re, 0.01)
assertEquals(1.0, Complex(-0.0).pow(Complex(0.0)).re, 0.01)
assertEquals(0.0, Complex(0.0).pow(Complex(2.0)).re, 0.01)
assertEquals(0.0, Complex(-0.0).pow(Complex(2.0)).re, 0.01)
assertEquals(1.0, Complex(-1.0).pow(Complex(2.0)).re, 0.01)
assertEquals(2.0, power(Complex(-4.0, 0.0), 0.5 + 0 * i).im, 0.01) assertEquals(2.0, power(Complex(-4.0, 0.0), 0.5 + 0 * i).im, 0.01)
assertEquals(2.0, power(Complex(-4.0, 0.0), 0.5).im, 0.01) assertEquals(2.0, power(Complex(-4.0, 0.0), 0.5).im, 0.01)
} }

View File

@ -11,23 +11,13 @@ objects to the expression by providing a context. Expressions can be used for a
performance calculations to code generation. performance calculations to code generation.
- [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains - [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
- [autodiff](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation - [autodiff](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
- [linear.parallel](#) : Parallel implementation for `LinearAlgebra`
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-core:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-core:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-core:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -36,6 +26,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-core:0.4.0-dev-1") implementation("space.kscience:kmath-core:0.4.0-dev-3")
} }
``` ```

File diff suppressed because it is too large Load Diff

View File

@ -71,4 +71,12 @@ readme {
id = "autodiff", id = "autodiff",
ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt"
) { "Automatic differentiation" } ) { "Automatic differentiation" }
feature(
id="Parallel linear algebra"
){
"""
Parallel implementation for `LinearAlgebra`
""".trimIndent()
}
} }

View File

@ -7,6 +7,7 @@ package space.kscience.kmath.expressions
import space.kscience.attributes.SafeType import space.kscience.attributes.SafeType
import space.kscience.attributes.WithType import space.kscience.attributes.WithType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
@ -30,12 +31,18 @@ public interface Expression<T> : WithType<T> {
public operator fun invoke(arguments: Map<Symbol, T>): T public operator fun invoke(arguments: Map<Symbol, T>): T
} }
/**
* Create an expression from a functional block.
*/
public fun <T> Expression(type: SafeType<T>, block: (Map<Symbol, T>) -> T): Expression<T> = object : Expression<T> { public fun <T> Expression(type: SafeType<T>, block: (Map<Symbol, T>) -> T): Expression<T> = object : Expression<T> {
override fun invoke(arguments: Map<Symbol, T>): T = block(arguments) override fun invoke(arguments: Map<Symbol, T>): T = block(arguments)
override val type: SafeType<T> = type override val type: SafeType<T> = type
} }
public inline fun <reified T> Expression(noinline block: (Map<Symbol, T>) -> T): Expression<T> =
Expression(safeTypeOf<T>(), block)
/** /**
* Specialization of [Expression] for [Double] allowing better performance because of using array. * Specialization of [Expression] for [Double] allowing better performance because of using array.
*/ */

View File

@ -54,11 +54,12 @@ public object Float64LinearSpace : LinearSpace<Double, Float64Field> {
require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
val rows = this@dot.rows.map { it.linearize() } val rows = this@dot.rows.map { it.linearize() }
val columns = other.columns.map { it.linearize() } val columns = other.columns.map { it.linearize() }
val indices = 0 until this.colNum
return buildMatrix(rowNum, other.colNum) { i, j -> return buildMatrix(rowNum, other.colNum) { i, j ->
val r = rows[i] val r = rows[i]
val c = columns[j] val c = columns[j]
var res = 0.0 var res = 0.0
for (l in r.indices) { for (l in indices) {
res += r[l] * c[l] res += r[l] * c[l]
} }
res res
@ -69,10 +70,11 @@ public object Float64LinearSpace : LinearSpace<Double, Float64Field> {
override fun Matrix<Double>.dot(vector: Point<Double>): Float64Buffer { override fun Matrix<Double>.dot(vector: Point<Double>): Float64Buffer {
require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" }
val rows = this@dot.rows.map { it.linearize() } val rows = this@dot.rows.map { it.linearize() }
val indices = 0 until this.colNum
return Float64Buffer(rowNum) { i -> return Float64Buffer(rowNum) { i ->
val r = rows[i] val r = rows[i]
var res = 0.0 var res = 0.0
for (j in r.indices) { for (j in indices) {
res += r[j] * vector[j] res += r[j] * vector[j]
} }
res res

View File

@ -4,25 +4,33 @@
*/ */
@file:Suppress("UnusedReceiverParameter") @file:Suppress("UnusedReceiverParameter")
@file:OptIn(PerformancePitfall::class)
package space.kscience.kmath.linear package space.kscience.kmath.linear
import space.kscience.attributes.Attributes import space.kscience.attributes.Attributes
import space.kscience.attributes.PolymorphicAttribute import space.kscience.attributes.PolymorphicAttribute
import space.kscience.attributes.safeTypeOf import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.* import space.kscience.kmath.structures.*
public interface LupDecomposition<T> { public interface LupDecomposition<T> {
public val linearSpace: LinearSpace<T, Field<T>>
public val elementAlgebra: Field<T> get() = linearSpace.elementAlgebra
public val pivot: IntBuffer public val pivot: IntBuffer
public val l: Matrix<T> public val l: Matrix<T>
public val u: Matrix<T> public val u: Matrix<T>
} }
/**
* Create a pivot matrix from pivot vector using provided [LinearSpace]
*/
public fun <T> LupDecomposition<T>.pivotMatrix(linearSpace: LinearSpace<T, Ring<T>>): Matrix<T> =
VirtualMatrix(linearSpace.type, l.rowNum, l.colNum) { row, column ->
if (column == pivot[row]) linearSpace.elementAlgebra.one else linearSpace.elementAlgebra.zero
}
/** /**
* Matrices with this feature support LU factorization with partial pivoting: *[p] &middot; a = [l] &middot; [u]* where * Matrices with this feature support LU factorization with partial pivoting: *[p] &middot; a = [l] &middot; [u]* where
* *a* is the owning matrix. * *a* is the owning matrix.
@ -31,12 +39,13 @@ public interface LupDecomposition<T> {
* @param lu combined L and U matrix * @param lu combined L and U matrix
*/ */
public class GenericLupDecomposition<T>( public class GenericLupDecomposition<T>(
override val linearSpace: LinearSpace<T, Field<T>>, public val elementAlgebra: Field<T>,
private val lu: Matrix<T>, private val lu: Matrix<T>,
override val pivot: IntBuffer, override val pivot: IntBuffer,
private val even: Boolean, private val even: Boolean,
) : LupDecomposition<T> { ) : LupDecomposition<T> {
override val l: Matrix<T> override val l: Matrix<T>
get() = VirtualMatrix(lu.type, lu.rowNum, lu.colNum, attributes = Attributes(LowerTriangular)) { i, j -> get() = VirtualMatrix(lu.type, lu.rowNum, lu.colNum, attributes = Attributes(LowerTriangular)) { i, j ->
when { when {
@ -51,11 +60,6 @@ public class GenericLupDecomposition<T>(
if (j >= i) lu[i, j] else elementAlgebra.zero if (j >= i) lu[i, j] else elementAlgebra.zero
} }
public val pivotMatrix: Matrix<T>
get() = VirtualMatrix(linearSpace.type, l.rowNum, l.colNum) { row, column ->
if (column == pivot[row]) elementAlgebra.one else elementAlgebra.zero
}
public val determinant: T by lazy { public val determinant: T by lazy {
elementAlgebra { (0 until l.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } } elementAlgebra { (0 until l.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } }
} }
@ -76,18 +80,23 @@ internal fun <T : Comparable<T>> LinearSpace<T, Ring<T>>.abs(value: T): T =
/** /**
* Create a lup decomposition of generic matrix. * Create a lup decomposition of generic matrix.
*/ */
public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup( public fun <T : Comparable<T>> Field<T>.lup(
matrix: Matrix<T>, matrix: Matrix<T>,
checkSingular: (T) -> Boolean, checkSingular: (T) -> Boolean,
): LupDecomposition<T> = elementAlgebra { ): GenericLupDecomposition<T> {
require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" } require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" }
val m = matrix.colNum val m = matrix.colNum
val pivot = IntArray(matrix.rowNum) val pivot = IntArray(matrix.rowNum)
//TODO just waits for multi-receivers val strides = RowStrides(ShapeND(matrix.rowNum, matrix.colNum))
with(BufferAccessor2D(matrix.rowNum, matrix.colNum, elementAlgebra.bufferFactory)) {
val lu = MutableBufferND(
strides,
bufferAlgebra.buffer(strides.linearSize) { offset ->
matrix[strides.index(offset)]
}
)
val lu = create(matrix)
// Initialize the permutation array and parity // Initialize the permutation array and parity
for (row in 0 until m) pivot[row] = row for (row in 0 until m) pivot[row] = row
@ -100,10 +109,11 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
for (col in 0 until m) { for (col in 0 until m) {
// upper // upper
for (row in 0 until col) { for (row in 0 until col) {
val luRow = lu.row(row) var sum = lu[row, col]
var sum = luRow[col] for (i in 0 until row){
for (i in 0 until row) sum -= luRow[i] * lu[i, col] sum -= lu[row, i] * lu[i, col]
luRow[col] = sum }
lu[row, col] = sum
} }
// lower // lower
@ -111,10 +121,11 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
var largest = -one var largest = -one
for (row in col until m) { for (row in col until m) {
val luRow = lu.row(row) var sum = lu[row, col]
var sum = luRow[col] for (i in 0 until col){
for (i in 0 until col) sum -= luRow[i] * lu[i, col] sum -= lu[row, i] * lu[i, col]
luRow[col] = sum }
lu[row, col] = sum
// maintain the best permutation choice // maintain the best permutation choice
if (abs(sum) > largest) { if (abs(sum) > largest) {
@ -128,13 +139,10 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
// Pivot if necessary // Pivot if necessary
if (max != col) { if (max != col) {
val luMax = lu.row(max)
val luCol = lu.row(col)
for (i in 0 until m) { for (i in 0 until m) {
val tmp = luMax[i] val tmp = lu[max, i]
luMax[i] = luCol[i] lu[max, i] = lu[col, i]
luCol[i] = tmp lu[col, i] = tmp
} }
val temp = pivot[max] val temp = pivot[max]
@ -148,64 +156,69 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
for (row in col + 1 until m) lu[row, col] /= luDiag for (row in col + 1 until m) lu[row, col] /= luDiag
} }
return GenericLupDecomposition(this@lup, lu.toStructure2D(), pivot.asBuffer(), even)
} return GenericLupDecomposition(this, lu.as2D(), pivot.asBuffer(), even)
} }
public fun LinearSpace<Double, Float64Field>.lup( public fun Field<Float64>.lup(
matrix: Matrix<Double>, matrix: Matrix<Double>,
singularityThreshold: Double = 1e-11, singularityThreshold: Double = 1e-11,
): LupDecomposition<Double> = lup(matrix) { it < singularityThreshold } ): GenericLupDecomposition<Double> = lup(matrix) { it < singularityThreshold }
internal fun <T> LinearSpace<T, Field<T>>.solve( private fun <T> Field<T>.solve(
lup: LupDecomposition<T>, lup: LupDecomposition<T>,
matrix: Matrix<T>, matrix: Matrix<T>,
): Matrix<T> { ): Matrix<T> {
require(matrix.rowNum == lup.l.rowNum) { "Matrix dimension mismatch. Expected ${lup.l.rowNum}, but got ${matrix.colNum}" } require(matrix.rowNum == lup.l.rowNum) { "Matrix dimension mismatch. Expected ${lup.l.rowNum}, but got ${matrix.colNum}" }
BufferAccessor2D(matrix.rowNum, matrix.colNum, elementAlgebra.bufferFactory).run { val strides = RowStrides(ShapeND(matrix.rowNum, matrix.colNum))
elementAlgebra {
// Apply permutations to b
val bp = create { _, _ -> zero }
for (row in 0 until rowNum) { // Apply permutations to b
val bpRow = bp.row(row) val bp = MutableBufferND(
strides,
bufferAlgebra.buffer(strides.linearSize) { _ -> zero }
)
for (row in 0 until matrix.rowNum) {
val pRow = lup.pivot[row] val pRow = lup.pivot[row]
for (col in 0 until matrix.colNum) bpRow[col] = matrix[pRow, col] for (col in 0 until matrix.colNum) {
bp[row, col] = matrix[pRow, col]
}
} }
// Solve LY = b // Solve LY = b
for (col in 0 until colNum) { for (col in 0 until matrix.colNum) {
val bpCol = bp.row(col)
for (i in col + 1 until colNum) { for (i in col + 1 until matrix.colNum) {
val bpI = bp.row(i)
val luICol = lup.l[i, col] val luICol = lup.l[i, col]
for (j in 0 until matrix.colNum) { for (j in 0 until matrix.colNum) {
bpI[j] -= bpCol[j] * luICol bp[i, j] -= bp[col, j] * luICol
} }
} }
} }
// Solve UX = Y // Solve UX = Y
for (col in colNum - 1 downTo 0) { for (col in matrix.colNum - 1 downTo 0) {
val bpCol = bp.row(col)
val luDiag = lup.u[col, col] val luDiag = lup.u[col, col]
for (j in 0 until matrix.colNum) bpCol[j] /= luDiag for (j in 0 until matrix.colNum) {
bp[col, j] /= luDiag
}
for (i in 0 until col) { for (i in 0 until col) {
val bpI = bp.row(i)
val luICol = lup.u[i, col] val luICol = lup.u[i, col]
for (j in 0 until matrix.colNum) bpI[j] -= bpCol[j] * luICol for (j in 0 until matrix.colNum) {
bp[i, j] -= bp[col, j] * luICol
}
} }
} }
return buildMatrix(matrix.rowNum, matrix.colNum) { i, j -> bp[i, j] } return bp.as2D()
}
}
} }
/** /**
* Produce a generic solver based on LUP decomposition * Produce a generic solver based on LUP decomposition
*/ */
@ -213,7 +226,7 @@ internal fun <T> LinearSpace<T, Field<T>>.solve(
public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lupSolver( public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lupSolver(
singularityCheck: (T) -> Boolean, singularityCheck: (T) -> Boolean,
): LinearSolver<T> = object : LinearSolver<T> { ): LinearSolver<T> = object : LinearSolver<T> {
override fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T> { override fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T> = elementAlgebra{
// Use existing decomposition if it is provided by matrix or linear space itself // Use existing decomposition if it is provided by matrix or linear space itself
val decomposition = a.getOrComputeAttribute(LUP) ?: lup(a, singularityCheck) val decomposition = a.getOrComputeAttribute(LUP) ?: lup(a, singularityCheck)
return solve(decomposition, b) return solve(decomposition, b)

View File

@ -25,5 +25,4 @@ public class TransposedMatrix<T>(public val origin: Matrix<T>) : Matrix<T> {
/** /**
* Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A`
*/ */
public val <T> Matrix<T>.transposed: Matrix<T> public fun <T> Matrix<T>.transposed(): Matrix<T> = (this as? TransposedMatrix<T>)?.origin ?: TransposedMatrix(this)
get() = (this as? TransposedMatrix<T>)?.origin ?: TransposedMatrix(this)

View File

@ -5,9 +5,11 @@
package space.kscience.kmath.nd package space.kscience.kmath.nd
import space.kscience.attributes.SafeType
import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.Float64Buffer
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
@ -20,7 +22,10 @@ import kotlin.math.pow as kpow
public class Float64BufferND( public class Float64BufferND(
indexes: ShapeIndexer, indexes: ShapeIndexer,
override val buffer: Float64Buffer, override val buffer: Float64Buffer,
) : MutableBufferND<Double>(indexes, buffer), MutableStructureNDOfDouble{ ) : MutableBufferND<Double>(indexes, buffer), MutableStructureNDOfDouble {
override val type: SafeType<Float64> get() = Float64Field.type
override fun getDouble(index: IntArray): Double = buffer[indices.offset(index)] override fun getDouble(index: IntArray): Double = buffer[indices.offset(index)]
override fun setDouble(index: IntArray, value: Double) { override fun setDouble(index: IntArray, value: Double) {

View File

@ -69,6 +69,29 @@ public interface Structure2D<out T> : StructureND<T> {
public companion object public companion object
} }
/**
* A linear accessor for a [MutableStructureND]
*/
@OptIn(PerformancePitfall::class)
public class MutableStructureNDAccessorBuffer<T>(
public val structure: MutableStructureND<T>,
override val size: Int,
private val indexer: (Int) -> IntArray,
) : MutableBuffer<T> {
override val type: SafeType<T> get() = structure.type
override fun set(index: Int, value: T) {
structure[indexer(index)] = value
}
override fun get(index: Int): T = structure[indexer(index)]
override fun toString(): String = "AccessorBuffer(structure=$structure, size=$size)"
override fun copy(): MutableBuffer<T> = MutableBuffer(type, size, ::get)
}
/** /**
* Represents mutable [Structure2D]. * Represents mutable [Structure2D].
*/ */
@ -87,14 +110,18 @@ public interface MutableStructure2D<T> : Structure2D<T>, MutableStructureND<T> {
*/ */
@PerformancePitfall @PerformancePitfall
override val rows: List<MutableBuffer<T>> override val rows: List<MutableBuffer<T>>
get() = List(rowNum) { i -> MutableBuffer(type, colNum) { j -> get(i, j) } } get() = List(rowNum) { i ->
MutableStructureNDAccessorBuffer(this, colNum) { j -> intArrayOf(i, j) }
}
/** /**
* The buffer of columns for this structure. It gets elements from the structure dynamically. * The buffer of columns for this structure. It gets elements from the structure dynamically.
*/ */
@PerformancePitfall @PerformancePitfall
override val columns: List<MutableBuffer<T>> override val columns: List<MutableBuffer<T>>
get() = List(colNum) { j -> MutableBuffer(type, rowNum) { i -> get(i, j) } } get() = List(colNum) { j ->
MutableStructureNDAccessorBuffer(this, rowNum) { i -> intArrayOf(i, j) }
}
} }
/** /**

View File

@ -5,9 +5,15 @@
package space.kscience.kmath.nd package space.kscience.kmath.nd
import space.kscience.attributes.SafeType
import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.Int32Field
import space.kscience.kmath.structures.Float64
public interface StructureNDOfDouble : StructureND<Double> { public interface StructureNDOfDouble : StructureND<Double> {
override val type: SafeType<Float64> get() = Float64Field.type
/** /**
* Guaranteed non-blocking access to content * Guaranteed non-blocking access to content
*/ */
@ -22,6 +28,7 @@ public fun StructureND<Double>.getDouble(index: IntArray): Double =
if (this is StructureNDOfDouble) getDouble(index) else get(index) if (this is StructureNDOfDouble) getDouble(index) else get(index)
public interface MutableStructureNDOfDouble : StructureNDOfDouble, MutableStructureND<Double> { public interface MutableStructureNDOfDouble : StructureNDOfDouble, MutableStructureND<Double> {
/** /**
* Guaranteed non-blocking access to content * Guaranteed non-blocking access to content
*/ */
@ -34,6 +41,9 @@ public fun MutableStructureND<Double>.getDouble(index: IntArray): Double =
public interface StructureNDOfInt : StructureND<Int> { public interface StructureNDOfInt : StructureND<Int> {
override val type: SafeType<Int> get() = Int32Field.type
/** /**
* Guaranteed non-blocking access to content * Guaranteed non-blocking access to content
*/ */

View File

@ -77,13 +77,11 @@ private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.zipInline(
return elementBufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) } return elementBufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) }
} }
public fun <T> BufferAlgebra<T, *>.buffer(size: Int, initializer: (Int) -> T): MutableBuffer<T> { public fun <T> BufferAlgebra<T, *>.buffer(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
return elementBufferFactory(size, initializer) elementBufferFactory(size, initializer)
}
public fun <T, A> A.buffer(initializer: (Int) -> T): MutableBuffer<T> where A : BufferAlgebra<T, *>, A : WithSize { public fun <T, A> A.buffer(initializer: (Int) -> T): MutableBuffer<T> where A : BufferAlgebra<T, *>, A : WithSize =
return elementBufferFactory(size, initializer) elementBufferFactory(size, initializer)
}
public fun <T, A : TrigonometricOperations<T>> BufferAlgebra<T, A>.sin(arg: Buffer<T>): Buffer<T> = public fun <T, A : TrigonometricOperations<T>> BufferAlgebra<T, A>.sin(arg: Buffer<T>): Buffer<T> =
mapInline(arg) { sin(it) } mapInline(arg) { sin(it) }

View File

@ -42,6 +42,8 @@ public inline fun <reified T> BufferFactory(): BufferFactory<T> = BufferFactory(
*/ */
public interface MutableBufferFactory<T> : BufferFactory<T> { public interface MutableBufferFactory<T> : BufferFactory<T> {
override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T> override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T>
public companion object
} }
/** /**

View File

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

View File

@ -39,6 +39,7 @@ public value class Float64Buffer(public val array: DoubleArray) : PrimitiveBuffe
} }
} }
@Deprecated("Use Float64Buffer instead", ReplaceWith("Float64Buffer"))
public typealias DoubleBuffer = Float64Buffer public typealias DoubleBuffer = Float64Buffer
/** /**

View File

@ -77,7 +77,6 @@ public inline fun <T> MutableBuffer(
size: Int, size: Int,
initializer: (Int) -> T, initializer: (Int) -> T,
): MutableBuffer<T> = when (type.kType) { ): MutableBuffer<T> = when (type.kType) {
typeOf<Boolean>() -> TODO()
typeOf<Int8>() -> Int8Buffer(size) { initializer(it) as Int8 } as MutableBuffer<T> typeOf<Int8>() -> Int8Buffer(size) { initializer(it) as Int8 } as MutableBuffer<T>
typeOf<Int16>() -> MutableBuffer.short(size) { initializer(it) as Int16 } as MutableBuffer<T> typeOf<Int16>() -> MutableBuffer.short(size) { initializer(it) as Int16 } as MutableBuffer<T>
typeOf<Int32>() -> MutableBuffer.int(size) { initializer(it) as Int32 } as MutableBuffer<T> typeOf<Int32>() -> MutableBuffer.int(size) { initializer(it) as Int32 } as MutableBuffer<T>

View File

@ -10,7 +10,6 @@ import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.algebra
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
@OptIn(PerformancePitfall::class) @OptIn(PerformancePitfall::class)
@ -29,18 +28,18 @@ class DoubleLUSolverTest {
} }
@Test @Test
fun testDecomposition() = Double.algebra.linearSpace.run { fun testDecomposition() = with(Double.algebra.linearSpace){
val matrix = matrix(2, 2)( val matrix = matrix(2, 2)(
3.0, 1.0, 3.0, 1.0,
2.0, 3.0 2.0, 3.0
) )
val lup = lup(matrix) val lup = elementAlgebra.lup(matrix)
//Check determinant //Check determinant
assertEquals(7.0, lup.determinant) // assertEquals(7.0, lup.determinant)
assertMatrixEquals(lup.pivotMatrix dot matrix, lup.l dot lup.u) assertMatrixEquals(lup.pivotMatrix(this) dot matrix, lup.l dot lup.u)
} }
@Test @Test

View File

@ -8,6 +8,7 @@ package space.kscience.kmath.linear
import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.algebra
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -21,7 +22,7 @@ class MatrixTest {
@Test @Test
fun testTranspose() = Double.algebra.linearSpace.run { fun testTranspose() = Double.algebra.linearSpace.run {
val matrix = one(3, 3) val matrix = one(3, 3)
val transposed = matrix.transposed val transposed = matrix.transposed()
assertTrue { StructureND.contentEquals(matrix, transposed) } assertTrue { StructureND.contentEquals(matrix, transposed) }
} }
@ -58,7 +59,7 @@ class MatrixTest {
} }
@Test @Test
fun test2DDot() = Double.algebra.linearSpace.run { fun test2DDot() = Float64Field.linearSpace {
val firstMatrix = buildMatrix(2, 3) { i, j -> (i + j).toDouble() } val firstMatrix = buildMatrix(2, 3) { i, j -> (i + j).toDouble() }
val secondMatrix = buildMatrix(3, 2) { i, j -> (i + j).toDouble() } val secondMatrix = buildMatrix(3, 2) { i, j -> (i + j).toDouble() }
@ -70,6 +71,5 @@ class MatrixTest {
assertEquals(8.0, result[0, 1]) assertEquals(8.0, result[0, 1])
assertEquals(8.0, result[1, 0]) assertEquals(8.0, result[1, 0])
assertEquals(14.0, result[1, 1]) assertEquals(14.0, result[1, 1])
} }
} }

View File

@ -0,0 +1,125 @@
/*
* 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.nd.*
import space.kscience.kmath.operations.Float64BufferOps
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.Float64Buffer
import space.kscience.kmath.structures.asBuffer
import java.util.stream.IntStream
public object Float64ParallelLinearSpace : LinearSpace<Double, Float64Field> {
override val elementAlgebra: Float64Field = Float64Field
override fun buildMatrix(
rows: Int,
columns: Int,
initializer: Float64Field.(i: Int, j: Int) -> Double,
): Matrix<Double> {
val shape = ShapeND(rows, columns)
val indexer = BufferAlgebraND.defaultIndexerBuilder(shape)
val buffer = IntStream.range(0, indexer.linearSize).parallel().mapToDouble { offset ->
val (i, j) = indexer.index(offset)
elementAlgebra.initializer(i, j)
}.toArray().asBuffer()
return MutableBufferND(
indexer,
buffer
).as2D()
}
override fun buildVector(size: Int, initializer: Float64Field.(Int) -> Double): Float64Buffer =
IntStream.range(0, size).parallel().mapToDouble{ Float64Field.initializer(it) }.toArray().asBuffer()
override fun Matrix<Double>.unaryMinus(): Matrix<Double> = Floa64FieldOpsND {
asND().map { -it }.as2D()
}
override fun Matrix<Double>.plus(other: Matrix<Double>): Matrix<Double> = Floa64FieldOpsND {
require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" }
asND().plus(other.asND()).as2D()
}
override fun Matrix<Double>.minus(other: Matrix<Double>): Matrix<Double> = Floa64FieldOpsND {
require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" }
asND().minus(other.asND()).as2D()
}
// Create a continuous in-memory representation of this vector for better memory layout handling
private fun Buffer<Double>.linearize() = if (this is Float64Buffer) {
this.array
} else {
DoubleArray(size) { get(it) }
}
@OptIn(PerformancePitfall::class)
override fun Matrix<Double>.dot(other: Matrix<Double>): Matrix<Double> {
require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
val rows = this@dot.rows.map { it.linearize() }
val columns = other.columns.map { it.linearize() }
val indices = 0 until this.colNum
return buildMatrix(rowNum, other.colNum) { i, j ->
val r = rows[i]
val c = columns[j]
var res = 0.0
for (l in indices) {
res += r[l] * c[l]
}
res
}
}
@OptIn(PerformancePitfall::class)
override fun Matrix<Double>.dot(vector: Point<Double>): Float64Buffer {
require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" }
val rows = this@dot.rows.map { it.linearize() }
val indices = 0 until this.colNum
return Float64Buffer(rowNum) { i ->
val r = rows[i]
var res = 0.0
for (j in indices) {
res += r[j] * vector[j]
}
res
}
}
override fun Matrix<Double>.times(value: Double): Matrix<Double> = Floa64FieldOpsND {
asND().map { it * value }.as2D()
}
public override fun Point<Double>.plus(other: Point<Double>): Float64Buffer = Float64BufferOps.run {
this@plus + other
}
public override fun Point<Double>.minus(other: Point<Double>): Float64Buffer = Float64BufferOps.run {
this@minus - other
}
public override fun Point<Double>.times(value: Double): Float64Buffer = Float64BufferOps.run {
scale(this@times, value)
}
public operator fun Point<Double>.div(value: Double): Float64Buffer = Float64BufferOps.run {
scale(this@div, 1.0 / value)
}
public override fun Double.times(v: Point<Double>): Float64Buffer = v * this
}
public val Float64LinearSpace.parallel: Float64ParallelLinearSpace get() = Float64ParallelLinearSpace

View File

@ -0,0 +1,58 @@
/*
* 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.attributes.SafeType
import java.util.stream.Collectors
import java.util.stream.IntStream
import kotlin.reflect.typeOf
/**
* A Java stream-based parallel version of [MutableBuffer].
* There is no parallelization for [Int8], [Int16] and [Float32] types.
* They are processed sequentially.
*/
@Suppress("UNCHECKED_CAST")
public fun <T> MutableBuffer.Companion.parallel(
type: SafeType<T>,
size: Int,
initializer: (Int) -> T,
): MutableBuffer<T> = when (type.kType) {
typeOf<Int8>() -> Int8Buffer(size) { initializer(it) as Int8 } as MutableBuffer<T>
typeOf<Int16>() -> Int16Buffer(size) { initializer(it) as Int16 } as MutableBuffer<T>
typeOf<Int32>() -> IntStream.range(0, size).parallel().map { initializer(it) as Int32 }.toArray()
.asBuffer() as MutableBuffer<T>
typeOf<Int64>() -> IntStream.range(0, size).parallel().mapToLong { initializer(it) as Int64 }.toArray()
.asBuffer() as MutableBuffer<T>
typeOf<Float>() -> Float32Buffer(size) { initializer(it) as Float } as MutableBuffer<T>
typeOf<Double>() -> IntStream.range(0, size).parallel().mapToDouble { initializer(it) as Float64 }.toArray()
.asBuffer() as MutableBuffer<T>
//TODO add unsigned types
else -> IntStream.range(0, size).parallel().mapToObj { initializer(it) }.collect(Collectors.toList<T>()).asMutableBuffer(type)
}
public class ParallelBufferFactory<T>(override val type: SafeType<T>) : MutableBufferFactory<T> {
override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T> {
TODO("Not yet implemented")
}
}
/**
* A Java stream-based parallel alternative to [MutableBufferFactory].
* See [MutableBuffer.Companion.parallel] for details.
*/
public fun <T> MutableBufferFactory.Companion.parallel(
type: SafeType<T>,
): MutableBufferFactory<T> = object : MutableBufferFactory<T> {
override val type: SafeType<T> = type
override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T> = MutableBuffer.parallel(type, size, builder)
}

View File

@ -0,0 +1,74 @@
/*
* 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.UnstableKMathAPI
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.Float64Field
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
@UnstableKMathAPI
@OptIn(PerformancePitfall::class)
@Suppress("UNUSED_VARIABLE")
class ParallelMatrixTest {
@Test
fun testTranspose() = Float64Field.linearSpace.parallel{
val matrix = one(3, 3)
val transposed = matrix.transposed()
assertTrue { StructureND.contentEquals(matrix, transposed) }
}
@Test
fun testBuilder() = Float64Field.linearSpace.parallel{
val matrix = matrix(2, 3)(
1.0, 0.0, 0.0,
0.0, 1.0, 2.0
)
assertEquals(2.0, matrix[1, 2])
}
@Test
fun testMatrixExtension() = Float64Field.linearSpace.parallel{
val transitionMatrix: Matrix<Double> = VirtualMatrix(type,6, 6) { row, col ->
when {
col == 0 -> .50
row + 1 == col -> .50
row == 5 && col == 5 -> 1.0
else -> 0.0
}
}
infix fun Matrix<Double>.pow(power: Int): Matrix<Double> {
var res = this
repeat(power - 1) {
res = res dot this@pow
}
return res
}
val toTenthPower = transitionMatrix pow 10
}
@Test
fun test2DDot() = Float64Field.linearSpace.parallel {
val firstMatrix = buildMatrix(2, 3) { i, j -> (i + j).toDouble() }
val secondMatrix = buildMatrix(3, 2) { i, j -> (i + j).toDouble() }
// val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() }
// val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() }
val result = firstMatrix dot secondMatrix
assertEquals(2, result.rowNum)
assertEquals(2, result.colNum)
assertEquals(8.0, result[0, 1])
assertEquals(8.0, result[1, 0])
assertEquals(14.0, result[1, 1])
}
}

View File

@ -6,19 +6,8 @@
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-coroutines:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -27,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-coroutines:0.4.0-dev-1") implementation("space.kscience:kmath-coroutines:0.4.0-dev-3")
} }
``` ```

View File

@ -6,6 +6,7 @@ kscience {
jvm() jvm()
js() js()
native() native()
wasm()
dependencies { dependencies {
api(project(":kmath-core")) api(project(":kmath-core"))

View File

@ -7,6 +7,7 @@ package space.kscience.kmath.streaming
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import space.kscience.kmath.operations.Int32Ring
import space.kscience.kmath.operations.asSequence import space.kscience.kmath.operations.asSequence
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -14,7 +15,7 @@ import kotlin.test.assertEquals
internal class RingBufferTest { internal class RingBufferTest {
@Test @Test
fun push() { fun push() {
val buffer = RingBuffer.build(20, Double.NaN) val buffer = RingBuffer(20, Double.NaN)
runBlocking { runBlocking {
for (i in 1..30) { for (i in 1..30) {
buffer.push(i.toDouble()) buffer.push(i.toDouble())
@ -30,7 +31,7 @@ internal class RingBufferTest {
while (true) emit(i++) while (true) emit(i++)
} }
val windowed = flow.windowed(10) val windowed = flow.windowed(10, Int32Ring)
runBlocking { runBlocking {
@Suppress("UNUSED_VARIABLE") val first = windowed.take(1).single() @Suppress("UNUSED_VARIABLE") val first = windowed.take(1).single()

View File

@ -6,19 +6,8 @@ A proof of concept module for adding type-safe dimensions to structures
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-dimensions:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -27,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-dimensions:0.4.0-dev-1") implementation("space.kscience:kmath-dimensions:0.4.0-dev-3")
} }
``` ```

View File

@ -6,6 +6,7 @@ kscience{
jvm() jvm()
js() js()
native() native()
wasm()
dependencies{ dependencies{
api(projects.kmathCore) api(projects.kmathCore)

View File

@ -153,7 +153,7 @@ public value class DMatrixContext<T : Any, out A : Ring<T>>(public val context:
context.run { this@unaryMinus.unaryMinus() }.coerce() context.run { this@unaryMinus.unaryMinus() }.coerce()
public inline fun <reified R : Dimension, reified C : Dimension> DMatrix<T, C, R>.transposed(): DMatrix<T, R, C> = public inline fun <reified R : Dimension, reified C : Dimension> DMatrix<T, C, R>.transposed(): DMatrix<T, R, C> =
context.run { (this@transposed as Matrix<T>).transposed }.coerce() context.run { (this@transposed as Matrix<T>).transposed() }.coerce()
public companion object { public companion object {
public val real: DMatrixContext<Double, Float64Field> = DMatrixContext(Double.algebra.linearSpace) public val real: DMatrixContext<Double, Float64Field> = DMatrixContext(Double.algebra.linearSpace)

View File

@ -0,0 +1,23 @@
/*
* 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.dimensions
import kotlin.reflect.KClass
private val dimensionMap: MutableMap<Int, Dimension> = hashMapOf(1 to D1, 2 to D2, 3 to D3)
@Suppress("UNCHECKED_CAST")
public actual fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D = dimensionMap
.entries
.map(MutableMap.MutableEntry<Int, Dimension>::value)
.find { it::class == type } as? D
?: error("Can't resolve dimension $type")
public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) {
object : Dimension {
override val dim: Int get() = dim
}
}

View File

@ -9,19 +9,8 @@ EJML based linear algebra implementation.
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-ejml:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-ejml:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-ejml:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -30,6 +19,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-ejml:0.4.0-dev-1") implementation("space.kscience:kmath-ejml:0.4.0-dev-3")
} }
``` ```

View File

@ -1,15 +1,15 @@
import space.kscience.kmath.ejml.codegen.ejmlCodegen
plugins { plugins {
id("space.kscience.gradle.jvm") id("space.kscience.gradle.jvm")
} }
val ejmlVerision = "0.43.1"
dependencies { dependencies {
api("org.ejml:ejml-ddense:0.41") api("org.ejml:ejml-ddense:$ejmlVerision")
api("org.ejml:ejml-fdense:0.41") api("org.ejml:ejml-fdense:$ejmlVerision")
api("org.ejml:ejml-dsparse:0.41") api("org.ejml:ejml-dsparse:$ejmlVerision")
api("org.ejml:ejml-fsparse:0.41") api("org.ejml:ejml-fsparse:$ejmlVerision")
api(project(":kmath-core")) api(projects.kmathCore)
} }
readme { readme {
@ -32,10 +32,10 @@ readme {
) { "LinearSpace implementations." } ) { "LinearSpace implementations." }
} }
kotlin.sourceSets.main { //kotlin.sourceSets.main {
val codegen by tasks.creating { // val codegen by tasks.creating {
ejmlCodegen(kotlin.srcDirs.first().absolutePath + "/space/kscience/kmath/ejml/_generated.kt") // ejmlCodegen(kotlin.srcDirs.first().absolutePath + "/space/kscience/kmath/ejml/_generated.kt")
} // }
//
kotlin.srcDirs(files().builtBy(codegen)) // kotlin.srcDirs(files().builtBy(codegen))
} //}

View File

@ -17,21 +17,18 @@ import org.ejml.sparse.csc.CommonOps_DSCC
import org.ejml.sparse.csc.CommonOps_FSCC import org.ejml.sparse.csc.CommonOps_FSCC
import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC
import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC
import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC
import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC
import space.kscience.attributes.SafeType import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.linear.* import space.kscience.kmath.linear.*
import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.Matrix
import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.nd.Structure2D
import space.kscience.kmath.nd.StructureAttribute
import space.kscience.kmath.operations.Float32Field import space.kscience.kmath.operations.Float32Field
import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.Float32
import space.kscience.kmath.structures.FloatBuffer import space.kscience.kmath.structures.IntBuffer
import kotlin.reflect.KClass import space.kscience.kmath.structures.asBuffer
import kotlin.reflect.cast
/** /**
* [EjmlVector] specialization for [Double]. * [EjmlVector] specialization for [Double].
@ -78,7 +75,6 @@ public class EjmlFloatMatrix<out M : FMatrix>(override val origin: M) : EjmlMatr
} }
/** /**
* [EjmlLinearSpace] implementation based on [CommonOps_DDRM], [DecompositionFactory_DDRM] operations and * [EjmlLinearSpace] implementation based on [CommonOps_DDRM], [DecompositionFactory_DDRM] operations and
* [DMatrixRMaj] matrices. * [DMatrixRMaj] matrices.
@ -217,77 +213,65 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, Float64Field, DMatri
override fun Double.times(v: Point<Double>): EjmlDoubleVector<DMatrixRMaj> = v * this override fun Double.times(v: Point<Double>): EjmlDoubleVector<DMatrixRMaj> = v * this
@UnstableKMathAPI override fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<Double>, attribute: A): V? {
override fun <F : StructureFeature> computeFeature(structure: Matrix<Double>, type: KClass<out F>): F? {
structure.getFeature(type)?.let { return it }
val origin = structure.toEjml().origin val origin = structure.toEjml().origin
return when (type) { val raw: Any? = when (attribute) {
InverseMatrixFeature::class -> object : InverseMatrixFeature<Double> { Inverted -> {
override val inverse: Matrix<Double> by lazy {
val res = origin.copy() val res = origin.copy()
CommonOps_DDRM.invert(res) CommonOps_DDRM.invert(res)
res.wrapMatrix() res.wrapMatrix()
} }
}
DeterminantFeature::class -> object : DeterminantFeature<Double> { Determinant -> CommonOps_DDRM.det(origin)
override val determinant: Double by lazy { CommonOps_DDRM.det(origin) } SVD -> object : SingularValueDecomposition<Double> {
} val ejmlSvd by lazy {
DecompositionFactory_DDRM
SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Double> { .svd(origin.numRows, origin.numCols, true, true, false)
private val svd by lazy {
DecompositionFactory_DDRM.svd(origin.numRows, origin.numCols, true, true, false)
.apply { decompose(origin.copy()) } .apply { decompose(origin.copy()) }
} }
override val u: Matrix<Double> get() = ejmlSvd.getU(null, false).wrapMatrix()
override val s: Matrix<Double> get() = ejmlSvd.getW(null).wrapMatrix()
override val v: Matrix<Double> get() = ejmlSvd.getV(null, false).wrapMatrix()
override val singularValues: Point<Double> get() = ejmlSvd.singularValues.asBuffer()
override val u: Matrix<Double> by lazy { svd.getU(null, false).wrapMatrix() }
override val s: Matrix<Double> by lazy { svd.getW(null).wrapMatrix() }
override val v: Matrix<Double> by lazy { svd.getV(null, false).wrapMatrix() }
override val singularValues: Point<Double> by lazy { DoubleBuffer(svd.singularValues) }
} }
QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> { QR -> object : QRDecomposition<Double> {
private val qr by lazy { val ejmlQr by lazy { DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } }
DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } override val q: Matrix<Double> get() = ejmlQr.getQ(null, false).wrapMatrix()
override val r: Matrix<Double> get() = ejmlQr.getR(null, false).wrapMatrix()
} }
override val q: Matrix<Double> by lazy { Cholesky -> object : CholeskyDecomposition<Double> {
qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
}
override val r: Matrix<Double> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
}
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
override val l: Matrix<Double> by lazy { override val l: Matrix<Double> by lazy {
val cholesky = val cholesky =
DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) }
cholesky.getT(null).wrapMatrix().withFeature(LFeature) cholesky.getT(null).wrapMatrix().withAttribute(LowerTriangular)
} }
} }
LupDecompositionFeature::class -> object : LupDecompositionFeature<Double> { LUP -> object : LupDecomposition<Double> {
private val lup by lazy { private val lup by lazy {
DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) }
} }
override val l: Matrix<Double> by lazy { override val l: Matrix<Double>
lup.getLower(null).wrapMatrix().withFeature(LFeature) get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular)
}
override val u: Matrix<Double> by lazy {
lup.getUpper(null).wrapMatrix().withFeature(UFeature)
}
override val p: Matrix<Double> by lazy { lup.getRowPivot(null).wrapMatrix() } override val u: Matrix<Double>
get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular)
override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer()
} }
else -> null else -> null
}?.let{
type.cast(it)
} }
@Suppress("UNCHECKED_CAST")
return raw as V?
} }
/** /**
@ -318,7 +302,6 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, Float64Field, DMatri
} }
/** /**
* [EjmlLinearSpace] implementation based on [CommonOps_FDRM], [DecompositionFactory_FDRM] operations and * [EjmlLinearSpace] implementation based on [CommonOps_FDRM], [DecompositionFactory_FDRM] operations and
* [FMatrixRMaj] matrices. * [FMatrixRMaj] matrices.
@ -457,77 +440,65 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, Float32Field, FMatrix
override fun Float.times(v: Point<Float>): EjmlFloatVector<FMatrixRMaj> = v * this override fun Float.times(v: Point<Float>): EjmlFloatVector<FMatrixRMaj> = v * this
@UnstableKMathAPI override fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<Float32>, attribute: A): V? {
override fun <F : StructureFeature> computeFeature(structure: Matrix<Float>, type: KClass<out F>): F? {
structure.getFeature(type)?.let { return it }
val origin = structure.toEjml().origin val origin = structure.toEjml().origin
return when (type) { val raw: Any? = when (attribute) {
InverseMatrixFeature::class -> object : InverseMatrixFeature<Float> { Inverted -> {
override val inverse: Matrix<Float> by lazy {
val res = origin.copy() val res = origin.copy()
CommonOps_FDRM.invert(res) CommonOps_FDRM.invert(res)
res.wrapMatrix() res.wrapMatrix()
} }
}
DeterminantFeature::class -> object : DeterminantFeature<Float> { Determinant -> CommonOps_FDRM.det(origin)
override val determinant: Float by lazy { CommonOps_FDRM.det(origin) } SVD -> object : SingularValueDecomposition<Float32> {
} val ejmlSvd by lazy {
DecompositionFactory_FDRM
SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Float> { .svd(origin.numRows, origin.numCols, true, true, false)
private val svd by lazy {
DecompositionFactory_FDRM.svd(origin.numRows, origin.numCols, true, true, false)
.apply { decompose(origin.copy()) } .apply { decompose(origin.copy()) }
} }
override val u: Matrix<Float32> get() = ejmlSvd.getU(null, false).wrapMatrix()
override val s: Matrix<Float32> get() = ejmlSvd.getW(null).wrapMatrix()
override val v: Matrix<Float32> get() = ejmlSvd.getV(null, false).wrapMatrix()
override val singularValues: Point<Float32> get() = ejmlSvd.singularValues.asBuffer()
override val u: Matrix<Float> by lazy { svd.getU(null, false).wrapMatrix() }
override val s: Matrix<Float> by lazy { svd.getW(null).wrapMatrix() }
override val v: Matrix<Float> by lazy { svd.getV(null, false).wrapMatrix() }
override val singularValues: Point<Float> by lazy { FloatBuffer(svd.singularValues) }
} }
QRDecompositionFeature::class -> object : QRDecompositionFeature<Float> { QR -> object : QRDecomposition<Float32> {
private val qr by lazy { val ejmlQr by lazy { DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) } }
DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) } override val q: Matrix<Float32> get() = ejmlQr.getQ(null, false).wrapMatrix()
override val r: Matrix<Float32> get() = ejmlQr.getR(null, false).wrapMatrix()
} }
override val q: Matrix<Float> by lazy { Cholesky -> object : CholeskyDecomposition<Float32> {
qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) override val l: Matrix<Float32> by lazy {
}
override val r: Matrix<Float> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
}
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Float> {
override val l: Matrix<Float> by lazy {
val cholesky = val cholesky =
DecompositionFactory_FDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } DecompositionFactory_FDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) }
cholesky.getT(null).wrapMatrix().withFeature(LFeature) cholesky.getT(null).wrapMatrix().withAttribute(LowerTriangular)
} }
} }
LupDecompositionFeature::class -> object : LupDecompositionFeature<Float> { LUP -> object : LupDecomposition<Float32> {
private val lup by lazy { private val lup by lazy {
DecompositionFactory_FDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } DecompositionFactory_FDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) }
} }
override val l: Matrix<Float> by lazy { override val l: Matrix<Float32>
lup.getLower(null).wrapMatrix().withFeature(LFeature) get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular)
}
override val u: Matrix<Float> by lazy {
lup.getUpper(null).wrapMatrix().withFeature(UFeature)
}
override val p: Matrix<Float> by lazy { lup.getRowPivot(null).wrapMatrix() } override val u: Matrix<Float32>
get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular)
override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer()
} }
else -> null else -> null
}?.let{
type.cast(it)
} }
@Suppress("UNCHECKED_CAST")
return raw as V?
} }
/** /**
@ -558,7 +529,6 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, Float32Field, FMatrix
} }
/** /**
* [EjmlLinearSpace] implementation based on [CommonOps_DSCC], [DecompositionFactory_DSCC] operations and * [EjmlLinearSpace] implementation based on [CommonOps_DSCC], [DecompositionFactory_DSCC] operations and
* [DMatrixSparseCSC] matrices. * [DMatrixSparseCSC] matrices.
@ -705,64 +675,52 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, Float64Field, DMatri
override fun Double.times(v: Point<Double>): EjmlDoubleVector<DMatrixSparseCSC> = v * this override fun Double.times(v: Point<Double>): EjmlDoubleVector<DMatrixSparseCSC> = v * this
@UnstableKMathAPI override fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<Double>, attribute: A): V? {
override fun <F : StructureFeature> computeFeature(structure: Matrix<Double>, type: KClass<out F>): F? {
structure.getFeature(type)?.let { return it }
val origin = structure.toEjml().origin val origin = structure.toEjml().origin
return when (type) { val raw: Any? = when (attribute) {
QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> { Inverted -> {
private val qr by lazy { val res = DMatrixRMaj(origin.numRows,origin.numCols)
DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } CommonOps_DSCC.invert(origin,res)
res.wrapMatrix()
} }
override val q: Matrix<Double> by lazy { Determinant -> CommonOps_DSCC.det(origin)
qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
QR -> object : QRDecomposition<Double> {
val ejmlQr by lazy { DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } }
override val q: Matrix<Double> get() = ejmlQr.getQ(null, false).wrapMatrix()
override val r: Matrix<Double> get() = ejmlQr.getR(null, false).wrapMatrix()
} }
override val r: Matrix<Double> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } Cholesky -> object : CholeskyDecomposition<Double> {
}
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
override val l: Matrix<Double> by lazy { override val l: Matrix<Double> by lazy {
val cholesky = val cholesky =
DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) } DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) }
(cholesky.getT(null) as DMatrix).wrapMatrix().withFeature(LFeature) (cholesky.getT(null) as DMatrix).wrapMatrix().withAttribute(LowerTriangular)
} }
} }
LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : LUP -> object : LupDecomposition<Double> {
LUDecompositionFeature<Double>, DeterminantFeature<Double>, InverseMatrixFeature<Double> { private val lup by lazy {
private val lu by lazy {
DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) }
} }
override val l: Matrix<Double> by lazy { override val l: Matrix<Double>
lu.getLower(null).wrapMatrix().withFeature(LFeature) get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular)
}
override val u: Matrix<Double> by lazy {
lu.getUpper(null).wrapMatrix().withFeature(UFeature)
}
override val inverse: Matrix<Double> by lazy { override val u: Matrix<Double>
var a = origin get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular)
val inverse = DMatrixRMaj(1, 1) override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer()
val solver = LinearSolverFactory_DSCC.lu(FillReducing.NONE)
if (solver.modifiesA()) a = a.copy()
val i = CommonOps_DDRM.identity(a.numRows)
solver.solve(i, inverse)
inverse.wrapMatrix()
}
override val determinant: Double by lazy { elementAlgebra.number(lu.computeDeterminant().real) }
} }
else -> null else -> null
}?.let{
type.cast(it)
} }
@Suppress("UNCHECKED_CAST")
return raw as V?
} }
/** /**
@ -793,7 +751,6 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, Float64Field, DMatri
} }
/** /**
* [EjmlLinearSpace] implementation based on [CommonOps_FSCC], [DecompositionFactory_FSCC] operations and * [EjmlLinearSpace] implementation based on [CommonOps_FSCC], [DecompositionFactory_FSCC] operations and
* [FMatrixSparseCSC] matrices. * [FMatrixSparseCSC] matrices.
@ -939,65 +896,52 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, Float32Field, FMatrix
} }
override fun Float.times(v: Point<Float>): EjmlFloatVector<FMatrixSparseCSC> = v * this override fun Float.times(v: Point<Float>): EjmlFloatVector<FMatrixSparseCSC> = v * this
override fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<Float32>, attribute: A): V? {
@UnstableKMathAPI
override fun <F : StructureFeature> computeFeature(structure: Matrix<Float>, type: KClass<out F>): F? {
structure.getFeature(type)?.let { return it }
val origin = structure.toEjml().origin val origin = structure.toEjml().origin
return when (type) { val raw: Any? = when (attribute) {
QRDecompositionFeature::class -> object : QRDecompositionFeature<Float> { Inverted -> {
private val qr by lazy { val res = FMatrixRMaj(origin.numRows,origin.numCols)
DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } CommonOps_FSCC.invert(origin,res)
res.wrapMatrix()
} }
override val q: Matrix<Float> by lazy { Determinant -> CommonOps_FSCC.det(origin)
qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
QR -> object : QRDecomposition<Float32> {
val ejmlQr by lazy { DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } }
override val q: Matrix<Float32> get() = ejmlQr.getQ(null, false).wrapMatrix()
override val r: Matrix<Float32> get() = ejmlQr.getR(null, false).wrapMatrix()
} }
override val r: Matrix<Float> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } Cholesky -> object : CholeskyDecomposition<Float32> {
} override val l: Matrix<Float32> by lazy {
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Float> {
override val l: Matrix<Float> by lazy {
val cholesky = val cholesky =
DecompositionFactory_FSCC.cholesky().apply { decompose(origin.copy()) } DecompositionFactory_FSCC.cholesky().apply { decompose(origin.copy()) }
(cholesky.getT(null) as FMatrix).wrapMatrix().withFeature(LFeature) (cholesky.getT(null) as FMatrix).wrapMatrix().withAttribute(LowerTriangular)
} }
} }
LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : LUP -> object : LupDecomposition<Float32> {
LUDecompositionFeature<Float>, DeterminantFeature<Float>, InverseMatrixFeature<Float> { private val lup by lazy {
private val lu by lazy {
DecompositionFactory_FSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } DecompositionFactory_FSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) }
} }
override val l: Matrix<Float> by lazy { override val l: Matrix<Float32>
lu.getLower(null).wrapMatrix().withFeature(LFeature) get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular)
}
override val u: Matrix<Float> by lazy {
lu.getUpper(null).wrapMatrix().withFeature(UFeature)
}
override val inverse: Matrix<Float> by lazy { override val u: Matrix<Float32>
var a = origin get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular)
val inverse = FMatrixRMaj(1, 1) override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer()
val solver = LinearSolverFactory_FSCC.lu(FillReducing.NONE)
if (solver.modifiesA()) a = a.copy()
val i = CommonOps_FDRM.identity(a.numRows)
solver.solve(i, inverse)
inverse.wrapMatrix()
}
override val determinant: Float by lazy { elementAlgebra.number(lu.computeDeterminant().real) }
} }
else -> null else -> null
}?.let{
type.cast(it)
} }
@Suppress("UNCHECKED_CAST")
return raw as V?
} }
/** /**

View File

@ -58,19 +58,19 @@ internal class EjmlMatrixTest {
@OptIn(UnstableKMathAPI::class) @OptIn(UnstableKMathAPI::class)
@Test @Test
fun features() { fun features() = EjmlLinearSpaceDDRM {
val m = randomMatrix val m = randomMatrix
val w = EjmlDoubleMatrix(m) val w = EjmlDoubleMatrix(m)
val det: Determinant<Double> = EjmlLinearSpaceDDRM.attributeForOrNull(w) ?: fail() val det: Double = w.getOrComputeAttribute(Determinant) ?: fail()
assertEquals(CommonOps_DDRM.det(m), det.determinant) assertEquals(CommonOps_DDRM.det(m), det)
val lup: LupDecompositionAttribute<Double> = EjmlLinearSpaceDDRM.attributeForOrNull(w) ?: fail() val lup: LupDecomposition<Double> = w.getOrComputeAttribute(LUP) ?: fail()
val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols) val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols)
.also { it.decompose(m.copy()) } .also { it.decompose(m.copy()) }
assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getLower(null)), lup.l) assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getLower(null)), lup.l)
assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getUpper(null)), lup.u) assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getUpper(null)), lup.u)
assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getRowPivot(null)), lup.p) assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getRowPivot(null)), lup.pivotMatrix(this))
} }
@Test @Test

View File

@ -9,19 +9,8 @@ Specialization of KMath APIs for Double numbers.
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-for-real:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-for-real:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-for-real:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -30,6 +19,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-for-real:0.4.0-dev-1") implementation("space.kscience:kmath-for-real:0.4.0-dev-3")
} }
``` ```

View File

@ -6,6 +6,7 @@ kscience {
jvm() jvm()
js() js()
native() native()
wasm()
dependencies { dependencies {
api(projects.kmathCore) api(projects.kmathCore)

View File

@ -7,7 +7,7 @@ package space.kscience.kmath.real
import space.kscience.kmath.linear.asMatrix import space.kscience.kmath.linear.asMatrix
import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.linearSpace
import space.kscience.kmath.linear.transpose import space.kscience.kmath.linear.transposed
import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.algebra
import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.Float64Buffer
import kotlin.test.Test import kotlin.test.Test
@ -34,7 +34,7 @@ internal class DoubleVectorTest {
val vector1 = Float64Buffer(5) { it.toDouble() } val vector1 = Float64Buffer(5) { it.toDouble() }
val vector2 = Float64Buffer(5) { 5 - it.toDouble() } val vector2 = Float64Buffer(5) { 5 - it.toDouble() }
val matrix1 = vector1.asMatrix() val matrix1 = vector1.asMatrix()
val matrix2 = vector2.asMatrix().transpose() val matrix2 = vector2.asMatrix().transposed()
val product = matrix1 dot matrix2 val product = matrix1 dot matrix2
assertEquals(5.0, product[1, 0]) assertEquals(5.0, product[1, 0])
assertEquals(6.0, product[2, 2]) assertEquals(6.0, product[2, 2])

View File

@ -11,19 +11,8 @@ Functions and interpolations.
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-functions:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-functions:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-functions:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -32,6 +21,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-functions:0.4.0-dev-1") implementation("space.kscience:kmath-functions:0.4.0-dev-3")
} }
``` ```

View File

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

View File

@ -92,7 +92,7 @@ public inline fun <reified T : Any> GaussIntegrator<T>.integrate(
range: ClosedRange<Double>, range: ClosedRange<Double>,
order: Int = 10, order: Int = 10,
intervals: Int = 10, intervals: Int = 10,
attributesBuilder: AttributesBuilder<UnivariateIntegrand<T>>.() -> Unit, attributesBuilder: AttributesBuilder<UnivariateIntegrand<T>>.() -> Unit = {},
noinline function: (Double) -> T, noinline function: (Double) -> T,
): UnivariateIntegrand<T> { ): UnivariateIntegrand<T> {
require(range.endInclusive > range.start) { "The range upper bound should be higher than lower bound" } require(range.endInclusive > range.start) { "The range upper bound should be higher than lower bound" }

View File

@ -23,7 +23,7 @@ import space.kscience.kmath.structures.MutableBufferFactory
*/ */
public class SplineInterpolator<T : Comparable<T>>( public class SplineInterpolator<T : Comparable<T>>(
override val algebra: Field<T>, override val algebra: Field<T>,
public val bufferFactory: MutableBufferFactory<T>, public val bufferFactory: MutableBufferFactory<T> = algebra.bufferFactory,
) : PolynomialInterpolator<T> { ) : PolynomialInterpolator<T> {
//TODO possibly optimize zeroed buffers //TODO possibly optimize zeroed buffers

View File

@ -9,6 +9,7 @@ package space.kscience.kmath.functions.testUtils
import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.structures.MutableBufferFactory
class IntModulo { class IntModulo {
@ -109,15 +110,17 @@ class IntModulo {
} }
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
class IntModuloRing : Ring<IntModulo>, ScaleOperations<IntModulo> { class IntModuloRing(modulus: Int) : Ring<IntModulo>, ScaleOperations<IntModulo> {
val modulus: Int val modulus: Int
constructor(modulus: Int) { init {
require(modulus != 0) { "modulus can not be zero" } require(modulus != 0) { "modulus can not be zero" }
this.modulus = if (modulus < 0) -modulus else modulus this.modulus = if (modulus < 0) -modulus else modulus
} }
override val bufferFactory: MutableBufferFactory<IntModulo> = MutableBufferFactory()
override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false)
override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false)

View File

@ -10,6 +10,7 @@ package space.kscience.kmath.functions.testUtils
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.NumbersAddOps
import space.kscience.kmath.structures.MutableBufferFactory
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
class Rational { class Rational {
@ -159,6 +160,7 @@ class Rational {
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
@OptIn(UnstableKMathAPI::class) @OptIn(UnstableKMathAPI::class)
object RationalField : Field<Rational>, NumbersAddOps<Rational> { object RationalField : Field<Rational>, NumbersAddOps<Rational> {
override val bufferFactory: MutableBufferFactory<Rational> = MutableBufferFactory()
override inline val zero: Rational get() = Rational.ZERO override inline val zero: Rational get() = Rational.ZERO
override inline val one: Rational get() = Rational.ONE override inline val one: Rational get() = Rational.ONE

View File

@ -18,15 +18,15 @@ import kotlin.test.assertEquals
class SplineIntegralTest { class SplineIntegralTest {
@Test @Test
fun integratePolynomial(){ fun integratePolynomial() {
val polynomial = Polynomial(1.0, 2.0, 3.0) val polynomial = Polynomial(1.0, 2.0, 3.0)
val integral = polynomial.integrate(Float64Field,1.0..2.0) val integral = polynomial.integrate(Float64Field, 1.0..2.0)
assertEquals(11.0, integral, 0.001) assertEquals(11.0, integral, 0.001)
} }
@Test @Test
fun gaussSin() { fun gaussSin() {
val res = Float64Field.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> val res = Float64Field.splineIntegrator.integrate(0.0..2 * PI, { IntegrandMaxCalls(5) }) { x ->
sin(x) sin(x)
} }
assertEquals(0.0, res.value, 1e-2) assertEquals(0.0, res.value, 1e-2)
@ -34,8 +34,8 @@ class SplineIntegralTest {
@Test @Test
fun gaussUniform() { fun gaussUniform() {
val res = Float64Field.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> val res = Float64Field.splineIntegrator.integrate(35.0..100.0, { IntegrandMaxCalls(20) }) { x ->
if(x in 30.0..50.0){ if (x in 30.0..50.0) {
1.0 1.0
} else { } else {
0.0 0.0

View File

@ -6,19 +6,8 @@
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-geometry:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-geometry:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-geometry:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -27,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-geometry:0.4.0-dev-1") implementation("space.kscience:kmath-geometry:0.4.0-dev-3")
} }
``` ```

View File

@ -7,8 +7,8 @@ package space.kscience.kmath.geometry
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.kmath.geometry.euclidean2d.DoubleVector2D import space.kscience.kmath.geometry.euclidean2d.Float64Vector2D
import space.kscience.kmath.geometry.euclidean3d.DoubleVector3D import space.kscience.kmath.geometry.euclidean3d.Float64Vector3D
/** /**
* A line formed by [start] vector of start and a [direction] vector. Direction vector is not necessarily normalized, * A line formed by [start] vector of start and a [direction] vector. Direction vector is not necessarily normalized,
@ -25,8 +25,8 @@ private data class LineImpl<out V : Any>(override val start: V, override val dir
public fun <V : Any> Line(base: V, direction: V): Line<V> = LineImpl(base, direction) public fun <V : Any> Line(base: V, direction: V): Line<V> = LineImpl(base, direction)
public typealias Line2D = Line<DoubleVector2D> public typealias Line2D = Line<Float64Vector2D>
public typealias Line3D = Line<DoubleVector3D> public typealias Line3D = Line<Float64Vector3D>
/** /**
* A directed line segment between [begin] and [end] * A directed line segment between [begin] and [end]
@ -49,5 +49,5 @@ public fun <V : Any> LineSegment<V>.line(algebra: GeometrySpace<V, *>): Line<V>
Line(begin, end - begin) Line(begin, end - begin)
} }
public typealias LineSegment2D = LineSegment<DoubleVector2D> public typealias LineSegment2D = LineSegment<Float64Vector2D>
public typealias LineSegment3D = LineSegment<DoubleVector3D> public typealias LineSegment3D = LineSegment<Float64Vector3D>

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.geometry package space.kscience.kmath.geometry
import space.kscience.attributes.SafeType
import space.kscience.kmath.linear.Point import space.kscience.kmath.linear.Point
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
@ -33,6 +34,9 @@ public fun <T> Buffer<T>.asVector3D(): Vector3D<T> = object : Vector3D<T> {
require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" } require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" }
} }
override val type: SafeType<T> = this@asVector3D.type
override val x: T get() = this@asVector3D[0] override val x: T get() = this@asVector3D[0]
override val y: T get() = this@asVector3D[1] override val y: T get() = this@asVector3D[1]
override val z: T get() = this@asVector3D[2] override val z: T get() = this@asVector3D[2]

View File

@ -11,6 +11,8 @@ import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import space.kscience.kmath.operations.Group
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.jvm.JvmInline import kotlin.jvm.JvmInline
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.floor import kotlin.math.floor
@ -28,11 +30,19 @@ public sealed interface Angle : Comparable<Angle> {
public operator fun div(other: Angle): Double public operator fun div(other: Angle): Double
public operator fun unaryMinus(): Angle public operator fun unaryMinus(): Angle
public companion object { public companion object: Group<Angle> {
public val zero: Radians = Radians(0.0) override val zero: Radians = Radians(0.0)
public val pi: Radians = Radians(PI) public val pi: Radians = Radians(PI)
public val piTimes2: Radians = Radians(PI * 2) public val piTimes2: Radians = Radians(PI * 2)
public val piDiv2: Radians = Radians(PI / 2) public val piDiv2: Radians = Radians(PI / 2)
override fun add(left: Angle, right: Angle): Angle = left + right
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
override fun Angle.unaryMinus(): Angle = -this
override val bufferFactory: MutableBufferFactory<Angle> = MutableBufferFactory()
} }
} }
@ -43,7 +53,7 @@ public object AngleSerializer : KSerializer<Angle> {
override fun deserialize(decoder: Decoder): Angle = decoder.decodeDouble().degrees override fun deserialize(decoder: Decoder): Angle = decoder.decodeDouble().degrees
override fun serialize(encoder: Encoder, value: Angle) { override fun serialize(encoder: Encoder, value: Angle) {
encoder.encodeDouble(value.degrees) encoder.encodeDouble(value.toDegrees().value)
} }
} }
@ -56,16 +66,16 @@ public value class Radians(public val value: Double) : Angle {
override fun toRadians(): Radians = this override fun toRadians(): Radians = this
override fun toDegrees(): Degrees = Degrees(value * 180 / PI) override fun toDegrees(): Degrees = Degrees(value * 180 / PI)
public override fun plus(other: Angle): Radians = Radians(value + other.radians) public override fun plus(other: Angle): Radians = Radians(value + other.toRadians().value)
public override fun minus(other: Angle): Radians = Radians(value - other.radians) public override fun minus(other: Angle): Radians = Radians(value - other.toRadians().value)
public override fun times(other: Number): Radians = Radians(value * other.toDouble()) public override fun times(other: Number): Radians = Radians(value * other.toDouble())
public override fun div(other: Number): Radians = Radians(value / other.toDouble()) public override fun div(other: Number): Radians = Radians(value / other.toDouble())
override fun div(other: Angle): Double = value / other.radians override fun div(other: Angle): Double = value / other.toRadians().value
public override fun unaryMinus(): Radians = Radians(-value) public override fun unaryMinus(): Radians = Radians(-value)
override fun compareTo(other: Angle): Int = value.compareTo(other.radians) override fun compareTo(other: Angle): Int = value.compareTo(other.toRadians().value)
} }
public fun sin(angle: Angle): Double = kotlin.math.sin(angle.toRadians().value) public fun sin(angle: Angle): Double = kotlin.math.sin(angle.toRadians().value)
@ -85,16 +95,16 @@ public value class Degrees(public val value: Double) : Angle {
override fun toRadians(): Radians = Radians(value * PI / 180) override fun toRadians(): Radians = Radians(value * PI / 180)
override fun toDegrees(): Degrees = this override fun toDegrees(): Degrees = this
public override fun plus(other: Angle): Degrees = Degrees(value + other.degrees) public override fun plus(other: Angle): Degrees = Degrees(value + other.toDegrees().value)
public override fun minus(other: Angle): Degrees = Degrees(value - other.degrees) public override fun minus(other: Angle): Degrees = Degrees(value - other.toDegrees().value)
public override fun times(other: Number): Degrees = Degrees(value * other.toDouble()) public override fun times(other: Number): Degrees = Degrees(value * other.toDouble())
public override fun div(other: Number): Degrees = Degrees(value / other.toDouble()) public override fun div(other: Number): Degrees = Degrees(value / other.toDouble())
override fun div(other: Angle): Double = value / other.degrees override fun div(other: Angle): Double = value / other.toDegrees().value
public override fun unaryMinus(): Degrees = Degrees(-value) public override fun unaryMinus(): Degrees = Degrees(-value)
override fun compareTo(other: Angle): Int = value.compareTo(other.degrees) override fun compareTo(other: Angle): Int = value.compareTo(other.toDegrees().value)
} }
public val Number.degrees: Degrees get() = Degrees(toDouble()) public val Number.degrees: Degrees get() = Degrees(toDouble())
@ -106,6 +116,6 @@ public val Angle.degrees: Double get() = toDegrees().value
* Normalized angle 2 PI range symmetric around [center]. By default, uses (0, 2PI) range. * Normalized angle 2 PI range symmetric around [center]. By default, uses (0, 2PI) range.
*/ */
public fun Angle.normalized(center: Angle = Angle.pi): Angle = public fun Angle.normalized(center: Angle = Angle.pi): Angle =
this - Angle.piTimes2 * floor((radians + PI - center.radians) / PI / 2) this - Angle.piTimes2 * floor((toRadians().value + PI - center.toRadians().value) / PI / 2)
public fun abs(angle: Angle): Angle = if (angle < Angle.zero) -angle else angle public fun abs(angle: Angle): Angle = if (angle < Angle.zero) -angle else angle

View File

@ -11,19 +11,22 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import space.kscience.attributes.SafeType
import space.kscience.kmath.geometry.GeometrySpace import space.kscience.kmath.geometry.GeometrySpace
import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.geometry.Vector2D
import space.kscience.kmath.operations.Float32Field import space.kscience.kmath.operations.Float32Field
import space.kscience.kmath.structures.Float32 import space.kscience.kmath.structures.Float32
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt import kotlin.math.sqrt
@Serializable(Float32Space2D.VectorSerializer::class) @Serializable(Float32Space2D.VectorSerializer::class)
public interface Float32Vector2D : Vector2D<Float> public interface Float32Vector2D : Vector2D<Float32>{
override val type: SafeType<Float32> get() = Float32Field.type
}
public object Float32Space2D : GeometrySpace<Float32Vector2D, Float32> { public object Float32Space2D : GeometrySpace<Float32Vector2D, Float32> {
@Serializable @Serializable
@SerialName("Float32Vector2D") @SerialName("Float32Vector2D")
private data class Vector2DImpl( private data class Vector2DImpl(
@ -72,6 +75,8 @@ public object Float32Space2D : GeometrySpace<Float32Vector2D, Float32> {
public val yAxis: Float32Vector2D = vector(0.0, 1.0) public val yAxis: Float32Vector2D = vector(0.0, 1.0)
override val defaultPrecision: Float32 = 1e-3f override val defaultPrecision: Float32 = 1e-3f
override val bufferFactory: MutableBufferFactory<Float32Vector2D> = MutableBufferFactory()
} }
public fun Float32Vector2D(x: Number, y: Number): Float32Vector2D = Float32Space2D.vector(x, y) public fun Float32Vector2D(x: Number, y: Number): Float32Vector2D = Float32Space2D.vector(x, y)

View File

@ -11,66 +11,77 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import space.kscience.attributes.SafeType
import space.kscience.kmath.geometry.GeometrySpace import space.kscience.kmath.geometry.GeometrySpace
import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.geometry.Vector2D
import space.kscience.kmath.linear.Float64LinearSpace
import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt import kotlin.math.sqrt
public typealias DoubleVector2D = Vector2D<Double> @Serializable(Float64Space2D.VectorSerializer::class)
public typealias Float64Vector2D = Vector2D<Double> public interface Float64Vector2D : Vector2D<Float64> {
override val type: SafeType<Float64> get() = Float64Field.type
}
@Deprecated("Use Float64Vector2D", ReplaceWith("Float64Vector2D"))
public typealias DoubleVector2D = Float64Vector2D
public val Vector2D<Double>.r: Double get() = Float64Space2D.norm(this)
/** /**
* 2D Euclidean space * 2D Euclidean space
*/ */
public object Float64Space2D : GeometrySpace<DoubleVector2D>, ScaleOperations<DoubleVector2D> { public object Float64Space2D : GeometrySpace<Float64Vector2D, Float64>, ScaleOperations<Float64Vector2D> {
@Serializable @Serializable
@SerialName("Float64Vector2D") @SerialName("Float64Vector2D")
private data class Vector2DImpl( private data class Vector2DImpl(
override val x: Double, override val x: Double,
override val y: Double, override val y: Double,
) : DoubleVector2D ) : Float64Vector2D
public object VectorSerializer : KSerializer<DoubleVector2D> { public object VectorSerializer : KSerializer<Float64Vector2D> {
private val proxySerializer = Vector2DImpl.serializer() private val proxySerializer = Vector2DImpl.serializer()
override val descriptor: SerialDescriptor get() = proxySerializer.descriptor override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
override fun deserialize(decoder: Decoder): DoubleVector2D = decoder.decodeSerializableValue(proxySerializer) override fun deserialize(decoder: Decoder): Float64Vector2D = decoder.decodeSerializableValue(proxySerializer)
override fun serialize(encoder: Encoder, value: DoubleVector2D) { override fun serialize(encoder: Encoder, value: Float64Vector2D) {
val vector = value as? Vector2DImpl ?: Vector2DImpl(value.x, value.y) val vector = value as? Vector2DImpl ?: Vector2DImpl(value.x, value.y)
encoder.encodeSerializableValue(proxySerializer, vector) encoder.encodeSerializableValue(proxySerializer, vector)
} }
} }
public fun vector(x: Number, y: Number): DoubleVector2D = Vector2DImpl(x.toDouble(), y.toDouble()) public fun vector(x: Number, y: Number): Float64Vector2D = Vector2DImpl(x.toDouble(), y.toDouble())
override val zero: DoubleVector2D by lazy { vector(0.0, 0.0) } override val zero: Float64Vector2D by lazy { vector(0.0, 0.0) }
override fun norm(arg: DoubleVector2D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2)) override fun norm(arg: Float64Vector2D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2))
override fun DoubleVector2D.unaryMinus(): DoubleVector2D = vector(-x, -y) override fun Float64Vector2D.unaryMinus(): Float64Vector2D = vector(-x, -y)
override fun DoubleVector2D.distanceTo(other: DoubleVector2D): Double = norm(this - other) override fun Float64Vector2D.distanceTo(other: Float64Vector2D): Double = norm(this - other)
override fun add(left: DoubleVector2D, right: DoubleVector2D): DoubleVector2D = override fun add(left: Float64Vector2D, right: Float64Vector2D): Float64Vector2D =
vector(left.x + right.x, left.y + right.y) vector(left.x + right.x, left.y + right.y)
override fun scale(a: DoubleVector2D, value: Double): DoubleVector2D = vector(a.x * value, a.y * value) override fun scale(a: Float64Vector2D, value: Double): Float64Vector2D = vector(a.x * value, a.y * value)
override fun DoubleVector2D.dot(other: DoubleVector2D): Double = x * other.x + y * other.y override fun Float64Vector2D.dot(other: Float64Vector2D): Double = x * other.x + y * other.y
public val xAxis: DoubleVector2D = vector(1.0, 0.0) public val xAxis: Float64Vector2D = vector(1.0, 0.0)
public val yAxis: DoubleVector2D = vector(0.0, 1.0) public val yAxis: Float64Vector2D = vector(0.0, 1.0)
override val defaultPrecision: Double = 1e-6 override val defaultPrecision: Double = 1e-6
override val bufferFactory: MutableBufferFactory<Float64Vector2D> = MutableBufferFactory()
} }
public fun Float64Vector2D(x: Number, y: Number): Float64Vector2D = Float64Space2D.vector(x, y) public fun Float64Vector2D(x: Number, y: Number): Float64Vector2D = Float64Space2D.vector(x, y)
public val Float64Vector2D.r: Float64 get() = Float64Space2D.norm(this)
public val Float64Field.euclidean2D: Float64Space2D get() = Float64Space2D public val Float64Field.euclidean2D: Float64Space2D get() = Float64Space2D

View File

@ -11,15 +11,19 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import space.kscience.attributes.SafeType
import space.kscience.kmath.geometry.GeometrySpace import space.kscience.kmath.geometry.GeometrySpace
import space.kscience.kmath.geometry.Vector3D import space.kscience.kmath.geometry.Vector3D
import space.kscience.kmath.operations.Float32Field import space.kscience.kmath.operations.Float32Field
import space.kscience.kmath.structures.Float32 import space.kscience.kmath.structures.Float32
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt import kotlin.math.sqrt
@Serializable(Float32Space3D.VectorSerializer::class) @Serializable(Float32Space3D.VectorSerializer::class)
public interface Float32Vector3D : Vector3D<Float> public interface Float32Vector3D : Vector3D<Float>{
override val type: SafeType<Float32> get() = Float32Field.type
}
public object Float32Space3D : GeometrySpace<Float32Vector3D, Float32> { public object Float32Space3D : GeometrySpace<Float32Vector3D, Float32> {
@ -101,6 +105,8 @@ public object Float32Space3D : GeometrySpace<Float32Vector3D, Float32> {
public val zAxis: Float32Vector3D = vector(0.0, 0.0, 1.0) public val zAxis: Float32Vector3D = vector(0.0, 0.0, 1.0)
override val defaultPrecision: Float32 = 1e-3f override val defaultPrecision: Float32 = 1e-3f
override val bufferFactory: MutableBufferFactory<Float32Vector3D> = MutableBufferFactory()
} }
public fun Float32Vector3D(x: Number, y: Number, z: Number): Float32Vector3D = Float32Space3D.vector(x, y, z) public fun Float32Vector3D(x: Number, y: Number, z: Number): Float32Vector3D = Float32Space3D.vector(x, y, z)

View File

@ -11,10 +11,13 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import space.kscience.attributes.SafeType
import space.kscience.kmath.geometry.GeometrySpace import space.kscience.kmath.geometry.GeometrySpace
import space.kscience.kmath.geometry.Vector3D import space.kscience.kmath.geometry.Vector3D
import space.kscience.kmath.linear.Float64LinearSpace import space.kscience.kmath.linear.Float64LinearSpace
import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt import kotlin.math.sqrt
@ -31,12 +34,16 @@ internal fun leviCivita(i: Int, j: Int, k: Int): Int = when {
else -> 0 else -> 0
} }
public typealias DoubleVector3D = Vector3D<Double> @Serializable(Float64Space3D.VectorSerializer::class)
public typealias Float64Vector3D = Vector3D<Double> public interface Float64Vector3D : Vector3D<Float64> {
override val type: SafeType<Float64> get() = Float64Field.type
}
public val DoubleVector3D.r: Double get() = Float64Space3D.norm(this) @Deprecated("Use Float64Vector3D", ReplaceWith("Float64Vector3D"))
public typealias DoubleVector3D = Float64Vector3D
public object Float64Space3D : GeometrySpace<DoubleVector3D, Double>{
public object Float64Space3D : GeometrySpace<Vector3D<Float64>, Double> {
public val linearSpace: Float64LinearSpace = Float64LinearSpace public val linearSpace: Float64LinearSpace = Float64LinearSpace
@ -46,52 +53,52 @@ public object Float64Space3D : GeometrySpace<DoubleVector3D, Double>{
override val x: Double, override val x: Double,
override val y: Double, override val y: Double,
override val z: Double, override val z: Double,
) : DoubleVector3D ) : Float64Vector3D
public object VectorSerializer : KSerializer<DoubleVector3D> { public object VectorSerializer : KSerializer<Float64Vector3D> {
private val proxySerializer = Vector3DImpl.serializer() private val proxySerializer = Vector3DImpl.serializer()
override val descriptor: SerialDescriptor get() = proxySerializer.descriptor override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
override fun deserialize(decoder: Decoder): DoubleVector3D = decoder.decodeSerializableValue(proxySerializer) override fun deserialize(decoder: Decoder): Float64Vector3D = decoder.decodeSerializableValue(proxySerializer)
override fun serialize(encoder: Encoder, value: DoubleVector3D) { override fun serialize(encoder: Encoder, value: Float64Vector3D) {
val vector = value as? Vector3DImpl ?: Vector3DImpl(value.x, value.y, value.z) val vector = value as? Vector3DImpl ?: Vector3DImpl(value.x, value.y, value.z)
encoder.encodeSerializableValue(proxySerializer, vector) encoder.encodeSerializableValue(proxySerializer, vector)
} }
} }
public fun vector(x: Double, y: Double, z: Double): DoubleVector3D = public fun vector(x: Double, y: Double, z: Double): Float64Vector3D =
Vector3DImpl(x, y, z) Vector3DImpl(x, y, z)
public fun vector(x: Number, y: Number, z: Number): DoubleVector3D = public fun vector(x: Number, y: Number, z: Number): Float64Vector3D =
vector(x.toDouble(), y.toDouble(), z.toDouble()) vector(x.toDouble(), y.toDouble(), z.toDouble())
override val zero: DoubleVector3D by lazy { vector(0.0, 0.0, 0.0) } override val zero: Float64Vector3D by lazy { vector(0.0, 0.0, 0.0) }
override fun norm(arg: DoubleVector3D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2) + arg.z.pow(2)) override fun norm(arg: Vector3D<Float64>): Double = sqrt(arg.x.pow(2) + arg.y.pow(2) + arg.z.pow(2))
public fun DoubleVector3D.norm(): Double = norm(this) public fun Vector3D<Float64>.norm(): Double = norm(this)
override fun DoubleVector3D.unaryMinus(): DoubleVector3D = vector(-x, -y, -z) override fun Vector3D<Float64>.unaryMinus(): Float64Vector3D = vector(-x, -y, -z)
override fun DoubleVector3D.distanceTo(other: DoubleVector3D): Double = (this - other).norm() override fun Vector3D<Float64>.distanceTo(other: Vector3D<Float64>): Double = (this - other).norm()
override fun add(left: DoubleVector3D, right: DoubleVector3D): DoubleVector3D = override fun add(left: Vector3D<Float64>, right: Vector3D<Float64>): Float64Vector3D =
vector(left.x + right.x, left.y + right.y, left.z + right.z) vector(left.x + right.x, left.y + right.y, left.z + right.z)
override fun scale(a: DoubleVector3D, value: Double): DoubleVector3D = override fun scale(a: Vector3D<Float64>, value: Double): Float64Vector3D =
vector(a.x * value, a.y * value, a.z * value) vector(a.x * value, a.y * value, a.z * value)
override fun DoubleVector3D.dot(other: DoubleVector3D): Double = override fun Vector3D<Float64>.dot(other: Vector3D<Float64>): Double =
x * other.x + y * other.y + z * other.z x * other.x + y * other.y + z * other.z
/** /**
* Compute vector product of [first] and [second]. The basis is assumed to be right-handed. * Compute vector product of [first] and [second]. The basis is assumed to be right-handed.
*/ */
public fun vectorProduct( public fun vectorProduct(
first: DoubleVector3D, first: Vector3D<Float64>,
second: DoubleVector3D, second: Vector3D<Float64>,
): DoubleVector3D { ): Float64Vector3D {
var x = 0.0 var x = 0.0
var y = 0.0 var y = 0.0
var z = 0.0 var z = 0.0
@ -110,13 +117,18 @@ public object Float64Space3D : GeometrySpace<DoubleVector3D, Double>{
/** /**
* Vector product with the right basis * Vector product with the right basis
*/ */
public infix fun DoubleVector3D.cross(other: DoubleVector3D): Vector3D<Double> = vectorProduct(this, other) public infix fun Vector3D<Float64>.cross(other: Vector3D<Float64>): Vector3D<Double> = vectorProduct(this, other)
public val xAxis: DoubleVector3D = vector(1.0, 0.0, 0.0) public val xAxis: Float64Vector3D = vector(1.0, 0.0, 0.0)
public val yAxis: DoubleVector3D = vector(0.0, 1.0, 0.0) public val yAxis: Float64Vector3D = vector(0.0, 1.0, 0.0)
public val zAxis: DoubleVector3D = vector(0.0, 0.0, 1.0) public val zAxis: Float64Vector3D = vector(0.0, 0.0, 1.0)
override val defaultPrecision: Double = 1e-6 override val defaultPrecision: Double = 1e-6
override val bufferFactory: MutableBufferFactory<Vector3D<Float64>> = MutableBufferFactory()
} }
public val Float64Field.euclidean3D: Float64Space3D get() = Float64Space3D public val Float64Field.euclidean3D: Float64Space3D get() = Float64Space3D
public val Float64Vector3D.r: Double get() = Float64Space3D.norm(this)

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.geometry.euclidean3d package space.kscience.kmath.geometry.euclidean3d
import space.kscience.attributes.SafeType
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.complex.* import space.kscience.kmath.complex.*
import space.kscience.kmath.geometry.* import space.kscience.kmath.geometry.*
@ -13,6 +14,7 @@ import space.kscience.kmath.linear.Matrix
import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.linearSpace
import space.kscience.kmath.linear.matrix import space.kscience.kmath.linear.matrix
import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.structures.Float64
import kotlin.math.* import kotlin.math.*
public operator fun Quaternion.times(other: Quaternion): Quaternion = QuaternionAlgebra.multiply(this, other) public operator fun Quaternion.times(other: Quaternion): Quaternion = QuaternionAlgebra.multiply(this, other)
@ -35,7 +37,7 @@ public infix fun Quaternion.dot(other: Quaternion): Double = w * other.w + x * o
/** /**
* Represent a vector as quaternion with zero a rotation angle. * Represent a vector as quaternion with zero a rotation angle.
*/ */
internal fun DoubleVector3D.asQuaternion(): Quaternion = Quaternion(0.0, x, y, z) internal fun Float64Vector3D.asQuaternion(): Quaternion = Quaternion(0.0, x, y, z)
/** /**
* Angle in radians denoted by this quaternion rotation * Angle in radians denoted by this quaternion rotation
@ -45,7 +47,7 @@ public val Quaternion.theta: Radians get() = (kotlin.math.acos(normalized().w) *
/** /**
* Create a normalized Quaternion from rotation angle and rotation vector * Create a normalized Quaternion from rotation angle and rotation vector
*/ */
public fun Quaternion.Companion.fromRotation(theta: Angle, vector: DoubleVector3D): Quaternion { public fun Quaternion.Companion.fromRotation(theta: Angle, vector: Float64Vector3D): Quaternion {
val s = sin(theta / 2) val s = sin(theta / 2)
val c = cos(theta / 2) val c = cos(theta / 2)
val norm = with(Float64Space3D) { vector.norm() } val norm = with(Float64Space3D) { vector.norm() }
@ -55,9 +57,9 @@ public fun Quaternion.Companion.fromRotation(theta: Angle, vector: DoubleVector3
/** /**
* An axis of quaternion rotation * An axis of quaternion rotation
*/ */
public val Quaternion.vector: DoubleVector3D public val Quaternion.vector: Float64Vector3D
get() { get() {
return object : DoubleVector3D { return object : Float64Vector3D {
private val sint2 = sqrt(1 - w * w) private val sint2 = sqrt(1 - w * w)
override val x: Double get() = this@vector.x / sint2 override val x: Double get() = this@vector.x / sint2
override val y: Double get() = this@vector.y / sint2 override val y: Double get() = this@vector.y / sint2
@ -69,7 +71,7 @@ public val Quaternion.vector: DoubleVector3D
/** /**
* Rotate a vector in a [Float64Space3D] with [quaternion] * Rotate a vector in a [Float64Space3D] with [quaternion]
*/ */
public fun Float64Space3D.rotate(vector: DoubleVector3D, quaternion: Quaternion): DoubleVector3D = public fun Float64Space3D.rotate(vector: Float64Vector3D, quaternion: Quaternion): Float64Vector3D =
with(QuaternionAlgebra) { with(QuaternionAlgebra) {
val p = vector.asQuaternion() val p = vector.asQuaternion()
(quaternion * p * quaternion.reciprocal).vector (quaternion * p * quaternion.reciprocal).vector
@ -80,15 +82,15 @@ public fun Float64Space3D.rotate(vector: DoubleVector3D, quaternion: Quaternion)
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun Float64Space3D.rotate( public fun Float64Space3D.rotate(
vector: DoubleVector3D, vector: Float64Vector3D,
composition: QuaternionAlgebra.() -> Quaternion, composition: QuaternionAlgebra.() -> Quaternion,
): DoubleVector3D = ): Float64Vector3D =
rotate(vector, QuaternionAlgebra.composition()) rotate(vector, QuaternionAlgebra.composition())
/** /**
* Rotate a [Float64] vector in 3D space with a rotation matrix * Rotate a [Float64] vector in 3D space with a rotation matrix
*/ */
public fun Float64Space3D.rotate(vector: DoubleVector3D, matrix: Matrix<Double>): DoubleVector3D { public fun Float64Space3D.rotate(vector: Float64Vector3D, matrix: Matrix<Double>): Vector3D<Float64> {
require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" } require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" }
return with(linearSpace) { (matrix dot vector).asVector3D() } return with(linearSpace) { (matrix dot vector).asVector3D() }
} }
@ -242,6 +244,8 @@ public fun Quaternion.Companion.fromEuler(
* A vector consisting of angles * A vector consisting of angles
*/ */
public data class AngleVector(override val x: Angle, override val y: Angle, override val z: Angle) : Vector3D<Angle> { public data class AngleVector(override val x: Angle, override val y: Angle, override val z: Angle) : Vector3D<Angle> {
override val type: SafeType<Angle> get() = Angle.type
public companion object public companion object
} }

View File

@ -5,8 +5,7 @@
package space.kscience.kmath.geometry package space.kscience.kmath.geometry
import space.kscience.kmath.geometry.euclidean2d.DoubleVector2D import space.kscience.kmath.structures.Float64
import space.kscience.kmath.geometry.euclidean3d.DoubleVector3D
import kotlin.math.abs import kotlin.math.abs
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -27,12 +26,12 @@ fun grid(
return xs.flatMap { x -> ys.map { y -> x to y } } return xs.flatMap { x -> ys.map { y -> x to y } }
} }
fun assertVectorEquals(expected: DoubleVector2D, actual: DoubleVector2D, absoluteTolerance: Double = 1e-3) { fun assertVectorEquals(expected: Vector2D<Float64>, actual: Vector2D<Float64>, absoluteTolerance: Double = 1e-3) {
assertEquals(expected.x, actual.x, absoluteTolerance) assertEquals(expected.x, actual.x, absoluteTolerance)
assertEquals(expected.y, actual.y, absoluteTolerance) assertEquals(expected.y, actual.y, absoluteTolerance)
} }
fun assertVectorEquals(expected: DoubleVector3D, actual: DoubleVector3D, absoluteTolerance: Double = 1e-6) { fun assertVectorEquals(expected: Vector3D<Float64>, actual: Vector3D<Float64>, absoluteTolerance: Double = 1e-6) {
assertEquals(expected.x, actual.x, absoluteTolerance) assertEquals(expected.x, actual.x, absoluteTolerance)
assertEquals(expected.y, actual.y, absoluteTolerance) assertEquals(expected.y, actual.y, absoluteTolerance)
assertEquals(expected.z, actual.z, absoluteTolerance) assertEquals(expected.z, actual.z, absoluteTolerance)

View File

@ -6,19 +6,8 @@
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-histograms:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-histograms:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-histograms:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -27,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-histograms:0.4.0-dev-1") implementation("space.kscience:kmath-histograms:0.4.0-dev-3")
} }
``` ```

View File

@ -6,6 +6,8 @@ kscience{
jvm() jvm()
js() js()
native() native()
wasm()
useCoroutines()
} }
//apply(plugin = "kotlinx-atomicfu") //apply(plugin = "kotlinx-atomicfu")
@ -21,7 +23,6 @@ kotlin.sourceSets {
dependencies { dependencies {
implementation(project(":kmath-for-real")) implementation(project(":kmath-for-real"))
implementation(projects.kmath.kmathStat) implementation(projects.kmath.kmathStat)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0")
} }
} }
} }

View File

@ -47,7 +47,7 @@ public interface Histogram<in T : Any, out V, out B : Bin<T, V>> {
} }
} }
public interface HistogramBuilder<in T : Any, V : Any> { public interface HistogramBuilder<in T, V> {
/** /**
* The default value increment for a bin * The default value increment for a bin
@ -61,9 +61,9 @@ public interface HistogramBuilder<in T : Any, V : Any> {
} }
public fun <T : Any> HistogramBuilder<T, *>.put(point: Point<out T>): Unit = putValue(point) public fun <T> HistogramBuilder<T, *>.put(point: Point<T>): Unit = putValue(point)
public fun <T : Any> HistogramBuilder<T, *>.put(vararg point: T): Unit = put(point.asBuffer()) public inline fun <reified T> HistogramBuilder<T, *>.put(vararg point: T): Unit = put(point.asList().asBuffer())
public fun HistogramBuilder<Double, *>.put(vararg point: Number): Unit = public fun HistogramBuilder<Double, *>.put(vararg point: Number): Unit =
put(Float64Buffer(point.map { it.toDouble() }.toDoubleArray())) put(Float64Buffer(point.map { it.toDouble() }.toDoubleArray()))

View File

@ -12,6 +12,7 @@ import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.floor import kotlin.math.floor
@OptIn(UnstableKMathAPI::class) @OptIn(UnstableKMathAPI::class)
@ -46,6 +47,8 @@ public class UniformHistogram1DGroup<V : Any, A>(
public val startPoint: Double = 0.0, public val startPoint: Double = 0.0,
) : Group<Histogram1D<Double, V>>, ScaleOperations<Histogram1D<Double, V>> where A : Ring<V>, A : ScaleOperations<V> { ) : Group<Histogram1D<Double, V>>, ScaleOperations<Histogram1D<Double, V>> where A : Ring<V>, A : ScaleOperations<V> {
override val bufferFactory: MutableBufferFactory<Histogram1D<Double, V>> = MutableBufferFactory()
override val zero: UniformHistogram1D<V> = UniformHistogram1D(this, emptyMap()) override val zero: UniformHistogram1D<V> = UniformHistogram1D(this, emptyMap())
/** /**

View File

@ -37,6 +37,8 @@ public class UniformHistogramGroupND<V : Any, A : Field<V>>(
require(!lower.indices.any { upper[it] - lower[it] < 0 }) { "Range for one of axis is not strictly positive" } require(!lower.indices.any { upper[it] - lower[it] < 0 }) { "Range for one of axis is not strictly positive" }
} }
override val bufferFactory: MutableBufferFactory<HistogramND<Double, HyperSquareDomain, V>> = MutableBufferFactory()
public val dimension: Int get() = lower.size public val dimension: Int get() = lower.size
override val shape: ShapeND = ShapeND(IntArray(binNums.size) { binNums[it] + 2 }) override val shape: ShapeND = ShapeND(IntArray(binNums.size) { binNums[it] + 2 })
@ -87,7 +89,7 @@ public class UniformHistogramGroupND<V : Any, A : Field<V>>(
builder: HistogramBuilder<Double, V>.() -> Unit, builder: HistogramBuilder<Double, V>.() -> Unit,
): HistogramND<Double, HyperSquareDomain, V> { ): HistogramND<Double, HyperSquareDomain, V> {
val ndCounter: BufferND<ObjectCounter<V>> = val ndCounter: BufferND<ObjectCounter<V>> =
StructureND.buffered(shape) { Counter.of(valueAlgebraND.elementAlgebra) } BufferND(shape) { Counter.of(valueAlgebraND.elementAlgebra) }
val hBuilder = object : HistogramBuilder<Double, V> { val hBuilder = object : HistogramBuilder<Double, V> {
override val defaultValue: V get() = valueAlgebraND.elementAlgebra.one override val defaultValue: V get() = valueAlgebraND.elementAlgebra.one
@ -97,7 +99,8 @@ public class UniformHistogramGroupND<V : Any, A : Field<V>>(
} }
} }
hBuilder.apply(builder) hBuilder.apply(builder)
val values: BufferND<V> = BufferND(ndCounter.indices, ndCounter.buffer.mapToBuffer(valueBufferFactory) { it.value }) val values: BufferND<V> =
BufferND(ndCounter.indices, ndCounter.buffer.mapToBuffer(valueBufferFactory) { it.value })
return HistogramND(this, values) return HistogramND(this, values)
} }
@ -128,8 +131,7 @@ public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
public fun Histogram.Companion.uniformDoubleNDFromRanges( public fun Histogram.Companion.uniformDoubleNDFromRanges(
vararg ranges: ClosedFloatingPointRange<Double>, vararg ranges: ClosedFloatingPointRange<Double>,
): UniformHistogramGroupND<Double, Float64Field> = ): UniformHistogramGroupND<Double, Float64Field> = uniformNDFromRanges(Floa64FieldOpsND, *ranges)
uniformNDFromRanges(Floa64FieldOpsND, *ranges, bufferFactory = ::Float64Buffer)
/** /**
@ -147,21 +149,18 @@ public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
bufferFactory: BufferFactory<V> = valueAlgebraND.elementAlgebra.bufferFactory, bufferFactory: BufferFactory<V> = valueAlgebraND.elementAlgebra.bufferFactory,
): UniformHistogramGroupND<V, A> = UniformHistogramGroupND( ): UniformHistogramGroupND<V, A> = UniformHistogramGroupND(
valueAlgebraND, valueAlgebraND,
DoubleBuffer(
ranges ranges
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first) .map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
.map(ClosedFloatingPointRange<Double>::start) .map(ClosedFloatingPointRange<Double>::start)
), .asBuffer(),
DoubleBuffer(
ranges ranges
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first) .map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
.map(ClosedFloatingPointRange<Double>::endInclusive) .map(ClosedFloatingPointRange<Double>::endInclusive)
), .asBuffer(),
ranges.map(Pair<ClosedFloatingPointRange<Double>, Int>::second).toIntArray(), ranges.map(Pair<ClosedFloatingPointRange<Double>, Int>::second).toIntArray(),
valueBufferFactory = bufferFactory valueBufferFactory = bufferFactory
) )
public fun Histogram.Companion.uniformDoubleNDFromRanges( public fun Histogram.Companion.uniformDoubleNDFromRanges(
vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>, vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>,
): UniformHistogramGroupND<Double, Float64Field> = ): UniformHistogramGroupND<Double, Float64Field> = uniformNDFromRanges(Floa64FieldOpsND, *ranges)
uniformNDFromRanges(Floa64FieldOpsND, *ranges, bufferFactory = ::Float64Buffer)

View File

@ -14,10 +14,7 @@ import space.kscience.kmath.misc.sorted
import space.kscience.kmath.operations.Group import space.kscience.kmath.operations.Group
import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.*
import space.kscience.kmath.structures.first
import space.kscience.kmath.structures.indices
import space.kscience.kmath.structures.last
import java.util.* import java.util.*
private fun <B : ClosedRange<Double>> TreeMap<Double, B>.getBin(value: Double): B? { private fun <B : ClosedRange<Double>> TreeMap<Double, B>.getBin(value: Double): B? {
@ -53,6 +50,8 @@ public class TreeHistogramGroup<V : Any, A>(
@PublishedApi internal val binFactory: (Double) -> DoubleDomain1D, @PublishedApi internal val binFactory: (Double) -> DoubleDomain1D,
) : Group<TreeHistogram<V>>, ScaleOperations<TreeHistogram<V>> where A : Ring<V>, A : ScaleOperations<V> { ) : Group<TreeHistogram<V>>, ScaleOperations<TreeHistogram<V>> where A : Ring<V>, A : ScaleOperations<V> {
override val bufferFactory: MutableBufferFactory<TreeHistogram<V>> = MutableBufferFactory()
internal inner class DomainCounter(val domain: DoubleDomain1D, val counter: Counter<V> = Counter.of(valueAlgebra)) : internal inner class DomainCounter(val domain: DoubleDomain1D, val counter: Counter<V> = Counter.of(valueAlgebra)) :
ClosedRange<Double> by domain.range ClosedRange<Double> by domain.range

View File

@ -7,19 +7,8 @@ Integration with [Jafama](https://github.com/jeffhain/jafama).
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-jafama:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-jafama:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-jafama:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -28,7 +17,7 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-jafama:0.4.0-dev-1") implementation("space.kscience:kmath-jafama:0.4.0-dev-3")
} }
``` ```

View File

@ -0,0 +1,128 @@
public final class space/kscience/kmath/jafama/JafamaDoubleField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/ScaleOperations {
public static final field INSTANCE Lspace/kscience/kmath/jafama/JafamaDoubleField;
public fun acos (D)Ljava/lang/Double;
public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
public fun acosh (D)Ljava/lang/Double;
public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
public fun add (DD)Ljava/lang/Double;
public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun asin (D)Ljava/lang/Double;
public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
public fun asinh (D)Ljava/lang/Double;
public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
public fun atan (D)Ljava/lang/Double;
public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
public fun atanh (D)Ljava/lang/Double;
public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
public fun cos (D)Ljava/lang/Double;
public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
public fun cosh (D)Ljava/lang/Double;
public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
public fun div (DD)Ljava/lang/Double;
public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun divide (DD)Ljava/lang/Double;
public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun exp (D)Ljava/lang/Double;
public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
public fun getOne ()Ljava/lang/Double;
public synthetic fun getOne ()Ljava/lang/Object;
public fun getZero ()Ljava/lang/Double;
public synthetic fun getZero ()Ljava/lang/Object;
public fun ln (D)Ljava/lang/Double;
public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
public fun minus (DD)Ljava/lang/Double;
public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun multiply (DD)Ljava/lang/Double;
public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun norm (D)Ljava/lang/Double;
public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
public fun number (Ljava/lang/Number;)Ljava/lang/Double;
public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
public fun plus (DD)Ljava/lang/Double;
public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun power (DLjava/lang/Number;)Ljava/lang/Double;
public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
public fun scale (DD)Ljava/lang/Double;
public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
public fun sin (D)Ljava/lang/Double;
public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
public fun sinh (D)Ljava/lang/Double;
public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
public fun sqrt (D)Ljava/lang/Double;
public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
public fun tan (D)Ljava/lang/Double;
public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
public fun tanh (D)Ljava/lang/Double;
public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
public fun times (DD)Ljava/lang/Double;
public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun unaryMinus (D)Ljava/lang/Double;
public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
}
public final class space/kscience/kmath/jafama/StrictJafamaDoubleField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/ScaleOperations {
public static final field INSTANCE Lspace/kscience/kmath/jafama/StrictJafamaDoubleField;
public fun acos (D)Ljava/lang/Double;
public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
public fun acosh (D)Ljava/lang/Double;
public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
public fun add (DD)Ljava/lang/Double;
public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun asin (D)Ljava/lang/Double;
public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
public fun asinh (D)Ljava/lang/Double;
public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
public fun atan (D)Ljava/lang/Double;
public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
public fun atanh (D)Ljava/lang/Double;
public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
public fun cos (D)Ljava/lang/Double;
public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
public fun cosh (D)Ljava/lang/Double;
public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
public fun div (DD)Ljava/lang/Double;
public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun divide (DD)Ljava/lang/Double;
public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun exp (D)Ljava/lang/Double;
public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
public fun getOne ()Ljava/lang/Double;
public synthetic fun getOne ()Ljava/lang/Object;
public fun getZero ()Ljava/lang/Double;
public synthetic fun getZero ()Ljava/lang/Object;
public fun ln (D)Ljava/lang/Double;
public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
public fun minus (DD)Ljava/lang/Double;
public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun multiply (DD)Ljava/lang/Double;
public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun norm (D)Ljava/lang/Double;
public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
public fun number (Ljava/lang/Number;)Ljava/lang/Double;
public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
public fun plus (DD)Ljava/lang/Double;
public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun power (DLjava/lang/Number;)Ljava/lang/Double;
public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
public fun scale (DD)Ljava/lang/Double;
public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
public fun sin (D)Ljava/lang/Double;
public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
public fun sinh (D)Ljava/lang/Double;
public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
public fun sqrt (D)Ljava/lang/Double;
public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
public fun tan (D)Ljava/lang/Double;
public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
public fun tanh (D)Ljava/lang/Double;
public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
public fun times (DD)Ljava/lang/Double;
public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun unaryMinus (D)Ljava/lang/Double;
public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
}

View File

@ -6,19 +6,8 @@
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-jupyter:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -27,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-jupyter:0.4.0-dev-1") implementation("space.kscience:kmath-jupyter:0.4.0-dev-3")
} }
``` ```

View File

@ -8,19 +8,8 @@
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-kotlingrad:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -29,6 +18,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-kotlingrad:0.4.0-dev-1") implementation("space.kscience:kmath-kotlingrad:0.4.0-dev-3")
} }
``` ```

View File

@ -7,6 +7,7 @@ package space.kscience.kmath.kotlingrad
import ai.hypergraph.kotlingrad.api.SFun import ai.hypergraph.kotlingrad.api.SFun
import ai.hypergraph.kotlingrad.api.SVar import ai.hypergraph.kotlingrad.api.SVar
import space.kscience.attributes.SafeType
import space.kscience.kmath.expressions.* import space.kscience.kmath.expressions.*
import space.kscience.kmath.operations.NumericAlgebra import space.kscience.kmath.operations.NumericAlgebra
@ -25,6 +26,8 @@ public class KotlingradExpression<T : Number, A : NumericAlgebra<T>>(
public val algebra: A, public val algebra: A,
public val mst: MST, public val mst: MST,
) : SpecialDifferentiableExpression<T, KotlingradExpression<T, A>> { ) : SpecialDifferentiableExpression<T, KotlingradExpression<T, A>> {
override val type: SafeType<T> = algebra.type
override fun invoke(arguments: Map<Symbol, T>): T = mst.interpret(algebra, arguments) override fun invoke(arguments: Map<Symbol, T>): T = mst.interpret(algebra, arguments)
override fun derivativeOrNull( override fun derivativeOrNull(

View File

@ -6,19 +6,8 @@
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-memory:0.4.0-dev-1`. The Maven coordinates of this project are `space.kscience:kmath-memory:0.4.0-dev-3`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-memory:0.4.0-dev-1'
}
```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
repositories { repositories {
@ -27,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-memory:0.4.0-dev-1") implementation("space.kscience:kmath-memory:0.4.0-dev-3")
} }
``` ```

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