Revise grammar of KDoc comments, refresh documentation files

This commit is contained in:
Iaroslav Postovalov 2021-05-07 19:59:21 +07:00
parent 065f95f912
commit afd5908784
98 changed files with 523 additions and 538 deletions

View File

@ -6,10 +6,10 @@
# KMath # KMath
Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based
Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior
designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like
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://mipt-npm.github.io/kmath/) [Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/)
@ -21,26 +21,33 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module.
# Goal # Goal
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native). * Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native)
.
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide 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.
## Non-goals ## Non-goals
* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API. * Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API.
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like * Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better
experience for those, who want to work with specific types. experience for those, who want to work with specific types.
## Features and stability ## Features and stability
KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels: KMath is a modular library. Different modules provide different features with different API stability guarantees. All
core modules are released with the same version, but with different API change policy. The features are described in
module definitions below. The module stability could have the following levels:
* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. * **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could
* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations. break any moment. You can still use it, but be sure to fix the specific version.
* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked
with `@UnstableKmathAPI` or other stability warning annotations.
* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor
versions, but not in patch versions. API is protected
with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool.
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
<!--Current feature list is [here](/docs/features.md)--> <!--Current feature list is [here](/docs/features.md)-->
@ -286,8 +293,8 @@ 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 Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both
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 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
@ -296,12 +303,15 @@ 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 execution in order to get better performance. KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for
execution to get better performance.
### Repositories ### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/)
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could
be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy:
```kotlin ```kotlin
repositories { repositories {
@ -319,6 +329,6 @@ 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 a feedback about what features are
required the most. Feel free to create feature requests. We are also welcome to code contributions, required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues
especially in issues marked with marked with
[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. [waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label.

View File

@ -2,16 +2,16 @@
The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an
operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up, operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up,
say `Space<T>`. Next one needs to run the actual operation in the context: say `Group<T>`. Next one needs to run the actual operation in the context:
```kotlin ```kotlin
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
val a: T = ... val a: T = ...
val b: T = ... val b: T = ...
val space: Space<T> = ... val group: Group<T> = ...
val c = space { a + b } val c = group { a + b }
``` ```
At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in
@ -20,66 +20,26 @@ geometry for vectors.
## Algebraic Structures ## Algebraic Structures
Mathematical contexts have the following hierarchy: Primary mathematical contexts have the following hierarchy:
**Algebra** ← **Space****Ring** ← **Field** `Field <: Ring <: Group <: Algebra`
These interfaces follow real algebraic structures: These interfaces follow real algebraic structures:
- [Space](https://mathworld.wolfram.com/VectorSpace.html) defines addition, its neutral element (i.e. 0) and scalar - [Group](https://mathworld.wolfram.com/Group.html) defines addition, its identity element (i.e., 0) and additive
multiplication; inverse (-x);
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1); - [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its identity element (i.e., 1);
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation. - [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`. A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`.
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot` interface. Also, contexts may have operations, which produce elements outside the context. For example, `Matrix.dot`
operation produces a matrix with new dimensions, which can be incompatible with initial matrix in terms of linear operation produces a matrix with new dimensions, which can be incompatible with initial matrix in linear operations.
operations.
## Algebraic Element
To achieve more familiar behavior (where you apply operations directly to mathematical objects), without involving
contexts KMath submits special type objects called `MathElement`. A `MathElement` is basically some object coupled to
a mathematical context. For example `Complex` is the pair of real numbers representing real and imaginary parts,
but it also holds reference to the `ComplexField` singleton, which allows performing direct operations on `Complex`
numbers without explicit involving the context like:
```kotlin
import space.kscience.kmath.operations.*
// Using elements
val c1 = Complex(1.0, 1.0)
val c2 = Complex(1.0, -1.0)
val c3 = c1 + c2 + 3.0.toComplex()
// Using context
val c4 = ComplexField { c1 + i - 2.0 }
```
Both notations have their pros and cons.
The hierarchy for algebraic elements follows the hierarchy for the corresponding algebraic structures.
**MathElement** ← **SpaceElement****RingElement** ← **FieldElement**
`MathElement<C>` is the generic common ancestor of the class with context.
One major distinction between algebraic elements and algebraic contexts is that elements have three type
parameters:
1. The type of elements, the field operates on.
2. The self-type of the element returned from operation (which has to be an algebraic element).
3. The type of the algebra over first type-parameter.
The middle type is needed for of algebra members do not store context. For example, it is impossible to add a context
to regular `Double`. The element performs automatic conversions from context types and back. One should use context
operations in all performance-critical places. The performance of element operations is not guaranteed.
## Spaces and Fields ## Spaces and Fields
KMath submits both contexts and elements for builtin algebraic structures: KMath introduces contexts for builtin algebraic structures:
```kotlin ```kotlin
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
@ -118,8 +78,9 @@ val element = NDElement.complex(shape = intArrayOf(2, 2)) { index: IntArray ->
``` ```
The `element` in this example is a member of the `Field` of 2D structures, each element of which is a member of its own The `element` in this example is a member of the `Field` of 2D structures, each element of which is a member of its own
`ComplexField`. It is important one does not need to create a special n-d class to hold complex `ComplexField`. It is important one does not need to create a special n-d class to hold complex numbers and implement
numbers and implement operations on it, one just needs to provide a field for its elements. operations on it, one just needs to provide a field for its elements.
**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts like **Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts
like
`MemorySpec`. `MemorySpec`.

View File

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

View File

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

View File

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

View File

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

View File

@ -1,14 +0,0 @@
# Features
* [Algebra](algebra.md) - [Context-based](contexts.md) operations on different primitives and structures.
* [NDStructures](nd-structure.md)
* [Linear algebra](linear.md) - Matrices, operations and linear equations solving. To be moved to separate module. Currently supports basic
api and multiple library back-ends.
* [Histograms](histograms.md) - Multidimensional histogram calculation and operations.
* [Expressions](expressions.md)
* Commons math integration

View File

@ -1,19 +1,31 @@
## Basic linear algebra layout ## Basic linear algebra layout
KMath support for linear algebra organized in a context-oriented way. Meaning that operations are in most cases declared KMath support for linear algebra organized in a context-oriented way, which means that operations are in most cases declared in context classes, and are not the members of classes that store data. This allows more flexible approach to maintain multiple back-ends. The new operations added as extensions to contexts instead of being member functions of data structures.
in context classes, and are not the members of classes that store data. This allows more flexible approach to maintain multiple
back-ends. The new operations added as extensions to contexts instead of being member functions of data structures.
Two major contexts used for linear algebra and hyper-geometry: The main context for linear algebra over matrices and vectors is `LinearSpace`, which defines addition and dot products of matrices and vectors:
* `VectorSpace` forms a mathematical space on top of array-like structure (`Buffer` and its type alias `Point` used for geometry). ```kotlin
import space.kscience.kmath.linear.*
* `MatrixContext` forms a space-like context for 2d-structures. It does not store matrix size and therefore does not implement LinearSpace.Companion.real {
`Space` interface (it is impossible to create zero element without knowing the matrix size). val vec = buildVector(10) { i -> i.toDouble() }
val mat = buildMatrix(10, 10) { i, j -> i.toDouble() + j }
## Vector spaces // Addition
vec + vec
mat + mat
// Multiplication by scalar
vec * 2.0
mat * 2.0
## Matrix operations // Dot product
mat dot vec
mat dot mat
}
```
## Back-end overview ## Backends overview
### EJML
### Commons Math

View File

@ -11,16 +11,16 @@ Let us consider following contexts:
```kotlin ```kotlin
// automatically build context most suited for given type. // automatically build context most suited for given type.
val autoField = NDField.auto(DoubleField, dim, dim) val autoField = NDField.auto(DoubleField, dim, dim)
// specialized nd-field for Double. It works as generic Double field as well // specialized nd-field for Double. It works as generic Double field as well.
val specializedField = NDField.real(dim, dim) val specializedField = NDField.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives. //A generic boxing field. It should be used for objects, not primitives.
val genericField = NDField.buffered(DoubleField, dim, dim) val genericField = NDField.buffered(DoubleField, dim, dim)
``` ```
Now let us perform several tests and see which implementation is best suited for each case: Now let us perform several tests and see, which implementation is best suited for each case:
## Test case ## Test case
In order to test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0` To test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0`
to it `n = 1000` times. to it `n = 1000` times.
## Specialized ## Specialized
@ -35,8 +35,8 @@ The code to run this looks like:
``` ```
The performance of this code is the best of all tests since it inlines all operations and is specialized for operation The performance of this code is the best of all tests since it inlines all operations and is specialized for operation
with doubles. We will measure everything else relative to this one, so time for this test will be `1x` (real time with doubles. We will measure everything else relative to this one, so time for this test will be `1x` (real time
on my computer is about 4.5 seconds). The only problem with this approach is that it requires to specify type on my computer is about 4.5 seconds). The only problem with this approach is that it requires specifying type
from the beginning. Everyone do so anyway, so it is the recommended approach. from the beginning. Everyone does so anyway, so it is the recommended approach.
## Automatic ## Automatic
Let's do the same with automatic field inference: Let's do the same with automatic field inference:
@ -49,7 +49,7 @@ Let's do the same with automatic field inference:
} }
``` ```
Ths speed of this operation is approximately the same as for specialized case since `NDField.auto` just Ths speed of this operation is approximately the same as for specialized case since `NDField.auto` just
returns the same `RealNDField` in this case. Of course it is usually better to use specialized method to be sure. returns the same `RealNDField` in this case. Of course, it is usually better to use specialized method to be sure.
## Lazy ## Lazy
Lazy field does not produce a structure when asked, instead it generates an empty structure and fills it on-demand Lazy field does not produce a structure when asked, instead it generates an empty structure and fills it on-demand
@ -63,7 +63,7 @@ When one calls
} }
} }
``` ```
The result will be calculated almost immediately but the result will be empty. In order to get the full result The result will be calculated almost immediately but the result will be empty. To get the full result
structure one needs to call all its elements. In this case computation overhead will be huge. So this field never structure one needs to call all its elements. In this case computation overhead will be huge. So this field never
should be used if one expects to use the full result structure. Though if one wants only small fraction, it could should be used if one expects to use the full result structure. Though if one wants only small fraction, it could
save a lot of time. save a lot of time.
@ -94,7 +94,7 @@ The boxing field produced by
} }
} }
``` ```
obviously is the slowest one, because it requires to box and unbox the `double` on each operation. It takes about is the slowest one, because it requires boxing and unboxing the `double` on each operation. It takes about
`15x` time (**TODO: there seems to be a problem here, it should be slow, but not that slow**). This field should `15x` time (**TODO: there seems to be a problem here, it should be slow, but not that slow**). This field should
never be used for primitives. never be used for primitives.
@ -123,6 +123,6 @@ for i in range(1000):
``` ```
gives the completion time of about `1.1x`, which means that specialized kotlin code in fact is working faster (I think it is gives the completion time of about `1.1x`, which means that specialized kotlin code in fact is working faster (I think it is
because better memory management). Of course if one writes `res += 1.0`, the performance will be different, because better memory management). Of course if one writes `res += 1.0`, the performance will be different,
but it would be differenc case, because numpy overrides `+=` with in-place operations. In-place operations are but it would be different case, because numpy overrides `+=` with in-place operations. In-place operations are
available in `kmath` with `MutableNDStructure` but there is no field for it (one can still work with mapping available in `kmath` with `MutableNDStructure` but there is no field for it (one can still work with mapping
functions). functions).

14
docs/readme.md Normal file
View File

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

View File

@ -6,10 +6,10 @@
# KMath # KMath
Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based
Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior
designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like
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://mipt-npm.github.io/kmath/) [Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/)
@ -21,26 +21,33 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module.
# Goal # Goal
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native). * Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native)
.
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide 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.
## Non-goals ## Non-goals
* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API. * Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API.
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like * Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better
experience for those, who want to work with specific types. experience for those, who want to work with specific types.
## Features and stability ## Features and stability
KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels: KMath is a modular library. Different modules provide different features with different API stability guarantees. All
core modules are released with the same version, but with different API change policy. The features are described in
module definitions below. The module stability could have the following levels:
* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. * **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could
* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations. break any moment. You can still use it, but be sure to fix the specific version.
* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked
with `@UnstableKmathAPI` or other stability warning annotations.
* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor
versions, but not in patch versions. API is protected
with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool.
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
<!--Current feature list is [here](/docs/features.md)--> <!--Current feature list is [here](/docs/features.md)-->
@ -86,8 +93,8 @@ 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 Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both
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 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
@ -96,12 +103,15 @@ 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 execution in order to get better performance. KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for
execution to get better performance.
### Repositories ### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/)
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could
be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy:
```kotlin ```kotlin
repositories { repositories {
@ -119,6 +129,6 @@ 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 a feedback about what features are
required the most. Feel free to create feature requests. We are also welcome to code contributions, required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues
especially in issues marked with marked with
[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. [waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label.

View File

@ -13,8 +13,8 @@ import space.kscience.kmath.kotlingrad.toKotlingradExpression
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
/** /**
* In this example, x^2-4*x-44 function is differentiated with Kotlin, and the autodiff result is compared with * In this example, *x<sup>2</sup> &minus; 4 x &minus; 44* function is differentiated with Kotlin, and the
* valid derivative in a certain point. * derivation result is compared with valid derivative in a certain point.
*/ */
fun main() { fun main() {
val actualDerivative = "x^2-4*x-44" val actualDerivative = "x^2-4*x-44"

View File

@ -13,8 +13,8 @@ import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.symja.toSymjaExpression import space.kscience.kmath.symja.toSymjaExpression
/** /**
* In this example, x^2-4*x-44 function is differentiated with Symja, and the autodiff result is compared with * In this example, *x<sup>2</sup> &minus; 4 x &minus; 44* function is differentiated with Symja, and the
* valid derivative in a certain point. * derivation result is compared with valid derivative in a certain point.
*/ */
fun main() { fun main() {
val actualDerivative = "x^2-4*x-44" val actualDerivative = "x^2-4*x-44"

View File

@ -25,8 +25,7 @@ import space.kscience.plotly.models.TraceValues
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt import kotlin.math.sqrt
//Forward declaration of symbols that will be used in expressions. // Forward declaration of symbols that will be used in expressions.
// This declaration is required for
private val a by symbol private val a by symbol
private val b by symbol private val b by symbol
private val c by symbol private val c by symbol

View File

@ -0,0 +1,15 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.jafama
import space.kscience.kmath.operations.invoke
fun main() {
val a = 2.0
val b = StrictJafamaDoubleField { exp(a) }
println(JafamaDoubleField { b + a })
println(StrictJafamaDoubleField { ln(b) })
}

View File

@ -1,17 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.jafama
import net.jafama.FastMath
fun main(){
val a = JafamaDoubleField.number(2.0)
val b = StrictJafamaDoubleField.power(FastMath.E,a)
println(JafamaDoubleField.add(b,a))
println(StrictJafamaDoubleField.ln(b))
}

View File

@ -10,9 +10,6 @@ import space.kscience.kmath.chains.Chain
import space.kscience.kmath.chains.collectWithState import space.kscience.kmath.chains.collectWithState
import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.distributions.NormalDistribution
/**
* The state of distribution averager.
*/
private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0) private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
/** /**

View File

@ -32,7 +32,7 @@ fun main() {
// automatically build context most suited for given type. // automatically build context most suited for given type.
val autoField = AlgebraND.auto(DoubleField, dim, dim) val autoField = AlgebraND.auto(DoubleField, dim, dim)
// specialized nd-field for Double. It works as generic Double field as well // specialized nd-field for Double. It works as generic Double field as well.
val realField = AlgebraND.real(dim, dim) val realField = AlgebraND.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives. //A generic boxing field. It should be used for objects, not primitives.
val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)

View File

@ -17,7 +17,7 @@ fun main() = BroadcastDoubleTensorAlgebra { // work in context with broadcast m
dataset += fromArray( dataset += fromArray(
intArrayOf(5), intArrayOf(5),
doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // rows means doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // row means
) )
@ -28,7 +28,7 @@ fun main() = BroadcastDoubleTensorAlgebra { // work in context with broadcast m
println("Mean:\n$mean") println("Mean:\n$mean")
println("Standard deviation:\n$std") println("Standard deviation:\n$std")
// also we can calculate other statistic as minimum and maximum of rows // also, we can calculate other statistic as minimum and maximum of rows
println("Minimum:\n${dataset.min(0, false)}") println("Minimum:\n${dataset.min(0, false)}")
println("Maximum:\n${dataset.max(0, false)}") println("Maximum:\n${dataset.max(0, false)}")

View File

@ -42,7 +42,7 @@ fun main() = BroadcastDoubleTensorAlgebra {// work in context with linear operat
// get P, L, U such that PA = LU // get P, L, U such that PA = LU
val (p, l, u) = a.lu() val (p, l, u) = a.lu()
// check that P is permutation matrix // check P is permutation matrix
println("P:\n$p") println("P:\n$p")
// L is lower triangular matrix and U is upper triangular matrix // L is lower triangular matrix and U is upper triangular matrix
println("L:\n$l") println("L:\n$l")

View File

@ -186,7 +186,7 @@ fun main() = BroadcastDoubleTensorAlgebra {
x += fromArray( x += fromArray(
intArrayOf(5), intArrayOf(5),
doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // rows means doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // row means
) )

View File

@ -65,8 +65,8 @@ fun main(): Unit = BroadcastDoubleTensorAlgebra { // work in context with broad
val datasetReduced = v dot stack(listOf(xScaled, yScaled)) val datasetReduced = v dot stack(listOf(xScaled, yScaled))
println("Reduced data:\n$datasetReduced") println("Reduced data:\n$datasetReduced")
// we can restore original data from reduced data. // we can restore original data from reduced data;
// for example, find 7th element of dataset // for example, find 7th element of dataset.
val n = 7 val n = 7
val restored = (datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean val restored = (datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean
println("Original value:\n${dataset[n]}") println("Original value:\n${dataset[n]}")

View File

@ -106,7 +106,7 @@ var executable = function (constants, arguments) {
}; };
``` ```
JS also supports very experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. JS also supports experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation.
Currently, only expressions inside `DoubleField` and `IntRing` are supported. Currently, only expressions inside `DoubleField` and `IntRing` are supported.
```kotlin ```kotlin
@ -161,7 +161,10 @@ public fun main() {
Result LaTeX: Result LaTeX:
<div style="background-color:white;">
![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3}) ![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3})
</div>
Result MathML (can be used with MathJax or other renderers): Result MathML (can be used with MathJax or other renderers):

View File

@ -77,7 +77,7 @@ var executable = function (constants, arguments) {
}; };
``` ```
JS also supports very experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. JS also supports experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation.
Currently, only expressions inside `DoubleField` and `IntRing` are supported. Currently, only expressions inside `DoubleField` and `IntRing` are supported.
```kotlin ```kotlin
@ -132,7 +132,10 @@ public fun main() {
Result LaTeX: Result LaTeX:
<div style="background-color:white;">
![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3}) ![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3})
</div>
Result MathML (can be used with MathJax or other renderers): Result MathML (can be used with MathJax or other renderers):

View File

@ -8,7 +8,7 @@ package space.kscience.kmath.ast.rendering
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
/** /**
* Mathematical typography syntax node. * Syntax node for mathematical typography.
* *
* @author Iaroslav Postovalov * @author Iaroslav Postovalov
*/ */
@ -301,7 +301,7 @@ public data class BinaryPlusSyntax(
} }
/** /**
* Represents binary, infix subtraction (*42 - 42*). * Represents binary, infix subtraction (*42 &minus; 42*).
* *
* @param left The minuend. * @param left The minuend.
* @param right The subtrahend. * @param right The subtrahend.

View File

@ -9,7 +9,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI
/** /**
* Abstraction of writing [MathSyntax] as a string of an actual markup language. Typical implementation should * Abstraction of writing [MathSyntax] as a string of an actual markup language. Typical implementation should
* involve traversal of MathSyntax with handling each its subtype. * involve traversal of MathSyntax with handling each subtype.
* *
* @author Iaroslav Postovalov * @author Iaroslav Postovalov
*/ */

View File

@ -49,7 +49,7 @@ else
NumberSyntax(string = s) NumberSyntax(string = s)
/** /**
* Special printing for numeric types which are printed in form of * Special printing for numeric types that are printed in form of
* *('-'? (DIGIT+ ('.' DIGIT+)? ('E' '-'? DIGIT+)? | 'Infinity')) | 'NaN'*. * *('-'? (DIGIT+ ('.' DIGIT+)? ('E' '-'? DIGIT+)? | 'Infinity')) | 'NaN'*.
* *
* @property types The suitable types. * @property types The suitable types.
@ -110,7 +110,7 @@ public class PrettyPrintFloats(public val types: Set<KClass<out Number>>) : Rend
} }
/** /**
* Special printing for numeric types which are printed in form of *'-'? DIGIT+*. * Special printing for numeric types that are printed in form of *'-'? DIGIT+*.
* *
* @property types The suitable types. * @property types The suitable types.
* @author Iaroslav Postovalov * @author Iaroslav Postovalov
@ -155,7 +155,7 @@ public class PrettyPrintPi(public val symbols: Set<String>) : RenderFeature {
} }
/** /**
* Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is * Abstract printing of unary operations that discards [MST] if their operation is not in [operations] or its type is
* not [MST.Unary]. * not [MST.Unary].
* *
* @param operations the allowed operations. If `null`, any operation is accepted. * @param operations the allowed operations. If `null`, any operation is accepted.
@ -176,7 +176,7 @@ public abstract class Unary(public val operations: Collection<String>?) : Render
} }
/** /**
* Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is * Abstract printing of unary operations that discards [MST] if their operation is not in [operations] or its type is
* not [MST.Binary]. * not [MST.Binary].
* *
* @property operations the allowed operations. If `null`, any operation is accepted. * @property operations the allowed operations. If `null`, any operation is accepted.

View File

@ -57,13 +57,13 @@ internal fun MethodVisitor.label(): Label = Label().also(::visitLabel)
/** /**
* Creates a class name for [Expression] subclassed to implement [mst] provided. * Creates a class name for [Expression] subclassed to implement [mst] provided.
* *
* This methods helps to avoid collisions of class name to prevent loading several classes with the same name. If there * These methods help to avoid collisions of class name to prevent loading several classes with the same name. If there
* is a colliding class, change [collision] parameter or leave it `0` to check existing classes recursively. * is a colliding class, change [collision] parameter or leave it `0` to check existing classes recursively.
* *
* @author Iaroslav Postovalov * @author Iaroslav Postovalov
*/ */
internal tailrec fun buildName(mst: MST, collision: Int = 0): String { internal tailrec fun buildName(mst: MST, collision: Int = 0): String {
val name = "space.kscience.kmath.asm.generated.AsmCompiledExpression_${mst.hashCode()}_$collision" val name = "space.kscience.kmath.asm.generated.CompiledExpression_${mst.hashCode()}_$collision"
try { try {
Class.forName(name) Class.forName(name)

View File

@ -31,7 +31,7 @@ public class DerivativeStructureField(
override fun number(value: Number): DerivativeStructure = const(value.toDouble()) override fun number(value: Number): DerivativeStructure = const(value.toDouble())
/** /**
* A class that implements both [DerivativeStructure] and a [Symbol] * A class implementing both [DerivativeStructure] and [Symbol].
*/ */
public inner class DerivativeStructureSymbol( public inner class DerivativeStructureSymbol(
size: Int, size: Int,

View File

@ -34,7 +34,7 @@ internal class AutoDiffTest {
println(z.derivative(x)) println(z.derivative(x))
println(z.derivative(y, x)) println(z.derivative(y, x))
assertEquals(z.derivative(x, y), z.derivative(y, x)) assertEquals(z.derivative(x, y), z.derivative(y, x))
//check that improper order cause failure // check improper order cause failure
assertFails { z.derivative(x, x, y) } assertFails { z.derivative(x, x, y) }
} }
} }

View File

@ -27,7 +27,7 @@ internal class OptimizeTest {
fun testGradientOptimization() { fun testGradientOptimization() {
val result = normal.optimize(x, y) { val result = normal.optimize(x, y) {
initialGuess(x to 1.0, y to 1.0) initialGuess(x to 1.0, y to 1.0)
//no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function // no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function.
} }
println(result.point) println(result.point)
println(result.value) println(result.value)

View File

@ -6,7 +6,7 @@
package space.kscience.kmath.expressions package space.kscience.kmath.expressions
/** /**
* Represents expression which structure can be differentiated. * Represents expression, which structure can be differentiated.
* *
* @param T the type this expression takes as argument and returns. * @param T the type this expression takes as argument and returns.
*/ */

View File

@ -43,7 +43,7 @@ public operator fun <T> Expression<T>.invoke(vararg pairs: Pair<Symbol, T>): T =
/** /**
* Calls this expression from arguments. * Calls this expression from arguments.
* *
* @param pairs the pairs of arguments' names to values. * @param pairs the pairs of arguments' names to value.
* @return a value. * @return a value.
*/ */
@JvmName("callByString") @JvmName("callByString")
@ -60,7 +60,7 @@ public operator fun <T> Expression<T>.invoke(vararg pairs: Pair<String, T>): T =
public interface ExpressionAlgebra<in T, E> : Algebra<E> { public interface ExpressionAlgebra<in T, E> : Algebra<E> {
/** /**
* A constant expression which does not depend on arguments * A constant expression that does not depend on arguments.
*/ */
public fun const(value: T): E public fun const(value: T): E
} }

View File

@ -18,7 +18,7 @@ public abstract class FunctionalExpressionAlgebra<T, out A : Algebra<T>>(
public val algebra: A, public val algebra: A,
) : ExpressionAlgebra<T, Expression<T>> { ) : ExpressionAlgebra<T, Expression<T>> {
/** /**
* Builds an Expression of constant expression which does not depend on arguments. * Builds an Expression of constant expression that does not depend on arguments.
*/ */
override fun const(value: T): Expression<T> = Expression { value } override fun const(value: T): Expression<T> = Expression { value }

View File

@ -8,8 +8,8 @@ package space.kscience.kmath.linear
import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as1D
/** /**
* A group of methods to solve for *X* in equation *X = A <sup>-1</sup> &middot; B*, where *A* and *B* are matrices or * A group of methods to solve for *X* in equation *X = A<sup>&minus;1</sup> &middot; B*, where *A* and *B* are
* vectors. * matrices or vectors.
* *
* @param T the type of items. * @param T the type of items.
*/ */

View File

@ -164,7 +164,7 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
public operator fun T.times(v: Point<T>): Point<T> = v * this public operator fun T.times(v: Point<T>): Point<T> = v * this
/** /**
* Get a feature of the structure in this scope. Structure features take precedence other context features * Get a feature of the structure in this scope. Structure features take precedence other context features.
* *
* @param F the type of feature. * @param F the type of feature.
* @param structure the structure. * @param structure the structure.
@ -195,7 +195,7 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
} }
/** /**
* Get a feature of the structure in this scope. Structure features take precedence other context features * Get a feature of the structure in this scope. Structure features take precedence other context features.
* *
* @param T the type of items in the matrices. * @param T the type of items in the matrices.
* @param F the type of feature. * @param F the type of feature.

View File

@ -114,7 +114,7 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
for (i in 0 until col) sum -= luRow[i] * lu[i, col] for (i in 0 until col) sum -= luRow[i] * lu[i, col]
luRow[col] = sum luRow[col] = sum
// maintain best permutation choice // maintain the best permutation choice
if (abs(sum) > largest) { if (abs(sum) > largest) {
largest = abs(sum) largest = abs(sum)
max = row max = row
@ -241,7 +241,7 @@ public fun LinearSpace<Double, DoubleField>.solveWithLup(a: Matrix<Double>, b: M
} }
/** /**
* Inverses a square matrix using LUP decomposition. Non square matrix will throw a error. * Inverses a square matrix using LUP decomposition. Non square matrix will throw an error.
*/ */
public fun LinearSpace<Double, DoubleField>.inverseWithLup(matrix: Matrix<Double>): Matrix<Double> = public fun LinearSpace<Double, DoubleField>.inverseWithLup(matrix: Matrix<Double>): Matrix<Double> =
solveWithLup(matrix, one(matrix.rowNum, matrix.colNum)) solveWithLup(matrix, one(matrix.rowNum, matrix.colNum))

View File

@ -31,7 +31,7 @@ public object ZeroFeature : DiagonalFeature
public object UnitFeature : DiagonalFeature public object UnitFeature : DiagonalFeature
/** /**
* Matrices with this feature can be inverted: [inverse] = `a`<sup>-1</sup> where `a` is the owning matrix. * Matrices with this feature can be inverted: *[inverse] = a<sup>&minus;1</sup>* where *a* is the owning matrix.
* *
* @param T the type of matrices' items. * @param T the type of matrices' items.
*/ */

View File

@ -22,7 +22,8 @@ public class MatrixWrapper<out T : Any> internal constructor(
) : Matrix<T> by origin { ) : Matrix<T> by origin {
/** /**
* Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the
* criteria.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@ -61,7 +62,7 @@ public operator fun <T : Any> Matrix<T>.plus(newFeatures: Collection<MatrixFeatu
} }
/** /**
* Diagonal matrix of ones. The matrix is virtual no actual matrix is created * Diagonal matrix of ones. The matrix is virtual no actual matrix is created.
*/ */
public fun <T : Any> LinearSpace<T, Ring<T>>.one( public fun <T : Any> LinearSpace<T, Ring<T>>.one(
rows: Int, rows: Int,
@ -87,7 +88,7 @@ public class TransposedFeature<out T : Any>(public val original: Matrix<T>) : Ma
* Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A`
*/ */
@OptIn(UnstableKMathAPI::class) @OptIn(UnstableKMathAPI::class)
public fun <T : Any> Matrix<T>.transpose(): Matrix<T> = getFeature<TransposedFeature<T>>()?.original ?: VirtualMatrix( public fun <T : Any> Matrix<T>.transpose(): Matrix<T> = getFeature<TransposedFeature<T>>()?.original ?: (VirtualMatrix(
colNum, colNum,
rowNum, rowNum,
) { i, j -> get(j, i) } + TransposedFeature(this) ) { i, j -> get(j, i) } + TransposedFeature(this))

View File

@ -7,8 +7,8 @@ package space.kscience.kmath.misc
/** /**
* Marks declarations that are still experimental in the KMath APIs, which means that the design of the corresponding * Marks declarations that are still experimental in the KMath APIs, which means that the design of the corresponding
* declarations has open issues which may (or may not) lead to their changes in the future. Roughly speaking, there is * declarations has open issues that may (or may not) lead to their changes in the future. Roughly speaking, there is
* a chance that those declarations will be deprecated in the near future or the semantics of their behavior may change * a chance of those declarations will be deprecated in the near future or the semantics of their behavior may change
* in some way that may break some code. * in some way that may break some code.
*/ */
@MustBeDocumented @MustBeDocumented
@ -17,7 +17,7 @@ package space.kscience.kmath.misc
public annotation class UnstableKMathAPI public annotation class UnstableKMathAPI
/** /**
* Marks API which could cause performance problems. The code, marked by this API is not necessary slow, but could cause * Marks API that could cause performance problems. The code marked by this API is unnecessary slow but could cause
* slow-down in some cases. Refer to the documentation and benchmark it to be sure. * slow-down in some cases. Refer to the documentation and benchmark it to be sure.
*/ */
@MustBeDocumented @MustBeDocumented

View File

@ -11,7 +11,7 @@ import space.kscience.kmath.structures.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
* An exception is thrown when the expected ans actual shape of NDArray differs. * An exception is thrown when the expected and actual shape of NDArray differ.
* *
* @property expected the expected shape. * @property expected the expected shape.
* @property actual the actual shape. * @property actual the actual shape.
@ -63,7 +63,7 @@ public interface AlgebraND<T, out C : Algebra<T>> {
structure.map { value -> this@invoke(value) } structure.map { value -> this@invoke(value) }
/** /**
* Get a feature of the structure in this scope. Structure features take precedence other context features * Get a feature of the structure in this scope. Structure features take precedence other context features.
* *
* @param F the type of feature. * @param F the type of feature.
* @param structure the structure. * @param structure the structure.
@ -79,7 +79,7 @@ public interface AlgebraND<T, out C : Algebra<T>> {
/** /**
* Get a feature of the structure in this scope. Structure features take precedence other context features * Get a feature of the structure in this scope. Structure features take precedence other context features.
* *
* @param T the type of items in the matrices. * @param T the type of items in the matrices.
* @param F the type of feature. * @param F the type of feature.
@ -130,15 +130,6 @@ public interface GroupND<T, out S : Group<T>> : Group<StructureND<T>>, AlgebraND
override fun add(a: StructureND<T>, b: StructureND<T>): StructureND<T> = override fun add(a: StructureND<T>, b: StructureND<T>): StructureND<T> =
combine(a, b) { aValue, bValue -> add(aValue, bValue) } combine(a, b) { aValue, bValue -> add(aValue, bValue) }
// /**
// * Element-wise multiplication by scalar.
// *
// * @param a the multiplicand.
// * @param k the multiplier.
// * @return the product.
// */
// override fun multiply(a: NDStructure<T>, k: Number): NDStructure<T> = a.map { multiply(it, k) }
// TODO move to extensions after KEEP-176 // TODO move to extensions after KEEP-176
/** /**
@ -226,7 +217,7 @@ public interface RingND<T, out R : Ring<T>> : Ring<StructureND<T>>, GroupND<T, R
* @param T the type of the element contained in ND structure. * @param T the type of the element contained in ND structure.
* @param F the type field over structure elements. * @param F the type field over structure elements.
*/ */
public interface FieldND<T, out F : Field<T>> : Field<StructureND<T>>, RingND<T, F>, ScaleOperations<StructureND<T>> { public interface FieldND<T, out F : Field<T>> : Field<StructureND<T>>, RingND<T, F> {
/** /**
* Element-wise division. * Element-wise division.
* *
@ -256,6 +247,15 @@ public interface FieldND<T, out F : Field<T>> : Field<StructureND<T>>, RingND<T,
*/ */
public operator fun T.div(arg: StructureND<T>): StructureND<T> = arg.map { divide(it, this@div) } public operator fun T.div(arg: StructureND<T>): StructureND<T> = arg.map { divide(it, this@div) }
/**
* Element-wise scaling.
*
* @param a the multiplicand.
* @param value the multiplier.
* @return the product.
*/
override fun scale(a: StructureND<T>, value: Double): StructureND<T> = a.map { scale(it, value) }
// @ThreadLocal // @ThreadLocal
// public companion object { // public companion object {
// private val realNDFieldCache: MutableMap<IntArray, RealNDField> = hashMapOf() // private val realNDFieldCache: MutableMap<IntArray, RealNDField> = hashMapOf()

View File

@ -110,7 +110,7 @@ internal class MutableBuffer1DWrapper<T>(val buffer: MutableBuffer<T>) : Mutable
} }
/** /**
* Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch.
*/ */
public fun <T> StructureND<T>.as1D(): Structure1D<T> = this as? Structure1D<T> ?: if (shape.size == 1) { public fun <T> StructureND<T>.as1D(): Structure1D<T> = this as? Structure1D<T> ?: if (shape.size == 1) {
when (this) { when (this) {

View File

@ -144,13 +144,16 @@ private class MutableStructure2DWrapper<T>(val structure: MutableStructureND<T>)
} }
/** /**
* Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch * Represents a [StructureND] as [Structure2D]. Throws runtime error in case of dimension mismatch.
*/ */
public fun <T> StructureND<T>.as2D(): Structure2D<T> = this as? Structure2D<T> ?: when (shape.size) { public fun <T> StructureND<T>.as2D(): Structure2D<T> = this as? Structure2D<T> ?: when (shape.size) {
2 -> Structure2DWrapper(this) 2 -> Structure2DWrapper(this)
else -> error("Can't create 2d-structure from ${shape.size}d-structure") else -> error("Can't create 2d-structure from ${shape.size}d-structure")
} }
/**
* Represents a [StructureND] as [Structure2D]. Throws runtime error in case of dimension mismatch.
*/
public fun <T> MutableStructureND<T>.as2D(): MutableStructure2D<T> = this as? MutableStructure2D<T> ?: when (shape.size) { public fun <T> MutableStructureND<T>.as2D(): MutableStructure2D<T> = this as? MutableStructure2D<T> ?: when (shape.size) {
2 -> MutableStructure2DWrapper(this) 2 -> MutableStructure2DWrapper(this)
else -> error("Can't create 2d-structure from ${shape.size}d-structure") else -> error("Can't create 2d-structure from ${shape.size}d-structure")

View File

@ -16,7 +16,7 @@ import kotlin.reflect.KClass
public interface StructureFeature public interface StructureFeature
/** /**
* Represents n-dimensional structure, i.e. multidimensional container of items of the same type and size. The number * Represents n-dimensional structure i.e., multidimensional container of items of the same type and size. The number
* of dimensions and items in an array is defined by its shape, which is a sequence of non-negative integers that * of dimensions and items in an array is defined by its shape, which is a sequence of non-negative integers that
* specify the sizes of each dimension. * specify the sizes of each dimension.
* *
@ -26,7 +26,7 @@ public interface StructureFeature
*/ */
public interface StructureND<out T> { public interface StructureND<out T> {
/** /**
* The shape of structure, i.e. non-empty sequence of non-negative integers that specify sizes of dimensions of * The shape of structure i.e., non-empty sequence of non-negative integers that specify sizes of dimensions of
* this structure. * this structure.
*/ */
public val shape: IntArray public val shape: IntArray
@ -53,8 +53,8 @@ public interface StructureND<out T> {
public fun elements(): Sequence<Pair<IntArray, T>> public fun elements(): Sequence<Pair<IntArray, T>>
/** /**
* Feature is some additional structure information which allows to access it special properties or hints. * Feature is some additional structure information that allows to access it special properties or hints.
* If the feature is not present, null is returned. * If the feature is not present, `null` is returned.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <F : StructureFeature> getFeature(type: KClass<out F>): F? = null public fun <F : StructureFeature> getFeature(type: KClass<out F>): F? = null
@ -177,7 +177,7 @@ public inline fun <T> MutableStructureND<T>.mapInPlace(action: (IntArray, T) ->
elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) }
/** /**
* A way to convert ND index to linear one and back. * A way to convert ND indices to linear one and back.
*/ */
public interface Strides { public interface Strides {
/** /**

View File

@ -23,15 +23,13 @@ public interface Algebra<T> {
* Wraps a raw string to [T] object. This method is designed for three purposes: * Wraps a raw string to [T] object. This method is designed for three purposes:
* *
* 1. Mathematical constants (`e`, `pi`). * 1. Mathematical constants (`e`, `pi`).
* 2. Variables for expression-like contexts (`a`, `b`, `c`...). * 1. Variables for expression-like contexts (`a`, `b`, `c`&hellip;).
* 3. Literals (`{1, 2}`, (`(3; 4)`)). * 1. Literals (`{1, 2}`, (`(3; 4)`)).
* *
* In case if algebra can't parse the string, this method must throw [kotlin.IllegalStateException]. * If algebra can't parse the string, then this method must throw [kotlin.IllegalStateException].
*
* Returns `null` if symbol could not be bound to the context
* *
* @param value the raw string. * @param value the raw string.
* @return an object. * @return an object or `null` if symbol could not be bound to the context.
*/ */
public fun bindSymbolOrNull(value: String): T? = null public fun bindSymbolOrNull(value: String): T? = null
@ -42,13 +40,12 @@ public interface Algebra<T> {
bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this") bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this")
/** /**
* Dynamically dispatches an unary operation with the certain name. * Dynamically dispatches a unary operation with the certain name.
* *
* This function must has two features: * Implementations must fulfil the following requirements:
* *
* 1. In case operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException].
* 2. This function is symmetric with second `unaryOperation` overload: * 1. Equivalence to [unaryOperation]: for any `a` and `b`, `unaryOperationFunction(a)(b) == unaryOperation(a, b)`.
* i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`.
* *
* @param operation the name of operation. * @param operation the name of operation.
* @return an operation. * @return an operation.
@ -57,13 +54,13 @@ public interface Algebra<T> {
error("Unary operation $operation not defined in $this") error("Unary operation $operation not defined in $this")
/** /**
* Dynamically invokes an unary operation with the certain name. * Dynamically invokes a unary operation with the certain name.
* *
* This function must follow two properties: * Implementations must fulfil the following requirements:
* *
* 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException].
* 2. This function is symmetric with second [unaryOperationFunction] overload: * 1. Equivalence to [unaryOperationFunction]: i.e., for any `a` and `b`,
* i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. * `unaryOperationFunction(a)(b) == unaryOperation(a, b)`.
* *
* @param operation the name of operation. * @param operation the name of operation.
* @param arg the argument of operation. * @param arg the argument of operation.
@ -74,11 +71,11 @@ public interface Algebra<T> {
/** /**
* Dynamically dispatches a binary operation with the certain name. * Dynamically dispatches a binary operation with the certain name.
* *
* This function must follow two properties: * Implementations must fulfil the following requirements:
* *
* 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException].
* 2. This function is symmetric with second [binaryOperationFunction] overload: * 1. Equivalence to [binaryOperation]: for any `a`, `b`, and `c`,
* i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`.
* *
* @param operation the name of operation. * @param operation the name of operation.
* @return an operation. * @return an operation.
@ -89,11 +86,11 @@ public interface Algebra<T> {
/** /**
* Dynamically invokes a binary operation with the certain name. * Dynamically invokes a binary operation with the certain name.
* *
* This function must follow two properties: * Implementations must fulfil the following requirements:
* *
* 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException].
* 2. This function is symmetric with second [binaryOperationFunction] overload: * 1. Equivalence to [binaryOperationFunction]: for any `a`, `b`, and `c`,
* i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`.
* *
* @param operation the name of operation. * @param operation the name of operation.
* @param left the first argument of operation. * @param left the first argument of operation.
@ -115,7 +112,7 @@ public fun <T> Algebra<T>.bindSymbol(symbol: Symbol): T = bindSymbol(symbol.iden
public inline operator fun <A : Algebra<*>, R> A.invoke(block: A.() -> R): R = run(block) public inline operator fun <A : Algebra<*>, R> A.invoke(block: A.() -> R): R = run(block)
/** /**
* Represents group without neutral element (also known as inverse semigroup), i.e. algebraic structure with * Represents group without neutral element (also known as inverse semigroup) i.e., algebraic structure with
* associative, binary operation [add]. * associative, binary operation [add].
* *
* @param T the type of element of this semispace. * @param T the type of element of this semispace.
@ -130,7 +127,7 @@ public interface GroupOperations<T> : Algebra<T> {
*/ */
public fun add(a: T, b: T): T public fun add(a: T, b: T): T
// Operations to be performed in this context. Could be moved to extensions in case of KEEP-176 // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176.
/** /**
* The negation of this element. * The negation of this element.
@ -192,7 +189,7 @@ public interface GroupOperations<T> : Algebra<T> {
} }
/** /**
* Represents group, i.e. algebraic structure with associative, binary operation [add]. * Represents group i.e., algebraic structure with associative, binary operation [add].
* *
* @param T the type of element of this semispace. * @param T the type of element of this semispace.
*/ */
@ -204,7 +201,7 @@ public interface Group<T> : GroupOperations<T> {
} }
/** /**
* Represents ring without multiplicative and additive identities, i.e. algebraic structure with * Represents ring without multiplicative and additive identities i.e., algebraic structure with
* associative, binary, commutative operation [add] and associative, operation [multiply] distributive over [add]. * associative, binary, commutative operation [add] and associative, operation [multiply] distributive over [add].
* *
* @param T the type of element of this semiring. * @param T the type of element of this semiring.
@ -240,7 +237,7 @@ public interface RingOperations<T> : GroupOperations<T> {
} }
/** /**
* Represents ring, i.e. algebraic structure with two associative binary operations called "addition" and * Represents ring i.e., algebraic structure with two associative binary operations called "addition" and
* "multiplication" and their neutral elements. * "multiplication" and their neutral elements.
* *
* @param T the type of element of this ring. * @param T the type of element of this ring.
@ -253,8 +250,9 @@ public interface Ring<T> : Group<T>, RingOperations<T> {
} }
/** /**
* Represents field without without multiplicative and additive identities, i.e. algebraic structure with associative, binary, commutative operations * Represents field without multiplicative and additive identities i.e., algebraic structure with associative, binary,
* [add] and [multiply]; binary operation [divide] as multiplication of left operand by reciprocal of right one. * commutative operations [add] and [multiply]; binary operation [divide] as multiplication of left operand by
* reciprocal of right one.
* *
* @param T the type of element of this semifield. * @param T the type of element of this semifield.
*/ */
@ -291,7 +289,7 @@ public interface FieldOperations<T> : RingOperations<T> {
} }
/** /**
* Represents field, i.e. algebraic structure with three operations: associative, commutative addition and * Represents field i.e., algebraic structure with three operations: associative, commutative addition and
* multiplication, and division. **This interface differs from the eponymous mathematical definition: fields in KMath * multiplication, and division. **This interface differs from the eponymous mathematical definition: fields in KMath
* also support associative multiplication by scalar.** * also support associative multiplication by scalar.**
* *

View File

@ -8,7 +8,7 @@ package space.kscience.kmath.operations
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
/** /**
* The generic mathematics elements which is able to store its context * The generic mathematics elements that is able to store its context
* *
* @param C the type of mathematical context for this element. * @param C the type of mathematical context for this element.
* @param T the type wrapped by this wrapper. * @param T the type wrapped by this wrapper.

View File

@ -121,7 +121,7 @@ public class BigInt internal constructor(
var r = ZERO var r = ZERO
val bitSize = val bitSize =
(BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: 0f + 1)).toInt() (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: (0f + 1))).toInt()
for (i in bitSize downTo 0) { for (i in bitSize downTo 0) {
r = r shl 1 r = r shl 1
@ -442,7 +442,7 @@ public fun UIntArray.toBigInt(sign: Byte): BigInt {
} }
/** /**
* Returns null if a valid number can not be read from a string * Returns `null` if a valid number cannot be read from a string
*/ */
public fun String.parseBigInteger(): BigInt? { public fun String.parseBigInteger(): BigInt? {
if (isEmpty()) return null if (isEmpty()) return null

View File

@ -26,11 +26,11 @@ public interface NumericAlgebra<T> : Algebra<T> {
/** /**
* Dynamically dispatches a binary operation with the certain name with numeric first argument. * Dynamically dispatches a binary operation with the certain name with numeric first argument.
* *
* This function must follow two properties: * Implementations must fulfil the following requirements:
* *
* 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 1. If operation is not defined in the structure, then function throws [kotlin.IllegalStateException].
* 2. This function is symmetric with the other [leftSideNumberOperation] overload: * 1. Equivalence to [leftSideNumberOperation]: for any `a`, `b`, and `c`,
* i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. * `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`.
* *
* @param operation the name of operation. * @param operation the name of operation.
* @return an operation. * @return an operation.
@ -41,11 +41,11 @@ public interface NumericAlgebra<T> : Algebra<T> {
/** /**
* Dynamically invokes a binary operation with the certain name with numeric first argument. * Dynamically invokes a binary operation with the certain name with numeric first argument.
* *
* This function must follow two properties: * Implementations must fulfil the following requirements:
* *
* 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException].
* 2. This function is symmetric with second [leftSideNumberOperation] overload: * 1. Equivalence to [leftSideNumberOperation]: for any `a`, `b`, and `c`,
* i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`.
* *
* @param operation the name of operation. * @param operation the name of operation.
* @param left the first argument of operation. * @param left the first argument of operation.
@ -58,11 +58,11 @@ public interface NumericAlgebra<T> : Algebra<T> {
/** /**
* Dynamically dispatches a binary operation with the certain name with numeric first argument. * Dynamically dispatches a binary operation with the certain name with numeric first argument.
* *
* This function must follow two properties: * Implementations must fulfil the following requirements:
* *
* 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException].
* 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: * 1. Equivalence to [rightSideNumberOperation]: for any `a`, `b`, and `c`,
* i.e. `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`.
* *
* @param operation the name of operation. * @param operation the name of operation.
* @return an operation. * @return an operation.
@ -73,11 +73,11 @@ public interface NumericAlgebra<T> : Algebra<T> {
/** /**
* Dynamically invokes a binary operation with the certain name with numeric second argument. * Dynamically invokes a binary operation with the certain name with numeric second argument.
* *
* This function must follow two properties: * Implementations must fulfil the following requirements:
* *
* 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException].
* 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: * 1. Equivalence to [rightSideNumberOperationFunction]: for any `a`, `b`, and `c`,
* i.e. `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. * `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`.
* *
* @param operation the name of operation. * @param operation the name of operation.
* @param left the first argument of operation. * @param left the first argument of operation.

View File

@ -330,13 +330,13 @@ public fun <T : AlgebraElement<T, out ExponentialOperations<T>>> atanh(arg: T):
*/ */
public interface Norm<in T : Any, out R> { public interface Norm<in T : Any, out R> {
/** /**
* Computes the norm of [arg] (i.e. absolute value or vector length). * Computes the norm of [arg] (i.e., absolute value or vector length).
*/ */
public fun norm(arg: T): R public fun norm(arg: T): R
} }
/** /**
* Computes the norm of [arg] (i.e. absolute value or vector length). * Computes the norm of [arg] (i.e., absolute value or vector length).
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <T : AlgebraElement<T, out Norm<T, R>>, R> norm(arg: T): R = arg.context.norm(arg) public fun <T : AlgebraElement<T, out Norm<T, R>>, R> norm(arg: T): R = arg.context.norm(arg)

View File

@ -32,7 +32,7 @@ public value class DoubleBuffer(public val array: DoubleArray) : MutableBuffer<D
* [init] function. * [init] function.
* *
* The function [init] is called for each array element sequentially starting from the first one. * The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an buffer element given its index. * It should return the value for a buffer element given its index.
*/ */
public inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = DoubleBuffer(DoubleArray(size) { init(it) }) public inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = DoubleBuffer(DoubleArray(size) { init(it) })
@ -47,7 +47,7 @@ public fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(dou
public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles) public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles)
/** /**
* Returns a new [DoubleArray] containing all of the elements of this [Buffer]. * Returns a new [DoubleArray] containing all the elements of this [Buffer].
*/ */
public fun Buffer<Double>.toDoubleArray(): DoubleArray = when (this) { public fun Buffer<Double>.toDoubleArray(): DoubleArray = when (this) {
is DoubleBuffer -> array.copyOf() is DoubleBuffer -> array.copyOf()

View File

@ -51,7 +51,7 @@ public fun FlaggedBuffer<*>.hasFlag(index: Int, flag: ValueFlag): Boolean = (get
public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, ValueFlag.MISSING) public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, ValueFlag.MISSING)
/** /**
* A real buffer which supports flags for each value like NaN or Missing * A [Double] buffer that supports flags for each value like `NaN` or Missing.
*/ */
public class FlaggedDoubleBuffer(public val values: DoubleArray, public val flags: ByteArray) : FlaggedBuffer<Double?>, public class FlaggedDoubleBuffer(public val values: DoubleArray, public val flags: ByteArray) : FlaggedBuffer<Double?>,
Buffer<Double?> { Buffer<Double?> {

View File

@ -34,7 +34,7 @@ public value class FloatBuffer(public val array: FloatArray) : MutableBuffer<Flo
* [init] function. * [init] function.
* *
* The function [init] is called for each array element sequentially starting from the first one. * The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an buffer element given its index. * It should return the value for a buffer element given its index.
*/ */
public inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer = FloatBuffer(FloatArray(size) { init(it) }) public inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer = FloatBuffer(FloatArray(size) { init(it) })
@ -44,7 +44,7 @@ public inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer = Fl
public fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats) public fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats)
/** /**
* Returns a new [FloatArray] containing all of the elements of this [Buffer]. * Returns a new [FloatArray] containing all the elements of this [Buffer].
*/ */
public fun Buffer<Float>.toFloatArray(): FloatArray = when (this) { public fun Buffer<Float>.toFloatArray(): FloatArray = when (this) {
is FloatBuffer -> array.copyOf() is FloatBuffer -> array.copyOf()

View File

@ -33,7 +33,7 @@ public value class IntBuffer(public val array: IntArray) : MutableBuffer<Int> {
* [init] function. * [init] function.
* *
* The function [init] is called for each array element sequentially starting from the first one. * The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an buffer element given its index. * It should return the value for a buffer element given its index.
*/ */
public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffer(IntArray(size) { init(it) }) public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffer(IntArray(size) { init(it) })
@ -43,7 +43,7 @@ public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffe
public fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints) public fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints)
/** /**
* Returns a new [IntArray] containing all of the elements of this [Buffer]. * Returns a new [IntArray] containing all the elements of this [Buffer].
*/ */
public fun Buffer<Int>.toIntArray(): IntArray = when (this) { public fun Buffer<Int>.toIntArray(): IntArray = when (this) {
is IntBuffer -> array.copyOf() is IntBuffer -> array.copyOf()

View File

@ -33,7 +33,7 @@ public value class LongBuffer(public val array: LongArray) : MutableBuffer<Long>
* [init] function. * [init] function.
* *
* The function [init] is called for each array element sequentially starting from the first one. * The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an buffer element given its index. * It should return the value for a buffer element given its index.
*/ */
public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongBuffer(LongArray(size) { init(it) }) public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongBuffer(LongArray(size) { init(it) })
@ -43,7 +43,7 @@ public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongB
public fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs) public fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs)
/** /**
* Returns a new [LongArray] containing all of the elements of this [Buffer]. * Returns a new [LongArray] containing all the elements of this [Buffer].
*/ */
public fun Buffer<Long>.toLongArray(): LongArray = when (this) { public fun Buffer<Long>.toLongArray(): LongArray = when (this) {
is LongBuffer -> array.copyOf() is LongBuffer -> array.copyOf()

View File

@ -31,7 +31,7 @@ public value class ShortBuffer(public val array: ShortArray) : MutableBuffer<Sho
* [init] function. * [init] function.
* *
* The function [init] is called for each array element sequentially starting from the first one. * The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an buffer element given its index. * It should return the value for a buffer element given its index.
*/ */
public inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer = ShortBuffer(ShortArray(size) { init(it) }) public inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer = ShortBuffer(ShortArray(size) { init(it) })
@ -41,7 +41,7 @@ public inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer = Sh
public fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts) public fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts)
/** /**
* Returns a new [ShortArray] containing all of the elements of this [Buffer]. * Returns a new [ShortArray] containing all the elements of this [Buffer].
*/ */
public fun Buffer<Short>.toShortArray(): ShortArray = when (this) { public fun Buffer<Short>.toShortArray(): ShortArray = when (this) {
is ShortBuffer -> array.copyOf() is ShortBuffer -> array.copyOf()

View File

@ -13,7 +13,7 @@ import kotlinx.coroutines.sync.withLock
/** /**
* A not-necessary-Markov chain of some type * A not-necessary-Markov chain of some type
* @param T - the chain element type * @param T the chain element type
*/ */
public interface Chain<out T> : Flow<T> { public interface Chain<out T> : Flow<T> {
/** /**
@ -22,7 +22,7 @@ public interface Chain<out T> : Flow<T> {
public suspend fun next(): T public suspend fun next(): T
/** /**
* Create a copy of current chain state. Consuming resulting chain does not affect initial chain * Create a copy of current chain state. Consuming resulting chain does not affect initial chain.
*/ */
public suspend fun fork(): Chain<T> public suspend fun fork(): Chain<T>
@ -62,9 +62,11 @@ public class MarkovChain<out R : Any>(private val seed: suspend () -> R, private
} }
/** /**
* A chain with possibly mutable state. The state must not be changed outside the chain. Two chins should never share the state * A chain with possibly mutable state. The state must not be changed outside the chain. Two chins should never share
* @param S - the state of the chain * the state.
* @param forkState - the function to copy current state without modifying it *
* @param S the state of the chain.
* @param forkState the function to copy current state without modifying it.
*/ */
public class StatefulChain<S, out R>( public class StatefulChain<S, out R>(
private val state: S, private val state: S,
@ -96,7 +98,7 @@ public class ConstantChain<out T>(public val value: T) : Chain<T> {
/** /**
* Map the chain result using suspended transformation. Initial chain result can no longer be safely consumed * Map the chain result using suspended transformation. Initial chain result can no longer be safely consumed
* since mapped chain consumes tokens. Accepts regular transformation function * since mapped chain consumes tokens. Accepts regular transformation function.
*/ */
public fun <T, R> Chain<T>.map(func: suspend (T) -> R): Chain<R> = object : Chain<R> { public fun <T, R> Chain<T>.map(func: suspend (T) -> R): Chain<R> = object : Chain<R> {
override suspend fun next(): R = func(this@map.next()) override suspend fun next(): R = func(this@map.next())

View File

@ -76,7 +76,7 @@ public fun Flow<Double>.chunked(bufferSize: Int): Flow<DoubleBuffer> = flow {
/** /**
* Map a flow to a moving window buffer. The window step is one. * Map a flow to a moving window buffer. The window step is one.
* In order to get different steps, one could use skip operation. * To get different steps, one could use skip operation.
*/ */
public fun <T> Flow<T>.windowed(window: Int): Flow<Buffer<T>> = flow { public fun <T> Flow<T>.windowed(window: Int): Flow<Buffer<T>> = flow {
require(window > 1) { "Window size must be more than one" } require(window > 1) { "Window size must be more than one" }

View File

@ -20,7 +20,7 @@ import kotlin.jvm.JvmInline
public interface DMatrix<out T, R : Dimension, C : Dimension> : Structure2D<T> { public interface DMatrix<out T, R : Dimension, C : Dimension> : Structure2D<T> {
public companion object { public companion object {
/** /**
* Coerces a regular matrix to a matrix with type-safe dimensions and throws a error if coercion failed * Coerces a regular matrix to a matrix with type-safe dimensions and throws an error if coercion failed
*/ */
public inline fun <T, reified R : Dimension, reified C : Dimension> coerce(structure: Structure2D<T>): DMatrix<T, R, C> { public inline fun <T, reified R : Dimension, reified C : Dimension> coerce(structure: Structure2D<T>): DMatrix<T, R, C> {
require(structure.rowNum == Dimension.dim<R>()) { require(structure.rowNum == Dimension.dim<R>()) {
@ -35,7 +35,7 @@ public interface DMatrix<out T, R : Dimension, C : Dimension> : Structure2D<T> {
} }
/** /**
* The same as [DMatrix.coerce] but without dimension checks. Use with caution * The same as [DMatrix.coerce] but without dimension checks. Use with caution.
*/ */
public fun <T, R : Dimension, C : Dimension> coerceUnsafe(structure: Structure2D<T>): DMatrix<T, R, C> = public fun <T, R : Dimension, C : Dimension> coerceUnsafe(structure: Structure2D<T>): DMatrix<T, R, C> =
DMatrixWrapper(structure) DMatrixWrapper(structure)

View File

@ -22,7 +22,7 @@ public typealias DoubleVector = Point<Double>
public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer() public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer()
/** /**
* Fill the vector of given [size] with given [value] * Fill the vector with given [size] with given [value]
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun Buffer.Companion.same(size: Int, value: Number): DoubleVector = double(size) { value.toDouble() } public fun Buffer.Companion.same(size: Int, value: Number): DoubleVector = double(size) { value.toDouble() }

View File

@ -45,8 +45,8 @@ public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange<Double
/** /**
* Convert double range to sequence. * Convert double range to sequence.
* *
* If the step is positive, than the sequence starts with the lower boundary and increments by [step] until current value is lower than upper boundary. * If the step is positive, then the sequence starts with the lower boundary and increments by [step] until current value is lower than upper boundary.
* The boundary itself is not necessary included. * The boundary itself is unnecessarily included.
* *
* If step is negative, the same goes from upper boundary downwards * If step is negative, the same goes from upper boundary downwards
*/ */

View File

@ -46,8 +46,8 @@ public fun <T : Comparable<T>> PiecewisePolynomial(
} }
/** /**
* An optimized piecewise which uses not separate pieces, but a range separated by delimiters. * An optimized piecewise that uses not separate pieces, but a range separated by delimiters.
* The pieces search is logarithmic * The pieces search is logarithmic.
*/ */
private class OrderedPiecewisePolynomial<T : Comparable<T>>( private class OrderedPiecewisePolynomial<T : Comparable<T>>(
override val pieces: List<Pair<ClosedRange<T>, Polynomial<T>>>, override val pieces: List<Pair<ClosedRange<T>, Polynomial<T>>>,
@ -79,7 +79,7 @@ public class PiecewiseBuilder<T : Comparable<T>>(delimiter: T) {
/** /**
* Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece)
* *
* @param right new rightmost position. If is less then current rightmost position, an error is thrown. * @param right new rightmost position. If is less than current rightmost position, an error is thrown.
* @param piece the sub-function. * @param piece the sub-function.
*/ */
public fun putRight(right: T, piece: Polynomial<T>) { public fun putRight(right: T, piece: Polynomial<T>) {
@ -91,7 +91,7 @@ public class PiecewiseBuilder<T : Comparable<T>>(delimiter: T) {
/** /**
* Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece)
* *
* @param left the new leftmost position. If is less then current rightmost position, an error is thrown. * @param left the new leftmost position. If is less than current rightmost position, an error is thrown.
* @param piece the sub-function. * @param piece the sub-function.
*/ */
public fun putLeft(left: T, piece: Polynomial<T>) { public fun putLeft(left: T, piece: Polynomial<T>) {
@ -114,7 +114,7 @@ public fun <T : Comparable<T>> PiecewisePolynomial(
): PiecewisePolynomial<T> = PiecewiseBuilder(startingPoint).apply(builder).build() ): PiecewisePolynomial<T> = PiecewiseBuilder(startingPoint).apply(builder).build()
/** /**
* Return a value of polynomial function with given [ring] an given [arg] or null if argument is outside of piecewise * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise
* definition. * definition.
*/ */
public fun <T : Comparable<T>, C : Ring<T>> PiecewisePolynomial<T>.value(ring: C, arg: T): T? = public fun <T : Comparable<T>, C : Ring<T>> PiecewisePolynomial<T>.value(ring: C, arg: T): T? =

View File

@ -10,15 +10,17 @@ import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.asBuffer
import space.kscience.kmath.structures.indices import space.kscience.kmath.structures.indices
/** /**
* A simple one-pass integrator based on Gauss rule * A simple one-pass integrator based on Gauss rule
* Following integrand features are accepted: * Following integrand features are accepted:
* [GaussIntegratorRuleFactory] - A factory for computing the Gauss integration rule. By default uses [GaussLegendreRuleFactory] *
* [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. * * [GaussIntegratorRuleFactory]&mdash;a factory for computing the Gauss integration rule. By default, uses
* [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. * [GaussLegendreRuleFactory].
* [UnivariateIntegrandRanges] - Set of ranges and number of points per range. Defaults to given [IntegrationRange] and [IntegrandMaxCalls] * * [IntegrationRange]&mdash;the univariate range of integration. By default, uses `0..1` interval.
* * [IntegrandMaxCalls]&mdash;the maximum number of function calls during integration. For non-iterative rules, always
* uses the maximum number of points. By default, uses 10 points.
* * [UnivariateIntegrandRanges]&mdash;set of ranges and number of points per range. Defaults to given
* [IntegrationRange] and [IntegrandMaxCalls].
*/ */
public class GaussIntegrator<T : Any>( public class GaussIntegrator<T : Any>(
public val algebra: Field<T>, public val algebra: Field<T>,
@ -71,14 +73,14 @@ public class GaussIntegrator<T : Any>(
} }
/** /**
* Create a Gauss-Legendre integrator for this field * Create a Gauss-Legendre integrator for this field.
* @see [GaussIntegrator] * @see [GaussIntegrator]
*/ */
public val <T:Any> Field<T>.gaussIntegrator: GaussIntegrator<T> get() = GaussIntegrator(this) public val <T : Any> Field<T>.gaussIntegrator: GaussIntegrator<T> get() = GaussIntegrator(this)
/** /**
* Integrate using [intervals] segments with Gauss-Legendre rule of [order] order * Integrate using [intervals] segments with Gauss-Legendre rule of [order] order.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <T : Any> GaussIntegrator<T>.integrate( public fun <T : Any> GaussIntegrator<T>.integrate(

View File

@ -72,7 +72,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory {
} }
// Get previous rule. // Get previous rule.
// If it has not been computed yet it will trigger a recursive call // If it has not been computed, yet it will trigger a recursive call
// to this method. // to this method.
val previousPoints: Buffer<Double> = getOrBuildRule(numPoints - 1).first val previousPoints: Buffer<Double> = getOrBuildRule(numPoints - 1).first
@ -146,7 +146,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory {
} }
// If "numPoints" is odd, 0 is a root. // If "numPoints" is odd, 0 is a root.
// Note: as written, the test for oddness will work for negative // Note: as written, the test for oddness will work for negative
// integers too (although it is not necessary here), preventing // integers too (although it is unnecessary here), preventing
// a FindBugs warning. // a FindBugs warning.
if (numPoints % 2 != 0) { if (numPoints % 2 != 0) {
var pmc = 1.0 var pmc = 1.0

View File

@ -13,9 +13,10 @@ import space.kscience.kmath.operations.sum
/** /**
* Use double pass Simpson rule integration with a fixed number of points. * Use double pass Simpson rule integration with a fixed number of points.
* Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls] * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls].
* [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. * * [IntegrationRange]&mdash;the univariate range of integration. By default, uses `0..1` interval.
* [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. * * [IntegrandMaxCalls]&mdash;the maximum number of function calls during integration. For non-iterative rules, always
* uses the maximum number of points. By default, uses 10 points.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public class SimpsonIntegrator<T : Any>( public class SimpsonIntegrator<T : Any>(
@ -63,12 +64,12 @@ public val <T : Any> Field<T>.simpsonIntegrator: SimpsonIntegrator<T> get() = Si
/** /**
* Use double pass Simpson rule integration with a fixed number of points. * Use double pass Simpson rule integration with a fixed number of points.
* Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls] * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls].
* [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. * * [IntegrationRange]&mdash;the univariate range of integration. By default, uses `0.0..1.0` interval.
* [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. * * [IntegrandMaxCalls]&mdash;the maximum number of function calls during integration. For non-iterative rules, always uses
* the maximum number of points. By default, uses 10 points.
*/ */
public object DoubleSimpsonIntegrator : UnivariateIntegrator<Double> { public object DoubleSimpsonIntegrator : UnivariateIntegrator<Double> {
private fun integrateRange( private fun integrateRange(
integrand: UnivariateIntegrand<Double>, range: ClosedRange<Double>, numPoints: Int, integrand: UnivariateIntegrand<Double>, range: ClosedRange<Double>, numPoints: Int,
): Double { ): Double {

View File

@ -45,8 +45,9 @@ public fun <T : Comparable<T>> PiecewisePolynomial<T>.integrate(
/** /**
* A generic spline-interpolation-based analytic integration * A generic spline-interpolation-based analytic integration
* [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. * * [IntegrationRange]&mdash;the univariate range of integration. By default, uses `0..1` interval.
* [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. * * [IntegrandMaxCalls]&mdash;the maximum number of function calls during integration. For non-iterative rules, always uses
* the maximum number of points. By default, uses 10 points.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public class SplineIntegrator<T : Comparable<T>>( public class SplineIntegrator<T : Comparable<T>>(
@ -57,6 +58,7 @@ public class SplineIntegrator<T : Comparable<T>>(
val range = integrand.getFeature<IntegrationRange>()?.range ?: 0.0..1.0 val range = integrand.getFeature<IntegrationRange>()?.range ?: 0.0..1.0
val interpolator: PolynomialInterpolator<T> = SplineInterpolator(algebra, bufferFactory) val interpolator: PolynomialInterpolator<T> = SplineInterpolator(algebra, bufferFactory)
val nodes: Buffer<Double> = integrand.getFeature<UnivariateIntegrationNodes>()?.nodes ?: run { val nodes: Buffer<Double> = integrand.getFeature<UnivariateIntegrationNodes>()?.nodes ?: run {
val numPoints = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: 100 val numPoints = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: 100
val step = (range.endInclusive - range.start) / (numPoints - 1) val step = (range.endInclusive - range.start) / (numPoints - 1)
@ -75,15 +77,16 @@ public class SplineIntegrator<T : Comparable<T>>(
/** /**
* A simplified double-based spline-interpolation-based analytic integration * A simplified double-based spline-interpolation-based analytic integration
* [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. * * [IntegrationRange]&mdash;the univariate range of integration. By default, uses `0.0..1.0` interval.
* [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. * * [IntegrandMaxCalls]&mdash;the maximum number of function calls during integration. For non-iterative rules, always
* uses the maximum number of points. By default, uses 10 points.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public object DoubleSplineIntegrator : UnivariateIntegrator<Double> { public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> { override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
val range = integrand.getFeature<IntegrationRange>()?.range ?: 0.0..1.0 val range = integrand.getFeature<IntegrationRange>()?.range ?: 0.0..1.0
val interpolator: PolynomialInterpolator<Double> = SplineInterpolator(DoubleField, ::DoubleBuffer) val interpolator: PolynomialInterpolator<Double> = SplineInterpolator(DoubleField, ::DoubleBuffer)
val nodes: Buffer<Double> = integrand.getFeature<UnivariateIntegrationNodes>()?.nodes ?: run { val nodes: Buffer<Double> = integrand.getFeature<UnivariateIntegrationNodes>()?.nodes ?: run {
val numPoints = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: 100 val numPoints = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: 100
val step = (range.endInclusive - range.start) / (numPoints - 1) val step = (range.endInclusive - range.start) / (numPoints - 1)

View File

@ -40,8 +40,8 @@ public class IntegrationRange(public val range: ClosedRange<Double>) : Integrand
} }
/** /**
* Set of univariate integration ranges. First components correspond to ranges themselves, second components to number of * Set of univariate integration ranges. First components correspond to the ranges themselves, second components to
* integration nodes per range * number of integration nodes per range.
*/ */
public class UnivariateIntegrandRanges(public val ranges: List<Pair<ClosedRange<Double>, Int>>) : IntegrandFeature { public class UnivariateIntegrandRanges(public val ranges: List<Pair<ClosedRange<Double>, Int>>) : IntegrandFeature {
public constructor(vararg pairs: Pair<ClosedRange<Double>, Int>) : this(pairs.toList()) public constructor(vararg pairs: Pair<ClosedRange<Double>, Int>) : this(pairs.toList())

View File

@ -11,7 +11,7 @@ import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.asBuffer
/** /**
* The binned data element. Could be a histogram bin with a number of counts or an artificial construct * The binned data element. Could be a histogram bin with a number of counts or an artificial construct.
*/ */
public interface Bin<in T : Any> : Domain<T> { public interface Bin<in T : Any> : Domain<T> {
/** /**

View File

@ -16,9 +16,10 @@ public val UnivariateDomain.center: Double
get() = (range.endInclusive + range.start) / 2 get() = (range.endInclusive + range.start) / 2
/** /**
* A univariate bin based an a range * A univariate bin based on a range
* @param value The value of histogram including weighting *
* @param standardDeviation Standard deviation of the bin value. Zero or negative if not applicable * @property value The value of histogram including weighting
* @property standardDeviation Standard deviation of the bin value. Zero or negative if not applicable
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public class UnivariateBin( public class UnivariateBin(

View File

@ -52,22 +52,4 @@ fun main() {
According to KMath benchmarks on GraalVM, Jafama functions are slower than JDK math; however, there are indications that on Hotspot Jafama is a bit faster. According to KMath benchmarks on GraalVM, Jafama functions are slower than JDK math; however, there are indications that on Hotspot Jafama is a bit faster.
<details> > **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**.
<summary>
Report for benchmark configuration <code>jafamaDouble</code>
</summary>
* Run on OpenJDK 64-Bit Server VM (build 11.0.11+8-jvmci-21.1-b05) with Java process:
```
/home/commandertvis/graalvm-ce-java11/bin/java -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCIProduct -XX:-UnlockExperimentalVMOptions -XX:ThreadPriorityPolicy=1 -javaagent:/home/commandertvis/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core-jvm/1.5.0/d8cebccdcddd029022aa8646a5a953ff88b13ac8/kotlinx-coroutines-core-jvm-1.5.0.jar -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -ea
```
* JMH 1.21 was used in `thrpt` mode with 1 warmup iteration by 1000 ms and 5 measurement iterations by 1000 ms.
| Benchmark | Score |
|:---------:|:-----:|
|`space.kscience.kmath.benchmarks.JafamaBenchmark.core`|14.35014650168397 &plusmn; 0.9200669832937576 ops/s|
|`space.kscience.kmath.benchmarks.JafamaBenchmark.jafama`|12.048429204455887 &plusmn; 1.2882929181842269 ops/s|
|`space.kscience.kmath.benchmarks.JafamaBenchmark.strictJafama`|12.977653357239152 &plusmn; 1.4122819627470866 ops/s|
</details>

View File

@ -1,6 +1,6 @@
# Module kmath-kotlingrad # Module kmath-kotlingrad
[Kotlin∇](https://www.htmlsymbols.xyz/unicode/U+2207) integration module. [Kotlin∇](https://github.com/breandan/kotlingrad) integration module.
- [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression. - [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression.
- [scalars-adapters](src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST - [scalars-adapters](src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST

View File

@ -1,6 +1,6 @@
# Module kmath-kotlingrad # Module kmath-kotlingrad
[Kotlin∇](https://www.htmlsymbols.xyz/unicode/U+2207) integration module. [Kotlin∇](https://github.com/breandan/kotlingrad) integration module.
${features} ${features}

View File

@ -156,6 +156,6 @@ public expect fun Memory.Companion.allocate(length: Int): Memory
/** /**
* Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied
* and could be mutated independently from the resulting [Memory]. * and could be mutated independently of the resulting [Memory].
*/ */
public expect fun Memory.Companion.wrap(array: ByteArray): Memory public expect fun Memory.Companion.wrap(array: ByteArray): Memory

View File

@ -95,7 +95,7 @@ public actual fun Memory.Companion.allocate(length: Int): Memory {
/** /**
* Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied
* and could be mutated independently from the resulting [Memory]. * and could be mutated independently of the resulting [Memory].
*/ */
public actual fun Memory.Companion.wrap(array: ByteArray): Memory { public actual fun Memory.Companion.wrap(array: ByteArray): Memory {
@Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array @Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array

View File

@ -103,7 +103,7 @@ public actual fun Memory.Companion.allocate(length: Int): Memory =
/** /**
* Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied
* and could be mutated independently from the resulting [Memory]. * and could be mutated independently of the resulting [Memory].
*/ */
public actual fun Memory.Companion.wrap(array: ByteArray): Memory = public actual fun Memory.Companion.wrap(array: ByteArray): Memory =
ByteBufferMemory(checkNotNull(ByteBuffer.wrap(array))) ByteBufferMemory(checkNotNull(ByteBuffer.wrap(array)))

View File

@ -60,7 +60,7 @@ internal class NativeMemory(
} }
override fun writeByte(offset: Int, value: Byte) { override fun writeByte(offset: Int, value: Byte) {
array.set(position(offset), value) array[position(offset)] = value
} }
override fun writeShort(offset: Int, value: Short) { override fun writeShort(offset: Int, value: Short) {
@ -85,7 +85,7 @@ internal class NativeMemory(
/** /**
* Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied
* and could be mutated independently from the resulting [Memory]. * and could be mutated independently of the resulting [Memory].
*/ */
public actual fun Memory.Companion.wrap(array: ByteArray): Memory = NativeMemory(array) public actual fun Memory.Companion.wrap(array: ByteArray): Memory = NativeMemory(array)

View File

@ -35,7 +35,7 @@ public sealed interface Nd4jArrayAlgebra<T, out C : Algebra<T>> : AlgebraND<T, C
public fun INDArray.wrap(): Nd4jArrayStructure<T> public fun INDArray.wrap(): Nd4jArrayStructure<T>
/** /**
* Unwraps to or acquires [INDArray] from [StructureND]. * Unwraps to or get [INDArray] from [StructureND].
*/ */
public val StructureND<T>.ndArray: INDArray public val StructureND<T>.ndArray: INDArray

View File

@ -17,7 +17,7 @@ import space.kscience.kmath.nd.StructureND
*/ */
public sealed class Nd4jArrayStructure<T> : MutableStructureND<T> { public sealed class Nd4jArrayStructure<T> : MutableStructureND<T> {
/** /**
* The wrapped [INDArray]. Since KMath uses [Int] indexes, assuming that the size of [INDArray] is less or equal to * The wrapped [INDArray]. Since KMath uses [Int] indexes, assuming the size of [INDArray] is less or equal to
* [Int.MAX_VALUE]. * [Int.MAX_VALUE].
*/ */
public abstract val ndArray: INDArray public abstract val ndArray: INDArray

View File

@ -29,7 +29,7 @@ public sealed interface Nd4jTensorAlgebra<T : Number> : AnalyticTensorAlgebra<T>
public fun INDArray.wrap(): Nd4jArrayStructure<T> public fun INDArray.wrap(): Nd4jArrayStructure<T>
/** /**
* Unwraps to or acquires [INDArray] from [StructureND]. * Unwraps to or gets [INDArray] from [StructureND].
*/ */
public val StructureND<T>.ndArray: INDArray public val StructureND<T>.ndArray: INDArray

View File

@ -22,7 +22,7 @@ public interface Distribution<T : Any> : Sampler<T> {
override fun sample(generator: RandomGenerator): Chain<T> override fun sample(generator: RandomGenerator): Chain<T>
/** /**
* An empty companion. Distribution factories should be written as its extensions * An empty companion. Distribution factories should be written as its extensions.
*/ */
public companion object public companion object
} }

View File

@ -10,12 +10,12 @@ import space.kscience.kmath.chains.SimpleChain
import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
/** /**
* A multivariate distribution which takes a map of parameters * A multivariate distribution that takes a map of parameters.
*/ */
public interface NamedDistribution<T> : Distribution<Map<String, T>> public interface NamedDistribution<T> : Distribution<Map<String, T>>
/** /**
* A multivariate distribution that has independent distributions for separate axis * A multivariate distribution that has independent distributions for separate axis.
*/ */
public class FactorizedDistribution<T>(public val distributions: Collection<NamedDistribution<T>>) : public class FactorizedDistribution<T>(public val distributions: Collection<NamedDistribution<T>>) :
NamedDistribution<T> { NamedDistribution<T> {

View File

@ -110,7 +110,7 @@ internal object InternalGamma {
x <= 8.0 -> { x <= 8.0 -> {
val n = floor(x - 1.5).toInt() val n = floor(x - 1.5).toInt()
val prod = (1..n).fold(1.0, { prod, i -> prod * (x - i) }) val prod = (1..n).fold(1.0) { prod, i -> prod * (x - i) }
logGamma1p(x - (n + 1)) + ln(prod) logGamma1p(x - (n + 1)) + ln(prod)
} }

View File

@ -11,27 +11,28 @@ import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.indices import space.kscience.kmath.structures.indices
/** /**
* A likelihood function optimization problem with provided derivatives * A likelihood function optimization problem with provided derivatives.
*/ */
public interface FunctionOptimization<T : Any> : Optimization<T> { public interface FunctionOptimization<T : Any> : Optimization<T> {
/** /**
* The optimization direction. If true search for function maximum, if false, search for the minimum * The optimization direction. If true search for function maximum, if false, search for the minimum.
*/ */
public var maximize: Boolean public var maximize: Boolean
/** /**
* Define the initial guess for the optimization problem * Defines the initial guess for the optimization problem.
*/ */
public fun initialGuess(map: Map<Symbol, T>) public fun initialGuess(map: Map<Symbol, T>)
/** /**
* Set a differentiable expression as objective function as function and gradient provider * Set a differentiable expression as objective function as function and gradient provider.
*/ */
public fun diffFunction(expression: DifferentiableExpression<T>) public fun diffFunction(expression: DifferentiableExpression<T>)
public companion object { public companion object {
/** /**
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic
* differentiation.
*/ */
public fun <T : Any, I : Any, A> chiSquared( public fun <T : Any, I : Any, A> chiSquared(
autoDiff: AutoDiffProcessor<T, I, A, Expression<T>>, autoDiff: AutoDiffProcessor<T, I, A, Expression<T>>,
@ -61,7 +62,7 @@ public interface FunctionOptimization<T : Any> : Optimization<T> {
} }
/** /**
* Define a chi-squared-based objective function * Defines a chi-squared-based objective function.
*/ */
public fun <T: Any, I : Any, A> FunctionOptimization<T>.chiSquared( public fun <T: Any, I : Any, A> FunctionOptimization<T>.chiSquared(
autoDiff: AutoDiffProcessor<T, I, A, Expression<T>>, autoDiff: AutoDiffProcessor<T, I, A, Expression<T>>,
@ -76,7 +77,7 @@ public fun <T: Any, I : Any, A> FunctionOptimization<T>.chiSquared(
} }
/** /**
* Optimize differentiable expression using specific [OptimizationProblemFactory] * Optimizes differentiable expression using specific [OptimizationProblemFactory].
*/ */
public fun <T : Any, F : FunctionOptimization<T>> DifferentiableExpression<T>.optimizeWith( public fun <T : Any, F : FunctionOptimization<T>> DifferentiableExpression<T>.optimizeWith(
factory: OptimizationProblemFactory<T, F>, factory: OptimizationProblemFactory<T, F>,

View File

@ -16,7 +16,7 @@ import kotlin.math.pow
*/ */
public interface NoDerivFunctionOptimization<T : Any> : Optimization<T> { public interface NoDerivFunctionOptimization<T : Any> : Optimization<T> {
/** /**
* The optimization direction. If true search for function maximum, if false, search for the minimum * The optimization direction. If `true` search for function maximum, search for the minimum otherwise.
*/ */
public var maximize: Boolean public var maximize: Boolean

View File

@ -24,7 +24,7 @@ public operator fun <T> OptimizationResult<T>.plus(
): OptimizationResult<T> = OptimizationResult(point, value, features + feature) ): OptimizationResult<T> = OptimizationResult(point, value, features + feature)
/** /**
* An optimization problem builder over [T] variables * A builder of optimization problems over [T] variables
*/ */
public interface Optimization<T : Any> { public interface Optimization<T : Any> {

View File

@ -14,9 +14,9 @@ import kotlin.math.*
/** /**
* Sampling from the [gamma distribution](http://mathworld.wolfram.com/GammaDistribution.html). * Sampling from the [gamma distribution](http://mathworld.wolfram.com/GammaDistribution.html).
* - For 0 < alpha < 1: * * For 0 < alpha < 1:
* Ahrens, J. H. and Dieter, U., Computer methods for sampling from gamma, beta, Poisson and binomial distributions, Computing, 12, 223-246, 1974. * Ahrens, J. H. and Dieter, U., Computer methods for sampling from gamma, beta, Poisson and binomial distributions, Computing, 12, 223-246, 1974.
* - For alpha >= 1: * * For alpha >= 1:
* Marsaglia and Tsang, A Simple Method for Generating Gamma Variables. ACM Transactions on Mathematical Software, Volume 26 Issue 3, September, 2000. * Marsaglia and Tsang, A Simple Method for Generating Gamma Variables. ACM Transactions on Mathematical Software, Volume 26 Issue 3, September, 2000.
* *
* Based on Commons RNG implementation. * Based on Commons RNG implementation.

View File

@ -20,7 +20,7 @@ import kotlin.math.min
* implements Vose's algorithm. * implements Vose's algorithm.
* *
* Vose, M.D., A linear algorithm for generating random numbers with a given distribution, IEEE Transactions on * Vose, M.D., A linear algorithm for generating random numbers with a given distribution, IEEE Transactions on
* Software Engineering, 17, 972-975, 1991. he algorithm will sample values in O(1) time after a pre-processing step * Software Engineering, 17, 972-975, 1991. The algorithm will sample values in O(1) time after a pre-processing step
* of O(n) time. * of O(n) time.
* *
* The alias tables are constructed using fraction probabilities with an assumed denominator of 253. In the generic * The alias tables are constructed using fraction probabilities with an assumed denominator of 253. In the generic
@ -77,7 +77,7 @@ public open class AliasMethodDiscreteSampler private constructor(
} }
override fun sample(generator: RandomGenerator): Chain<Int> = generator.chain { override fun sample(generator: RandomGenerator): Chain<Int> = generator.chain {
// This implements the algorithm as per Vose (1991): // This implements the algorithm in accordance with Vose (1991):
// v = uniform() in [0, 1) // v = uniform() in [0, 1)
// j = uniform(n) in [0, n) // j = uniform(n) in [0, n)
// if v < prob[j] then // if v < prob[j] then
@ -95,7 +95,7 @@ public open class AliasMethodDiscreteSampler private constructor(
// p(j) == 1 => j // p(j) == 1 => j
// However it is assumed these edge cases are rare: // However it is assumed these edge cases are rare:
// //
// The probability table will be 1 for approximately 1/n samples, i.e. only the // The probability table will be 1 for approximately 1/n samples i.e., only the
// last unpaired probability. This is only worth checking for when the table size (n) // last unpaired probability. This is only worth checking for when the table size (n)
// is small. But in that case the user should zero-pad the table for performance. // is small. But in that case the user should zero-pad the table for performance.
// //
@ -211,7 +211,7 @@ public open class AliasMethodDiscreteSampler private constructor(
// c: 2=2/3; 6=1/3 (6 is the alias) // c: 2=2/3; 6=1/3 (6 is the alias)
// d: 1=1/3; 6=2/3 (6 is the alias) // d: 1=1/3; 6=2/3 (6 is the alias)
// //
// The sample is obtained by randomly selecting a section, then choosing which category // The sample is obtained by randomly selecting a section, then choosing, which category
// from the pair based on a uniform random deviate. // from the pair based on a uniform random deviate.
val sumProb = InternalUtils.validateProbabilities(probabilities) val sumProb = InternalUtils.validateProbabilities(probabilities)
// Allow zero-padding // Allow zero-padding
@ -241,9 +241,9 @@ public open class AliasMethodDiscreteSampler private constructor(
val alias = IntArray(n) val alias = IntArray(n)
// This loop uses each large in turn to fill the alias table for small probabilities that // This loop uses each large in turn to fill the alias table for small probabilities that
// do not reach the requirement to fill an entire section alone (i.e. p < mean). // do not reach the requirement to fill an entire section alone (i.e., p < mean).
// Since the sum of the small should be less than the sum of the large it should use up // Since the sum of the small should be less than the sum of the large it should use up
// all the small first. However floating point round-off can result in // all the small first. However, floating point round-off can result in
// misclassification of items as small or large. The Vose algorithm handles this using // misclassification of items as small or large. The Vose algorithm handles this using
// a while loop conditioned on the size of both sets and a subsequent loop to use // a while loop conditioned on the size of both sets and a subsequent loop to use
// unpaired items. // unpaired items.

View File

@ -13,7 +13,7 @@ import kotlin.math.exp
/** /**
* Sampler for the Poisson distribution. * Sampler for the Poisson distribution.
* - Kemp, A, W, (1981) Efficient Generation of Logarithmically Distributed Pseudo-Random Variables. Journal of the Royal Statistical Society. Vol. 30, No. 3, pp. 249-253. * * Kemp, A, W, (1981) Efficient Generation of Logarithmically Distributed Pseudo-Random Variables. Journal of the Royal Statistical Society. Vol. 30, No. 3, pp. 249-253.
* This sampler is suitable for mean < 40. For large means, LargeMeanPoissonSampler should be used instead. * This sampler is suitable for mean < 40. For large means, LargeMeanPoissonSampler should be used instead.
* *
* Note: The algorithm uses a recurrence relation to compute the Poisson probability and a rolling summation for the cumulative probability. When the mean is large the initial probability (Math.exp(-mean)) is zero and an exception is raised by the constructor. * Note: The algorithm uses a recurrence relation to compute the Poisson probability and a rolling summation for the cumulative probability. When the mean is large the initial probability (Math.exp(-mean)) is zero and an exception is raised by the constructor.
@ -66,8 +66,7 @@ public class KempSmallMeanPoissonSampler internal constructor(
public fun KempSmallMeanPoissonSampler(mean: Double): KempSmallMeanPoissonSampler { public fun KempSmallMeanPoissonSampler(mean: Double): KempSmallMeanPoissonSampler {
require(mean > 0) { "Mean is not strictly positive: $mean" } require(mean > 0) { "Mean is not strictly positive: $mean" }
val p0 = exp(-mean) val p0 = exp(-mean)
// Probability must be positive. As mean increases then p(0) decreases. // Probability must be positive. As mean increases, p(0) decreases.
require(p0 > 0) { "No probability for mean: $mean" } require(p0 > 0) { "No probability for mean: $mean" }
return KempSmallMeanPoissonSampler(p0, mean) return KempSmallMeanPoissonSampler(p0, mean)
} }

View File

@ -18,11 +18,11 @@ private const val PIVOT = 40.0
/** /**
* Sampler for the Poisson distribution. * Sampler for the Poisson distribution.
* - For small means, a Poisson process is simulated using uniform deviates, as described in * * For small means, a Poisson process is simulated using uniform deviates, as described in
* Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3 * Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3
* Important integer-valued distributions: The Poisson distribution. Addison Wesley. * Important integer-valued distributions: The Poisson distribution. Addison Wesley.
* The Poisson process (and hence, the returned value) is bounded by 1000 * mean. * The Poisson process (and hence, the returned value) is bounded by 1000 * mean.
* - For large means, we use the rejection algorithm described in * * For large means, we use the rejection algorithm described in
* Devroye, Luc. (1981). The Computer Generation of Poisson Random Variables Computing vol. 26 pp. 197-207. * Devroye, Luc. (1981). The Computer Generation of Poisson Random Variables Computing vol. 26 pp. 197-207.
* *
* Based on Commons RNG implementation. * Based on Commons RNG implementation.
@ -35,10 +35,10 @@ public fun PoissonSampler(mean: Double): Sampler<Int> {
/** /**
* Sampler for the Poisson distribution. * Sampler for the Poisson distribution.
* - For small means, a Poisson process is simulated using uniform deviates, as described in * * For small means, a Poisson process is simulated using uniform deviates, as described in
* Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3 Important * Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3 Important
* integer-valued distributions: The Poisson distribution. Addison Wesley. * integer-valued distributions: The Poisson distribution. Addison Wesley.
* - The Poisson process (and hence, the returned value) is bounded by 1000 * mean. * * The Poisson process (and hence, the returned value) is bounded by 1000 * mean.
* This sampler is suitable for mean < 40. For large means, [LargeMeanPoissonSampler] should be used instead. * This sampler is suitable for mean < 40. For large means, [LargeMeanPoissonSampler] should be used instead.
* *
* Based on Commons RNG implementation. * Based on Commons RNG implementation.

View File

@ -23,7 +23,7 @@ public interface RandomGenerator {
public fun nextDouble(): Double public fun nextDouble(): Double
/** /**
* A chunk of doubles of given [size] * A chunk of doubles of given [size].
*/ */
public fun nextDoubleBuffer(size: Int): DoubleBuffer = DoubleBuffer(size) { nextDouble() } public fun nextDoubleBuffer(size: Int): DoubleBuffer = DoubleBuffer(size) { nextDouble() }
@ -57,7 +57,7 @@ public interface RandomGenerator {
public fun nextLong(until: Long): Long public fun nextLong(until: Long): Long
/** /**
* Fills a subrange of the specified byte [array] starting from [fromIndex] inclusive and ending [toIndex] exclusive * Fills a subrange with the specified byte [array] starting from [fromIndex] inclusive and ending [toIndex] exclusive
* with random bytes. * with random bytes.
* *
* @return [array] with the subrange filled with random bytes. * @return [array] with the subrange filled with random bytes.
@ -70,7 +70,7 @@ public interface RandomGenerator {
public fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) } public fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) }
/** /**
* Create a new generator which is independent from current generator (operations on new generator do not affect this one * Create a new generator that is independent of current generator (operations on new generator do not affect this one
* and vise versa). The statistical properties of new generator should be the same as for this one. * and vise versa). The statistical properties of new generator should be the same as for this one.
* For pseudo-random generator, the fork is keeping the same sequence of numbers for given call order for each run. * For pseudo-random generator, the fork is keeping the same sequence of numbers for given call order for each run.
* *

View File

@ -32,7 +32,7 @@ public class BasicSampler<out T : Any>(public val chainBuilder: (RandomGenerator
} }
/** /**
* A space of samplers. Allows to perform simple operations on distributions. * A space of samplers. Allows performing simple operations on distributions.
* *
* @property algebra the space to provide addition and scalar multiplication for [T]. * @property algebra the space to provide addition and scalar multiplication for [T].
*/ */

View File

@ -30,9 +30,10 @@ public interface BlockingStatistic<in T, out R> : Statistic<T, R> {
/** /**
* A statistic tha could be computed separately on different blocks of data and then composed * A statistic tha could be computed separately on different blocks of data and then composed
* @param T - source type *
* @param I - intermediate block type * @param T the source type.
* @param R - result type * @param I the intermediate block type.
* @param R the result type.
*/ */
public interface ComposableStatistic<in T, I, out R> : Statistic<T, R> { public interface ComposableStatistic<in T, I, out R> : Statistic<T, R> {
//compute statistic on a single block //compute statistic on a single block

View File

@ -55,7 +55,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un
/** /**
* Generates [Byte] values and places them into a user-supplied array. * Generates [Byte] values and places them into a user-supplied array.
* *
* The number of random bytes produced is equal to the length of the the byte array. * The number of random bytes produced is equal to the length of the byte array.
* *
* @param bytes byte array in which to put the random bytes. * @param bytes byte array in which to put the random bytes.
*/ */

View File

@ -23,7 +23,7 @@ public interface LinearOpsTensorAlgebra<T> : TensorPartialDivisionAlgebra<T> {
/** /**
* Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input.
* Given a square matrix `A`, return the matrix `AInv` satisfying * Given a square matrix `A`, return the matrix `AInv` satisfying
* `A dot AInv = AInv dot A = eye(a.shape[0])`. * `A dot AInv == AInv dot A == eye(a.shape[0])`.
* For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv
* *
* @return the multiplicative inverse of a matrix. * @return the multiplicative inverse of a matrix.
@ -36,25 +36,27 @@ public interface LinearOpsTensorAlgebra<T> : TensorPartialDivisionAlgebra<T> {
* Computes the Cholesky decomposition of a Hermitian (or symmetric for real-valued matrices) * Computes the Cholesky decomposition of a Hermitian (or symmetric for real-valued matrices)
* positive-definite matrix or the Cholesky decompositions for a batch of such matrices. * positive-definite matrix or the Cholesky decompositions for a batch of such matrices.
* Each decomposition has the form: * Each decomposition has the form:
* Given a tensor `input`, return the tensor `L` satisfying `input = L dot L.H`, * Given a tensor `input`, return the tensor `L` satisfying `input = L dot LH`,
* where L is a lower-triangular matrix and L.H is the conjugate transpose of L, * where `L` is a lower-triangular matrix and `LH` is the conjugate transpose of `L`,
* which is just a transpose for the case of real-valued input matrices. * which is just a transpose for the case of real-valued input matrices.
* For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky
* *
* @return the batch of L matrices. * @receiver the `input`.
* @return the batch of `L` matrices.
*/ */
public fun Tensor<T>.cholesky(): Tensor<T> public fun Tensor<T>.cholesky(): Tensor<T>
/** /**
* QR decomposition. * QR decomposition.
* *
* Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `Q to R` of tensors.
* Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q dot R``, * Given a tensor `input`, return tensors `Q to R` satisfying `input == Q dot R`,
* with `Q` being an orthogonal matrix or batch of orthogonal matrices * with `Q` being an orthogonal matrix or batch of orthogonal matrices
* and `R` being an upper triangular matrix or batch of upper triangular matrices. * and `R` being an upper triangular matrix or batch of upper triangular matrices.
* For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr
* *
* @return pair of Q and R tensors. * @receiver the `input`.
* @return pair of `Q` and `R` tensors.
*/ */
public fun Tensor<T>.qr(): Pair<Tensor<T>, Tensor<T>> public fun Tensor<T>.qr(): Pair<Tensor<T>, Tensor<T>>
@ -67,7 +69,8 @@ public interface LinearOpsTensorAlgebra<T> : TensorPartialDivisionAlgebra<T> {
* `L` being a lower triangular matrix or batch of matrices, * `L` being a lower triangular matrix or batch of matrices,
* `U` being an upper triangular matrix or batch of matrices. * `U` being an upper triangular matrix or batch of matrices.
* *
* * @return triple of P, L and U tensors * @receiver the `input`.
* @return triple of P, L and U tensors
*/ */
public fun Tensor<T>.lu(): Triple<Tensor<T>, Tensor<T>, Tensor<T>> public fun Tensor<T>.lu(): Triple<Tensor<T>, Tensor<T>, Tensor<T>>
@ -75,22 +78,25 @@ public interface LinearOpsTensorAlgebra<T> : TensorPartialDivisionAlgebra<T> {
* Singular Value Decomposition. * Singular Value Decomposition.
* *
* Computes the singular value decomposition of either a matrix or batch of matrices `input`. * Computes the singular value decomposition of either a matrix or batch of matrices `input`.
* The singular value decomposition is represented as a triple `(U, S, V)`, * The singular value decomposition is represented as a triple `Triple(U, S, V)`,
* such that `input = U dot diagonalEmbedding(S) dot V.H`, * such that `input = U dot diagonalEmbedding(S) dot VH`,
* where V.H is the conjugate transpose of V. * where `VH` is the conjugate transpose of V.
* If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. * If `input` is a batch of tensors, then `U`, `S`, and `VH` are also batched with the same batch dimensions as
* `input`.
* For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd
* *
* @return triple `(U, S, V)`. * @receiver the `input`.
* @return triple `Triple(U, S, V)`.
*/ */
public fun Tensor<T>.svd(): Triple<Tensor<T>, Tensor<T>, Tensor<T>> public fun Tensor<T>.svd(): Triple<Tensor<T>, Tensor<T>, Tensor<T>>
/** /**
* Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, * Returns eigenvalues and eigenvectors of a real symmetric matrix `input` or a batch of real symmetric matrices,
* represented by a pair (eigenvalues, eigenvectors). * represented by a pair `eigenvalues to eigenvectors`.
* For more information: https://pytorch.org/docs/stable/generated/torch.symeig.html * For more information: https://pytorch.org/docs/stable/generated/torch.symeig.html
* *
* @return a pair (eigenvalues, eigenvectors) * @receiver the `input`.
* @return a pair `eigenvalues to eigenvectors`
*/ */
public fun Tensor<T>.symEig(): Pair<Tensor<T>, Tensor<T>> public fun Tensor<T>.symEig(): Pair<Tensor<T>, Tensor<T>>

View File

@ -14,7 +14,6 @@ import space.kscience.kmath.operations.Algebra
* @param T the type of items in the tensors. * @param T the type of items in the tensors.
*/ */
public interface TensorAlgebra<T> : Algebra<Tensor<T>> { public interface TensorAlgebra<T> : Algebra<Tensor<T>> {
/** /**
* Returns a single tensor value of unit dimension if tensor shape equals to [1]. * Returns a single tensor value of unit dimension if tensor shape equals to [1].
* *
@ -189,7 +188,7 @@ public interface TensorAlgebra<T> : Algebra<Tensor<T>> {
/** /**
* View this tensor as the same size as [other]. * View this tensor as the same size as [other].
* ``this.viewAs(other) is equivalent to this.view(other.shape)``. * `this.viewAs(other)` is equivalent to `this.view(other.shape)`.
* For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html * For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html
* *
* @param other the result tensor has the same size as other. * @param other the result tensor has the same size as other.
@ -217,14 +216,14 @@ public interface TensorAlgebra<T> : Algebra<Tensor<T>> {
* a 1 is prepended to its dimension for the purpose of the batched matrix multiply and removed after. * a 1 is prepended to its dimension for the purpose of the batched matrix multiply and removed after.
* If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix * If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix
* multiple and removed after. * multiple and removed after.
* The non-matrix (i.e. batch) dimensions are broadcast (and thus must be broadcastable). * The non-matrix (i.e., batch) dimensions are broadcast (and thus must be broadcastable).
* For example, if `input` is a (j &times; 1 &times; n &times; n) tensor and `other` is a * For example, if `input` is a (j &times; 1 &times; n &times; n) tensor and `other` is a
* (k &times; n &times; n) tensor, out will be a (j &times; k &times; n &times; n) tensor. * (k &times; n &times; n) tensor, out will be a (j &times; k &times; n &times; n) tensor.
* *
* For more information: https://pytorch.org/docs/stable/generated/torch.matmul.html * For more information: https://pytorch.org/docs/stable/generated/torch.matmul.html
* *
* @param other tensor to be multiplied * @param other tensor to be multiplied.
* @return mathematical product of two tensors * @return a mathematical product of two tensors.
*/ */
public infix fun Tensor<T>.dot(other: Tensor<T>): Tensor<T> public infix fun Tensor<T>.dot(other: Tensor<T>): Tensor<T>
@ -234,7 +233,7 @@ public interface TensorAlgebra<T> : Algebra<Tensor<T>> {
* To facilitate creating batched diagonal matrices, * To facilitate creating batched diagonal matrices,
* the 2D planes formed by the last two dimensions of the returned tensor are chosen by default. * the 2D planes formed by the last two dimensions of the returned tensor are chosen by default.
* *
* The argument [offset] controls which diagonal to consider: * The argument [offset] controls, which diagonal to consider:
* 1. If [offset] = 0, it is the main diagonal. * 1. If [offset] = 0, it is the main diagonal.
* 1. If [offset] > 0, it is above the main diagonal. * 1. If [offset] > 0, it is above the main diagonal.
* 1. If [offset] < 0, it is below the main diagonal. * 1. If [offset] < 0, it is below the main diagonal.
@ -321,7 +320,7 @@ public interface TensorAlgebra<T> : Algebra<Tensor<T>> {
* *
* @param dim the dimension to reduce. * @param dim the dimension to reduce.
* @param keepDim whether the output tensor has [dim] retained or not. * @param keepDim whether the output tensor has [dim] retained or not.
* @return the the index of maximum value of each row of the input tensor in the given dimension [dim]. * @return the index of maximum value of each row of the input tensor in the given dimension [dim].
*/ */
public fun Tensor<T>.argMax(dim: Int, keepDim: Boolean): Tensor<T> public fun Tensor<T>.argMax(dim: Int, keepDim: Boolean): Tensor<T>
} }

View File

@ -49,7 +49,7 @@ public interface TensorPartialDivisionAlgebra<T> : TensorAlgebra<T> {
/** /**
* Each element of this tensor is divided by each element of the [other] tensor. * Each element of this tensor is divided by each element of the [other] tensor.
* *
* @param other tensor to be divide by. * @param other tensor to be divided by.
*/ */
public operator fun Tensor<T>.divAssign(other: Tensor<T>) public operator fun Tensor<T>.divAssign(other: Tensor<T>)
} }

View File

@ -90,37 +90,37 @@ public open class DoubleTensorAlgebra :
} }
/** /**
* Returns a tensor filled with the scalar value 0.0, with the shape defined by the variable argument [shape]. * Returns a tensor filled with the scalar value `0.0`, with the shape defined by the variable argument [shape].
* *
* @param shape array of integers defining the shape of the output tensor. * @param shape array of integers defining the shape of the output tensor.
* @return tensor filled with the scalar value 0.0, with the [shape] shape. * @return tensor filled with the scalar value `0.0`, with the [shape] shape.
*/ */
public fun zeros(shape: IntArray): DoubleTensor = full(0.0, shape) public fun zeros(shape: IntArray): DoubleTensor = full(0.0, shape)
/** /**
* Returns a tensor filled with the scalar value 0.0, with the same shape as a given array. * Returns a tensor filled with the scalar value `0.0`, with the same shape as a given array.
* *
* @return tensor filled with the scalar value 0.0, with the same shape as `input` tensor. * @return tensor filled with the scalar value `0.0`, with the same shape as `input` tensor.
*/ */
public fun Tensor<Double>.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) public fun Tensor<Double>.zeroesLike(): DoubleTensor = tensor.fullLike(0.0)
/** /**
* Returns a tensor filled with the scalar value 1.0, with the shape defined by the variable argument [shape]. * Returns a tensor filled with the scalar value `1.0`, with the shape defined by the variable argument [shape].
* *
* @param shape array of integers defining the shape of the output tensor. * @param shape array of integers defining the shape of the output tensor.
* @return tensor filled with the scalar value 1.0, with the [shape] shape. * @return tensor filled with the scalar value `1.0`, with the [shape] shape.
*/ */
public fun ones(shape: IntArray): DoubleTensor = full(1.0, shape) public fun ones(shape: IntArray): DoubleTensor = full(1.0, shape)
/** /**
* Returns a tensor filled with the scalar value 1.0, with the same shape as a given array. * Returns a tensor filled with the scalar value `1.0`, with the same shape as a given array.
* *
* @return tensor filled with the scalar value 1.0, with the same shape as `input` tensor. * @return tensor filled with the scalar value `1.0`, with the same shape as `input` tensor.
*/ */
public fun Tensor<Double>.onesLike(): DoubleTensor = tensor.fullLike(1.0) public fun Tensor<Double>.onesLike(): DoubleTensor = tensor.fullLike(1.0)
/** /**
* Returns a 2-D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere.
* *
* @param n the number of rows and columns * @param n the number of rows and columns
* @return a 2-D tensor with ones on the diagonal and zeros elsewhere. * @return a 2-D tensor with ones on the diagonal and zeros elsewhere.
@ -311,7 +311,6 @@ public open class DoubleTensorAlgebra :
return resTensor return resTensor
} }
override fun Tensor<Double>.view(shape: IntArray): DoubleTensor { override fun Tensor<Double>.view(shape: IntArray): DoubleTensor {
checkView(tensor, shape) checkView(tensor, shape)
return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart)
@ -444,7 +443,7 @@ public open class DoubleTensorAlgebra :
/** /**
* Compares element-wise two tensors. * Compares element-wise two tensors.
* Comparison of two Double values occurs with 1e-5 precision. * Comparison of two Double values occurs with `1e-5` precision.
* *
* @param other the tensor to compare with `input` tensor. * @param other the tensor to compare with `input` tensor.
* @return true if two tensors have the same shape and elements, false otherwise. * @return true if two tensors have the same shape and elements, false otherwise.
@ -473,23 +472,24 @@ public open class DoubleTensorAlgebra :
} }
/** /**
* Returns a tensor of random numbers drawn from normal distributions with 0.0 mean and 1.0 standard deviation. * Returns a tensor of random numbers drawn from normal distributions with `0.0` mean and `1.0` standard deviation.
* *
* @param shape the desired shape for the output tensor. * @param shape the desired shape for the output tensor.
* @param seed the random seed of the pseudo-random number generator. * @param seed the random seed of the pseudo-random number generator.
* @return tensor of a given shape filled with numbers from the normal distribution * @return tensor of a given shape filled with numbers from the normal distribution
* with 0.0 mean and 1.0 standard deviation. * with `0.0` mean and `1.0` standard deviation.
*/ */
public fun randomNormal(shape: IntArray, seed: Long = 0): DoubleTensor = public fun randomNormal(shape: IntArray, seed: Long = 0): DoubleTensor =
DoubleTensor(shape, getRandomNormals(shape.reduce(Int::times), seed)) DoubleTensor(shape, getRandomNormals(shape.reduce(Int::times), seed))
/** /**
* Returns a tensor with the same shape as `input` of random numbers drawn from normal distributions * Returns a tensor with the same shape as `input` of random numbers drawn from normal distributions
* with 0.0 mean and 1.0 standard deviation. * with `0.0` mean and `1.0` standard deviation.
* *
* @receiver the `input`.
* @param seed the random seed of the pseudo-random number generator. * @param seed the random seed of the pseudo-random number generator.
* @return tensor with the same shape as `input` filled with numbers from the normal distribution * @return a tensor with the same shape as `input` filled with numbers from the normal distribution
* with 0.0 mean and 1.0 standard deviation. * with `0.0` mean and `1.0` standard deviation.
*/ */
public fun Tensor<Double>.randomNormalLike(seed: Long = 0): DoubleTensor = public fun Tensor<Double>.randomNormalLike(seed: Long = 0): DoubleTensor =
DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed))
@ -512,10 +512,10 @@ public open class DoubleTensorAlgebra :
} }
/** /**
* Builds tensor from rows of input tensor * Builds tensor from rows of the input tensor.
* *
* @param indices the [IntArray] of 1-dimensional indices * @param indices the [IntArray] of 1-dimensional indices
* @return tensor with rows corresponding to rows by [indices] * @return tensor with rows corresponding to row by [indices]
*/ */
public fun Tensor<Double>.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) public fun Tensor<Double>.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] })
@ -615,12 +615,12 @@ public open class DoubleTensorAlgebra :
} }
/** /**
* Returns the covariance matrix M of given vectors. * Returns the covariance matrix `M` of given vectors.
* *
* M[i, j] contains covariance of i-th and j-th given vectors * `M[i, j]` contains covariance of `i`-th and `j`-th given vectors
* *
* @param tensors the [List] of 1-dimensional tensors with same shape * @param tensors the [List] of 1-dimensional tensors with same shape
* @return the covariance matrix * @return `M`.
*/ */
public fun cov(tensors: List<Tensor<Double>>): DoubleTensor { public fun cov(tensors: List<Tensor<Double>>): DoubleTensor {
check(tensors.isNotEmpty()) { "List must have at least 1 element" } check(tensors.isNotEmpty()) { "List must have at least 1 element" }
@ -703,14 +703,14 @@ public open class DoubleTensorAlgebra :
/** /**
* Unpacks the data and pivots from a LU factorization of a tensor. * Unpacks the data and pivots from a LU factorization of a tensor.
* Given a tensor [luTensor], return tensors (P, L, U) satisfying ``P * luTensor = L * U``, * Given a tensor [luTensor], return tensors `Triple(P, L, U)` satisfying `P dot luTensor = L dot U`,
* with `P` being a permutation matrix or batch of matrices, * with `P` being a permutation matrix or batch of matrices,
* `L` being a lower triangular matrix or batch of matrices, * `L` being a lower triangular matrix or batch of matrices,
* `U` being an upper triangular matrix or batch of matrices. * `U` being an upper triangular matrix or batch of matrices.
* *
* @param luTensor the packed LU factorization data * @param luTensor the packed LU factorization data
* @param pivotsTensor the packed LU factorization pivots * @param pivotsTensor the packed LU factorization pivots
* @return triple of P, L and U tensors * @return triple of `P`, `L` and `U` tensors
*/ */
public fun luPivot( public fun luPivot(
luTensor: Tensor<Double>, luTensor: Tensor<Double>,
@ -746,14 +746,15 @@ public open class DoubleTensorAlgebra :
/** /**
* QR decomposition. * QR decomposition.
* *
* Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `Q to R` of tensors.
* Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q * R``, * Given a tensor `input`, return tensors `Q to R` satisfying `input == Q dot R`,
* with `Q` being an orthogonal matrix or batch of orthogonal matrices * with `Q` being an orthogonal matrix or batch of orthogonal matrices
* and `R` being an upper triangular matrix or batch of upper triangular matrices. * and `R` being an upper triangular matrix or batch of upper triangular matrices.
* *
* @param epsilon permissible error when comparing tensors for equality. * @receiver the `input`.
* @param epsilon the permissible error when comparing tensors for equality.
* Used when checking the positive definiteness of the input matrix or matrices. * Used when checking the positive definiteness of the input matrix or matrices.
* @return pair of Q and R tensors. * @return a pair of `Q` and `R` tensors.
*/ */
public fun Tensor<Double>.cholesky(epsilon: Double): DoubleTensor { public fun Tensor<Double>.cholesky(epsilon: Double): DoubleTensor {
checkSquareMatrix(shape) checkSquareMatrix(shape)
@ -793,13 +794,14 @@ public open class DoubleTensorAlgebra :
* Singular Value Decomposition. * Singular Value Decomposition.
* *
* Computes the singular value decomposition of either a matrix or batch of matrices `input`. * Computes the singular value decomposition of either a matrix or batch of matrices `input`.
* The singular value decomposition is represented as a triple `(U, S, V)`, * The singular value decomposition is represented as a triple `Triple(U, S, V)`,
* such that ``input = U.dot(diagonalEmbedding(S).dot(V.T))``. * such that `input == U dot diagonalEmbedding(S) dot V.transpose()`.
* If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. * If `input` is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as `input.
* *
* @param epsilon permissible error when calculating the dot product of vectors, * @receiver the `input`.
* i.e. the precision with which the cosine approaches 1 in an iterative algorithm. * @param epsilon permissible error when calculating the dot product of vectors
* @return triple `(U, S, V)`. * i.e., the precision with which the cosine approaches 1 in an iterative algorithm.
* @return a triple `Triple(U, S, V)`.
*/ */
public fun Tensor<Double>.svd(epsilon: Double): Triple<DoubleTensor, DoubleTensor, DoubleTensor> { public fun Tensor<Double>.svd(epsilon: Double): Triple<DoubleTensor, DoubleTensor, DoubleTensor> {
val size = tensor.dimension val size = tensor.dimension
@ -834,11 +836,11 @@ public open class DoubleTensorAlgebra :
/** /**
* Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices,
* represented by a pair (eigenvalues, eigenvectors). * represented by a pair `eigenvalues to eigenvectors`.
* *
* @param epsilon permissible error when comparing tensors for equality * @param epsilon the permissible error when comparing tensors for equality
* and when the cosine approaches 1 in the SVD algorithm. * and when the cosine approaches 1 in the SVD algorithm.
* @return a pair (eigenvalues, eigenvectors) * @return a pair `eigenvalues to eigenvectors`.
*/ */
public fun Tensor<Double>.symEig(epsilon: Double): Pair<DoubleTensor, DoubleTensor> { public fun Tensor<Double>.symEig(epsilon: Double): Pair<DoubleTensor, DoubleTensor> {
checkSymmetric(tensor, epsilon) checkSymmetric(tensor, epsilon)
@ -857,11 +859,11 @@ public open class DoubleTensorAlgebra :
* Computes the determinant of a square matrix input, or of each square matrix in a batched input * Computes the determinant of a square matrix input, or of each square matrix in a batched input
* using LU factorization algorithm. * using LU factorization algorithm.
* *
* @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero * @param epsilon the error in the LU algorithm&mdash;permissible error when comparing the determinant of a matrix
* with zero.
* @return the determinant. * @return the determinant.
*/ */
public fun Tensor<Double>.detLU(epsilon: Double = 1e-9): DoubleTensor { public fun Tensor<Double>.detLU(epsilon: Double = 1e-9): DoubleTensor {
checkSquareMatrix(tensor.shape) checkSquareMatrix(tensor.shape)
val luTensor = tensor.copy() val luTensor = tensor.copy()
val pivotsTensor = tensor.setUpPivots() val pivotsTensor = tensor.setUpPivots()
@ -889,9 +891,9 @@ public open class DoubleTensorAlgebra :
* Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input
* using LU factorization algorithm. * using LU factorization algorithm.
* Given a square matrix `a`, return the matrix `aInv` satisfying * Given a square matrix `a`, return the matrix `aInv` satisfying
* ``a.dot(aInv) = aInv.dot(a) = eye(a.shape[0])``. * `a dot aInv == aInv dot a == eye(a.shape[0])`.
* *
* @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero * @param epsilon error in the LU algorithm&mdash;permissible error when comparing the determinant of a matrix with zero
* @return the multiplicative inverse of a matrix. * @return the multiplicative inverse of a matrix.
*/ */
public fun Tensor<Double>.invLU(epsilon: Double = 1e-9): DoubleTensor { public fun Tensor<Double>.invLU(epsilon: Double = 1e-9): DoubleTensor {
@ -908,16 +910,16 @@ public open class DoubleTensorAlgebra :
} }
/** /**
* LUP decomposition * LUP decomposition.
* *
* Computes the LUP decomposition of a matrix or a batch of matrices. * Computes the LUP decomposition of a matrix or a batch of matrices.
* Given a tensor `input`, return tensors (P, L, U) satisfying ``P * input = L * U``, * Given a tensor `input`, return tensors `Triple(P, L, U)` satisfying `P dot input == L dot U`,
* with `P` being a permutation matrix or batch of matrices, * with `P` being a permutation matrix or batch of matrices,
* `L` being a lower triangular matrix or batch of matrices, * `L` being a lower triangular matrix or batch of matrices,
* `U` being an upper triangular matrix or batch of matrices. * `U` being an upper triangular matrix or batch of matrices.
* *
* @param epsilon permissible error when comparing the determinant of a matrix with zero * @param epsilon permissible error when comparing the determinant of a matrix with zero.
* @return triple of P, L and U tensors * @return triple of `P`, `L` and `U` tensors.
*/ */
public fun Tensor<Double>.lu(epsilon: Double = 1e-9): Triple<DoubleTensor, DoubleTensor, DoubleTensor> { public fun Tensor<Double>.lu(epsilon: Double = 1e-9): Triple<DoubleTensor, DoubleTensor, DoubleTensor> {
val (lu, pivots) = tensor.luFactor(epsilon) val (lu, pivots) = tensor.luFactor(epsilon)

View File

@ -14,7 +14,7 @@ import space.kscience.kmath.tensors.core.DoubleTensor
import kotlin.math.* import kotlin.math.*
/** /**
* Returns a reference to [IntArray] containing all of the elements of this [Buffer] or copy the data. * Returns a reference to [IntArray] containing all the elements of this [Buffer] or copy the data.
*/ */
internal fun Buffer<Int>.array(): IntArray = when (this) { internal fun Buffer<Int>.array(): IntArray = when (this) {
is IntBuffer -> array is IntBuffer -> array
@ -22,7 +22,7 @@ internal fun Buffer<Int>.array(): IntArray = when (this) {
} }
/** /**
* Returns a reference to [DoubleArray] containing all of the elements of this [Buffer] or copy the data. * Returns a reference to [DoubleArray] containing all the elements of this [Buffer] or copy the data.
*/ */
@PublishedApi @PublishedApi
internal fun Buffer<Double>.array(): DoubleArray = when (this) { internal fun Buffer<Double>.array(): DoubleArray = when (this) {